Skip to content
On this page

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.

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

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

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

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

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

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

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.

Library released under ISC License.