Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@observablehq/plot

observablehq257.5kISC0.6.17TypeScript support: included

A JavaScript library for exploratory data visualization.

readme

Observable Plot

The Observable Plot logo, spelling out the letters P-L-O-T in pastel shapes.

Observable Plot is a free, open-source, JavaScript library for visualizing tabular data, focused on accelerating exploratory data analysis. It has a concise, memorable, yet expressive API, featuring scales and layered marks in the grammar of graphics style.

<picture> <source media="(prefers-color-scheme: dark)" srcset="https://observablehq.observablehq.cloud/oss-analytics/@observablehq/plot/downloads-dark.svg"> Daily downloads of Observable Plot </picture>

Daily downloads of Observable Plot · oss-analytics

Documentation 📚

https://observablehq.com/plot/

Examples 🖼️

https://observablehq.com/@observablehq/plot-gallery

Releases 🚀

See our CHANGELOG and summary release notes.

Getting help 🏠

See our community guide.

Contributing 🙏

See CONTRIBUTING.md.

changelog

Observable Plot - Changelog

Year: Current (2025) · 2024 · 2023 · 2022 · 2021

0.6.17

Released TDB, 2025.

The clip mark option now supports GeoJSON objects 🌎 in addition to the named frame and sphere clipping methods, allowing the visual extent of marks to be limited to arbitrary polygons. For instance, this Voronoi mesh of world airports is clipped to land boundaries:

a map of world airports with a Voronoi mesh clipped to land

Plot.plot({
  projection: {type: "orthographic", rotate: [110, -50]},
  marks: [
    Plot.dot(airports, {x: "longitude", y: "latitude", fill: "red", r: 1}),
    Plot.voronoiMesh(airports, {x: "longitude", y: "latitude", clip: land}),
    Plot.sphere(),
    Plot.geo(land)
  ]
})

The GeoJSON object passed to the clip option is rendered as a clipPath element using the same path data that a geo mark would produce, respecting the plot’s top-level projection option, if any. For performance, clipPath elements are shared by marks clipped with the same GeoJSON object. For example, the raster mark and contour mark below show atmospheric water vapor measurements across the United States from NASA Earth Observations; both marks are clipped to the nation’s boundary, censoring the (absurd) values that would otherwise be interpolated between Alaska, Southern California, and Hawai’i.

a map of water vapor measurements in the United States

Plot.raster(vapor, {
  fill: Plot.identity,
  width: 360,
  height: 180,
  x1: -180, y1: 90, x2: 180, y2: -90,
  interpolate: "barycentric",
  blur: 10,
  clip: nation
}).plot()

[The code for the map above is too long to reproduce here in its entirety; click the image above for the complete code.]

The clip mark option can also be used to clip against arbitrary polygons, not just geographic boundaries. For example, to show the value of Math.atan2 over the unit circle:

the value of atan2 across the unit disc, encoded as color

Plot.raster({
  x1: -1, x2: 1, y1: -1, y2: 1,
  fill: (x, y) => Math.atan2(y, x),
  clip: {
    type: "Polygon",
    coordinates: [
      d3.range(0, 2 * Math.PI, 0.1).map((angle) => [Math.cos(angle), Math.sin(angle)])
    ]
  }
}).plot({width: 300, aspectRatio: 1})

The interactive tip associated with a waffle mark is now anchored to the “center” of the visual representation of the associated datum. That center depends on the shape that is referenced. For fun, here’s a chart from out unit tests showing these anchoring points for various amounts of waffling. Baffling!

waffle mark with the anchor position of each datum marked with its value

For earlier changes, continue to the 2024 CHANGELOG.