@hpcc-js/observablehq-compiler 1.4.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/ojscc.mjs +13 -19
- package/dist/index.css +2 -1
- package/dist/index.css.map +7 -0
- package/dist/index.js +24 -7999
- package/dist/index.js.map +7 -1
- package/package.json +42 -52
- package/src/__package__.ts +2 -2
- package/src/compiler.ts +34 -22
- package/src/cst.ts +27 -23
- package/src/index.ts +4 -3
- package/src/observable-shim.ts +2 -0
- package/src/parse.ts +136 -0
- package/src/types.ts +180 -0
- package/src/util.ts +6 -3
- package/src/writer.ts +9 -6
- package/types/compiler.d.ts +7 -8
- package/types/cst.d.ts +0 -1
- package/types/index.d.ts +4 -4
- package/types/observable-shim.d.ts +2 -0
- package/types/parse.d.ts +26 -0
- package/types/types.d.ts +165 -0
- package/types/util.d.ts +2 -3
- package/types/writer.d.ts +2 -3
- package/dist/index.esm.css +0 -1
- package/dist/index.esm.js +0 -7999
- package/dist/index.esm.js.map +0 -1
- package/dist/index.esm.min.js +0 -4
- package/dist/index.esm.min.js.map +0 -1
- package/dist/index.min.js +0 -4
- package/dist/index.min.js.map +0 -1
- package/src/__tests__/File Attachments.ts +0 -895
- package/src/__tests__/Introduction to Imports.ts +0 -749
- package/src/__tests__/Observable TimeChart.ts +0 -772
- package/src/__tests__/index.ts +0 -13
- package/src/__tests__/m1.mjs +0 -3
- package/src/__tests__/node.ts +0 -199
- package/types/__package__.d.ts +0 -4
- package/types/__package__.d.ts.map +0 -1
- package/types/__tests__/File Attachments.d.ts +0 -110
- package/types/__tests__/File Attachments.d.ts.map +0 -1
- package/types/__tests__/Introduction to Imports.d.ts +0 -120
- package/types/__tests__/Introduction to Imports.d.ts.map +0 -1
- package/types/__tests__/Observable TimeChart.d.ts +0 -111
- package/types/__tests__/Observable TimeChart.d.ts.map +0 -1
- package/types/__tests__/index.d.ts +0 -2
- package/types/__tests__/index.d.ts.map +0 -1
- package/types/__tests__/node.d.ts +0 -2
- package/types/__tests__/node.d.ts.map +0 -1
- package/types/compiler.d.ts.map +0 -1
- package/types/cst.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/util.d.ts.map +0 -1
- package/types/writer.d.ts.map +0 -1
- package/types-3.4/__package__.d.ts +0 -4
- package/types-3.4/__tests__/File Attachments.d.ts +0 -110
- package/types-3.4/__tests__/Introduction to Imports.d.ts +0 -120
- package/types-3.4/__tests__/Observable TimeChart.d.ts +0 -111
- package/types-3.4/__tests__/index.d.ts +0 -2
- package/types-3.4/__tests__/node.d.ts +0 -2
- package/types-3.4/compiler.d.ts +0 -112
- package/types-3.4/cst.d.ts +0 -42
- package/types-3.4/index.d.ts +0 -5
- package/types-3.4/util.d.ts +0 -30
- package/types-3.4/writer.d.ts +0 -19
|
@@ -1,772 +0,0 @@
|
|
|
1
|
-
export const timechart = {
|
|
2
|
-
"id": "01b9f5889f32d3e6",
|
|
3
|
-
"slug": "timechart",
|
|
4
|
-
"trashed": false,
|
|
5
|
-
"description": "",
|
|
6
|
-
"likes": 99,
|
|
7
|
-
"publish_level": "public",
|
|
8
|
-
"forks": 1,
|
|
9
|
-
"fork_of": null,
|
|
10
|
-
"update_time": "2021-10-26T00:12:05.970Z",
|
|
11
|
-
"publish_time": "2021-04-21T16:50:27.577Z",
|
|
12
|
-
"publish_version": 1602,
|
|
13
|
-
"latest_version": 1602,
|
|
14
|
-
"thumbnail": "b5c772e23e58a13c935d721ba487648b8c81be0f03530ccdfb126cf439fc5252",
|
|
15
|
-
"default_thumbnail": "76f5a7a0f5639576fa2192726f81f687a476ae6f1760b88fc608e458088be2e6",
|
|
16
|
-
"roles": [],
|
|
17
|
-
"sharing": null,
|
|
18
|
-
"owner": {
|
|
19
|
-
"id": "f35c755083683fe5",
|
|
20
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/5a51c3b908225a581d20577e488e2aba8cbc9541c52982c638638c370c3e5e8e",
|
|
21
|
-
"login": "observablehq",
|
|
22
|
-
"name": "Observable",
|
|
23
|
-
"bio": "Use data to think, together.",
|
|
24
|
-
"home_url": "https://observablehq.com",
|
|
25
|
-
"type": "team",
|
|
26
|
-
"tier": "enterprise"
|
|
27
|
-
},
|
|
28
|
-
"creator": {
|
|
29
|
-
"id": "074c414ad1d825f5",
|
|
30
|
-
"github_login": "mbostock",
|
|
31
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
32
|
-
"login": "mbostock",
|
|
33
|
-
"name": "Mike Bostock",
|
|
34
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
35
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
36
|
-
"tier": "basic"
|
|
37
|
-
},
|
|
38
|
-
"authors": [
|
|
39
|
-
{
|
|
40
|
-
"id": "074c414ad1d825f5",
|
|
41
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
42
|
-
"name": "Mike Bostock",
|
|
43
|
-
"login": "mbostock",
|
|
44
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
45
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
46
|
-
"github_login": "mbostock",
|
|
47
|
-
"tier": "basic",
|
|
48
|
-
"approved": true,
|
|
49
|
-
"description": ""
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
"collections": [
|
|
53
|
-
{
|
|
54
|
-
"id": "7eea0c678f957b61",
|
|
55
|
-
"type": "public",
|
|
56
|
-
"slug": "libraries",
|
|
57
|
-
"title": "Libraries",
|
|
58
|
-
"description": "Reusable notebooks, ready for import and remix.",
|
|
59
|
-
"update_time": "2020-12-01T00:42:27.585Z",
|
|
60
|
-
"pinned": true,
|
|
61
|
-
"ordered": true,
|
|
62
|
-
"custom_thumbnail": "a578557db9cf6c6689c756dd42172a43ad8d87b195c9589fcbe1e9a0cae9cdef",
|
|
63
|
-
"default_thumbnail": "5a8d92da8e3ba985b0f568c02543420a883fe44998e12fb266cdb0a907d0b98d",
|
|
64
|
-
"thumbnail": "a578557db9cf6c6689c756dd42172a43ad8d87b195c9589fcbe1e9a0cae9cdef",
|
|
65
|
-
"listing_count": 25,
|
|
66
|
-
"parent_collection_count": 1,
|
|
67
|
-
"owner": {
|
|
68
|
-
"id": "f35c755083683fe5",
|
|
69
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/5a51c3b908225a581d20577e488e2aba8cbc9541c52982c638638c370c3e5e8e",
|
|
70
|
-
"login": "observablehq",
|
|
71
|
-
"name": "Observable",
|
|
72
|
-
"bio": "Use data to think, together.",
|
|
73
|
-
"home_url": "https://observablehq.com",
|
|
74
|
-
"type": "team",
|
|
75
|
-
"tier": "enterprise"
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
],
|
|
79
|
-
"files": [],
|
|
80
|
-
"comments": [
|
|
81
|
-
{
|
|
82
|
-
"id": "c1cb43d1f29b329a",
|
|
83
|
-
"content": "I don't see a demo of using TimeAxis, especially combined with a TimeChart within a single cell (to get a grid behind all the TimeCharts?)",
|
|
84
|
-
"node_id": 810,
|
|
85
|
-
"create_time": "2021-04-20T17:56:17.801Z",
|
|
86
|
-
"update_time": null,
|
|
87
|
-
"resolved": true,
|
|
88
|
-
"user": {
|
|
89
|
-
"id": "595405df3c534894",
|
|
90
|
-
"github_login": "enjalot",
|
|
91
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/549bdb0c368027004b51c4e95459e9c224331e0fec9c4cc97d181f83e55ab7f9",
|
|
92
|
-
"login": "enjalot",
|
|
93
|
-
"name": "Ian Johnson",
|
|
94
|
-
"bio": "pixel flipper, data sifter. trying to see what I can while I'm here",
|
|
95
|
-
"home_url": "http://enjalot.github.io",
|
|
96
|
-
"tier": "basic"
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
"id": "e94ad11ff619c2ae",
|
|
101
|
-
"content": "It’s not intended to be used that way, primarily; it’s intended to be used with one cell per chart, so that you can use the Observable UI to reorder the time series or comment on them separately. But we could include an example of that as an advanced topic.",
|
|
102
|
-
"node_id": 810,
|
|
103
|
-
"create_time": "2021-04-20T19:07:08.746Z",
|
|
104
|
-
"update_time": null,
|
|
105
|
-
"resolved": true,
|
|
106
|
-
"user": {
|
|
107
|
-
"id": "074c414ad1d825f5",
|
|
108
|
-
"github_login": "mbostock",
|
|
109
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
110
|
-
"login": "mbostock",
|
|
111
|
-
"name": "Mike Bostock",
|
|
112
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
113
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
114
|
-
"tier": "basic"
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"id": "c56f3e64b046d26a",
|
|
119
|
-
"content": "Added example, and also set the default marginTop to 0 instead of -16 so that you have to opt-in to the special overlapping behavior.",
|
|
120
|
-
"node_id": 810,
|
|
121
|
-
"create_time": "2021-04-21T16:32:27.753Z",
|
|
122
|
-
"update_time": null,
|
|
123
|
-
"resolved": true,
|
|
124
|
-
"user": {
|
|
125
|
-
"id": "074c414ad1d825f5",
|
|
126
|
-
"github_login": "mbostock",
|
|
127
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
128
|
-
"login": "mbostock",
|
|
129
|
-
"name": "Mike Bostock",
|
|
130
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
131
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
132
|
-
"tier": "basic"
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
"id": "a9022775a908bb19",
|
|
137
|
-
"content": "Thank you for continuing your wonderful work!\nNot to be critical, but I can't help but wonder about the usability of the TimeChart representation.\nEven after using the tooltip and reading the other notebooks that describe Horizon Charts, I struggle to understand how to interpret the combination of color and vertical offset. Perhaps adding a color swatch legend with labeled value ranges would help?\nAlso, is TimeChart recommended for any time-series or just data with smooth/continuously varying values like those that can be approximated with sine -- I wonder how easy it would be to interpret if the values did not vary smoothly, such as random values.\nThanks!",
|
|
138
|
-
"node_id": 810,
|
|
139
|
-
"create_time": "2021-04-22T18:42:36.922Z",
|
|
140
|
-
"update_time": null,
|
|
141
|
-
"resolved": true,
|
|
142
|
-
"user": {
|
|
143
|
-
"id": "ba5c813f0f621f19",
|
|
144
|
-
"github_login": "jonhelfman",
|
|
145
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/a404535763c16060490629d896d876b5b4cea8c603c4993b2aaed749a15b041a",
|
|
146
|
-
"login": "jonhelfman",
|
|
147
|
-
"name": "Jonathan Helfman",
|
|
148
|
-
"bio": "Student of math, d3, svg, etc. Prototyper of visualizations for electronics design and test. ",
|
|
149
|
-
"home_url": "",
|
|
150
|
-
"tier": "basic"
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"id": "b50ff7cf4c649ac5",
|
|
155
|
-
"content": "I’ve been using horizon charts for years (e.g. [1]) so I would say try it for a while and see if you like it? It’s definitely my go-to for looking at time series. If you have strictly random (or highly noisy) values you’re not likely to see anything interesting by visualizing anyway, so it’s hard to answer your question directly.\n\nAlso, if you want to ease it to horizon charts, you could start by setting the bands: 1 option and you’ll get a basic area chart.\n\n[1] https://square.github.io/cubism/",
|
|
156
|
-
"node_id": 810,
|
|
157
|
-
"create_time": "2021-04-22T19:07:24.992Z",
|
|
158
|
-
"update_time": null,
|
|
159
|
-
"resolved": true,
|
|
160
|
-
"user": {
|
|
161
|
-
"id": "074c414ad1d825f5",
|
|
162
|
-
"github_login": "mbostock",
|
|
163
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
164
|
-
"login": "mbostock",
|
|
165
|
-
"name": "Mike Bostock",
|
|
166
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
167
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
168
|
-
"tier": "basic"
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"id": "6a53b6d8646cf35a",
|
|
173
|
-
"content": "Thanks for your response and the link. Sorry for not being clearer, but when I ask about usability I am attempting to speak for the person who may not be an expert in interpreting visualizations. \nOur time-series customers are used to oscilloscope traces and I'm just wondering if they can benefit from horizon charts.\nSince most charts that use color to show quantities include a legend to aid interpretation, please consider this as a suggestion for possibly improving TimeChart to make it more usable/useful for the non-expert. \nRegarding the question about smoothly varying values -- yes strictly random is a bad example -- a better example would be a dataset consisting of smoothly varying values (like you have) but with some far/extreme outliers mixed in. I'm not seeing that sort of data on the Cubism page either. . .\nThanks again!",
|
|
174
|
-
"node_id": 810,
|
|
175
|
-
"create_time": "2021-04-22T22:45:28.711Z",
|
|
176
|
-
"update_time": null,
|
|
177
|
-
"resolved": true,
|
|
178
|
-
"user": {
|
|
179
|
-
"id": "ba5c813f0f621f19",
|
|
180
|
-
"github_login": "jonhelfman",
|
|
181
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/a404535763c16060490629d896d876b5b4cea8c603c4993b2aaed749a15b041a",
|
|
182
|
-
"login": "jonhelfman",
|
|
183
|
-
"name": "Jonathan Helfman",
|
|
184
|
-
"bio": "Student of math, d3, svg, etc. Prototyper of visualizations for electronics design and test. ",
|
|
185
|
-
"home_url": "",
|
|
186
|
-
"tier": "basic"
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"id": "7aeba419a860937d",
|
|
191
|
-
"content": "I recommend reading the paper for more about the rationale for the design of horizon charts:\n\nhttp://vis.berkeley.edu/papers/horizon/\n\nIn my experience, yes, horizon charts do take a bit of introduction, but that readers quickly become familiar with the form and find it intuitive. I feel horizon charts are best for displays such as time-series dashboards that you look at frequently or repeatedly; if it’s a form that you see often, the cost of learning the form is amortized over time. Horizon charts are especially good because you can see both small variations (within a band = position) and large variations (across bands = color). That’s what is meant by a “compact” representation versus the equivalent area chart.\n\nAs a practical matter, there isn’t really room for a y-axis with this sort of display, and it would introduce a lot of noise if you repeated it for each chart. It might be reasonable to include a threshold color legend (see https://observablehq.com/@d3/color-legend for one implementation) but since the display is interactive rather than static you can also simply mouseover the chart to read the exact values.\n\nWe once used horizon charts on the front page of the New York Times in print. I can’t find a good link for it, and admittedly it was only a single-band horizon chart with diverging values (for the forecast probabilities of Republican and Democrat Senate candidates), but here’s a Pinterest screenshot someone captured:\n\nhttps://user-images.githubusercontent.com/230541/115891515-04611980-a40b-11eb-8af9-20afa344f93f.png",
|
|
192
|
-
"node_id": 810,
|
|
193
|
-
"create_time": "2021-04-23T15:12:13.029Z",
|
|
194
|
-
"update_time": null,
|
|
195
|
-
"resolved": true,
|
|
196
|
-
"user": {
|
|
197
|
-
"id": "074c414ad1d825f5",
|
|
198
|
-
"github_login": "mbostock",
|
|
199
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
200
|
-
"login": "mbostock",
|
|
201
|
-
"name": "Mike Bostock",
|
|
202
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
203
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
204
|
-
"tier": "basic"
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
"id": "9f98adbdc28e3ce5",
|
|
209
|
-
"content": "Being able to specify a baseline around which the values hover around would be convenient as well. E.g. values that hover around 1.",
|
|
210
|
-
"node_id": 915,
|
|
211
|
-
"create_time": "2021-04-22T16:19:51.661Z",
|
|
212
|
-
"update_time": null,
|
|
213
|
-
"resolved": true,
|
|
214
|
-
"user": {
|
|
215
|
-
"id": "3c5ecb707ecd20a7",
|
|
216
|
-
"github_login": "Martien",
|
|
217
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/40dc8e4f86d0cf89184b173b4d1d88336e5728c175479f33261ced3496adb3c2",
|
|
218
|
-
"login": "martien",
|
|
219
|
-
"name": "Martien van Steenbergen",
|
|
220
|
-
"bio": "Wise Fool.\nVisioneer.",
|
|
221
|
-
"home_url": "http://aardrock.com",
|
|
222
|
-
"tier": "basic"
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
"id": "a17cc51c55fb0a8b",
|
|
227
|
-
"content": "The charts assume a zero baseline, but you could pass TimeChart values that are relative to the baseline if you prefer (and you could use a custom format function to undo the effect of the baseline). For example, data.map(({date, value}) => ({date, value: value - 1})) and then {format: value => value + 1}.",
|
|
228
|
-
"node_id": 915,
|
|
229
|
-
"create_time": "2021-04-22T17:05:46.431Z",
|
|
230
|
-
"update_time": null,
|
|
231
|
-
"resolved": true,
|
|
232
|
-
"user": {
|
|
233
|
-
"id": "074c414ad1d825f5",
|
|
234
|
-
"github_login": "mbostock",
|
|
235
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
236
|
-
"login": "mbostock",
|
|
237
|
-
"name": "Mike Bostock",
|
|
238
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
239
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
240
|
-
"tier": "basic"
|
|
241
|
-
}
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
"id": "535d199303fa5090",
|
|
245
|
-
"content": "Yes, thanks. I’m doing the value: value - 1. The format: value + 1 is a nice touch which I didn’t realise at first. See https://observablehq.com/@martien/covid-19-netherlands-basic-reproduction-number-timechart",
|
|
246
|
-
"node_id": 915,
|
|
247
|
-
"create_time": "2021-04-22T18:21:57.507Z",
|
|
248
|
-
"update_time": null,
|
|
249
|
-
"resolved": true,
|
|
250
|
-
"user": {
|
|
251
|
-
"id": "3c5ecb707ecd20a7",
|
|
252
|
-
"github_login": "Martien",
|
|
253
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/40dc8e4f86d0cf89184b173b4d1d88336e5728c175479f33261ced3496adb3c2",
|
|
254
|
-
"login": "martien",
|
|
255
|
-
"name": "Martien van Steenbergen",
|
|
256
|
-
"bio": "Wise Fool.\nVisioneer.",
|
|
257
|
-
"home_url": "http://aardrock.com",
|
|
258
|
-
"tier": "basic"
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
"id": "05c41aea14c99db4",
|
|
263
|
-
"content": "Would \"wrap\" perhaps have been a better choice, given that negative values wrap around on y?",
|
|
264
|
-
"node_id": 1152,
|
|
265
|
-
"create_time": "2021-04-22T09:13:44.338Z",
|
|
266
|
-
"update_time": null,
|
|
267
|
-
"resolved": true,
|
|
268
|
-
"user": {
|
|
269
|
-
"id": "07362516b5994994",
|
|
270
|
-
"github_login": "mootari",
|
|
271
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/0d7defa821f38094c03bad23b9b360a5364e6e97e21fc238c39ddc48db7994ad",
|
|
272
|
-
"login": "mootari",
|
|
273
|
-
"name": "Fabian Iwand",
|
|
274
|
-
"bio": "Web developer and autodidact with an interest in creative coding.",
|
|
275
|
-
"home_url": "https://twitter.com/mootari",
|
|
276
|
-
"tier": "basic"
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
"id": "d7ad16ddd73edf8d",
|
|
281
|
-
"content": "This terminology was adopted from the original horizon charts paper. See figure 2.\n\nhttp://vis.berkeley.edu/papers/horizon/2009-TimeSeries-CHI.pdf",
|
|
282
|
-
"node_id": 1152,
|
|
283
|
-
"create_time": "2021-04-22T17:04:14.382Z",
|
|
284
|
-
"update_time": null,
|
|
285
|
-
"resolved": true,
|
|
286
|
-
"user": {
|
|
287
|
-
"id": "074c414ad1d825f5",
|
|
288
|
-
"github_login": "mbostock",
|
|
289
|
-
"avatar_url": "https://avatars.observableusercontent.com/avatar/82811927da99f8938001b2ef1f552ad2c47083e46ebc55a3a146a5a5848c4519",
|
|
290
|
-
"login": "mbostock",
|
|
291
|
-
"name": "Mike Bostock",
|
|
292
|
-
"bio": "Building a better computational medium. Founder @observablehq. Creator @d3. Former @nytgraphics. Pronounced BOSS-tock.",
|
|
293
|
-
"home_url": "https://bost.ocks.org/mike/",
|
|
294
|
-
"tier": "basic"
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
],
|
|
298
|
-
"commenting_lock": null,
|
|
299
|
-
"suggestion_from": null,
|
|
300
|
-
"suggestions_to": [],
|
|
301
|
-
"version": 1602,
|
|
302
|
-
"title": "Observable TimeChart",
|
|
303
|
-
"license": "isc",
|
|
304
|
-
"copyright": "Copyright 2021 Observable, Inc.",
|
|
305
|
-
"nodes": [
|
|
306
|
-
{
|
|
307
|
-
"id": 0,
|
|
308
|
-
"value": "md`<h1 style=\"display: none;\">Observable TimeChart</h1>\n\n# TimeChart\n\nTimeChart is an importable component for visualizing time-series data. It can show many signals time-aligned as space-efficient horizon charts. If you hover over a chart, all charts on the page show the value at that time, aiding interpretation.`",
|
|
309
|
-
"pinned": false,
|
|
310
|
-
"mode": "js",
|
|
311
|
-
"data": null,
|
|
312
|
-
"name": null
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
"id": 472,
|
|
316
|
-
"value": "TimeAxis({interval, start, stop})",
|
|
317
|
-
"pinned": false,
|
|
318
|
-
"mode": "js",
|
|
319
|
-
"data": null,
|
|
320
|
-
"name": null
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
"id": 475,
|
|
324
|
-
"value": "viewof blues = TimeChart(wave({max: 100, round: true}), {title: \"Blues\", interval, start, stop, max: 100, scheme: \"blues\", marginTop: -16})",
|
|
325
|
-
"pinned": false,
|
|
326
|
-
"mode": "js",
|
|
327
|
-
"data": null,
|
|
328
|
-
"name": null
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
"id": 481,
|
|
332
|
-
"value": "viewof greens = TimeChart(add(wave({max: 100, round: true, shift: 50, pow: 20}), wave({max: 20, round: true, period: 12})), {title: \"Greens\", interval, start, stop, max: 120, scheme: \"greens\", marginTop: -16})",
|
|
333
|
-
"pinned": false,
|
|
334
|
-
"mode": "js",
|
|
335
|
-
"data": null,
|
|
336
|
-
"name": null
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
"id": 478,
|
|
340
|
-
"value": "viewof reds = TimeChart(add(blues, greens), {title: \"Reds\", interval, start, stop, max: 130, scheme: \"reds\", marginTop: -16})",
|
|
341
|
-
"pinned": false,
|
|
342
|
-
"mode": "js",
|
|
343
|
-
"data": null,
|
|
344
|
-
"name": null
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
"id": 810,
|
|
348
|
-
"value": "md`To use in your notebook:\n\n~~~js\nimport {TimeChart, TimeAxis} from \"@observablehq/timechart\"\n~~~\n\nThen, call TimeChart and TimeAxis to create charts as described below.`",
|
|
349
|
-
"pinned": false,
|
|
350
|
-
"mode": "js",
|
|
351
|
-
"data": null,
|
|
352
|
-
"name": null
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
"id": 437,
|
|
356
|
-
"value": "md`---\n\n## Configuration\n\nTimeChart expects a consistent *x*-axis across plots so that you can see coincident patterns. TimeChart also expects exactly one data point per pixel to maximize data density. When you call TimeChart and TimeAxis, you pass in these options.`",
|
|
357
|
-
"pinned": false,
|
|
358
|
-
"mode": "js",
|
|
359
|
-
"data": null,
|
|
360
|
-
"name": null
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
"id": 409,
|
|
364
|
-
"value": "interval = d3.utcMinute.every(10) // sample frequency",
|
|
365
|
-
"pinned": true,
|
|
366
|
-
"mode": "js",
|
|
367
|
-
"data": null,
|
|
368
|
-
"name": null
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
"id": 268,
|
|
372
|
-
"value": "stop = interval() // exclusive",
|
|
373
|
-
"pinned": true,
|
|
374
|
-
"mode": "js",
|
|
375
|
-
"data": null,
|
|
376
|
-
"name": null
|
|
377
|
-
},
|
|
378
|
-
{
|
|
379
|
-
"id": 270,
|
|
380
|
-
"value": "start = interval.offset(stop, -width) // inclusive",
|
|
381
|
-
"pinned": true,
|
|
382
|
-
"mode": "js",
|
|
383
|
-
"data": null,
|
|
384
|
-
"name": null
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
"id": 875,
|
|
388
|
-
"value": "md`TimeChart expects *interval* to be specified as a [d3-time interval](https://github.com/d3/d3-time), though you can also use a named time interval such as “hour” or “minute” if you prefer.`",
|
|
389
|
-
"pinned": false,
|
|
390
|
-
"mode": "js",
|
|
391
|
-
"data": null,
|
|
392
|
-
"name": null
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
"id": 418,
|
|
396
|
-
"value": "md`---\n\n## Example usage\n\nFirst we need data: an array of {*date*, *value*} objects at the expected time interval, such as hourly. TimeChart treats missing data as having zero value. We’ll use fake data here (a sine wave with random noise). You’ll want to replace this fake data with a [database client](/@observablehq/databases) or by fetching from an API.`",
|
|
397
|
-
"pinned": false,
|
|
398
|
-
"mode": "js",
|
|
399
|
-
"data": null,
|
|
400
|
-
"name": null
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
"id": 267,
|
|
404
|
-
"value": "signups = wave({min: 0, max: 200, period: 120, round: true}) // fake data!",
|
|
405
|
-
"pinned": true,
|
|
406
|
-
"mode": "js",
|
|
407
|
-
"data": null,
|
|
408
|
-
"name": null
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
"id": 493,
|
|
412
|
-
"value": "md`Next we need an axis. This is a separate component so that it needn’t be repeated for each chart. Sprinkle as many as you like throughout your notebook.`",
|
|
413
|
-
"pinned": false,
|
|
414
|
-
"mode": "js",
|
|
415
|
-
"data": null,
|
|
416
|
-
"name": null
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
"id": 466,
|
|
420
|
-
"value": "TimeAxis({interval, start, stop})",
|
|
421
|
-
"pinned": true,
|
|
422
|
-
"mode": "js",
|
|
423
|
-
"data": null,
|
|
424
|
-
"name": null
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
"id": 498,
|
|
428
|
-
"value": "md`Lastly, a chart! TimeChart takes two arguments, *data* and *options*. The *data* an array of {*date*, *value*} objects, as shown above. Three options are required, and below we pass in the corresponding cells of the same name we defined above:\n\n* *interval* - the time interval of the data (*e.g.*, hourly)\n* *start* - the start time of the chart (inclusive)\n* *stop* - the stop time of the chart (exclusive)\n\nIn addition, we recommend:\n\n* *title* - so that people know what they’re looking at\n* *max* - the maximum expected *y*-value, for consistency over time`",
|
|
429
|
-
"pinned": false,
|
|
430
|
-
"mode": "js",
|
|
431
|
-
"data": null,
|
|
432
|
-
"name": null
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
"id": 72,
|
|
436
|
-
"value": "TimeChart(signups, {interval, start, stop, title: \"Sign-ups\", max: 240})",
|
|
437
|
-
"pinned": true,
|
|
438
|
-
"mode": "js",
|
|
439
|
-
"data": null,
|
|
440
|
-
"name": null
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
"id": 905,
|
|
444
|
-
"value": "md`TimeChart generates a [horizon chart](/@d3/horizon-chart) with four bands by default. You can change the number of bands as desired. A single band will produce a conventional area chart.`",
|
|
445
|
-
"pinned": false,
|
|
446
|
-
"mode": "js",
|
|
447
|
-
"data": null,
|
|
448
|
-
"name": null
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
"id": 911,
|
|
452
|
-
"value": "TimeChart(signups, {interval, start, stop, title: \"Sign-ups\", max: 240, bands: 1})",
|
|
453
|
-
"pinned": true,
|
|
454
|
-
"mode": "js",
|
|
455
|
-
"data": null,
|
|
456
|
-
"name": null
|
|
457
|
-
},
|
|
458
|
-
{
|
|
459
|
-
"id": 1325,
|
|
460
|
-
"value": "md`The *scheme* option, which defaults to RdGy—red for negative, gray for positive—controls which colors are used for the bands. All ColorBrewer sequential and diverging color schemes are supported; see [D3 Color Schemes](/@d3/color-schemes). You may also pass in an array of arrays as the *scheme* argument following the same structure as D3 (*e.g.*, d3.schemeBlues).`",
|
|
461
|
-
"pinned": false,
|
|
462
|
-
"mode": "js",
|
|
463
|
-
"data": null,
|
|
464
|
-
"name": null
|
|
465
|
-
},
|
|
466
|
-
{
|
|
467
|
-
"id": 1330,
|
|
468
|
-
"value": "TimeChart(signups, {interval, start, stop, title: \"Sign-ups\", max: 240, scheme: \"PuRd\"})",
|
|
469
|
-
"pinned": true,
|
|
470
|
-
"mode": "js",
|
|
471
|
-
"data": null,
|
|
472
|
-
"name": null
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
"id": 915,
|
|
476
|
-
"value": "md`---\n\n## Advanced usage: negative values\n\nIf the data includes negative values, these values will by default hang down from the top of the chart in red.`",
|
|
477
|
-
"pinned": false,
|
|
478
|
-
"mode": "js",
|
|
479
|
-
"data": null,
|
|
480
|
-
"name": null
|
|
481
|
-
},
|
|
482
|
-
{
|
|
483
|
-
"id": 970,
|
|
484
|
-
"value": "TimeChart(posneg, {interval, start, stop})",
|
|
485
|
-
"pinned": false,
|
|
486
|
-
"mode": "js",
|
|
487
|
-
"data": null,
|
|
488
|
-
"name": null
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
"id": 1464,
|
|
492
|
-
"value": "md`Plotting negative values is also useful for paired signals, for example incoming (positive) and outgoing (negative) traffic volume to a network switch. Set the *marginTop* option to -16 to remove the gap between cells.`",
|
|
493
|
-
"pinned": false,
|
|
494
|
-
"mode": "js",
|
|
495
|
-
"data": null,
|
|
496
|
-
"name": null
|
|
497
|
-
},
|
|
498
|
-
{
|
|
499
|
-
"id": 1455,
|
|
500
|
-
"value": "TimeChart(wave({min: 0, max: 1}), {title: \"Incoming\", interval, start, stop, max: 1, format: \"+.2f\"})",
|
|
501
|
-
"pinned": false,
|
|
502
|
-
"mode": "js",
|
|
503
|
-
"data": null,
|
|
504
|
-
"name": null
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
"id": 1457,
|
|
508
|
-
"value": "TimeChart(wave({min: 0, max: -1}), {title: \"Outgoing\", interval, start, stop, max: 1, marginTop: -16, format: \"+.2f\"})",
|
|
509
|
-
"pinned": false,
|
|
510
|
-
"mode": "js",
|
|
511
|
-
"data": null,
|
|
512
|
-
"name": null
|
|
513
|
-
},
|
|
514
|
-
{
|
|
515
|
-
"id": 1178,
|
|
516
|
-
"value": "md`The *mode* option changes the behavior of the horizon chart for negative values. The allowed values are:\n\n* *offset* - negative values to hang down from the top\n* *mirror* - reflect so that negative values grow up from the bottom\n\nThe default *offset* mode is preferred for accessibility, as *mirror* relys solely on hue to distinguish between positive and negative values. To better show the two modes, below are single-band charts without random noise.`",
|
|
517
|
-
"pinned": false,
|
|
518
|
-
"mode": "js",
|
|
519
|
-
"data": null,
|
|
520
|
-
"name": null
|
|
521
|
-
},
|
|
522
|
-
{
|
|
523
|
-
"id": 1152,
|
|
524
|
-
"value": "TimeChart(wave({min: -1, max: 1, noise: 0}), {interval, start, stop, bands: 1, mode: \"offset\"})",
|
|
525
|
-
"pinned": true,
|
|
526
|
-
"mode": "js",
|
|
527
|
-
"data": null,
|
|
528
|
-
"name": null
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
"id": 1181,
|
|
532
|
-
"value": "TimeChart(wave({min: -1, max: 1, noise: 0}), {interval, start, stop, bands: 1, mode: \"mirror\"})",
|
|
533
|
-
"pinned": true,
|
|
534
|
-
"mode": "js",
|
|
535
|
-
"data": null,
|
|
536
|
-
"name": null
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
"id": 1194,
|
|
540
|
-
"value": "md`You should choose a diverging color scheme when plotting negative values: BrBG, PRGn, PiYG, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, or Spectral. If you specify a sequential color scheme (such as blues), negative values will be drawn in gray.`",
|
|
541
|
-
"pinned": false,
|
|
542
|
-
"mode": "js",
|
|
543
|
-
"data": null,
|
|
544
|
-
"name": null
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
"id": 1028,
|
|
548
|
-
"value": "TimeChart(posneg, {interval, start, stop, scheme: \"piyg\"})",
|
|
549
|
-
"pinned": true,
|
|
550
|
-
"mode": "js",
|
|
551
|
-
"data": null,
|
|
552
|
-
"name": null
|
|
553
|
-
},
|
|
554
|
-
{
|
|
555
|
-
"id": 1090,
|
|
556
|
-
"value": "TimeChart(posneg, {interval, start, stop, scheme: \"rdbu\"})",
|
|
557
|
-
"pinned": true,
|
|
558
|
-
"mode": "js",
|
|
559
|
-
"data": null,
|
|
560
|
-
"name": null
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
"id": 1239,
|
|
564
|
-
"value": "TimeChart(posneg, {interval, start, stop, scheme: \"blues\"})",
|
|
565
|
-
"pinned": true,
|
|
566
|
-
"mode": "js",
|
|
567
|
-
"data": null,
|
|
568
|
-
"name": null
|
|
569
|
-
},
|
|
570
|
-
{
|
|
571
|
-
"id": 1318,
|
|
572
|
-
"value": "posneg = wave({min: -1, max: 1}) // fake data with some negative values",
|
|
573
|
-
"pinned": true,
|
|
574
|
-
"mode": "js",
|
|
575
|
-
"data": null,
|
|
576
|
-
"name": null
|
|
577
|
-
},
|
|
578
|
-
{
|
|
579
|
-
"id": 748,
|
|
580
|
-
"value": "md`---\n\n## Advanced usage: custom defaults\n\nThe TimeChart.defaults function returns a TimeChart-like function that has the specified options as defaults. This is useful to avoid repeating options that should by shared by all charts on the page, such as *interval*, *start*, and *stop*. You can also change the default color scheme.`",
|
|
581
|
-
"pinned": false,
|
|
582
|
-
"mode": "js",
|
|
583
|
-
"data": null,
|
|
584
|
-
"name": null
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
"id": 751,
|
|
588
|
-
"value": "timeChart = TimeChart.defaults({interval, start, stop, scheme: \"purples\"})",
|
|
589
|
-
"pinned": true,
|
|
590
|
-
"mode": "js",
|
|
591
|
-
"data": null,
|
|
592
|
-
"name": null
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
"id": 763,
|
|
596
|
-
"value": "timeAxis = TimeAxis.defaults({interval, start, stop})",
|
|
597
|
-
"pinned": true,
|
|
598
|
-
"mode": "js",
|
|
599
|
-
"data": null,
|
|
600
|
-
"name": null
|
|
601
|
-
},
|
|
602
|
-
{
|
|
603
|
-
"id": 783,
|
|
604
|
-
"value": "timeAxis()",
|
|
605
|
-
"pinned": true,
|
|
606
|
-
"mode": "js",
|
|
607
|
-
"data": null,
|
|
608
|
-
"name": null
|
|
609
|
-
},
|
|
610
|
-
{
|
|
611
|
-
"id": 754,
|
|
612
|
-
"value": "timeChart(signups, {title: \"Sign-ups\"})",
|
|
613
|
-
"pinned": true,
|
|
614
|
-
"mode": "js",
|
|
615
|
-
"data": null,
|
|
616
|
-
"name": null
|
|
617
|
-
},
|
|
618
|
-
{
|
|
619
|
-
"id": 738,
|
|
620
|
-
"value": "md`---\n\n## Advanced usage: onclick\n\nThe *onclick* option takes a function to be called when the user clicks on the chart. You can use this, for example, to open another notebook or to drive something else on the page (say with a mutable). Call this.invert(*event*) to have TimeChart lookup the data that was clicked on.`",
|
|
621
|
-
"pinned": false,
|
|
622
|
-
"mode": "js",
|
|
623
|
-
"data": null,
|
|
624
|
-
"name": null
|
|
625
|
-
},
|
|
626
|
-
{
|
|
627
|
-
"id": 743,
|
|
628
|
-
"value": "timeChart(signups, {\n title: \"Sign-ups\", \n onclick(event) {\n const {date} = this.invert(event);\n open(`/d/e817ba556034bba5?date=${date.toISOString()}`, `target=_blank`);\n }\n})",
|
|
629
|
-
"pinned": true,
|
|
630
|
-
"mode": "js",
|
|
631
|
-
"data": null,
|
|
632
|
-
"name": null
|
|
633
|
-
},
|
|
634
|
-
{
|
|
635
|
-
"id": 788,
|
|
636
|
-
"value": "md`---\n\n## Advanced usage: views\n\nTimeChart is compatible with Observable’s viewof operator. The value of the chart is the data you pass in.`",
|
|
637
|
-
"pinned": false,
|
|
638
|
-
"mode": "js",
|
|
639
|
-
"data": null,
|
|
640
|
-
"name": null
|
|
641
|
-
},
|
|
642
|
-
{
|
|
643
|
-
"id": 792,
|
|
644
|
-
"value": "viewof florps = timeChart(wave(), {title: \"Florps\"})",
|
|
645
|
-
"pinned": true,
|
|
646
|
-
"mode": "js",
|
|
647
|
-
"data": null,
|
|
648
|
-
"name": null
|
|
649
|
-
},
|
|
650
|
-
{
|
|
651
|
-
"id": 796,
|
|
652
|
-
"value": "florps",
|
|
653
|
-
"pinned": true,
|
|
654
|
-
"mode": "js",
|
|
655
|
-
"data": null,
|
|
656
|
-
"name": null
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
"id": 1498,
|
|
660
|
-
"value": "md`---\n\n## Advanced usage: multiple charts in one cell\n\nTypically each chart goes in its own cell for ease of ordering and commenting. But if desired you can combine multiple charts and an axis in a cell as shown below.`",
|
|
661
|
-
"pinned": false,
|
|
662
|
-
"mode": "js",
|
|
663
|
-
"data": null,
|
|
664
|
-
"name": null
|
|
665
|
-
},
|
|
666
|
-
{
|
|
667
|
-
"id": 1500,
|
|
668
|
-
"value": "html`${timeAxis()}${[wave(), wave()].map((data, i) => timeChart(data, {title: `wave ${i}`}))}`",
|
|
669
|
-
"pinned": true,
|
|
670
|
-
"mode": "js",
|
|
671
|
-
"data": null,
|
|
672
|
-
"name": null
|
|
673
|
-
},
|
|
674
|
-
{
|
|
675
|
-
"id": 422,
|
|
676
|
-
"value": "md`---\n\n## Implementation`",
|
|
677
|
-
"pinned": false,
|
|
678
|
-
"mode": "js",
|
|
679
|
-
"data": null,
|
|
680
|
-
"name": null
|
|
681
|
-
},
|
|
682
|
-
{
|
|
683
|
-
"id": 5,
|
|
684
|
-
"value": "TimeChart = {\n let clientX = document.body.clientWidth + 14;\n\n function TimeChart(data, options = {}) {\n\n // If data is a promise, render nothing, then replace it with the actual chart later.\n if (typeof data.then === \"function\") {\n const chart = TimeChart([], options);\n Promise.resolve(data).then((data) => chart.replaceWith(TimeChart(data, options)));\n return chart;\n }\n\n // Extract option.s\n let {\n interval,\n max = d3.quantile(data, 0.99, d => Math.abs(d.value) || NaN) || 1,\n label, // alias for title\n title = label,\n locale = \"en-US\",\n dateFormat = localeFormat(locale),\n format = localeFormat(locale),\n marginTop = 0, // try -16 to remove the gap between cells\n marginLeft = 0,\n marginRight = 0,\n height = 49, // inclusive of margin\n width,\n stop,\n start,\n bands = 4,\n onclick,\n curve = d3.curveStepBefore,\n scheme = d3.schemeRdGy,\n mode = \"offset\"\n } = options;\n \n // Normalize string arguments\n if (typeof format === \"string\") format = d3.format(format);\n else if (typeof format !== \"function\") format = localeFormat(locale, format);\n if (typeof dateFormat === \"string\") dateFormat = d3.utcFormat(dateFormat);\n else if (typeof dateFormat !== \"function\") dateFormat = localeFormat(locale, dateFormat);\n interval = maybeInterval(interval);\n curve = maybeCurve(curve);\n scheme = maybeScheme(scheme);\n mode = maybeMode(mode);\n bands = Math.floor(bands);\n if (!(bands >= 1 && bands < scheme.length)) throw new Error(`invalid bands: ${bands}`);\n if (stop === undefined) stop = interval();\n if (start === undefined) start = interval.offset(stop, -width);\n \n // Normalize the color scheme\n let colors;\n if (scheme.length < 11) { // assume sequential, pad with greys\n colors = scheme[Math.max(3, bands)];\n if (bands < 3) colors = colors.slice(3 - bands).concat(new Array(3 - bands));\n colors = [...d3.reverse(d3.schemeGreys[colors.length]), undefined, ...colors];\n } else { // otherwise assume diverging\n colors = scheme[Math.max(3, 2 * bands + 1)];\n }\n\n // Normalize the data to the given interval, filling in any missing data with zeroes.\n const values = new Map(data.map(d => [+d.date, +d.value]));\n const [ymin, ymax] = d3.extent(values, ([, value]) => value);\n data = interval.range(start, stop).map(date => ({date, value: values.get(+date) || 0}));\n if (width === undefined) width = data.length;\n\n const x = d3.scaleUtc([start, stop], [marginLeft, width - marginRight]);\n const y = d3.scaleLinear([0, max], [0, -bands * height]);\n const clip = DOM.uid(\"clip\");\n const path = DOM.uid(\"path\");\n\n const svg = d3.create(\"svg\")\n .attr(\"viewBox\", `0 ${-marginTop} ${width} ${height}`)\n .attr(\"width\", width)\n .attr(\"height\", height)\n .property(\"style\", `\n display: block;\n font: 12px var(--sans-serif, system-ui, sans-serif);\n font-variant-numeric: tabular-nums;\n margin: 0 0 ${+marginTop}px calc(100% - ${width}px);\n overflow: visible;\n `);\n\n const tooltip = svg.append(\"title\");\n\n svg.append(\"clipPath\")\n .attr(\"id\", clip.id)\n .append(\"rect\")\n .attr(\"y\", 0)\n .attr(\"width\", width)\n .attr(\"height\", height);\n\n svg.append(\"defs\").append(\"path\")\n .attr(\"id\", path.id)\n .attr(\"d\", d3.area()\n .curve(curve)\n .defined(d => !isNaN(d.value))\n .x(d => round(x(d.date)))\n .y0(0)\n .y1(d => round(y(d.value)))\n (data));\n\n const g = svg.append(\"g\")\n .attr(\"clip-path\", clip);\n\n g.append(\"g\")\n .selectAll(\"use\")\n .data(d3.range(bands)\n .map(i => [i, colors[i + 1 + (colors.length >> 1)]])\n .filter(([i, color]) => color != null && ymax > max * i / bands))\n .join(\"use\")\n .attr(\"fill\", ([, color]) => color)\n .attr(\"transform\", ([i]) => `translate(0,${(i + 1) * height})`)\n .attr(\"xlink:href\", path.href);\n\n g.append(\"g\")\n .selectAll(\"use\")\n .data(d3.range(bands)\n .map(i => [i, colors[(colors.length >> 1) - 1 - i]])\n .filter(([i, color]) => color != null && -ymin > max * i / bands))\n .join(\"use\")\n .attr(\"fill\", ([, color]) => color)\n .attr(\"transform\", mode === \"mirror\"\n ? ([i]) => `translate(0,${(i + 1) * height}) scale(1,-1)`\n : ([i]) => `translate(0,${-i * height})`)\n .attr(\"xlink:href\", path.href);\n\n const overlay = svg.append(\"g\");\n\n if (title != null) overlay.append(\"text\")\n .attr(\"class\", \"title\")\n .attr(\"font-weight\", \"bold\")\n .attr(\"stroke-linecap\", \"round\")\n .attr(\"stroke-linejoin\", \"round\")\n .attr(\"y\", 2 * 16)\n .attr(\"dy\", \"0.32em\")\n .text(title + \"\");\n\n overlay.append(\"text\")\n .attr(\"class\", \"label\")\n .attr(\"stroke-linecap\", \"round\")\n .attr(\"stroke-linejoin\", \"round\")\n .attr(\"text-anchor\", \"end\")\n .attr(\"y\", height - 16 - 1)\n .attr(\"dx\", -3)\n .attr(\"dy\", \"0.32em\");\n\n overlay.selectAll(\"text\")\n .select(function() {\n const clone = this.cloneNode(true);\n return this.parentNode.insertBefore(clone, this);\n })\n .attr(\"fill\", \"none\")\n .attr(\"stroke\", \"white\")\n .attr(\"stroke-width\", 4);\n\n overlay.append(\"line\")\n .attr(\"class\", \"line\")\n .attr(\"stroke\", \"white\")\n .attr(\"stroke-dasharray\", \"1,1\")\n .style(\"mix-blend-mode\", \"screen\")\n .attr(\"y1\", 0)\n .attr(\"y2\", height);\n\n overlay.select(\"line\").clone(true)\n .attr(\"stroke\", \"black\")\n .attr(\"stroke-dashoffset\", 1);\n\n const overlayLine = overlay.selectAll(\".line\");\n const overlayLabel = overlay.selectAll(\".label\");\n const overlayText = overlay.selectAll(\".title\");\n\n function invert(event) {\n const [mx] = d3.pointer(event, svg.node());\n const i = d3.bisector(d => d.date).left(data, x.invert(mx), 0, data.length - 1);\n return data[i];\n }\n\n function mousemoved(event) {\n clientX = event.clientX;\n const d = invert(event);\n overlayLabel.attr(\"x\", x(d.date)).text(format(d.value));\n overlayLine.attr(\"x1\", x(d.date) - 0.5).attr(\"x2\", x(d.date) - 0.5);\n tooltip.text(dateFormat(d.date));\n }\n\n function resized() {\n overlayText.attr(\"x\", Math.max(0, width - document.body.clientWidth) + 4);\n }\n\n resized();\n addEventListener(\"resize\", resized);\n addEventListener(\"mousemove\", mousemoved);\n requestAnimationFrame(() => mousemoved({clientX, clientY: 0}));\n\n Inputs.disposal(svg.node()).then(() => {\n removeEventListener(\"resize\", resized);\n removeEventListener(\"mousemove\", mousemoved);\n });\n\n return Object.assign(svg.node(), {onclick, value: data, invert});\n }\n\n TimeChart.defaults = defaults => {\n return (data, options) => {\n return TimeChart(data, {...defaults, ...options});\n };\n };\n\n return TimeChart;\n}",
|
|
685
|
-
"pinned": true,
|
|
686
|
-
"mode": "js",
|
|
687
|
-
"data": null,
|
|
688
|
-
"name": null
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
"id": 464,
|
|
692
|
-
"value": "TimeAxis = {\n function TimeAxis({\n interval,\n width,\n height = 33,\n marginLeft = 0,\n marginRight = 0,\n stop,\n start,\n } = {}) {\n interval = maybeInterval(interval);\n if (stop === undefined) stop = interval();\n if (start === undefined) start = interval.offset(stop, -width);\n if (width === undefined) width = interval.range(start, stop).length;\n return html`<svg viewBox=\"0 0 ${width} ${height}\" width=${width} height=${height} style=\"display: block; margin-left: calc(100% - ${width}px);\">\n ${d3.create(\"svg:g\")\n .call(d3.axisTop(d3.scaleTime([start, stop], [marginLeft, width - marginRight])).ticks(width / 120))\n .call(g => g.select(\".domain\").remove())\n .call(g => g.selectAll(\".tick line\").clone(true).attr(\"y2\", \"100vh\").attr(\"stroke-opacity\", 0.12))\n .attr(\"transform\", `translate(0, 33)`)\n .node()}\n </svg>`;\n }\n\n TimeAxis.defaults = defaults => {\n return options => {\n return TimeAxis({...defaults, ...options});\n };\n };\n\n return TimeAxis;\n}",
|
|
693
|
-
"pinned": true,
|
|
694
|
-
"mode": "js",
|
|
695
|
-
"data": null,
|
|
696
|
-
"name": null
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
"id": 1160,
|
|
700
|
-
"value": "function round(x) {\n return Math.round(x * 2) / 2;\n}",
|
|
701
|
-
"pinned": true,
|
|
702
|
-
"mode": "js",
|
|
703
|
-
"data": null,
|
|
704
|
-
"name": null
|
|
705
|
-
},
|
|
706
|
-
{
|
|
707
|
-
"id": 829,
|
|
708
|
-
"value": "function maybeInterval(interval) {\n if (interval == null) throw new Error(\"missing interval\");\n if (!(interval && typeof interval.range === \"function\")) {\n const i = (interval + \"\").toLowerCase();\n switch (i) {\n case \"millisecond\":\n case \"second\":\n case \"minute\":\n case \"hour\":\n case \"day\":\n case \"week\":\n case \"sunday\":\n case \"monday\":\n case \"tuesday\":\n case \"wednesday\":\n case \"thursday\":\n case \"friday\":\n case \"saturday\":\n case \"month\":\n case \"year\":\n return d3[`utc${camelize(i)}`];\n }\n throw new Error(`invalid interval: ${interval}`);\n }\n return interval; \n}",
|
|
709
|
-
"pinned": true,
|
|
710
|
-
"mode": "js",
|
|
711
|
-
"data": null,
|
|
712
|
-
"name": null
|
|
713
|
-
},
|
|
714
|
-
{
|
|
715
|
-
"id": 838,
|
|
716
|
-
"value": "function maybeCurve(curve) {\n if (curve == null) throw new Error(\"missing curve\");\n if (typeof curve !== \"function\") {\n const c = d3[`curve${camelize(curve)}`];\n if (c === undefined) throw new Error(`unknown curve: ${curve}`);\n curve = c;\n }\n return curve;\n}",
|
|
717
|
-
"pinned": true,
|
|
718
|
-
"mode": "js",
|
|
719
|
-
"data": null,
|
|
720
|
-
"name": null
|
|
721
|
-
},
|
|
722
|
-
{
|
|
723
|
-
"id": 832,
|
|
724
|
-
"value": "function maybeScheme(scheme) {\n if (scheme == null) throw new Error(\"missing scheme\");\n if (!Array.isArray(scheme)) {\n const s = (scheme + \"\").toLowerCase();\n switch (s) {\n case \"brbg\": return d3.schemeBrBG;\n case \"prgn\": return d3.schemePRGn;\n case \"piyg\": return d3.schemePiYG;\n case \"puor\": return d3.schemePuOr;\n case \"rdbu\": return d3.schemeRdBu;\n case \"rdgy\": return d3.schemeRdGy;\n case \"rdylbu\": return d3.schemeRdYlBu;\n case \"rdylgn\": return d3.schemeRdYlGn;\n case \"spectral\": return d3.schemeSpectral;\n case \"blues\": return d3.schemeBlues;\n case \"greens\": return d3.schemeGreens;\n case \"greys\": return d3.schemeGreys;\n case \"oranges\": return d3.schemeOranges;\n case \"purples\": return d3.schemePurples;\n case \"reds\": return d3.schemeReds;\n case \"bugn\": return d3.schemeBuGn;\n case \"bupu\": return d3.schemeBuPu;\n case \"gnbu\": return d3.schemeGnBu;\n case \"orrd\": return d3.schemeOrRd;\n case \"pubu\": return d3.schemePuBu;\n case \"pubugn\": return d3.schemePuBuGn;\n case \"purd\": return d3.schemePuRd;\n case \"rdpu\": return d3.schemeRdPu;\n case \"ylgn\": return d3.schemeYlGn;\n case \"ylgnbu\": return d3.schemeYlGnBu;\n case \"ylorbr\": return d3.schemeYlOrBr;\n case \"ylorrd\": return d3.schemeYlOrRd;\n }\n throw new Error(`invalid scheme: ${scheme}`);\n }\n return scheme;\n}",
|
|
725
|
-
"pinned": true,
|
|
726
|
-
"mode": "js",
|
|
727
|
-
"data": null,
|
|
728
|
-
"name": null
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
"id": 1067,
|
|
732
|
-
"value": "function maybeMode(mode) {\n switch (mode = (mode + \"\").toLowerCase()) {\n case \"offset\": case \"mirror\": return mode;\n }\n throw new Error(`unknown mode: ${mode}`);\n}",
|
|
733
|
-
"pinned": true,
|
|
734
|
-
"mode": "js",
|
|
735
|
-
"data": null,
|
|
736
|
-
"name": null
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
"id": 847,
|
|
740
|
-
"value": "function camelize(string) {\n return string\n .toLowerCase()\n .split(/-/g)\n .map(([f, ...r]) => `${f.toUpperCase()}${r.join(\"\")}`)\n .join(\"\");\n}",
|
|
741
|
-
"pinned": true,
|
|
742
|
-
"mode": "js",
|
|
743
|
-
"data": null,
|
|
744
|
-
"name": null
|
|
745
|
-
},
|
|
746
|
-
{
|
|
747
|
-
"id": 1560,
|
|
748
|
-
"value": "function localeFormat(locale, format) {\n return date => date.toLocaleString(locale, format);\n}",
|
|
749
|
-
"pinned": true,
|
|
750
|
-
"mode": "js",
|
|
751
|
-
"data": null,
|
|
752
|
-
"name": null
|
|
753
|
-
},
|
|
754
|
-
{
|
|
755
|
-
"id": 506,
|
|
756
|
-
"value": "function wave({\n min = 0,\n max = 1, \n shift = 0,\n period = 24 * 6, // matching the default 10-minute interval\n noise = 0.2,\n pow = 1,\n round = false\n} = {}) {\n return interval.range(start, stop).map((date, i) => {\n const t = (Math.sin((i - shift) / period * 2 * Math.PI) + 1) / 2;\n const n = Math.random();\n let value = +min + (max - min) * (t ** pow * (1 - noise) + n * noise);\n if (round) value = Math.round(value);\n return {date, value};\n });\n}",
|
|
757
|
-
"pinned": true,
|
|
758
|
-
"mode": "js",
|
|
759
|
-
"data": null,
|
|
760
|
-
"name": null
|
|
761
|
-
},
|
|
762
|
-
{
|
|
763
|
-
"id": 552,
|
|
764
|
-
"value": "function add(first, ...series) {\n return first.map(({date, value}, i) => ({date, value: value + d3.sum(series, s => s[i].value)}));\n}",
|
|
765
|
-
"pinned": true,
|
|
766
|
-
"mode": "js",
|
|
767
|
-
"data": null,
|
|
768
|
-
"name": null
|
|
769
|
-
}
|
|
770
|
-
],
|
|
771
|
-
"resolutions": []
|
|
772
|
-
};
|