Skip to content

Commit 763f0fd

Browse files
committed
fixes two issues with temporal contours:
1. blur2 does not support dates 2. the contour ticks should be derived as utc ticks not numerical ticks closes #2250
1 parent 7daaa9a commit 763f0fd

File tree

3 files changed

+111
-6
lines changed

3 files changed

+111
-6
lines changed

src/marks/contour.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import {blur2, contours, geoPath, max, min, nice, range, ticks, thresholdSturges} from "d3";
1+
import {blur2, contours, geoPath, max, min, nice, range, ticks, thresholdSturges, scaleUtc} from "d3";
22
import {createChannels} from "../channel.js";
33
import {create} from "../context.js";
4-
import {labelof, identity, arrayify, map} from "../options.js";
4+
import {labelof, identity, arrayify, map, isTemporal} from "../options.js";
55
import {applyPosition} from "../projection.js";
66
import {applyChannelStyles, applyDirectStyles, applyIndirectStyles, applyTransform, styles} from "../style.js";
77
import {initializer} from "../transforms/basic.js";
@@ -115,7 +115,8 @@ function contourGeometry({thresholds, interval, ...options}) {
115115
const {pixelSize: k, width: w = Math.round(Math.abs(dx) / k), height: h = Math.round(Math.abs(dy) / k)} = this;
116116
const kx = w / dx;
117117
const ky = h / dy;
118-
const V = channels.value.value;
118+
const temporal = isTemporal(channels.value.value);
119+
const V = temporal && this.blur > 0 ? Float64Array.from(channels.value.value) : channels.value.value;
119120
const VV = []; // V per facet
120121

121122
// Interpolate the raster grid, as needed.
@@ -149,7 +150,7 @@ function contourGeometry({thresholds, interval, ...options}) {
149150
if (this.blur > 0) for (const V of VV) blur2({data: V, width: w, height: h}, this.blur);
150151

151152
// Compute the contour thresholds.
152-
const T = maybeTicks(thresholds, V, ...finiteExtent(VV));
153+
const T = maybeTicks(thresholds, V, ...finiteExtent(VV), temporal);
153154
if (T === null) throw new Error(`unsupported thresholds: ${thresholds}`);
154155

155156
// Compute the (maybe faceted) contours.
@@ -187,10 +188,11 @@ function contourGeometry({thresholds, interval, ...options}) {
187188
// thresholds across facets. When an interval is used, note that the lowest
188189
// threshold should be below (or equal) to the lowest value, or else some data
189190
// will be missing.
190-
function maybeTicks(thresholds, V, min, max) {
191+
function maybeTicks(thresholds, V, min, max, temporal) {
191192
if (typeof thresholds?.range === "function") return thresholds.range(thresholds.floor(min), max);
192193
if (typeof thresholds === "function") thresholds = thresholds(V, min, max);
193194
if (typeof thresholds !== "number") return arrayify(thresholds);
195+
if (temporal) return scaleUtc().domain([min, max]).nice(thresholds).ticks(thresholds);
194196
const tz = ticks(...nice(min, max, thresholds), thresholds);
195197
while (tz[tz.length - 1] >= max) tz.pop();
196198
while (tz[1] < min) tz.shift();

test/output/walmartsDateContours.html

Lines changed: 72 additions & 0 deletions
Large diffs are not rendered by default.

test/plots/walmarts.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as Plot from "@observablehq/plot";
22
import * as d3 from "d3";
3-
import {mesh} from "topojson-client";
3+
import {feature, mesh} from "topojson-client";
44
import {test} from "test/plot";
55

66
test(async function walmarts() {
@@ -37,3 +37,34 @@ test(async function walmarts() {
3737
]
3838
});
3939
});
40+
41+
test(async function walmartsDateContours() {
42+
const [walmarts, [statemesh, nation]] = await Promise.all([
43+
d3.tsv<any>("data/walmarts.tsv", d3.autoType),
44+
d3.json<any>("data/us-counties-10m.json").then((us) => [
45+
mesh(us, {
46+
type: "GeometryCollection",
47+
geometries: us.objects.states.geometries.filter((d) => d.id !== "02" && d.id !== "15")
48+
}),
49+
feature(us, us.objects.nation)
50+
])
51+
]);
52+
return Plot.plot({
53+
width: 960,
54+
height: 600,
55+
projection: "albers",
56+
color: {legend: true, label: "Mean opening date"},
57+
clip: nation,
58+
marks: [
59+
Plot.contour(walmarts, {
60+
x: "longitude",
61+
y: "latitude",
62+
fill: "date",
63+
interpolate: "random-walk",
64+
blur: 5
65+
}),
66+
Plot.geo(statemesh, {strokeOpacity: 0.25}),
67+
Plot.geo(nation, {strokeWidth: 1.5})
68+
]
69+
});
70+
});

0 commit comments

Comments
 (0)