Observable Plot
repository·main·Indexed 26 days ago
https://github.com/observablehq/plotA JavaScript library for rapid, expressive data visualization of tabular data following the grammar of graphics paradigm. It provides a variety of marks including dot, image, geo, and density, along with support for geographic projections, window transforms, and complex faceting. Version 0.6.17 supports features such as color and opacity legends, custom render functions in marks, and server-side rendering via a custom document option.
What's inside @observablehq/plot
- Observable Plot is an open-source JavaScript library designed for visualizing tabular data and accelerating exploratory data analysis. It uses a grammar of graphics approach, allowing you to create visualizations by assigning data columns to visual properties of marks (such as position, color, or size) using scales and layered marks.
Understand Plot Transforms
mainTransforms derive data as part of the plot specification, helping to reshape data for visualization (e.g., calculating medians, binning, or rolling averages).
Key characteristics:
- Not required: You can aggregate data manually using libraries like D3 and pass the results to marks.
- Two-argument pattern: Most built-in transforms take two arguments:
options(transform-specific settings) andmark options(settings to be passed through to the mark). The transform returns a new options object containing the transformed mark options. - Composability: Transforms can be nested. For example, you can apply a
normalizetransform on top of abintransform. - Implicit transforms: Many marks have built-in transforms. For example,
rectYapplies an implicitstackYtransform when using theyoption.
Understand Scales in Observable Plot
mainScales convert abstract data values (like time, temperature, or categories) into visual values (like x and y positions, color, radius, or opacity).
In Plot, marks bind data channels to scales. While channel names often match scale names (e.g., the
xchannel uses thexscale), they can differ (e.g., an area mark'sy1andy2channels both bind to theyscale). You can also use scale overrides to opt-out of a default scale for a specific channel.Key concepts:
- Domain: The input abstract values (e.g., a date range
[start, end]or a set of categories['A', 'B']). - Range: The output visual values (e.g., pixel positions
[left, right]or a color extent['blue', 'red']). - Type: The nature of the input data (e.g.,
linearorordinal).
- Domain: The input abstract values (e.g., a date range
Core Concepts of Observable Plot
mainObservable Plot is a JavaScript library designed for exploratory data visualization. Unlike traditional charting libraries that use predefined chart types, Plot uses a layered approach based on geometric shapes called Marks.
Key concepts include:
- Marks: Layered geometric shapes (e.g., bars, dots, lines) used to build visualizations.
- Scales: Functions that map abstract data values (like time or temperature) to visual values (like position or color).
- Transforms: On-the-fly data derivations, such as binning quantitative values or computing rolling averages.
- Facets: The use of small multiples to repeat a plot across different partitions of data for easier comparison.
- Projections: Support for GeoJSON and D3's spherical projection system for geographic mapping.
Use built-in intervals in Plot
mainObservable Plot provides built-in interval implementations that can be used with the
tickoption for scales, thethresholdsoption for bin transforms, or other purposes.Intervals implement several core methods:
floor(value): Returns the greatest interval boundary less than or equal to the specified value.offset(value, [step]): Returns the value equal tovalueplusstepintervals (defaults to 1).range(start, stop): Returns an array of values representing every interval boundary fromstart(inclusive) tostop(exclusive).ceil(value): Returns the least interval boundary greater than or equal to the specified value.
Use the select transform to filter marks
mainThe
selecttransform filters a mark's index to show a subset of the data, typically used to pull a single value or a sample subset out of each series (e.g., labeling the last point in a line chart).Important: The transform uses input order, not natural order by value, to determine first and last. For example, if a dataset is in reverse chronological order, the 'first' element is the most recent.
To group data into series, use the
z,fill, orstrokechannels in the same way asareaorlinemarks.Plot.plot({ y: {grid: true}, marks: [ Plot.ruleY([0]), Plot.line(aapl, {x: "Date", y: "Close"}), Plot.text(aapl, Plot.selectLast({x: "Date", y: "Close", text: "Close", frameAnchor: "bottom", dy: -6})) ] })Use the Tip mark for interactive or static annotations
mainThe
Plot.tipmark displays text or name-value pairs in a floating box anchored to an (x, y) position.It can be used in two primary ways:
- Interactive Tips: Paired with a pointer transform (like
Plot.pointerXorPlot.pointer) to reveal details when hovering over data points. - Static Annotations: Used to draw attention to specific points by providing fixed coordinates and a
titlechannel.
By default, if multiple tips and pointer transforms are present, the
pooloption istrue, meaning only one tip is visible at a time. Setpool: falseto allow multiple tips to be visible simultaneously.// Interactive example using pointerX Plot.plot({ y: {grid: true}, marks: [ Plot.lineY(aapl, {x: "Date", y: "Close"}), Plot.tip(aapl, Plot.pointerX({x: "Date", y: "Close"})) ] }) // Static annotation example Plot.plot({ y: {grid: true}, marks: [ Plot.lineY(aapl, {x: "Date", y: "Close"}), Plot.tip( [`Apple stock reaches a new high of $133 on Feb. 23, 2015.`], {x: new Date("2015-02-23"), y: 133, dy: -3, anchor: "bottom"} ) ] })- Interactive Tips: Paired with a pointer transform (like
Use the Window transform for rolling statistics
mainThe window transform is a specialized map transform used to compute moving windows and derive summary statistics (like rolling averages, minimums, or maximums) from them. It can be applied to specific channels using
Plot.windowXorPlot.windowY, or used generally withPlot.windowinside aPlot.mapcall.Note that the transform uses the input order of the data to determine the window alignment, not the natural value order. If your data is not sorted chronologically, use a sort transform first.
Plot.plot({ y: { grid: true, label: "Temperature (°F)" }, marks: [ Plot.areaY(sftemp, {x: "date", y1: "low", y2: "high", fillOpacity: 0.3}), Plot.lineY(sftemp, Plot.windowY(k, {x: "date", y: "low", stroke: "blue"})), Plot.lineY(sftemp, Plot.windowY(k, {x: "date", y: "high", stroke: "red"})) ] })Use the density mark
mainThe
Plot.densitymark shows the estimated density of two-dimensional or one-dimensional point clouds using contours (isolines). It is useful for visualizing concentrations in dense datasets to avoid overplotting.Key Features:
- 2D Density: Visualizes concentrations of $(x, y)$ points.
- 1D Density: Visualizes the distribution of a single dimension (e.g., just $x$).
- Projections: Supports Plot's projection system (e.g., for geographic density maps).
- Color Encoding: Using the keyword
densityforstrokeorfillcreates a sequential color encoding based on density values. - Faceting: Supports
fxandfyfor comparison across facets. Thresholds are automatically synchronized to the series with the highest density to facilitate comparison.
Plot.plot({ marks: [ Plot.density(data, {x: "waiting", y: "eruptions", stroke: "blue"}) ] })Use the tip mark for interactive details
mainThe
Plot.tipmark displays text or name-value pairs in a floating box anchored to a position. It is designed to work with pointer interactions so that only the point closest to the pointer is rendered, allowing users to reveal details by hovering.Implicit Tip
You can enable an implicit tip mark by setting
tip: trueon a mark option:Plot.lineY(data, {x: "Date", y: "Close", tip: true}).plot()Explicit Tip
For more control, use
Plot.tipas a separate mark. You can pair it withPlot.pointerXorPlot.pointerYto find the closest point:Plot.plot({ marks: [ Plot.lineY(data, {x: "Date", y: "Close"}), Plot.tip(data, Plot.pointerX({x: "Date", y: "Close"})) ] })Static Annotations
You can also use
Plot.tipfor static commentary by providing an array of strings (for multi-line text) and an anchor position:Plot.tip( [`Your multi-line text here...`], {x: dateValue, y: value, dy: -3, anchor: "bottom"} )Plot.lineY(aapl, {x: "Date", y: "Close", tip: true}).plot()Work with GeoJSON data and property shorthand
mainAs of version 0.6.16, all marks support GeoJSON data and property shorthand. When using a GeoJSON
FeatureCollection, you can use a property name directly as a channel option (e.g.,fill: "unemployment"), which is shorthand for(d) => d.properties.unemployment. Additionally, thegeomark now supports thetip: trueoption, which uses an implicit centroid transform to enable interactive tooltips.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 }) ] })Use the projection option in Plot
mainThe
projectionplot option applies a two-dimensional projection in place ofxandyscales. While typically used withgeomarks to create maps, it can be used with any mark supportingxandychannels (e.g.,dot,text,arrow,rect).For marks using
x1,y1,x2, andy2channels, the projection applies to both points. For other marks, it applies to the singlex,ypoint.Supported built-in named projections include:
equirectangular(plate carrée)orthographicstereographicmercatorequal-earthazimuthal-equal-areaazimuthal-equidistantconic-conformalconic-equal-areaconic-equidistantgnomonictransverse-mercatoralbersalbers-usaidentityreflect-y(identity withypointing up)null(default, for pre-projected geometry)