# Projections

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})
]
})
```

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()
]
})
```

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})
]
})
```

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()
]
})
```

`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()
]
})
```

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}})`

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"})
]
})
```

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.