# Projections ^0.6.1

A **projection** maps abstract coordinates in *x* and *y* to pixel positions on screen. Most often, abstract coordinates are spherical (degrees longitude and latitude), as when rendering a geographic map. For example, below we show earthquakes in the last seven days with a magnitude of 2.5 or higher as reported by the USGS. Use the slider to adjust the *orthographic* projection’s center of longitude.

```
Plot.plot({
projection: {type: "orthographic", rotate: [-longitude, -30]},
r: {transform: (d) => Math.pow(10, d)}, // convert Richter to amplitude
marks: [
Plot.geo(land, {fill: "currentColor", fillOpacity: 0.2}),
Plot.sphere(),
Plot.dot(earthquakes, {x: "longitude", y: "latitude", r: "magnitude", stroke: "red", fill: "red", fillOpacity: 0.2})
]
})
```

```
Plot.plot({
projection: {type: "orthographic", rotate: [-longitude, -30]},
r: {transform: (d) => Math.pow(10, d)}, // convert Richter to amplitude
marks: [
Plot.geo(land, {fill: "currentColor", fillOpacity: 0.2}),
Plot.sphere(),
Plot.dot(earthquakes, {x: "longitude", y: "latitude", r: "magnitude", stroke: "red", fill: "red", fillOpacity: 0.2})
]
})
```

Above, a geo mark draws polygons representing land and a sphere mark draws the outline of the globe. A dot mark draws earthquakes as circles sized by magnitude.

The geo mark is “projection aware” so that it can handle all the nuances of projecting spherical polygons to the screen — leaning on d3-geo to provide adaptive sampling with configurable precision, antimeridian cutting, and clipping. The dot mark is not; instead, Plot applies the projection in place of the *x* and *y* scales. Hence, projections work with any mark that consumes continuous **x** and **y** channels — as well as marks that use **x1** & **y1** and **x2** & **y2**. Each mark implementation decides whether to handle projections specially or to treat the projection as any other position scale. (For example, the line mark is projection-aware to draw geodesics.)

INFO

Marks that require *band* scales (bars, cells, and ticks) cannot be used with projections. Likewise one-dimensional marks such as rules cannot be used, though see #1164.

Plot provides a variety of built-in projections. And as above, all world projections can be rotated to show a different aspect.

Fork```
Plot.plot({
projection: "equirectangular",
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor"}),
Plot.sphere()
]
})
```

```
Plot.plot({
projection: "equirectangular",
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor"}),
Plot.sphere()
]
})
```

Why so many? Each projection has its strengths and weaknesses:

*conformal*projections preserve angles and local shape,*equal-area*projections preserve area (use these for choropleths),*equidistant*projections preserve distance from one (or two) points,*azimuthal*projections expand radially from a central feature,*cylindrical*projections have symmetry around the axis of rotation,- the
*stereographic*projection preserves circles, and - the
*gnomonic*projection displays all great circles as straight lines!

No single projection is best at everything. It is impossible, for example, for a projection to be both conformal and equal-area.

In addition to world projections, Plot provides the U.S.-centric *albers-usa* conic equal-area projection with an inset of Alaska and Hawaii. (Note that the scale for Alaska is diminished: it is projected at 0.35× its true relative area.)

```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(nation),
Plot.geo(statemesh, {strokeOpacity: 0.2})
]
})
```

```
Plot.plot({
projection: "albers-usa",
marks: [
Plot.geo(nation),
Plot.geo(statemesh, {strokeOpacity: 0.2})
]
})
```

TIP

Use the *albers-usa* projection for U.S.-centric choropleth maps.

For maps that focus on a specific region, use the **domain** option to zoom in. This object should be a GeoJSON object. For example, you can use d3.geoCircle to generate a circle of a given radius centered at a given longitude and latitude. You can also use the **inset** options for a bit of padding around the **domain**.

```
Plot.plot({
projection: {
type: "azimuthal-equidistant",
rotate: [-9, -34],
domain: circle,
inset: 10
},
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor", fillOpacity: 0.3}),
Plot.geo(circle, {stroke: "red", strokeWidth: 2}),
Plot.frame()
]
})
```

```
Plot.plot({
projection: {
type: "azimuthal-equidistant",
rotate: [-9, -34],
domain: circle,
inset: 10
},
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor", fillOpacity: 0.3}),
Plot.geo(circle, {stroke: "red", strokeWidth: 2}),
Plot.frame()
]
})
```

`circle = d3.geoCircle().center([9, 34]).radius(radius)()`

`circle = d3.geoCircle().center([9, 34]).radius(radius)()`

If none of Plot’s built-in projections meet your needs, you can use any of D3’s extended projections by specifying the **projection** option as a function that returns a D3 projection. Below, a map of Antarctica in a polar aspect of the *azimuthal-equidistant* projection.

