Skip to content

Commit 3ae634d

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 283d8e1 commit 3ae634d

File tree

3 files changed

+111
-6
lines changed

3 files changed

+111
-6
lines changed

src/marks/contour.js

+7-5
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

+72
Large diffs are not rendered by default.

test/plots/walmarts.ts

+32-1
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

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

0 commit comments

Comments
 (0)