# 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.

Fork
js
``````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
js
``````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.)

Fork
js
``````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.

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

Fork
js
``````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.

Fork
js
``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
js
``````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.

## 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.

Resources
Observable