# Centroid transform ^0.6.2

Plot offers two transforms that derive centroids from GeoJSON geometries: centroid and geoCentroid. These transforms can be used by any mark that accepts **x** and **y** channels. Below, a text mark labels the U.S. states.

```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(statemesh),
Plot.text(states, Plot.centroid({text: (d) => d.properties.name, fill: "currentColor", stroke: "white"}))
]
})
```

```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(statemesh),
Plot.text(states, Plot.centroid({text: (d) => d.properties.name, fill: "currentColor", stroke: "white"}))
]
})
```

For fun, we can pass county centroids to the voronoi mark.

Fork`Plot.voronoi(counties, Plot.centroid()).plot({projection: "albers"})`

`Plot.voronoi(counties, Plot.centroid()).plot({projection: "albers"})`

While the centroid transform computes the centroid of a geometry *after* projection, the geoCentroid transform computes it *before* projection, then projects the resulting coordinates. This difference has a few implications, as follows.

As an initializer, the centroid transform operates *after* the geometries have been projected to screen coordinates. The resulting **x** and **y** channels reference the pixel coordinates of the planar centroid of the *projected* shapes. No assumption is made about the geometries: they can be in any coordinate system, and the returned value is in the frame — as long as the projected geometry returns at least one visible point.

`Plot.dot(counties, Plot.centroid()).plot({projection: "albers-usa"})`

`Plot.dot(counties, Plot.centroid()).plot({projection: "albers-usa"})`

The geoCentroid transform is more specialized as the **x** and **y** channels it derives represent the longitudes and latitudes of the centroids of the given GeoJSON geometries, before projection. It expects the geometries to be specified in *spherical* coordinates. It is more correct, in a geospatial sense — for example, the spherical centroid always represents the center of mass of the original shape, and it will be rotated exactly in line with the projection’s rotate argument. However, this also means that it might land outside the frame if only a part of the land mass is visible, and might be clipped by the projection. In practice, the difference is generally imperceptible.

`Plot.dot(counties, Plot.geoCentroid()).plot({projection: "albers-usa"})`

`Plot.dot(counties, Plot.geoCentroid()).plot({projection: "albers-usa"})`

The geoCentroid transform is slightly faster than the centroid initializer — which might be useful if you have tens of thousands of features and want to show their density on a hexbin map:

Fork`Plot.dot(counties, Plot.hexbin({r:"count"}, Plot.geoCentroid())).plot({projection: "albers"})`

`Plot.dot(counties, Plot.hexbin({r:"count"}, Plot.geoCentroid())).plot({projection: "albers"})`

Combined with the pointer transform, the centroid transform can add interactive tips on a map:

Fork```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(statemesh, {strokeOpacity: 0.2}),
Plot.geo(nation),
Plot.dot(states, Plot.centroid({fill: "red", stroke: "white"})),
Plot.tip(states, Plot.pointer(Plot.centroid({title: (d) => d.properties.name})))
]
})
```

```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(statemesh, {strokeOpacity: 0.2}),
Plot.geo(nation),
Plot.dot(states, Plot.centroid({fill: "red", stroke: "white"})),
Plot.tip(states, Plot.pointer(Plot.centroid({title: (d) => d.properties.name})))
]
})
```

## centroid(*options*)

`Plot.centroid({geometry: Plot.identity})`

`Plot.centroid({geometry: Plot.identity})`

The centroid initializer derives **x** and **y** channels representing the planar (projected) centroids for the given GeoJSON geometry. If the **geometry** option is not specified, the mark’s data is assumed to be GeoJSON objects.

## geoCentroid(*options*)

`Plot.geoCentroid({geometry: Plot.identity})`

`Plot.geoCentroid({geometry: Plot.identity})`

The geoCentroid transform derives **x** and **y** channels representing the spherical centroids for the given GeoJSON geometry. If the **geometry** option is not specified, the mark’s data is assumed to be GeoJSON objects.