Skip to content

Geo mark ^0.6.1

The geo mark draws geographic features — polygons, lines, points, and other geometry — often as thematic maps. It works with Plot’s projection system. For example, the choropleth map below shows unemployment by county in the United States.

Fork
js
Plot.plot({
  projection: "albers-usa",
  color: {
    type: "quantile",
    n: 9,
    scheme: "blues",
    label: "Unemployment (%)",
    legend: true
  },
  marks: [
    Plot.geo(counties, {
      fill: "unemployment",
      title: (d) => `${d.properties.name} ${d.properties.unemployment}%`,
      tip: true
    })
  ]
})

A geo mark’s data is typically GeoJSON. You can pass a single GeoJSON object, a feature or geometry collection, or an array or iterable of GeoJSON objects; Plot automatically normalizes these into an array of features or geometries. When a mark’s data is GeoJSON, Plot will look for the specified field name (such as unemployment above, for fill) in the GeoJSON object’s properties if the object does not have this property directly. prerelease

The size of Point and MultiPoint geometries is controlled by the r option. For example, below we show earthquakes in the last seven days with a magnitude of 2.5 or higher as reported by the USGS. As with the dot mark, the effective radius is controlled by the r scale, which is by default a sqrt scale such that the area of a point is proportional to its value. And likewise point geometries are by default sorted by descending radius to reduce occlusion, drawing the smallest circles on top. Set the sort option to null to use input order instead.

Fork
js
Plot.plot({
  projection: "equirectangular",
  r: {transform: (r) => Math.pow(10, r)}, // Richter to amplitude
  marks: [
    Plot.geo(land, {fill: "currentColor", fillOpacity: 0.2}),
    Plot.sphere(),
    Plot.geo(earthquakes, {
      r: "mag",
      fill: "red",
      fillOpacity: 0.2,
      stroke: "red",
      title: "title",
      href: "url",
      target: "_blank"
    })
  ]
})

TIP

Click on any of the earthquakes above to see details.

The graticule helper draws a uniform grid of meridians (lines of constant longitude) and parallels (lines of constant latitude) every 10° between ±80° latitude; for the polar regions, meridians are drawn every 90°. The sphere helper draws the outline of the projected sphere.

Fork
js
Plot.plot({
  inset: 2,
  projection: {type: "orthographic", rotate: [0, -30, 20]},
  marks: [
    Plot.sphere({fill: "white", stroke: "currentColor"}),
    Plot.graticule({strokeOpacity: 0.3})
  ]
})

The geo mark’s geometry channel can be used to generate geometry from a non-GeoJSON data source. For example, below we visualize the shockwave created by the explosion of the Hunga Tonga–Hunga Haʻapai volcano on January 15, 2022 with a series of geodesic circles of increasing radius.

Fork
js
Plot.plot({
  projection: {
    type: "equal-earth",
    rotate: [90, 0]
  },
  color: {
    legend: true,
    label: "Distance from Tonga (km)",
    transform: (d) => 111.2 * d, // degrees to km
    zero: true
  },
  marks: [
    Plot.geo(land),
    Plot.geo([0.5, 179.5].concat(d3.range(10, 171, 10)), {
      geometry: d3.geoCircle().center([-175.38, -20.57]).radius((r) => r),
      stroke: (r) => r,
      strokeWidth: 2
    }),
    Plot.sphere()
  ]
})

By default, the geo mark doesn’t have x and y channels; when you use the tip option, the centroid transform is implicitly applied on the geometries to compute the tip position by generating x and y channels. prerelease You can alternatively specify these channels explicitly. The centroids are shown below in red.

Fork
js
Plot.plot({
  projection: "albers-usa",
  marks: [
    Plot.geo(states, {strokeOpacity: 0.1, tip: true, title: "name"}),
    Plot.geo(nation),
    Plot.dot(states, Plot.centroid({fill: "red", stroke: "white"}))
  ]
})

The geo mark supports faceting. Below, a comic strip of sorts shows the locations of Walmart store openings in past decades.

Fork
js
Plot.plot({
  margin: 0,
  padding: 0,
  projection: "albers",
  fy: {interval: "10 years"},
  marks: [
    Plot.geo(statemesh, {strokeOpacity: 0.2}),
    Plot.geo(nation),
    Plot.geo(walmarts, {fy: "date", r: 1.5, fill: "blue", tip: true, title: "date"}),
    Plot.axisFy({frameAnchor: "top", dy: 30, tickFormat: (d) => `${d.getUTCFullYear()}’s`})
  ]
})

INFO

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

Lastly, the geo mark is not limited to spherical geometries! Plot’s projection system includes planar projections, which allow you to work with shapes — such as contours — generated on an arbitrary flat surface.

Geo options

The geometry channel specifies the geometry (GeoJSON object) to draw; if not specified, the mark’s data is assumed to be GeoJSON.

In addition to the standard mark options, the r option controls the size of Point and MultiPoint geometries. It can be specified as either a channel or constant. When r is specified as a number, it is interpreted as a constant radius in pixels; otherwise it is interpreted as a channel and the effective radius is controlled by the r scale. If the r option is not specified it defaults to 3 pixels. Geometries with a nonpositive radius are not drawn. If r is a channel, geometries will be sorted by descending radius by default.

The x and y position channels may also be specified in conjunction with the tip option. prerelease These are bound to the x and y scale (or projection), respectively.

geo(data, options)

js
Plot.geo(counties, {fill: "rate"})

Returns a new geo mark with the given data and options. If data is a GeoJSON feature collection, then the mark’s data is data.features; if data is a GeoJSON geometry collection, then the mark’s data is data.geometries; if data is some other GeoJSON object, then the mark’s data is the single-element array [data]. If the geometry option is not specified, data is assumed to be a GeoJSON object or an iterable of GeoJSON objects.

sphere(options) ^0.6.1

js
Plot.sphere()

Returns a new geo mark with a Sphere geometry object and the given options.

graticule(options) ^0.6.1

js
Plot.graticule()

Returns a new geo mark with a 10° global graticule geometry object and the given options.