This example shows how to plot daily time intervals in the style of Eric Boam’s Seven Months of Sleep. (The data here is fake.)
This graph uses a time scale to plot time-of-day along the y-axis. Time scales are normally used to plot absolute time: a specific moment on a specific day in a specific year. Here, though, we’re interested in studying the daily pattern, so the start and end times for each sleep interval are converted to offsets (elapsed times) relative to the midnight immediately preceeding the start time. Given an interval d:
var midnight = d3.utcDay.floor(d[0]),
startOffset = d[0] - midnight,
endOffset = d[1] - midnight;
The offsets are measured in milliseconds since that’s the JavaScript convention. To avoid inconsistencies across browser local time zones, the dates are represented as local times in the data but parsed as UTC. The resulting Date objects are inconsistent with the original dates, but the difference is irrelevant because we just want to plot the local time-of-day.
Also, this representation makes it easy to convert an offset back to an absolute time on an arbitrary day for using with a d3.scaleUtc and d3.utcFormat. The arbitrary day is the UNIX epoch:
function date(offset) {
return new Date(offset);
}
A similar technique is used in my visualization of Eric Fischer’s Twitter feed.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.data {
fill: steelblue;
}
.axis--y .tick line {
stroke: #fff;
stroke-opacity: 0.8;
}
.axis--x .tick line {
stroke: #000;
stroke-opacity: 0.25;
}
.axis .domain {
display: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var parseTime = d3.utcParse("%Y-%m-%dT%H:%M:%S.%L"),
formatHour = d3.utcFormat("%-I:%M %p"),
formatMonth = d3.utcFormat("%B");
var svg = d3.select("svg"),
margin = {top: 0, right: 0, bottom: 0, left: 70},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleUtc()
.rangeRound([0, width]);
var y = d3.scaleUtc()
.domain([date(19.65 * 36e5), date(32.35 * 36e5)]) // about 7:40 PM to 8:20 AM
.rangeRound([0, height]);
var area = d3.area()
.curve(d3.curveStepAfter)
.x(function(d) { return x(d.day); })
.y0(function(d) { return y(date(d[0] - d.day)); })
.y1(function(d) { return y(date(d[1] - d.day)); });
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y)
.tickFormat(formatHour)
.tickSize(-width)
.tickPadding(10));
d3.csv("sleep.csv", type, function(error, data) {
if (error) throw error;
var date0 = data[0].day,
date1 = d3.utcDay.offset(data[data.length - 1].day, 1);
x.domain([date0, date1]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(formatMonth)
.tickSize(-height)
.tickPadding(-10))
.selectAll("text")
.attr("text-anchor", "start")
.attr("x", 10)
.attr("dy", null);
g.insert("path", ".axis")
.datum(data.concat({day: date1, 0: 0, 1: 0})) // for step-after
.attr("class", "data")
.attr("d", area);
});
function type(d) {
d = [parseTime(d.asleep), parseTime(d.awake)];
d.day = d3.utcDay.floor(d[0]);
return d;
}
function date(offset) {
return new Date(offset);
}
</script>
#!/usr/bin/env node
var d3 = require("d3");
var hour = 36e5,
date0 = new Date(2016, 5, 1),
date1 = d3.timeMonth.offset(date0, 7),
timeFormat = d3.timeFormat("%Y-%m-%dT%H:%M:%S.%L"),
data = d3.timeDays(date0, date1).map(fakeDatum(22 * hour, 8 * hour, 0.5 * hour));
process.stdout.write(d3.csvFormat(data) + "\n");
function fakeDatum(offset, duration, deviation) {
var random = d3.randomNormal(0, deviation);
return function(date) {
return {
asleep: timeFormat(new Date(+date + random() + offset)),
awake: timeFormat(new Date(+date + random() + offset + duration))
};
};
}
asleep,awake
2016-06-01T22:00:11.942,2016-06-02T05:24:56.877
2016-06-02T22:06:38.621,2016-06-03T05:01:12.771
2016-06-03T21:22:08.347,2016-06-04T06:38:30.906
2016-06-04T21:59:35.031,2016-06-05T04:46:39.798
2016-06-05T21:39:50.396,2016-06-06T04:40:52.970
2016-06-06T23:01:36.793,2016-06-07T06:46:53.771
2016-06-07T21:19:37.152,2016-06-08T05:54:52.999
2016-06-08T22:03:37.596,2016-06-09T05:55:48.665
2016-06-09T22:48:49.202,2016-06-10T05:44:16.569
2016-06-10T21:38:46.273,2016-06-11T04:49:54.359
2016-06-11T22:27:32.649,2016-06-12T06:03:21.422
2016-06-12T22:44:15.736,2016-06-13T07:09:17.746
2016-06-13T21:47:55.150,2016-06-14T06:28:54.528
2016-06-14T22:03:48.329,2016-06-15T05:21:41.680
2016-06-15T21:49:35.901,2016-06-16T05:55:36.426
2016-06-16T21:26:03.427,2016-06-17T06:35:43.980
2016-06-17T23:01:04.235,2016-06-18T06:10:02.337
2016-06-18T21:53:16.604,2016-06-19T05:56:33.018
2016-06-19T21:46:22.054,2016-06-20T06:16:53.612
2016-06-20T21:40:59.829,2016-06-21T06:13:21.603
2016-06-21T21:20:50.964,2016-06-22T05:57:31.615
2016-06-22T21:56:15.373,2016-06-23T05:47:55.715
2016-06-23T22:29:42.049,2016-06-24T05:57:21.136
2016-06-24T22:06:26.393,2016-06-25T06:48:54.859
2016-06-25T21:59:10.693,2016-06-26T06:02:39.104
2016-06-26T22:19:02.422,2016-06-27T06:09:21.681
2016-06-27T21:24:13.693,2016-06-28T05:46:32.159
2016-06-28T22:16:47.551,2016-06-29T05:30:29.142
2016-06-29T22:08:11.772,2016-06-30T05:44:53.721
2016-06-30T21:39:59.945,2016-07-01T06:35:02.050
2016-07-01T21:11:29.536,2016-07-02T06:40:16.195
2016-07-02T22:36:34.439,2016-07-03T06:04:45.694
2016-07-03T21:27:03.093,2016-07-04T06:08:32.228
2016-07-04T21:57:03.456,2016-07-05T06:03:17.918
2016-07-05T21:23:36.667,2016-07-06T05:55:27.259
2016-07-06T22:02:48.697,2016-07-07T05:16:21.445
2016-07-07T22:00:23.864,2016-07-08T05:52:17.379
2016-07-08T22:35:51.676,2016-07-09T05:57:14.687
2016-07-09T21:42:28.964,2016-07-10T06:39:58.602
2016-07-10T21:58:23.032,2016-07-11T06:24:59.331
2016-07-11T22:55:40.516,2016-07-12T06:16:50.101
2016-07-12T21:54:25.107,2016-07-13T06:20:14.051
2016-07-13T21:58:34.478,2016-07-14T05:04:28.938
2016-07-14T22:03:25.047,2016-07-15T06:24:51.000
2016-07-15T22:07:02.239,2016-07-16T05:12:10.988
2016-07-16T22:17:20.832,2016-07-17T06:46:13.246
2016-07-17T22:26:16.742,2016-07-18T05:11:16.263
2016-07-18T22:48:47.053,2016-07-19T05:58:40.052
2016-07-19T21:38:24.027,2016-07-20T05:35:41.065
2016-07-20T22:11:33.176,2016-07-21T05:31:28.638
2016-07-21T22:08:52.986,2016-07-22T06:29:55.395
2016-07-22T21:28:45.297,2016-07-23T06:36:12.098
2016-07-23T21:57:37.824,2016-07-24T05:56:38.309
2016-07-24T22:13:16.835,2016-07-25T06:22:41.693
2016-07-25T22:04:07.014,2016-07-26T06:00:58.073
2016-07-26T21:59:51.743,2016-07-27T06:10:38.707
2016-07-27T22:21:43.421,2016-07-28T05:38:59.399
2016-07-28T21:40:40.072,2016-07-29T05:33:41.253
2016-07-29T21:53:50.727,2016-07-30T05:06:52.643
2016-07-30T21:01:40.841,2016-07-31T06:25:19.526
2016-07-31T21:22:34.049,2016-08-01T06:02:11.300
2016-08-01T22:01:15.460,2016-08-02T05:28:35.733
2016-08-02T22:23:19.970,2016-08-03T06:16:38.863
2016-08-03T21:50:52.815,2016-08-04T05:41:15.186
2016-08-04T22:08:45.913,2016-08-05T05:34:47.699
2016-08-05T22:27:36.226,2016-08-06T06:10:01.000
2016-08-06T22:21:28.037,2016-08-07T06:12:16.517
2016-08-07T22:25:18.310,2016-08-08T06:41:58.419
2016-08-08T22:29:22.481,2016-08-09T06:06:01.048
2016-08-09T21:24:11.188,2016-08-10T05:13:49.806
2016-08-10T22:08:06.070,2016-08-11T06:13:29.810
2016-08-11T22:56:54.783,2016-08-12T07:03:33.333
2016-08-12T22:08:42.154,2016-08-13T06:48:09.494
2016-08-13T22:34:35.437,2016-08-14T06:02:18.112
2016-08-14T21:48:41.412,2016-08-15T06:26:20.858
2016-08-15T21:58:24.751,2016-08-16T05:34:26.954
2016-08-16T22:09:15.284,2016-08-17T06:01:32.671
2016-08-17T22:14:04.142,2016-08-18T06:27:57.498
2016-08-18T21:50:48.905,2016-08-19T06:40:35.026
2016-08-19T22:26:12.694,2016-08-20T06:03:47.044
2016-08-20T21:23:27.508,2016-08-21T04:53:22.649
2016-08-21T21:14:10.386,2016-08-22T05:45:17.094
2016-08-22T22:32:19.139,2016-08-23T05:27:47.498
2016-08-23T22:18:17.801,2016-08-24T05:43:31.429
2016-08-24T21:49:59.507,2016-08-25T06:21:35.597
2016-08-25T22:34:53.626,2016-08-26T06:23:46.190
2016-08-26T21:59:54.919,2016-08-27T05:41:28.656
2016-08-27T22:17:33.665,2016-08-28T06:22:43.512
2016-08-28T22:26:17.904,2016-08-29T05:56:46.079
2016-08-29T22:13:12.812,2016-08-30T06:32:15.552
2016-08-30T22:09:25.867,2016-08-31T06:08:44.253
2016-08-31T21:48:07.009,2016-09-01T06:28:38.149
2016-09-01T21:56:09.094,2016-09-02T06:01:00.956
2016-09-02T22:23:36.485,2016-09-03T06:16:00.035
2016-09-03T22:15:11.278,2016-09-04T06:45:39.631
2016-09-04T22:03:17.405,2016-09-05T05:37:23.027
2016-09-05T20:55:46.430,2016-09-06T06:02:23.536
2016-09-06T23:20:43.155,2016-09-07T06:21:55.625
2016-09-07T21:29:23.213,2016-09-08T05:58:51.733
2016-09-08T21:20:43.018,2016-09-09T05:59:53.674
2016-09-09T21:37:51.883,2016-09-10T05:56:27.781
2016-09-10T22:52:59.937,2016-09-11T06:39:25.814
2016-09-11T20:58:48.284,2016-09-12T05:52:10.124
2016-09-12T22:42:36.211,2016-09-13T06:20:24.174
2016-09-13T21:26:47.624,2016-09-14T06:22:45.357
2016-09-14T22:15:04.113,2016-09-15T05:58:24.014
2016-09-15T22:30:48.743,2016-09-16T06:14:29.037
2016-09-16T21:48:48.847,2016-09-17T05:44:32.082
2016-09-17T21:36:18.019,2016-09-18T05:59:07.454
2016-09-18T21:18:48.193,2016-09-19T05:33:37.613
2016-09-19T23:00:47.530,2016-09-20T05:50:25.413
2016-09-20T22:02:34.052,2016-09-21T06:15:21.956
2016-09-21T22:27:21.058,2016-09-22T06:51:16.539
2016-09-22T21:18:54.324,2016-09-23T06:08:52.213
2016-09-23T22:06:52.794,2016-09-24T06:02:55.204
2016-09-24T20:55:28.967,2016-09-25T06:01:37.374
2016-09-25T22:49:56.021,2016-09-26T05:25:23.372
2016-09-26T21:20:36.642,2016-09-27T06:27:11.296
2016-09-27T22:06:59.354,2016-09-28T05:43:29.519
2016-09-28T21:48:26.105,2016-09-29T06:36:00.514
2016-09-29T21:33:58.756,2016-09-30T06:59:53.779
2016-09-30T22:23:59.710,2016-10-01T05:41:11.553
2016-10-01T22:18:19.023,2016-10-02T06:07:46.209
2016-10-02T21:13:58.146,2016-10-03T05:40:54.638
2016-10-03T22:13:53.748,2016-10-04T06:16:40.628
2016-10-04T21:36:13.572,2016-10-05T05:46:26.505
2016-10-05T22:47:04.082,2016-10-06T06:16:54.190
2016-10-06T21:51:39.591,2016-10-07T05:43:58.235
2016-10-07T23:11:17.888,2016-10-08T05:43:40.614
2016-10-08T21:55:47.770,2016-10-09T06:05:27.475
2016-10-09T22:55:37.263,2016-10-10T07:02:18.046
2016-10-10T21:37:53.631,2016-10-11T05:30:50.230
2016-10-11T22:26:38.920,2016-10-12T06:00:50.667
2016-10-12T21:45:58.205,2016-10-13T05:58:11.630
2016-10-13T22:39:35.008,2016-10-14T06:28:17.236
2016-10-14T21:56:13.389,2016-10-15T06:13:19.767
2016-10-15T22:10:25.083,2016-10-16T07:00:16.188
2016-10-16T21:03:34.987,2016-10-17T06:13:49.564
2016-10-17T22:06:33.189,2016-10-18T05:50:43.757
2016-10-18T22:23:42.858,2016-10-19T05:16:27.125
2016-10-19T22:20:48.260,2016-10-20T05:36:20.362
2016-10-20T22:15:23.358,2016-10-21T06:13:50.057
2016-10-21T21:39:52.355,2016-10-22T06:06:02.845
2016-10-22T21:45:00.025,2016-10-23T06:03:11.832
2016-10-23T21:31:10.730,2016-10-24T06:20:06.396
2016-10-24T22:07:53.957,2016-10-25T06:33:50.358
2016-10-25T22:18:36.247,2016-10-26T05:45:12.212
2016-10-26T22:18:52.389,2016-10-27T05:59:50.223
2016-10-27T22:42:14.831,2016-10-28T06:12:57.580
2016-10-28T21:25:43.261,2016-10-29T06:40:36.375
2016-10-29T22:09:35.621,2016-10-30T04:22:28.969
2016-10-30T20:26:03.801,2016-10-31T04:49:25.885
2016-10-31T21:47:08.478,2016-11-01T05:34:39.103
2016-11-01T21:24:03.325,2016-11-02T06:02:53.806
2016-11-02T20:51:43.826,2016-11-03T06:05:49.063
2016-11-03T21:51:57.335,2016-11-04T05:48:59.983
2016-11-04T22:12:10.034,2016-11-05T05:57:18.667
2016-11-05T21:39:28.002,2016-11-06T06:00:20.210
2016-11-06T21:51:41.501,2016-11-07T06:47:06.210
2016-11-07T22:16:11.272,2016-11-08T05:48:00.335
2016-11-08T20:57:05.165,2016-11-09T05:49:30.976
2016-11-09T21:59:39.464,2016-11-10T06:11:19.588
2016-11-10T22:13:37.989,2016-11-11T05:57:01.287
2016-11-11T21:38:38.657,2016-11-12T06:31:12.856
2016-11-12T21:58:43.070,2016-11-13T07:21:21.669
2016-11-13T22:08:45.370,2016-11-14T05:29:38.375
2016-11-14T22:19:56.174,2016-11-15T06:29:30.474
2016-11-15T22:07:45.324,2016-11-16T05:33:20.261
2016-11-16T21:58:59.960,2016-11-17T06:32:16.830
2016-11-17T21:52:51.907,2016-11-18T06:10:07.543
2016-11-18T22:51:02.533,2016-11-19T05:43:44.644
2016-11-19T21:03:28.845,2016-11-20T06:30:22.160
2016-11-20T22:00:11.251,2016-11-21T06:11:42.886
2016-11-21T21:07:42.006,2016-11-22T05:15:17.569
2016-11-22T22:16:33.066,2016-11-23T05:35:48.042
2016-11-23T21:21:42.433,2016-11-24T06:43:50.439
2016-11-24T22:10:16.479,2016-11-25T05:24:14.501
2016-11-25T21:21:35.528,2016-11-26T05:46:37.247
2016-11-26T21:54:18.382,2016-11-27T05:22:14.885
2016-11-27T20:56:51.970,2016-11-28T06:24:23.997
2016-11-28T22:31:35.756,2016-11-29T05:38:28.878
2016-11-29T22:52:15.888,2016-11-30T05:33:58.603
2016-11-30T21:48:29.412,2016-12-01T05:46:17.146
2016-12-01T22:07:18.586,2016-12-02T06:35:23.553
2016-12-02T21:38:31.536,2016-12-03T06:33:03.987
2016-12-03T21:26:33.781,2016-12-04T05:27:06.236
2016-12-04T21:54:56.851,2016-12-05T06:01:23.206
2016-12-05T22:09:48.931,2016-12-06T06:23:59.403
2016-12-06T21:09:32.060,2016-12-07T06:26:13.400
2016-12-07T21:52:09.791,2016-12-08T05:30:50.051
2016-12-08T22:07:48.418,2016-12-09T05:44:54.568
2016-12-09T22:19:14.730,2016-12-10T06:03:07.832
2016-12-10T21:47:32.866,2016-12-11T05:38:37.218
2016-12-11T21:29:06.277,2016-12-12T06:46:29.007
2016-12-12T21:45:25.863,2016-12-13T05:54:21.639
2016-12-13T21:42:07.623,2016-12-14T05:59:25.558
2016-12-14T22:13:11.789,2016-12-15T06:06:13.621
2016-12-15T22:54:39.228,2016-12-16T06:18:43.216
2016-12-16T22:17:29.293,2016-12-17T05:25:36.101
2016-12-17T22:05:18.674,2016-12-18T06:06:02.676
2016-12-18T22:19:10.397,2016-12-19T06:18:34.049
2016-12-19T21:33:16.023,2016-12-20T06:25:11.988
2016-12-20T22:17:57.257,2016-12-21T05:47:03.158
2016-12-21T22:05:47.787,2016-12-22T06:17:23.136
2016-12-22T21:15:18.084,2016-12-23T06:30:54.819
2016-12-23T22:20:37.216,2016-12-24T06:04:28.468
2016-12-24T23:24:00.663,2016-12-25T05:56:18.096
2016-12-25T22:27:47.179,2016-12-26T05:48:14.225
2016-12-26T22:40:16.737,2016-12-27T05:51:42.063
2016-12-27T22:01:11.393,2016-12-28T06:32:49.421
2016-12-28T22:17:14.517,2016-12-29T05:37:40.144
2016-12-29T21:21:08.582,2016-12-30T05:26:38.677
2016-12-30T21:45:32.471,2016-12-31T06:15:52.291
2016-12-31T21:32:12.126,2017-01-01T06:43:38.269