```
Plot.plot({
width: 688,
height: 688,
projection: ({width, height}) => d3.geoAzimuthalEquidistant()
.rotate([0, 90])
.translate([width / 2, height / 2])
.scale(width)
.clipAngle(40),
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor"}),
Plot.frame()
]
})
```

```
Plot.plot({
width: 688,
height: 688,
projection: ({width, height}) => d3.geoAzimuthalEquidistant()
.rotate([0, 90])
.translate([width / 2, height / 2])
.scale(width)
.clipAngle(40),
marks: [
Plot.graticule(),
Plot.geo(land, {fill: "currentColor"}),
Plot.frame()
]
})
```

While this notebook mostly details spherical projections, you can use the *identity* projection to display planar geometry. For example, below we draw a schematic of the second floor of the Westport House in Dundee, Ireland.

`Plot.geo(westport).plot({projection: {type: "identity", domain: westport}})`

`Plot.geo(westport).plot({projection: {type: "identity", domain: westport}})`

TIP

There’s also a *reflect-y* projection in case *y* points up↑, which is often the case with projected reference systems.

Naturally, Plot’s projection system is compatible with its faceting system. Below, a comic strip of sorts shows the locations of Walmart store openings in past decades.

Fork```
Plot.plot({
marginLeft: 0,
marginRight: 0,
projection: "albers",
fx: {
interval: "10 years",
tickFormat: (d) => `${d.getUTCFullYear()}’s`,
label: null
},
marks: [
Plot.geo(statemesh, {strokeOpacity: 0.1}),
Plot.geo(nation),
Plot.dot(walmarts, {fx: "date", x: "longitude", y: "latitude", r: 1, fill: "currentColor"})
]
})
```

```
Plot.plot({
marginLeft: 0,
marginRight: 0,
projection: "albers",
fx: {
interval: "10 years",
tickFormat: (d) => `${d.getUTCFullYear()}’s`,
label: null
},
marks: [
Plot.geo(statemesh, {strokeOpacity: 0.1}),
Plot.geo(nation),
Plot.dot(walmarts, {fx: "date", x: "longitude", y: "latitude", r: 1, fill: "currentColor"})
]
})
```

INFO

This uses the **interval** scale option to bin temporal data into facets by decade.

To learn more about mapping with Plot, see our hands-on tutorials:

## Projection options

The **projection** plot option applies a two-dimensional (often geographic) projection in place of **x** and **y** scales. It is typically used in conjunction with a geo mark to produce a map, but can be used with any mark that supports **x** and **y** channels, such as dot, text, arrow, and rect. For marks that use **x1**, **y1**, **x2**, and **y2** channels, the two projected points are ⟨*x1*, *y1*⟩ and ⟨*x2*, *y2*⟩; otherwise, the projected point is ⟨*x*, *y*⟩.

The following built-in named projections are supported:

*equirectangular*- the equirectangular, or*plate carrée*, projection*orthographic*- the orthographic projection*stereographic*- the stereographic projection*mercator*- the Mercator projection*equal-earth*- the Equal Earth projection by Šavrič*et al.**azimuthal-equal-area*- the azimuthal equal-area projection*azimuthal-equidistant*- the azimuthal equidistant projection*conic-conformal*- the conic conformal projection*conic-equal-area*- the conic equal-area projection*conic-equidistant*- the conic equidistant projection*gnomonic*- the gnomonic projection*transverse-mercator*- the transverse Mercator projection*albers*- the Albers’ conic equal-area projection*albers-usa*- a composite Albers conic equal-area projection suitable for the United States*identity*- the identity projection for planar geometry*reflect-y*- like the identity projection, but*y*points up- null (default) - the null projection for pre-projected geometry in screen coordinates

In addition to these named projections, the **projection** option may be specified as a D3 projection, or any custom projection that implements *projection*.stream, or a function that receives a configuration object ({*width*, *height*, ...*options*}) and returns such a projection. In the last case, the width and height represent the frame dimensions minus any insets.

If the **projection** option is specified as an object, the following additional projection options are supported:

**type**- one of the projection names above**parallels**- the standard parallels (for conic projections only)**precision**- the sampling threshold**rotate**- a two- or three- element array of Euler angles to rotate the sphere**domain**- a GeoJSON object to fit in the center of the (inset) frame**inset**- inset by the given amount in pixels when fitting to the frame (default zero)**insetLeft**- inset from the left edge of the frame (defaults to inset)**insetRight**- inset from the right edge of the frame (defaults to inset)**insetTop**- inset from the top edge of the frame (defaults to inset)**insetBottom**- inset from the bottom edge of the frame (defaults to inset)**clip**- the projection clipping method

The following projection clipping methods are supported for **clip**:

*frame*or true (default) - clip to the extent of the frame (including margins but not insets)- a number - clip to a great circle of the given radius in degrees centered around the origin
- null or false - do not clip

Whereas the **clip** mark option is implemented using SVG clipping, the **clip** projection option affects the generated geometry and typically produces smaller SVG output.