From 2c6e052f5bae042c3b25fdecf15c0df201734f37 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 15 Jun 2024 18:34:29 -0700 Subject: [PATCH 1/2] more geojson-aware --- src/marks/geo.js | 18 ------------------ src/options.js | 22 +++++++++++++++++++--- test/plots/country-centroids.ts | 2 +- test/plots/us-county-choropleth.ts | 2 +- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/marks/geo.js b/src/marks/geo.js index e986539377..903794406d 100644 --- a/src/marks/geo.js +++ b/src/marks/geo.js @@ -67,24 +67,6 @@ function scaleProjection({x: X, y: Y}) { } export function geo(data, {geometry = identity, ...options} = {}) { - switch (data?.type) { - case "FeatureCollection": - data = data.features; - break; - case "GeometryCollection": - data = data.geometries; - break; - case "Feature": - case "LineString": - case "MultiLineString": - case "MultiPoint": - case "MultiPolygon": - case "Point": - case "Polygon": - case "Sphere": - data = [data]; - break; - } return new Geo(data, {geometry, ...options}); } diff --git a/src/options.js b/src/options.js index a170e4c003..d7abbadf0e 100644 --- a/src/options.js +++ b/src/options.js @@ -47,7 +47,7 @@ function floater(f) { } export const singleton = [null]; // for data-less decoration marks, e.g. frame -export const field = (name) => (d) => d[name]; +export const field = (name) => (d) => { const v = d[name]; return v === undefined && d.type === "Feature" ? d.properties?.[name] : v; }; // prettier-ignore export const indexOf = {transform: range}; export const identity = {transform: (d) => d}; export const zero = () => 0; @@ -131,8 +131,24 @@ export function keyword(input, name, allowed) { } // Promotes the specified data to an array as needed. -export function arrayify(data) { - return data == null || data instanceof Array || data instanceof TypedArray ? data : Array.from(data); +export function arrayify(values) { + if (values == null || values instanceof Array || values instanceof TypedArray) return values; + switch (values.type) { + case "FeatureCollection": + return values.features; + case "GeometryCollection": + return values.geometries; + case "Feature": + case "LineString": + case "MultiLineString": + case "MultiPoint": + case "MultiPolygon": + case "Point": + case "Polygon": + case "Sphere": + return [values]; + } + return Array.from(values); } // An optimization of type.from(values, f): if the given values are already an diff --git a/test/plots/country-centroids.ts b/test/plots/country-centroids.ts index 2d61f236cd..55dd28a407 100644 --- a/test/plots/country-centroids.ts +++ b/test/plots/country-centroids.ts @@ -5,7 +5,7 @@ import {feature} from "topojson-client"; export async function countryCentroids() { const world = await d3.json("data/countries-110m.json"); const land = feature(world, world.objects.land); - const countries = feature(world, world.objects.countries).features; + const countries = feature(world, world.objects.countries); return Plot.plot({ projection: "mercator", marks: [ diff --git a/test/plots/us-county-choropleth.ts b/test/plots/us-county-choropleth.ts index a8d2ac2ce6..73dfb256d6 100644 --- a/test/plots/us-county-choropleth.ts +++ b/test/plots/us-county-choropleth.ts @@ -23,7 +23,7 @@ export async function usCountyChoropleth() { label: "Unemployment (%)" }, marks: [ - Plot.geo(counties, {fill: (d) => unemployment.get(d.id), title: (d) => d.properties.name}), + Plot.geo(counties, {fill: (d) => unemployment.get(d.id), title: "name"}), Plot.geo(statemesh, {stroke: "white"}) ] }); From 58b9182a56344a8b014583a3361469bf12dbac31 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sun, 16 Jun 2024 09:39:00 -0700 Subject: [PATCH 2/2] use GeoJSON collections --- docs/marks/geo.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/marks/geo.md b/docs/marks/geo.md index 895accc15f..eeea8d1875 100644 --- a/docs/marks/geo.md +++ b/docs/marks/geo.md @@ -11,8 +11,8 @@ const walmarts = shallowRef({type: "FeatureCollection", features: []}); const world = shallowRef(null); const statemesh = computed(() => us.value ? topojson.mesh(us.value, us.value.objects.states, (a, b) => a !== b) : {type: null}); const nation = computed(() => us.value ? topojson.feature(us.value, us.value.objects.nation) : {type: null}); -const states = computed(() => us.value ? topojson.feature(us.value, us.value.objects.states).features : []); -const counties = computed(() => us.value ? topojson.feature(us.value, us.value.objects.counties).features : []); +const states = computed(() => us.value ? topojson.feature(us.value, us.value.objects.states) : {type: null}); +const counties = computed(() => us.value ? topojson.feature(us.value, us.value.objects.counties) : {type: null}); const land = computed(() => world.value ? topojson.feature(world.value, world.value.objects.land) : {type: null}); onMounted(() => {