# Delaunay marks

Given set of points in **x** and **y**, the **Delaunay marks** compute the Delaunay triangulation, its dual the Voronoi tessellation, and the convex hull.

The voronoi mark computes the region closest to each point (its *Voronoi cell*). The cell can be empty if another point shares the exact same coordinates. Together, the cells cover the entire plot. Voronoi diagrams can group related points with color, for example.

```
Plot.plot({
color: {legend: true},
marks: [
Plot.voronoi(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "species", fillOpacity: 0.2, stroke: "white"}),
Plot.frame(),
Plot.dot(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "species"})
]
})
```

Each cell is associated with a particular data point, and channels such as **stroke**, **fill**, **fillOpacity**, **strokeOpacity**, **href**, *etc.*, work as they do on other marks, such as dots.

To show the local density of a scatterplot, one can draw the whole boundary at once with voronoiMesh. Whereas the voronoi mark will draw shared cell boundaries twice, the mesh will draw them only once.

Fork```
Plot.plot({
marks: [
Plot.voronoiMesh(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"}),
Plot.dot(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "species"})
]
})
```

The boundary between two neighboring Voronoi cells is a line segment defined by equal distance from their two respective points. The construction of the Voronoi diagram involves the computation of the Delaunay graph, which defines these neighbors. Use delaunayMesh to draw the graph.

Fork```
Plot.plot({
marks: [
Plot.delaunayMesh(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", z: "species", stroke: "species", strokeOpacity: 0.5}),
Plot.dot(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "species"})
]
})
```

As shown above, the Delaunay graph is computed separately for each color; specifying **z**, **stroke**, or **fill** creates independent series.

Another derivative of the Delaunay graph is the convex hull of a set of points: the polygon with the minimum perimeter that contains all the points. The hull mark will draw this hull.

Fork```
Plot.plot({
marks: [
Plot.hull(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", fill: "species", fillOpacity: 0.2}),
Plot.dot(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", stroke: "species"})
]
})
```

Using independent series is not recommended in the case of the voronoi and voronoiMesh marks as it will result in an unreadable chart due to overlapping Voronoi diagrams, but it can be useful to color the links of the Delaunay graph based on some property of data, such as the body mass of penguins below.

Fork```
Plot.plot({
color: {legend: true},
marks: [
Plot.delaunayLink(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm", stroke: "body_mass_g", strokeWidth: 1.5})
]
})
```

CAUTION

The link color is driven by one arbitrary extremity of each edge; this might change in the future.

The Delaunay marks can be one-dimensional, too.

Fork```
Plot.plot({
marks: [
Plot.voronoi(penguins, {x: "body_mass_g", fill: "species"}),
Plot.voronoiMesh(penguins, {x: "body_mass_g", stroke: "white", strokeOpacity: 1})
]
})
```

The Delaunay marks also work with Plot’s projection system, as in this Voronoi diagram showing the distribution of Walmart stores in the contiguous United States.

Fork```
Plot.plot({
projection: "albers",
marks: [
Plot.geo(nation),
Plot.dot(walmarts, {x: "longitude", y: "latitude", fill: "currentColor", r: 1}),
Plot.voronoiMesh(walmarts, {x: "longitude", y: "latitude"})
]
})
```

CAUTION

Distances between projected points are not exactly proportional to the corresponding distances on the sphere. This creates a discrepancy between the planar Voronoi diagram and its spherical counterpart. For greater accuracy, use d3-geo-voronoi with the geo mark.

## delaunayLink(*data*, *options*)

`Plot.delaunayLink(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})`

Draws links for each edge of the Delaunay triangulation of the points given by the **x** and **y** channels. Supports the same options as the link mark, except that **x1**, **y1**, **x2**, and **y2** are derived automatically from **x** and **y**. When an aesthetic channel is specified (such as **stroke** or **strokeWidth**), the link inherits the corresponding channel value from one of its two endpoints arbitrarily.

If a **z** channel is specified, the input points are grouped by *z*, and separate Delaunay triangulations are constructed for each group.

## delaunayMesh(*data*, *options*)

`Plot.delaunayMesh(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})`

Draws a mesh of the Delaunay triangulation of the points given by the **x** and **y** channels. The **stroke** option defaults to *currentColor*, and the **strokeOpacity** defaults to 0.2. The **fill** option is not supported. When an aesthetic channel is specified (such as **stroke** or **strokeWidth**), the mesh inherits the corresponding channel value from one of its constituent points arbitrarily.

If a **z** channel is specified, the input points are grouped by *z*, and separate Delaunay triangulations are constructed for each group.

## hull(*data*, *options*)

`Plot.hull(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})`

Draws a convex hull around the points given by the **x** and **y** channels. The **stroke** option defaults to *currentColor* and the **fill** option defaults to *none*. When an aesthetic channel is specified (such as **stroke** or **strokeWidth**), the hull inherits the corresponding channel value from one of its constituent points arbitrarily.

If a **z** channel is specified, the input points are grouped by *z*, and separate convex hulls are constructed for each group. If the **z** channel is not specified, it defaults to either the **fill** channel, if any, or the **stroke** channel, if any.

## voronoi(*data*, *options*)

`Plot.voronoi(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})`

Draws polygons for each cell of the Voronoi tessellation of the points given by the **x** and **y** channels.

If a **z** channel is specified, the input points are grouped by *z*, and separate Voronoi tessellations are constructed for each group.

## voronoiMesh(*data*, *options*)

`Plot.voronoiMesh(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})`

Draws a mesh for the cell boundaries of the Voronoi tessellation of the points given by the **x** and **y** channels. The **stroke** option defaults to *currentColor*, and the **strokeOpacity** defaults to 0.2. The **fill** option is not supported. When an aesthetic channel is specified (such as **stroke** or **strokeWidth**), the mesh inherits the corresponding channel value from one of its constituent points arbitrarily.

If a **z** channel is specified, the input points are grouped by *z*, and separate Voronoi tessellations are constructed for each group.