Skip to content

Commit c5962e2

Browse files
author
James Goldie
committed
Polish up time series chart
1 parent a0d1330 commit c5962e2

File tree

4 files changed

+58
-53
lines changed

4 files changed

+58
-53
lines changed

docs/examples/time-series/TimeSeriesChart.svelte

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,20 @@
11
<script>
2-
// import { fly } from "svelte/transition";
2+
import { blur } from "svelte/transition"
33
import { extent } from "d3-array"
4-
import { scaleLinear } from "d3-scale"
5-
import { scaleSequential } from "d3-scale"
4+
import { scaleLinear, scaleSequential } from "d3-scale"
65
import { interpolateYlGnBu, interpolateYlOrRd, select, axisLeft, axisBottom, format, tickFormat, formatLocale } from "d3"
7-
import { regressionLinear } from "d3-regression"
8-
// ,
9-
// should ba array of objects with:
10-
// x
11-
// y
12-
// colour
13-
// tooltip text maybe?
6+
7+
// should be an array of objects with:
8+
// year
9+
// value
1410
export let data = []
11+
export let valueSuffix = "°C"
1512
export let colourScheme = "cool" // or warm
1613
$: console.log(colourScheme)
1714
$: colourRamp = (colourScheme == "cool") ?
1815
interpolateYlGnBu :
1916
interpolateYlOrRd
2017
21-
// calculate trend line from data
22-
const regress = regressionLinear()
23-
.x(d => d.date)
24-
.y(d => d.value)
25-
.domain(extent(data.map(d => d.date)))
26-
27-
$: trendLine = regress(data)
28-
29-
3018
// dimensions bound to size of container
3119
let height = 500
3220
let width = 300
@@ -51,7 +39,7 @@
5139
5240
// temperature formatter (for x-axis)
5341
const tempFormat = formatLocale({
54-
currency: ["", "°C"]
42+
currency: ["", valueSuffix]
5543
});
5644
5745
// axes
@@ -89,13 +77,16 @@
8977
<svg width={width} height={height}>
9078

