diff --git a/src/marks/delaunay.js b/src/marks/delaunay.js
index cf8c696c01..57a927d22e 100644
--- a/src/marks/delaunay.js
+++ b/src/marks/delaunay.js
@@ -1,16 +1,16 @@
import {group, pathRound as path, select, Delaunay} from "d3";
import {create} from "../context.js";
import {maybeCurve} from "../curve.js";
+import {defined} from "../defined.js";
import {Mark} from "../mark.js";
import {markers, applyMarkers} from "../marker.js";
import {constant, maybeTuple, maybeZ} from "../options.js";
-import {
- applyChannelStyles,
- applyDirectStyles,
- applyFrameAnchor,
- applyIndirectStyles,
- applyTransform
-} from "../style.js";
+import {applyPosition} from "../projection.js";
+import {applyFrameAnchor, applyTransform} from "../style.js";
+import {applyChannelStyles, applyDirectStyles, applyIndirectStyles} from "../style.js";
+import {basic, initializer} from "../transforms/basic.js";
+import {exclusiveFacets} from "../transforms/exclusiveFacets.js";
+import {maybeGroup} from "../transforms/group.js";
const delaunayLinkDefaults = {
ariaLabel: "delaunay link",
@@ -221,45 +221,45 @@ class Voronoi extends Mark {
y: {value: y, scale: "y", optional: true},
z: {value: z, optional: true}
},
- options,
+ initializer(options, function (data, facets, channels, scales, dimensions, context) {
+ let {x: X, y: Y, z: Z} = channels;
+ ({x: X, y: Y} = applyPosition(channels, scales, context));
+ Z = Z?.value;
+ const C = new Array((X ?? Y).length).fill(null);
+ const [cx, cy] = applyFrameAnchor(this, dimensions);
+ const xi = X ? (i) => X[i] : constant(cx);
+ const yi = Y ? (i) => Y[i] : constant(cy);
+ for (let I of facets) {
+ if (X) I = I.filter((i) => defined(xi(i)));
+ if (Y) I = I.filter((i) => defined(yi(i)));
+ for (const [, J] of maybeGroup(I, Z)) {
+ const delaunay = Delaunay.from(J, xi, yi);
+ const voronoi = voronoiof(delaunay, dimensions);
+ for (let i = 0, n = J.length; i < n; ++i) {
+ C[J[i]] = voronoi.renderCell(i);
+ }
+ }
+ }
+ return {data, facets, channels: {cells: {value: C}}};
+ }),
voronoiDefaults
);
}
render(index, scales, channels, dimensions, context) {
const {x, y} = scales;
- const {x: X, y: Y, z: Z} = channels;
- const [cx, cy] = applyFrameAnchor(this, dimensions);
- const xi = X ? (i) => X[i] : constant(cx);
- const yi = Y ? (i) => Y[i] : constant(cy);
- const mark = this;
-
- function cells(index) {
- const delaunay = Delaunay.from(index, xi, yi);
- const voronoi = voronoiof(delaunay, dimensions);
- select(this)
- .selectAll()
- .data(index)
- .enter()
- .append("path")
- .call(applyDirectStyles, mark)
- .attr("d", (_, i) => voronoi.renderCell(i))
- .call(applyChannelStyles, mark, channels);
- }
-
+ const {x: X, y: Y, cells: C} = channels;
return create("svg:g", context)
.call(applyIndirectStyles, this, dimensions, context)
.call(applyTransform, this, {x: X && x, y: Y && y})
- .call(
- Z
- ? (g) =>
- g
- .selectAll()
- .data(group(index, (i) => Z[i]).values())
- .enter()
- .append("g")
- .each(cells)
- : (g) => g.datum(index).each(cells)
- )
+ .call((g) => {
+ g.selectAll()
+ .data(index)
+ .enter()
+ .append("path")
+ .call(applyDirectStyles, this)
+ .attr("d", (i) => C[i])
+ .call(applyChannelStyles, this, channels);
+ })
.node();
}
}
@@ -296,8 +296,8 @@ export function hull(data, options) {
return delaunayMark(Hull, data, options);
}
-export function voronoi(data, options) {
- return delaunayMark(Voronoi, data, options);
+export function voronoi(data, {x, y, initializer, ...options} = {}) {
+ return delaunayMark(Voronoi, data, {...basic({...options, x, y}, exclusiveFacets), initializer});
}
export function voronoiMesh(data, options) {
diff --git a/src/style.js b/src/style.js
index 53601f3f62..deeb66346f 100644
--- a/src/style.js
+++ b/src/style.js
@@ -297,6 +297,7 @@ export function* groupIndex(I, position, mark, channels) {
}
}
+// TODO avoid creating a new clip-path each time?
// Note: may mutate selection.node!
function applyClip(selection, mark, dimensions, context) {
let clipUrl;
diff --git a/test/output/penguinCulmenVoronoi.svg b/test/output/penguinCulmenVoronoi.svg
index d5be80710c..633d3c10dd 100644
--- a/test/output/penguinCulmenVoronoi.svg
+++ b/test/output/penguinCulmenVoronoi.svg
@@ -465,7 +465,6 @@
-
@@ -517,7 +516,6 @@
-
@@ -654,7 +652,6 @@
-
@@ -677,7 +674,6 @@
-
@@ -757,4 +753,5 @@
+
\ No newline at end of file
diff --git a/test/output/penguinCulmenVoronoiExclude.svg b/test/output/penguinCulmenVoronoiExclude.svg
new file mode 100644
index 0000000000..5db2c7a863
--- /dev/null
+++ b/test/output/penguinCulmenVoronoiExclude.svg
@@ -0,0 +1,1161 @@
+
\ No newline at end of file
diff --git a/test/output/penguinCulmenVoronoiExcludeHex.svg b/test/output/penguinCulmenVoronoiExcludeHex.svg
new file mode 100644
index 0000000000..c58a662cb4
--- /dev/null
+++ b/test/output/penguinCulmenVoronoiExcludeHex.svg
@@ -0,0 +1,315 @@
+
\ No newline at end of file
diff --git a/test/output/penguinVoronoi1D.svg b/test/output/penguinVoronoi1D.svg
index 23bf873942..564a4f0268 100644
--- a/test/output/penguinVoronoi1D.svg
+++ b/test/output/penguinVoronoi1D.svg
@@ -37,51 +37,12 @@
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
Adelie (FEMALE)
Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (null)
- Torgersen
-
- Adelie (null)
- Torgersen
-
- Adelie (null)
- Torgersen
-
- Adelie (null)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
@@ -91,270 +52,75 @@
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Dream
-
- Adelie (MALE)
- Dream
Adelie (FEMALE)
Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
Adelie (FEMALE)
Dream
-
- Adelie (MALE)
- Dream
Adelie (FEMALE)
Dream
-
- Adelie (MALE)
- Dream
Adelie (MALE)
Dream
Adelie (null)
Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
Adelie (MALE)
Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
Adelie (MALE)
Biscoe
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
Adelie (FEMALE)
Dream
Adelie (MALE)
Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Biscoe
Adelie (MALE)
Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
-
- Adelie (MALE)
- Biscoe
Adelie (FEMALE)
Biscoe
@@ -364,384 +130,93 @@
Adelie (FEMALE)
Biscoe
-
- Adelie (MALE)
- Biscoe
-
- Adelie (FEMALE)
- Biscoe
Adelie (MALE)
Biscoe
-
- Adelie (FEMALE)
- Biscoe
Adelie (MALE)
Biscoe
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
Adelie (FEMALE)
Torgersen
-
- Adelie (MALE)
- Torgersen
Adelie (FEMALE)
Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Torgersen
-
- Adelie (MALE)
- Torgersen
-
- Adelie (FEMALE)
- Torgersen
Adelie (MALE)
Torgersen
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
Adelie (MALE)
Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Adelie (FEMALE)
- Dream
-
- Adelie (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (MALE)
Dream
-
- Chinstrap (MALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (MALE)
Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (MALE)
Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
Chinstrap (MALE)
Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (MALE)
Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (FEMALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
Chinstrap (MALE)
Dream
-
- Chinstrap (MALE)
- Dream
-
- Chinstrap (FEMALE)
- Dream
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
@@ -751,42 +226,9 @@
Gentoo (MALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (null)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
@@ -799,267 +241,81 @@
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (null)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (null)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
Gentoo (MALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
-
- Gentoo (null)
- Biscoe
-
- Gentoo (MALE)
- Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (FEMALE)
- Biscoe
Gentoo (MALE)
Biscoe
Gentoo (FEMALE)
Biscoe
-
- Gentoo (MALE)
- Biscoe
diff --git a/test/output/usCountyVoronoi.svg b/test/output/usCountyVoronoi.svg
new file mode 100644
index 0000000000..73b71aae02
--- /dev/null
+++ b/test/output/usCountyVoronoi.svg
@@ -0,0 +1,6234 @@
+
\ No newline at end of file
diff --git a/test/output/usCountyVoronoiMesh.svg b/test/output/usCountyVoronoiMesh.svg
new file mode 100644
index 0000000000..98767d5a97
--- /dev/null
+++ b/test/output/usCountyVoronoiMesh.svg
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/test/output/usStateCapitalsVoronoi.svg b/test/output/usStateCapitalsVoronoi.svg
index 25ecb0ebcf..c34eef764b 100644
--- a/test/output/usStateCapitalsVoronoi.svg
+++ b/test/output/usStateCapitalsVoronoi.svg
@@ -66,58 +66,16 @@
-
+
- Alabama
- Arizona
- Arkansas
- California
- Colorado
- Connecticut
- Delaware
- Florida
- Georgia
- Idaho
- Illinois
- Indiana
- Iowa
- Kansas
- Kentucky
- Louisiana
- Maine
- Maryland
- Massachusetts
- Michigan
- Minnesota
- Mississippi
- Missouri
- Montana
- Nebraska
- Nevada
- New Hampshire
- New Jersey
- New Mexico
- North Carolina
- North Dakota
- New York
- Ohio
- Oklahoma
- Oregon
- Pennsylvania
- Rhode Island
- South Carolina
- South Dakota
- Tennessee
- Texas
- Utah
- Vermont
- Virginia
- Washington
- West Virginia
- Wisconsin
- Wyoming
+
+
+
+
+
+
diff --git a/test/output/usStateCentroidVoronoi.svg b/test/output/usStateCentroidVoronoi.svg
new file mode 100644
index 0000000000..cc0ca4df88
--- /dev/null
+++ b/test/output/usStateCentroidVoronoi.svg
@@ -0,0 +1,84 @@
+
\ No newline at end of file
diff --git a/test/output/usStateGeoCentroidVoronoi.svg b/test/output/usStateGeoCentroidVoronoi.svg
new file mode 100644
index 0000000000..2ad229543d
--- /dev/null
+++ b/test/output/usStateGeoCentroidVoronoi.svg
@@ -0,0 +1,84 @@
+
\ No newline at end of file
diff --git a/test/plots/index.ts b/test/plots/index.ts
index 6b4742539e..a5d272dc46 100644
--- a/test/plots/index.ts
+++ b/test/plots/index.ts
@@ -322,6 +322,7 @@ export * from "./us-congress-age-symbol-explicit.js";
export * from "./us-congress-age.js";
export * from "./us-county-choropleth.js";
export * from "./us-county-spikes.js";
+export * from "./us-county-voronoi.js";
export * from "./us-population-state-age-dots.js";
export * from "./us-population-state-age.js";
export * from "./us-president-favorability-dots.js";
diff --git a/test/plots/penguin-culmen-voronoi.ts b/test/plots/penguin-culmen-voronoi.ts
index 07d2d7f96c..ecb99cf817 100644
--- a/test/plots/penguin-culmen-voronoi.ts
+++ b/test/plots/penguin-culmen-voronoi.ts
@@ -6,7 +6,49 @@ export async function penguinCulmenVoronoi() {
return Plot.plot({
marks: [
Plot.dot(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "currentColor", r: 1.5}),
- Plot.voronoi(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", stroke: "species"})
+ Plot.voronoi(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", stroke: "species", tip: true})
+ ]
+ });
+}
+
+export async function penguinCulmenVoronoiExclude() {
+ const penguins = await d3.csv("data/penguins.csv", d3.autoType);
+ const xy = {fx: "species", x: "culmen_depth_mm", y: "culmen_length_mm"};
+ return Plot.plot({
+ inset: 10,
+ marks: [
+ Plot.frame(),
+ Plot.dot(penguins, {...xy, facet: "exclude", fill: "currentColor", r: 1.5}),
+ Plot.dot(penguins, {...xy, facet: "include", fillOpacity: 0.25, fill: "currentColor", r: 1.5}),
+ Plot.voronoiMesh(penguins, {...xy, facet: "exclude"}),
+ Plot.voronoi(
+ penguins,
+ Plot.pointer({
+ ...xy,
+ facet: "exclude",
+ stroke: "species",
+ fill: "species",
+ fillOpacity: 0.2,
+ maxRadius: Infinity
+ })
+ )
+ ]
+ });
+}
+
+export async function penguinCulmenVoronoiExcludeHex() {
+ const penguins = await d3.csv("data/penguins.csv", d3.autoType);
+ const xy = {fx: "species", x: "culmen_depth_mm", y: "culmen_length_mm"};
+ return Plot.plot({
+ inset: 20,
+ marks: [
+ Plot.frame(),
+ Plot.dot(penguins, Plot.hexbin({}, {...xy, facet: "exclude", stroke: "species", fill: "species"})),
+ Plot.voronoiMesh(penguins, Plot.hexbin({}, {...xy, facet: "exclude", strokeOpacity: 1})),
+ Plot.voronoi(
+ penguins,
+ Plot.pointer(Plot.hexbin({}, {...xy, facet: "exclude", strokeWidth: 2, maxRadius: Infinity}))
+ )
]
});
}
diff --git a/test/plots/us-county-voronoi.ts b/test/plots/us-county-voronoi.ts
new file mode 100644
index 0000000000..d721f0777c
--- /dev/null
+++ b/test/plots/us-county-voronoi.ts
@@ -0,0 +1,31 @@
+import * as Plot from "@observablehq/plot";
+import * as d3 from "d3";
+import {feature} from "topojson-client";
+
+const transform = (data, facets) => ({data, facets: facets.map((I) => I.slice(1))});
+
+export async function usCountyVoronoi() {
+ const counties = await d3
+ .json("data/us-counties-10m.json")
+ .then((us) => feature(us, us.objects.counties).features);
+ return Plot.plot({
+ projection: "albers",
+ marks: [
+ Plot.voronoi(counties, Plot.geoCentroid({transform, stroke: "red"})),
+ Plot.voronoi(counties, Plot.centroid({transform, stroke: "blue", mixBlendMode: "multiply"}))
+ ]
+ });
+}
+
+export async function usCountyVoronoiMesh() {
+ const counties = await d3
+ .json("data/us-counties-10m.json")
+ .then((us) => feature(us, us.objects.counties).features);
+ return Plot.plot({
+ projection: "albers",
+ marks: [
+ Plot.voronoiMesh(counties, Plot.geoCentroid({transform, stroke: "red", strokeOpacity: 1})),
+ Plot.voronoiMesh(counties, Plot.centroid({transform, stroke: "blue", strokeOpacity: 1, mixBlendMode: "multiply"}))
+ ]
+ });
+}
diff --git a/test/plots/us-state-capitals-voronoi.ts b/test/plots/us-state-capitals-voronoi.ts
index c89d09e5e5..a2481cfa07 100644
--- a/test/plots/us-state-capitals-voronoi.ts
+++ b/test/plots/us-state-capitals-voronoi.ts
@@ -16,8 +16,65 @@ export async function usStateCapitalsVoronoi() {
marks: [
Plot.geo(nation, {fill: "currentColor", fillOpacity: 0.2}),
Plot.dot(capitals, {x: "longitude", y: "latitude", r: 2.5, fill: "currentColor"}),
- Plot.voronoi(capitals, {x: "longitude", y: "latitude", clip: "sphere", title: "state", pointerEvents: "all"}),
+ Plot.voronoiMesh(capitals, {x: "longitude", y: "latitude", clip: "sphere"}),
+ Plot.voronoi(
+ capitals,
+ Plot.pointer({
+ x: "longitude",
+ y: "latitude",
+ clip: "sphere",
+ title: "state",
+ stroke: "red",
+ fill: "red",
+ fillOpacity: 0.4,
+ pointerEvents: "all",
+ maxRadius: Infinity
+ })
+ ),
Plot.sphere({strokeWidth: 2})
]
});
}
+
+async function voronoiMap(centroid) {
+ const [nation, states] = await d3
+ .json("data/us-counties-10m.json")
+ .then((us) => [feature(us, us.objects.nation), feature(us, us.objects.states)]);
+ return Plot.plot({
+ width: 640,
+ height: 640,
+ margin: 1,
+ projection: ({width, height}) =>
+ d3.geoAzimuthalEqualArea().rotate([96, -40]).clipAngle(24).fitSize([width, height], {type: "Sphere"}),
+ marks: [
+ Plot.geo(nation, {fill: "currentColor", fillOpacity: 0.2}),
+ Plot.dot(states.features, centroid({r: 2.5, fill: "currentColor"})),
+ Plot.voronoiMesh(states.features, centroid({clip: "sphere"})),
+ Plot.voronoi(
+ states.features,
+ Plot.pointer(
+ centroid({
+ x: "longitude",
+ y: "latitude",
+ clip: "sphere",
+ title: "state",
+ stroke: "red",
+ fill: "red",
+ fillOpacity: 0.4,
+ pointerEvents: "all",
+ maxRadius: Infinity
+ })
+ )
+ ),
+ Plot.sphere({strokeWidth: 2})
+ ]
+ });
+}
+
+export async function usStateCentroidVoronoi() {
+ return voronoiMap(Plot.centroid);
+}
+
+export async function usStateGeoCentroidVoronoi() {
+ return voronoiMap(Plot.geoCentroid);
+}