9179
<g>
92-
{#each data as { year, value }}
80+
{#each data as { year, value } (year) }
9381
<!-- points go here-->
9482
<circle
9583
cx="{xScale(year)}px"
9684
cy="{yScale(value)}px"
9785
r="5"
98-
fill="{colourScale(value)}">
86+
fill="{colourScale(value)}"
87+
in:blur={{ duration: 500 }}
88+
out:blur={{ duration: 500 }}
89+
>
9990
</circle>
10091
{/each}
10192
</g>

docs/examples/time-series/index.qmd

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,23 @@ sverto:
1616

1717
Let's do something more useful: a time series of temperature extremes.
1818

19-
In Quarto, we'll download the data for two cities (Melbourne and Brisbane), letting the user choose which to display. We'll also let them choose a month and the extreme to display.
19+
In Quarto, we'll download the data for two cities (Melbourne and Brisbane), letting the user choose which to display. We'll also create controls using [Observable Inputs](https://observablehq.com/documentation/inputs/overview) to let them choose a month and the extreme to display.
2020

21-
:::{.callout-tip appearance="simple"}
21+
:::{.callout-info appearance="simple" title="What is this data?" collapse="true"}
2222
In climate parlance, the highest temperature of the day is called the "daily maximum temperature", or `tmax` for short. The coldest temperature of the day is called "daily minimum temperature", or `tmin` for short.
2323

2424
I'm just calling them "daytime temperature" and "nighttime temperature" here — although the lowest temperature can technically happen during the day, it's usually at night!
2525
:::
2626

2727
Once the data has been appropriately filtered and calculated, we'll pass it to our Svelte chart.
2828

29-
The chart is fairly agnostic in the sense that it could be used with other time series datasets too, rather than being tailored specifically to this one. It expects a prop called `data`, which is an array of objects that each have a numerical `year` and a `value`.
29+
The chart expects a prop called `data`, which is an array of objects that each have a numerical `year` and a `value`.
3030

31-
:::{.callout-note collapse="true" appearance="simple"}
32-
We could generalise this chart further if we wanted: we could have it expect columns called `x` and `y`, and perhaps allow full date objects as the x values.
33-
:::
31+
:::{.callout-tip appearance="simple" collapse="true" title="Can I use this chart with other data?"}
32+
You can! This chart can plot any series of data, although it expects a numerical x value called `year` (it doesn't handle full dates) and a numerical y value called `value`.
3433

34+
The y-axis has a suffix that is set to `"°C"` by default, but you could change this to `°F`, `kph` or something else if you had some other kind of data!
35+
:::
3536

3637
:::{.panel-input}
3738

@@ -60,8 +61,6 @@ viewof selectedVariable = Inputs.select(
6061
)
6162
```
6263

63-
Let's also let users select a month and whether to look at the hottest, coldest or average temperature:
64-
6564
```{ojs}
6665
//| label: controls-season-metric
6766
viewof selectedSeason = Inputs.select(
@@ -99,7 +98,7 @@ viewof selectedMetric = Inputs.select(
9998

10099
:::
101100

102-
Now let's use [Arquero](https://github.com/uwdata/arquero) to download and filter the selected data.
101+
Now we'll use [Arquero](https://github.com/uwdata/arquero) to download and filter the selected data.
103102

104103

105104
```{ojs}
@@ -137,17 +136,12 @@ finalData = allMetrics
137136
.rename(aq.names("year", "value"))
138137
```
139138

140-
And so we have our data! Here it is as a table, so we can see what we're sending to Svelte:
139+
Now that the data's processed, we're ready to make the chart:
141140

142-
:::{.callout-note title="Table of values" collapse="true" appearance="simple"}
143-
```{ojs}
144-
//| label: data-table
145-
Inputs.table(finalData)
146-
```
141+
:::{.callout-tip appearance="simple"}
142+
Try changing from Daytime to Nighttime!
147143
:::
148144

149-
But, more importantly, here it is as an animated chart:
150-
151145
```{ojs}
152146
//| label: import-chart
153147
timeSeriesChart = new TimeSeriesChart.default({
@@ -162,6 +156,7 @@ And there we go! And now to send our data to it:
162156

163157
```{ojs}
164158
//| label: update-chart-data
159+
//| output: false
165160
timeSeriesChart.data = finalData.objects()
166161
```
167162

@@ -170,5 +165,36 @@ This chart also takes an additional prop: `colourScheme` can be either `cool` or
170165

171166
```{ojs}
172167
//| label: update-chart-colours
168+
//| output: false
173169
timeSeriesChart.colourScheme = selectedVariable == "tmax" ? "warm" : "cool"
174170
```
171+
172+
:::{.callout-tip appearance="simple"}
173+
Use `//| output: false` when you update props so that they aren't displayed underneath the cell.
174+
:::
175+
176+
# Building the chart
177+
178+
Here's the code in the Svelte file:
179+
180+
:::{.callout-note appearance="simple" collapse="true" title="BarChart.svelte"}
181+
```{.html}
182+
{{< include TimeSeriesChart.svelte >}}
183+
```
184+
:::
185+
186+
This chart has a few differences from the [simpler barchart example](../barchart):
187+
188+
1. We make the chart responsive to changes in window size by wrapping the `<svg>` in a `<main`> and using `bind:clientHeight` and `bind:clientWidth` to track the space available to the chart
189+
2. Since this is designed for more data, we use axes instead of labelling each datum. We use [`d3-axis`](https://d3js.org/d3-axis) for this. Instead of directly drawing the SVG elements of the axis, we create a placeholder and then use D3's functions to create the content, making them reactive to changes in data or window size with `$:`
190+
3. Instead of passing in colour directly, we let the user in Quarto choose a colour scheme (`"warm"` or `"cool"`). In this example, the colour scheme is connected to the Daytime or Nighttime option.
191+
192+
And here's the processed data as a table, so we can see what we're sending to Svelte. Note the two columns, `year` and `value`:
193+
194+
:::{.callout-note title="Table of values" collapse="true" appearance="simple"}
195+
```{ojs}
196+
//| label: data-table
197+
Inputs.table(finalData)
198+
```
199+
:::
200+

docs/package-lock.json

Lines changed: 1 addition & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"svelte": "^3.0.0"
1717
},
1818
"dependencies": {
19-
"d3": "^7.9.0",
20-
"d3-regression": "^1.3.10"
19+
"d3": "^7.9.0"
2120
}
2221
}

0 commit comments

Comments
 (0)