0.6.6 • Published 1 year ago

think-plot v0.6.6

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

Observable Plot

Observable Plot is a JavaScript library for exploratory data visualization. If you are new to Plot, we highly recommend first reading these notebooks to introduce Plot’s core concepts such as marks and scales:

This README is intended as a technical reference for Plot’s API. For more, please see:

Installing

In Observable notebooks, Plot and D3 are available by default as part of the standard library.

For use with Webpack, Rollup, or other Node-based bundlers, Plot is typically installed via a package manager such as Yarn or npm. (Plot is distributed as an ES module; see Sindre Sorhus’s guide for help upgrading.)

yarn add @observablehq/plot

Plot can then be imported as a namespace:

import * as Plot from "@observablehq/plot";

In vanilla HTML, Plot can be imported as an ES module, say from jsDelivr:

<script type="module">

import * as Plot from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";

document.body.append(Plot.plot(options));

</script>

Plot is also available as a UMD bundle for legacy browsers.

<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script src="https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6"></script>
<script>

document.body.append(Plot.plot(options));

</script>

See also our Plot + React example.

Plot.plot(options)

Renders a new plot given the specified options and returns the corresponding SVG or HTML figure element. All options are optional.

Mark options

The marks option specifies an array of marks to render. Each mark has its own data and options; see the respective mark type (e.g., bar or dot) for which mark options are supported. Each mark may be a nested array of marks, allowing composition. Marks may also be a function which returns an SVG element, if you wish to insert some arbitrary content into your plot. And marks may be null or undefined, which produce no output; this is useful for showing marks conditionally (e.g., when a box is checked). Marks are drawn in z order, last on top. For example, here a single rule at y = 0 is drawn on top of blue bars for the alphabet dataset.

Plot.plot({
  marks: [
    Plot.barY(alphabet, {x: "letter", y: "frequency", fill: "steelblue"}),
    Plot.ruleY([0])
  ]
})

Layout options

These options determine the overall layout of the plot; all are specified as numbers in pixels:

  • marginTop - the top margin
  • marginRight - the right margin
  • marginBottom - the bottom margin
  • marginLeft - the left margin
  • margin - shorthand for the four margins
  • width - the outer width of the plot (including margins)
  • height - the outer height of the plot (including margins)
  • aspectRatio - the desired aspect ratio of data (affecting default height)

The default width is 640. On Observable, the width can be set to the standard width to make responsive plots. The default height is chosen automatically based on the plot’s associated scales; for example, if y is linear and there is no fy scale, it might be 396. The default margins depend on the maximum margins of the plot’s constituent marks. While most marks default to zero margins (because they are drawn inside the chart area), Plot’s axis mark has non-zero default margins.

The aspectRatio option, if not null, computes a default height such that a variation of one unit in the x dimension is represented by the corresponding number of pixels as a variation in the y dimension of one unit. Note: when using facets, set the fx and fy scales’ round option to false if you need an exact aspect ratio.

The style option allows custom styles to override Plot’s defaults. It may be specified either as a string of inline styles (e.g., "color: red;", in the same fashion as assigning element.style) or an object of properties (e.g., {color: "red"}, in the same fashion as assigning element.style properties). Note that unitless numbers (quirky lengths) such as {padding: 20} may not be supported by some browsers; you should instead specify a string with units such as {padding: "20px"}. By default, the returned plot has a white background, a max-width of 100%, and the system-ui font. Plot’s marks and axes default to currentColor, meaning that they will inherit the surrounding content’s color. For example, a dark theme:

Plot.plot({
  marks: …,
  style: {
    background: "black",
    color: "white"
  }
})

If a caption is specified, Plot.plot wraps the generated SVG element in an HTML figure element with a figcaption, returning the figure. To specify an HTML caption, consider using the html tagged template literal; otherwise, the specified string represents text that will be escaped as needed.

Plot.plot({
  marks: …,
  caption: html`Figure 1. This chart has a <i>fancy</i> caption.`
})

The generated SVG element has a random class name which applies a default stylesheet. Use the top-level className option to specify that class name.

The document option specifies the document used to create plot elements. It defaults to window.document, but can be changed to another document, say when using a virtual DOM library for server-side rendering in Node.

Scale options

Plot passes data through scales as needed before rendering marks. A scale maps abstract values such as time or temperature to visual values such as position or color. Within a given plot, marks share scales. For example, if a plot has two Plot.line marks, both share the same x and y scales for a consistent representation of data. (Plot does not currently support dual-axis charts, which are not advised.)

Plot.plot({
  marks: [
    Plot.line(aapl, {x: "Date", y: "Close"}),
    Plot.line(goog, {x: "Date", y: "Close"})
  ]
})

Each scale’s options are specified as a nested options object with the corresponding scale name within the top-level plot options:

  • x - horizontal position
  • y - vertical position
  • r - radius (size)
  • color - fill or stroke
  • opacity - fill or stroke opacity
  • length - linear length (for vectors)
  • symbol - categorical symbol (for dots)

For example, to set the domain for the x and y scales:

Plot.plot({
  x: {
    domain: [new Date("1880-01-01"), new Date("2016-11-01")]
  },
  y: {
    domain: [-0.78, 1.35]
  }
})

Plot supports many scale types. Some scale types are for quantitative data: values that can be added or subtracted, such as temperature or time. Other scale types are for ordinal or categorical data: unquantifiable values that can only be ordered, such as t-shirt sizes, or values with no inherent order that can only be tested for equality, such as types of fruit. Some scale types are further intended for specific visual encodings: for example, as position or color.

You can set the scale type explicitly via the scale.type option, though typically the scale type is inferred automatically. Some marks mandate a particular scale type: for example, Plot.barY requires that the x scale is a band scale. Some scales have a default type: for example, the radius scale defaults to sqrt and the opacity scale defaults to linear. Most often, the scale type is inferred from associated data, pulled either from the domain (if specified) or from associated channels. Strings and booleans imply an ordinal scale; dates imply a UTC scale; and anything else is linear. Unless they represent text, we recommend explicitly converting strings to more specific types when loading data (e.g., with d3.autoType or Observable’s FileAttachment). For simplicity’s sake, Plot assumes that data is consistently typed; type inference is based solely on the first non-null, non-undefined value.

For quantitative data (i.e. numbers), a mathematical transform may be applied to the data by changing the scale type:

  • linear (default) - linear transform (translate and scale)
  • pow - power (exponential) transform
  • sqrt - square-root transform (pow transform with exponent = 0.5)
  • log - logarithmic transform
  • symlog - bi-symmetric logarithmic transform per Webber et al.

The appropriate transform depends on the data’s distribution and what you wish to know. A sqrt transform exaggerates differences between small values at the expense of large values; it is a special case of the pow transform which has a configurable scale.exponent (0.5 for sqrt). A log transform is suitable for comparing orders of magnitude and can only be used when the domain does not include zero. The base defaults to 10 and can be specified with the scale.base option; note that this only affects the axis ticks and not the scale’s behavior. A symlog transform is more elaborate, but works well with wide-range values that include zero; it can be configured with the scale.constant option (default 1).

For temporal data (i.e. dates), two variants of a linear scale are also supported:

  • utc (default, recommended) - UTC time
  • time - local time

UTC is recommended over local time as charts in UTC time are guaranteed to appear consistently to all viewers whereas charts in local time will depend on the viewer’s time zone. Due to limitations in JavaScript’s Date class, Plot does not yet support an explicit time zone other than UTC.

For ordinal data (e.g., strings), use the ordinal scale type or the point or band position scale types. The categorical scale type is also supported; it is equivalent to ordinal except as a color scale, where it provides a different default color scheme. (Since position is inherently ordinal or even quantitative, categorical data must be assigned an effective order when represented as position, and hence categorical and ordinal may be considered synonymous in context.)

You can opt-out of a scale using the identity scale type. This is useful if you wish to specify literal colors or pixel positions within a mark channel rather than relying on the scale to convert abstract values into visual values. For position scales (x and y), an identity scale is still quantitative and may produce an axis, yet unlike a linear scale the domain and range are fixed based on the plot layout. (To opt out of a scale for a single channel, you can specify the channel values as a {value, scale} object; see mark options.)

Quantitative scales, as well as identity position scales, coerce channel values to numbers; both null and undefined are coerced to NaN. Similarly, time scales coerce channel values to dates; numbers are assumed to be milliseconds since UNIX epoch, while strings are assumed to be in ISO 8601 format.

A scale’s domain (the extent of its inputs, abstract values) and range (the extent of its outputs, visual values) are typically inferred automatically. You can set them explicitly using these options:

  • scale.domain - typically min, max, or an array of ordinal or categorical values
  • scale.range - typically min, max, or an array of ordinal or categorical values
  • scale.unknown - the desired output value (defaults to undefined) for invalid input values
  • scale.reverse - reverses the domain (or in somes cases, the range), say to flip the chart along x or y
  • scale.interval - an interval or time interval (for interval data; see below)

For most quantitative scales, the default domain is the min, max of all values associated with the scale. For the radius and opacity scales, the default domain is 0, max to ensure a meaningful value encoding. For ordinal scales, the default domain is the set of all distinct values associated with the scale in natural ascending order; for a different order, set the domain explicitly or add a sort option to an associated mark. For threshold scales, the default domain is 0 to separate negative and non-negative values. For quantile scales, the default domain is the set of all defined values associated with the scale. If a scale is reversed, it is equivalent to setting the domain as max, min instead of min, max.

The default range depends on the scale: for position scales (x, y, fx, and fy), the default range depends on the plot’s size and margins. For color scales, there are default color schemes for quantitative, ordinal, and categorical data. For opacity, the default range is 0, 1. And for radius, the default range is designed to produce dots of “reasonable” size assuming a sqrt scale type for accurate area representation: zero maps to zero, the first quartile maps to a radius of three pixels, and other values are extrapolated. This convention for radius ensures that if the scale’s data values are all equal, dots have the default constant radius of three pixels, while if the data varies, dots will tend to be larger.

The behavior of the scale.unknown option depends on the scale type. For quantitative and temporal scales, the unknown value is used whenever the input value is undefined, null, or NaN. For ordinal or categorical scales, the unknown value is returned for any input value outside the domain. For band or point scales, the unknown option has no effect; it is effectively always equal to undefined. If the unknown option is set to undefined (the default), or null or NaN, then the affected input values will be considered undefined and filtered from the output.

For data at regular intervals, such as integer values or daily samples, the scale.interval option can be used to enforce uniformity. The specified interval—such as d3.utcMonth—must expose an interval.floor(value), interval.offset(value), and interval.range(start, stop) functions. The option can also be specified as a number, in which case it will be promoted to a numeric interval with the given step. The option can alternatively be specified as a string (second, minute, hour, day, week, month, quarter, half, year, monday, tuesday, wednesday, thursday, friday, saturday, sunday) naming the corresponding UTC interval. This option sets the default scale.transform to the given interval’s interval.floor function. In addition, the default scale.domain is an array of uniformly-spaced values spanning the extent of the values associated with the scale.

Quantitative scales can be further customized with additional options:

  • scale.clamp - if true, clamp input values to the scale’s domain
  • scale.nice - if true (or a tick count), extend the domain to nice round values
  • scale.zero - if true, extend the domain to include zero if needed
  • scale.percent - if true, transform proportions in 0, 1 to percentages in 0, 100

Clamping is typically used in conjunction with setting an explicit domain since if the domain is inferred, no values will be outside the domain. Clamping is useful for focusing on a subset of the data while ensuring that extreme values remain visible, but use caution: clamped values may need an annotation to avoid misinterpretation. Top-level clamp, nice, and zero options are supported as shorthand for setting the respective option on all scales.

The scale.transform option allows you to apply a function to all values before they are passed through the scale. This is convenient for transforming a scale’s data, say to convert to thousands or between temperature units.

Plot.plot({
  y: {
    label: "↑ Temperature (°F)",
    transform: f => f * 9 / 5 + 32 // convert Celsius to Fahrenheit
  },
  marks: …
})

plot.scale(scaleName)

Scale definitions can be exposed through the plot.scale(scaleName) function of a returned plot. The scaleName must be one of the known scale names: "x", "y", "fx", "fy", "r", "color", "opacity", "symbol", or "length". If the associated plot has no scale with the given scaleName, returns undefined.

const plot = Plot.plot(…); // render a plot
const color = plot.scale("color"); // retrieve the color scale object
console.log(color.range); // inspect the color scale’s range, ["red", "blue"]

Plot.scale(options)

You can also create a standalone scale with Plot.scale(options). The options object must define at least one scale; see Scale options for how to define a scale. For example, here is a linear color scale with the default domain of 0, 1 and default scheme turbo:

const color = Plot.scale({color: {type: "linear"}});

Scale objects

Both plot.scale and Plot.scale return scale objects. These objects represent the actual (or “materialized”) scale options used by Plot, including the domain, range, interpolate function, etc. The scale’s label, if any, is also returned; however, note that other axis properties are not currently exposed. Point and band scales also expose their materialized bandwidth and step.

To reuse a scale across plots, pass the corresponding scale object into another plot specification:

const plot1 = Plot.plot(…);
const plot2 = Plot.plot({…, color: plot1.scale("color")});

For convenience, scale objects expose a scale.apply(input) method which returns the scale’s output for the given input value. When applicable, scale objects also expose a scale.invert(output) method which returns the corresponding input value from the scale’s domain for the given output value.

Position options

The position scales (x, y, fx, and fy) support additional options:

  • scale.inset - inset the default range by the specified amount in pixels
  • scale.round - round the output value to the nearest integer (whole pixel)

The x and fx scales support asymmetric insets for more precision. Replace inset by:

  • scale.insetLeft - insets the start of the default range by the specified number of pixels
  • scale.insetRight - insets the end of the default range by the specified number of pixels

Similarly, the y and fy scales support asymmetric insets with:

  • scale.insetTop - insets the top of the default range by the specified number of pixels
  • scale.insetBottom - insets the bottom of the default range by the specified number of pixels

The inset scale options can provide “breathing room” to separate marks from axes or the plot’s edge. For example, in a scatterplot with a Plot.dot with the default 3-pixel radius and 1.5-pixel stroke width, an inset of 5 pixels prevents dots from overlapping with the axes. The scale.round option is useful for crisp edges by rounding to the nearest pixel boundary.

In addition to the generic ordinal scale type, which requires an explicit output range value for each input domain value, Plot supports special point and band scale types for encoding ordinal data as position. These scale types accept a min, max range similar to quantitative scales, and divide this continuous interval into discrete points or bands based on the number of distinct values in the domain (i.e., the domain’s cardinality). If the associated marks have no effective width along the ordinal dimension—such as a dot, rule, or tick—then use a point scale; otherwise, say for a bar, use a band scale. In the image below, the top x scale is a point scale while the bottom x scale is a band scale; see Plot: Scales for an interactive version.

Ordinal position scales support additional options, all specified as proportions in 0, 1:

  • scale.padding - how much of the range to reserve to inset first and last point or band
  • scale.align - where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end)

For a band scale, you can further fine-tune padding:

  • scale.paddingInner - how much of the range to reserve to separate adjacent bands
  • scale.paddingOuter - how much of the range to reserve to inset first and last band

Align defaults to 0.5 (centered). Band scale padding defaults to 0.1 (10% of available space reserved for separating bands), while point scale padding defaults to 0.5 (the gap between the first point and the edge is half the distance of the gap between points, and likewise for the gap between the last point and the opposite edge). Note that rounding and mark insets (e.g., for bars and rects) also affect separation between adjacent marks.

Plot automatically generates axis and optionally grid marks for position scales. (For more control, declare these marks explicitly.) You can configure the implicit axes with the following scale options:

  • scale.axis - the orientation: top or bottom (or both) for x and fx; left or right (or both) for y and fy; null to suppress
  • scale.ticks - the approximate number of ticks to generate, or interval, or array of values
  • scale.tickSize - the length of each tick (in pixels; default 6 for x and y, or 0 for fx and fy)
  • scale.tickSpacing - the approximate number of pixels between ticks (if scale.ticks is not specified)
  • scale.tickPadding - the separation between the tick and its label (in pixels; default 3)
  • scale.tickFormat - either a function or specifier string to format tick values; see Formats
  • scale.tickRotate - whether to rotate tick labels (an angle in degrees clockwise; default 0)
  • scale.grid - if true, draw grid lines across the plot for each tick
  • scale.line - if true, draw the axis line (only for x and y)
  • scale.label - a string to label the axis
  • scale.labelAnchor - the label anchor: top, right, bottom, left, or center
  • scale.labelOffset - the label position offset (in pixels; default depends on margins and orientation)
  • scale.fontVariant - the font-variant attribute for axis ticks; defaults to tabular-nums for quantitative axes
  • scale.ariaLabel - a short label representing the axis in the accessibility tree
  • scale.ariaDescription - a textual description for the axis

Top-level options are also supported as shorthand: grid (for x and y only; see facet.grid), label, axis, inset, round, align, and padding.

Projection options

The top-level projection 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:

  • projection.type - one of the projection names above
  • projection.parallels - the standard parallels (for conic projections only)
  • projection.precision - the sampling threshold
  • projection.rotate - a two- or three- element array of Euler angles to rotate the sphere
  • projection.domain - a GeoJSON object to fit in the center of the (inset) frame
  • projection.inset - inset by the given amount in pixels when fitting to the frame (default zero)
  • projection.insetLeft - inset from the left edge of the frame (defaults to inset)
  • projection.insetRight - inset from the right edge of the frame (defaults to inset)
  • projection.insetTop - inset from the top edge of the frame (defaults to inset)
  • projection.insetBottom - inset from the bottom edge of the frame (defaults to inset)
  • projection.clip - the projection clipping method

The following projection clipping methods are supported for projection.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 mark.clip option is implemented using SVG clipping, the projection.clip option affects the generated geometry and typically produces smaller SVG output.

Color options

The normal scale types—linear, sqrt, pow, log, symlog, and ordinal—can be used to encode color. In addition, Plot supports special scale types for color:

  • categorical - equivalent to ordinal, but defaults to the tableau10 scheme
  • sequential - equivalent to linear
  • cyclical - equivalent to linear, but defaults to the rainbow scheme
  • threshold - encodes based on the specified discrete thresholds; defaults to the rdylbu scheme
  • quantile - encodes based on the computed quantile thresholds; defaults to the rdylbu scheme
  • quantize - transforms a continuous domain into quantized thresholds; defaults to the rdylbu scheme
  • diverging - like linear, but with a pivot; defaults to the rdbu scheme
  • diverging-log - like log, but with a pivot that defaults to 1; defaults to the rdbu scheme
  • diverging-pow - like pow, but with a pivot; defaults to the rdbu scheme
  • diverging-sqrt - like sqrt, but with a pivot; defaults to the rdbu scheme
  • diverging-symlog - like symlog, but with a pivot; defaults to the rdbu scheme

For a threshold scale, the domain represents n (typically numeric) thresholds which will produce a range of n + 1 output colors; the ith color of the range applies to values that are smaller than the ith element of the domain and larger or equal to the i - 1th element of the domain. For a quantile scale, the domain represents all input values to the scale, and the n option specifies how many quantiles to compute from the domain; n quantiles will produce n - 1 thresholds, and an output range of n colors. For a quantize scale, the domain will be transformed into approximately n quantized values, where n is an option that defaults to 5.

By default, all diverging color scales are symmetric around the pivot; set symmetric to false if you want to cover the whole extent on both sides.

Color scales support two additional options:

  • scale.scheme - a named color scheme in lieu of a range, such as reds
  • scale.interpolate - in conjunction with a range, how to interpolate colors

For quantile and quantize color scales, the scale.scheme option is used in conjunction with scale.n, which determines how many quantiles or quantized values to compute, and thus the number of elements in the scale’s range; it defaults to 5 (for quintiles in the case of a quantile scale).

The following sequential scale schemes are supported for both quantitative and ordinal data:

  • blues
  • greens
  • greys
  • oranges
  • purples
  • reds
  • bugn
  • bupu
  • gnbu
  • orrd
  • pubu
  • pubugn
  • purd
  • rdpu
  • ylgn
  • ylgnbu
  • ylorbr
  • ylorrd
  • cividis
  • inferno
  • magma
  • plasma
  • viridis
  • cubehelix
  • turbo
  • warm
  • cool

The default color scheme, turbo, was chosen primarily to ensure high-contrast visibility. Color schemes such as blues make low-value marks difficult to see against a white background, for better or for worse. To use a subset of a continuous color scheme (or any single-argument interpolate function), set the scale.range property to the corresponding subset of 0, 1; for example, to use the first half of the rainbow color scheme, use a range of 0, 0.5. By default, the full range 0, 1 is used. If you wish to encode a quantitative value without hue, consider using opacity rather than color (e.g., use Plot.dot’s strokeOpacity instead of stroke).

The following diverging scale schemes are supported:

  • brbg
  • prgn
  • piyg
  • puor
  • rdbu
  • rdgy
  • rdylbu
  • rdylgn
  • spectral
  • burd
  • buylrd

Picking a diverging color scheme name defaults the scale type to diverging; set the scale type to linear to treat the color scheme as sequential instead. Diverging color scales support a scale.pivot option, which defaults to zero. Values below the pivot will use the lower half of the color scheme (e.g., reds for the rdgy scheme), while values above the pivot will use the upper half (grays for rdgy).

The following cylical color schemes are supported:

  • rainbow
  • sinebow

The following categorical color schemes are supported:

  • accent (8 colors)
  • category10 (10 colors)
  • dark2 (8 colors)
  • paired (12 colors)
  • pastel1 (9 colors)
  • pastel2 (8 colors)
  • set1 (9 colors)
  • set2 (8 colors)
  • set3 (12 colors)
  • tableau10 (10 colors)

The following color interpolators are supported:

  • rgb - RGB (red, green, blue)
  • hsl - HSL (hue, saturation, lightness)
  • lab - CIELAB (a.k.a. “Lab”)
  • hcl - CIELChab (a.k.a. “LCh” or “HCL”)

For example, to use CIELChab:

Plot.plot({
  color: {
    range: ["red", "blue"],
    interpolate: "hcl"
  },
  marks: …
})

Or to use gamma-corrected RGB (via d3-interpolate):

Plot.plot({
  color: {
    range: ["red", "blue"],
    interpolate: d3.interpolateRgb.gamma(2.2)
  },
  marks: …
})

Sort options

If an ordinal scale’s domain is not set, it defaults to natural ascending order; to order the domain by associated values in another dimension, either compute the domain manually (consider d3.groupSort) or use an associated mark’s sort option. For example, to sort bars by ascending frequency rather than alphabetically by letter:

Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y"}})

The sort option is an object whose keys are ordinal scale names, such as x or fx, and whose values are mark channel names, such as y, y1, or y2. By specifying an existing channel rather than a new value, you avoid repeating the order definition and can refer to channels derived by transforms (such as stack or bin). When sorting on the x, if no such channel is defined, the x2 channel will be used instead if available, and similarly for y and y2; this is useful for marks that implicitly stack such as area, bar, and rect. A sort value may also be specified as width or height, representing derived channels |x2 - x1| and |y2 - y1| respectively.

Note that there may be multiple associated values in the secondary dimension for a given value in the primary ordinal dimension. The secondary values are therefore grouped for each associated primary value, and each group is then aggregated by applying a reducer. Lastly the primary values are sorted based on the associated reduced value in natural ascending order to produce the domain. The default reducer is max, but may be changed by specifying the reduce option. The above code is shorthand for:

Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", reduce: "max"}})

Generally speaking, a reducer only needs to be specified when there are multiple secondary values for a given primary value. See the group transform for the list of supported reducers.

For descending rather than ascending order, use the reverse option:

Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", reverse: true}})

An additional limit option truncates the domain to the first n values after sorting. If limit is negative, the last n values are used instead. Hence, a positive limit with reverse = true will return the top n values in descending order. If limit is an array lo, hi, the ith values with loi < hi will be selected. (Note that like the basic filter transform, limiting the x domain here does not affect the computation of the y domain, which is computed independently without respect to filtering.)

Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", limit: 5}})

If different sort options are needed for different ordinal scales, the channel name can be replaced with a value object with additional per-scale options.

Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: {value: "y", reverse: true}}})

If the input channel is data, then the reducer is passed groups of the mark’s data; this is typically used in conjunction with a custom reducer function, as when the built-in single-channel reducers are insufficient.

Note: when the value of the sort option is a string or a function, it is interpreted as a basic sort transform. To use both sort options and a sort transform, use Plot.sort.

Facet options

Plot’s faceting system produces small multiples by partitioning data in discrete sets and repeating the plot for each set. When faceting, two additional band scales may be configured:

  • fx - the horizontal position, a band scale
  • fy - the vertical position, a band scale

Faceting may either be specified at the top level of the plot or on individual marks. When specified at the top level, the following options indicate which data should be faceted, and how:

  • facet.data - the data to be faceted
  • facet.x - the horizontal position; bound to the fx scale, which must be band
  • facet.y - the vertical position; bound to the fy scale, which must be band

With top-level faceting, any mark that uses the specified facet data will be faceted by default, whereas marks that use different data will be repeated across all facets. (See the mark.facet option below for more). When specified at the mark level, facets can be defined for each mark via the mark.fx or mark.fy channel options.

Here is an example of top-level faceting:

Plot.plot({
  facet: {
    data: penguins,
    x: "sex",
    y: "island"
  },
  marks: [
    Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm"})
  ]
})

And here is the equivalent mark-level faceting:

Plot.plot({
  marks: [
    Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", fx: "sex", fy: "island"})
  ]
})

Regardless of whether top- or mark-level faceting is used, the fx and fy channels are strictly ordinal or categorical (i.e., discrete); each distinct channel value defines a facet. Quantitative data must be manually discretized for faceting, say by rounding or binning. (Automatic binning for quantitative data may be added in the future; see #14.) When mark-level faceting is used, the fx and fy channels are computed prior to the mark’s transform, if any (i.e., facet channels are not transformed).

The following top-level facet constant options are also supported:

  • facet.marginTop - the top margin
  • facet.marginRight - the right margin
  • facet.marginBottom - the bottom margin
  • facet.marginLeft - the left margin
  • facet.margin - shorthand for the four margins
  • facet.grid - if true, draw grid lines for each facet
  • facet.label - if null, disable default facet axis labels

Faceting can be explicitly enabled or disabled on a mark with the mark.facet option, which accepts the following values:

  • auto (default) - automatically determine if this mark should be faceted
  • include (or true) - draw the subset of the mark’s data in the current facet
  • exclude - draw the subset of the mark’s data not in the current facet
  • super - draw this mark in a single frame that covers all facets
  • null (or false) - repeat this mark’s data across all facets (i.e., no faceting)

When a mark uses super faceting, it is not allowed to use position scales (x, y, fx, or fy); super faceting is intended for decorations, such as labels and legends.

When top-level faceting is used, the default auto setting is equivalent to include when the mark data is strictly equal to the top-level facet data; otherwise it is equivalent to null. When the include or exclude facet mode is chosen, the mark data must be parallel to the top-level facet data: the data must have the same length and order. If the data are not parallel, then the wrong data may be shown in each facet. The default auto therefore requires strict equality (===) for safety, and using the facet data as mark data is recommended when using the exclude facet mode. (To construct parallel data safely, consider using array.map on the facet data.)

When mark-level faceting is used, the default auto setting is equivalent to include: the mark will be faceted if either the mark.fx or mark.fy channel option (or both) is specified. The null or false option will disable faceting, while exclude draws the subset of the mark’s data not in the current facet.

The mark.facetAnchor option controls the placement of the mark with respect to the facets. It supports the following settings:

  • null - display the mark on each non-empty facet (default for all marks, with the exception of axis marks)
  • top, right, bottom, or left - display the mark on facets on the specified side
  • top-empty, right-empty, bottom-empty, or left-empty - display the mark on facets that have an empty space on the specified side (the empty space being either the margin, or an empty facet); this is the default for axis marks
  • empty - display the mark on empty facets only

Legends

Plot can generate legends for color, opacity, and symbol scales. (An opacity scale is treated as a color scale with varying transparency.) For an inline legend, use the scale.legend option:

  • scale.legend - if truthy, generate a legend for the given scale

If the scale.legend option is true, the default legend will be produced for the scale; otherwise, the meaning of the legend option depends on the scale. For quantitative color scales, it defaults to ramp but may be set to swatches for a discrete scale (most commonly for threshold color scales); for ordinal color scales and symbol scales, only the swatches value is supported.

For example, this scatterplot includes a swatches legend for the ordinal color scale:

Plot.plot({
  color: {
    legend: true
  },
  marks: [
    Plot.dot(athletes, {x: "weight", y: "height", stroke: "sex"})
  ]
})

Whereas this scatterplot would render a ramp legend for its diverging color scale:

Plot.plot({
  color: {
    type: "diverging",
    legend: true
  },
  marks: [
    Plot.dot(gistemp, {x: "Date", y: "Anomaly", stroke: "Anomaly"})
  ]
})

plot.legend(scaleName, options)

Given an existing plot returned by Plot.plot, returns a detached legend for the plot’s scale with the given scaleName. The scaleName must refer to a scale that supports legends: either "color", "opacity", or "symbol". For example:

myplot = Plot.plot(…)
mylegend = myplot.legend("color")

Or, with additional options:

mylegend = myplot.legend("color", {width: 320})

If there is no scale with the given scaleName on the given plot, then plot.legend will return undefined.

Categorical and ordinal color legends are rendered as swatches, unless options.legend is set to ramp. The swatches can be configured with the following options:

  • options.tickFormat - a format function for the labels
  • options.swatchSize - the size of the swatch (if square)
  • options.swatchWidth - the swatches’ width
  • options.swatchHeight - the swatches’ height
  • options.columns - the number of swatches per row
  • options.marginLeft - the legend’s left margin
  • options.className - a class name, that defaults to a randomly generated string scoping the styles
  • options.width - the legend’s width (in pixels)

Symbol legends are rendered as swatches and support the options above in addition to the following options:

  • options.fill - the symbol fill color
  • options.fillOpacity - the symbol fill opacity; defaults to 1
  • options.stroke - the symbol stroke color
  • options.strokeOpacity - the symbol stroke opacity; defaults to 1
  • options.strokeWidth - the symbol stroke width; defaults to 1.5
  • options.r - the symbol radius; defaults to 4.5 pixels

The fill and stroke symbol legend options can be specified as “color” to apply the color scale when the symbol scale is a redundant encoding. The fill defaults to none. The stroke defaults to currentColor if the fill is none, and to none otherwise. The fill and stroke options may also be inherited from the corresponding options on an associated dot mark.

Continuous color legends are rendered as a ramp, and can be configured with the following options:

  • options.label - the scale’s label
  • options.ticks - the desired number of ticks, or an array of tick values
  • options.tickFormat - a format function for the legend’s ticks
  • options.tickSize - the tick size
  • options.round - if true (default), round tick positions to pixels
  • options.width - the legend’s width
  • options.height - the legend’s height
  • options.marginTop - the legend’s top margin
  • options.marginRight - the legend’s right margin
  • options.marginBottom - the legend’s bottom margin
  • options.marginLeft - the legend’s left margin

The style legend option allows custom styles to override Plot’s defaults; it has the same behavior as in Plot’s top-level layout options.

Plot.legend(options)

Returns a standalone legend for the scale defined by the given options object. The options object must define at least one scale; see Scale options for how to define a scale. For example, here is a ramp legend of a linear color scale with the default domain of 0, 1 and default scheme turbo:

Plot.legend({color: {type: "linear"}})

The options object may also include any additional legend options described in the previous section. For example, to make the above legend slightly wider:

Plot.legend({
  width: 320,
  color: {
    type: "linear"
  }
})

Marks

Marks visualize data as geometric shapes such as bars, dots, and lines. An single mark can generate multiple shapes: for example, passing a Plot.barY to Plot.plot will produce a bar for each element in the associated data. Multiple marks can be layered into plots.

Mark constructors take two arguments: data and options. Together these describe a tabular dataset and how to visualize it. Option values that must be the same for all of a mark’s generated shapes are known as constants, whereas option values that may vary across a mark’s generated shapes are known as channels. Channels are typically bound to scales and encode abstract data values, such as time or temperature, as visual values, such as position or color. (Channels can also be used to order ordinal domains; see sort options.)

A mark’s data is most commonly an array of objects representing a tabular dataset, such as the result of loading a CSV file, while a mark’s options bind channels (such as x and y) to columns in the data (such as units and fruit).

sales = [
  {units: 10, fruit: "peach"},
  {units: 20, fruit: "pear"},
  {units: 40, fruit: "plum"},
  {units: 30, fruit: "plum"}
]
Plot.dot(sales, {x: "units", y: "fruit"}).plot()

While a column name such as "units" is the most concise way of specifying channel values, values can also be specified as functions for greater flexibility, say to transform data or derive a new column on the fly. Channel functions are invoked for each datum (d) in the data and return the corresponding channel value. (This is similar to how D3’s selection.attr accepts functions, though note that Plot channel functions should return abstract values, not visual values.)

Plot.dot(sales, {x: d => d.units * 1000, y: d => d.fruit}).plot()

Plot also supports columnar data for greater efficiency with bigger datasets; for example, data can be specified as any array of the appropriate length (or any iterable or value compatible with Array.from), and then separate arrays of values can be passed as options.

index = [0, 1, 2, 3]
units = [10, 20, 40, 30]
fruits = ["peach", "pear", "plum", "plum"]
Plot.dot(index, {x: units, y: fruits}).plot()

Channel values can also be specified as numbers for constant values, say for a fixed baseline with an area.

Plot.area(aapl, {x1: "Date", y1: 0, y2: "Close"}).plot()

Missing and invalid data are handled specifically for each mark type and channel. In most cases, if the provided channel value for a given datum is null, undefined, or (strictly) NaN, the mark will implicitly filter the datum and not generate a corresponding output. In some cases, such as the radius (r) of a dot, the channel value must additionally be positive. Plot.line and Plot.area will stop the path before any invalid point and start again at the next valid point, thus creating interruptions rather than interpolating between valid points. Titles will only be added if they are non-empty.

All marks support the following style options:

  • fill - fill color
  • fillOpacity - fill opacity (a number between 0 and 1)
  • stroke - stroke color
  • strokeWidth - stroke width (in pixels)
  • strokeOpacity - stroke opacity (a number between 0 and 1)
  • strokeLinejoin - how to join lines (bevel, miter, miter-clip, or round)
  • strokeLinecap - how to cap lines (butt, round, or square)
  • strokeMiterlimit - to limit the length of miter joins
  • strokeDasharray - a comma-separated list of dash lengths (typically in pixels)
  • strokeDashoffset - the stroke dash offset (typically in pixels)
  • opacity - object opacity (a number between 0 and 1)
  • mixBlendMode - the blend mode (e.g., multiply)
  • shapeRendering - the shape-rendering mode (e.g., crispEdges)
  • paintOrder - the paint order (e.g., stroke)
  • dx - horizontal offset (in pixels; defaults to 0)
  • dy - vertical offset (in pixels; defaults to 0)
  • target - link target (e.g., “_blank” for a new window); for use with the href channel
  • ariaDescription - a textual description of the mark’s contents
  • ariaHidden - if true, hide this content from the accessibility tree
  • pointerEvents - the pointer events (e.g., none)
  • clip - whether and how to clip the mark

If the clip option is frame (or equivalently true), the mark is clipped to the frame’s dimensions; if the clip option is null (or equivalently false), the mark is not clipped. If the clip option is sphere, then a geographic projection is required and the mark will be clipped to the projected sphere (e.g., the front hemisphere when using the orthographic projection).

For all marks except text, the dx and dy options are rendered as a transform property, possibly including a 0.5px offset on low-density screens.

All marks support the following optional channels:

  • fill - a fill color; bound to the color scale
  • fillOpacity - a fill opacity; bound to the opacity scale
  • stroke - a stroke color; bound to the color scale
  • strokeOpacity - a stroke opacity; bound to the opacity scale
  • strokeWidth - a stroke width (in pixels)
  • opacity - an object opacity; bound to the opacity scale
  • title - a tooltip (a string of text, possibly with newlines)
  • href - a URL to link to
  • ariaLabel - a short label representing the value in the accessibility tree

The fill, fillOpacity, stroke, strokeWidth, strokeOpacity, and opacity options can be specified as either channels or constants. When the fill or stroke is specified as a function or array, it is interpreted as a channel; when the fill or stroke is specified as a string, it is interpreted as a constant if a valid CSS color and otherwise it is interpreted as a column name for a channel. Similarly when the fill opacity, stroke opacity, object opacity, stroke width, or radius is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel.

The scale associated with any channel can be overridden by specifying the channel as an object with a value property specifying the channel values and a scale property specifying the desired scale name or null for an unscaled channel. For example, to force the stroke channel to be unscaled, interpreting the associated values as literal color strings:

Plot.dot(data, {stroke: {value: "fieldName", scale: null}})

To instead force the stroke channel to be bound to the color scale regardless of the provided values, say:

Plot.dot(data, {stroke: {value: "fieldName", scale: "color"}})

The color channels (fill and stroke) are bound to the color scale by default, unless the provided values are all valid CSS color strings or nullish, in which case the values are interpreted literally and unscaled.

In addition to functions of data, arrays, and column names, channel values can be specified as an object with a transform method; this transform method is passed the mark’s array of data and must return the corresponding array of channel values. (Whereas a channel value specified as a function is invoked repeatedly for each element in the mark’s data, similar to array.map, the transform method is invoked only once being passed the entire array of data.) For example, to pass the mark’s data directly to the x channel, equivalent to Plot.identity:

Plot.dot(numbers, {x: {transform: data => data}})

The title, href, and ariaLabel options can only be specified as channels. When these options are specified as a string, the string refers to the name of a column in the mark’s associated data. If you’d like every instance of a particular mark to have the same value, specify the option as a function that returns the desired value, e.g. () => "Hello, world!".

The rectangular marks (bar, cell, frame, and rect) support insets and rounded corner constant options:

  • insetTop - inset the top edge
  • insetRight - inset the right edge
  • insetBottom - inset the bottom edge
  • insetLeft - inset the left edge
  • rx - the x radius for rounded corners
  • ry - the y radius for rounded corners

Insets are specified in pixels. Corner radii are specified in either pixels or percentages (strings). Both default to zero. Insets are typically used to ensure a one-pixel gap between adjacent bars; note that the bin transform provides default insets, and that the band scale padding defaults to 0.1, which also provides separation.

For marks that support the frameAnchor option, it may be specified as one of the four sides (top, right, bottom, left), one of the four corners (top-left, top-right, bottom-right, bottom-left), or the middle of the frame.

mark.plot(options)

Given a mark, such as the result of calling Plot.barY, you can call mark.plot to render a plot. This is shorthand for calling Plot.plot where the marks option specifies this single mark.

const mark = Plot.barY(alphabet, {x: "letter", y: "frequency"});
return mark.plot();

More commonly this shorthand is written as a single expression:

Plot.barY(alphabet, {x: "letter", y: "frequency"}).plot()

This is equivalent to:

Plot.plot({marks: [Plot.barY(alphabet, {x: "letter", y: "frequency"})]})

If needed, you can pass additional options to mark.plot, which is equivalent to passing options to Plot.plot. (If the marks option is used, additional marks are concatenated with the shorthand mark.)

Plot.barY(alphabet, {x: "letter", y: "frequency"}).plot({width: 1024})

Plot.marks(...marks)

A convenience method for composing a mark from a series of other marks. Returns an array of marks that implements the mark.plot function. See the box mark implementation for an example.

Area

Source · Examples · Draws regions formed by a baseline (x1, y1) and a topline (x2, y2) as in an area chart. Often the baseline represents y = 0. While not required, typically the x and y scales are both quantitative.

The following channels are required:

  • x1 - the horizontal position of the baseline; bound to the x scale
  • y1 - the vertical position of the baseline; bound to the y scale

In addition to the standard mark options, the following optional channels are supported:

  • x2 - the horizontal position of the topline; bound to the x scale
  • y2 - the vertical position of the topline; bound to the y scale
  • z - a categorical value to group data into series

If x2 is not specified, it defaults to x1. If y2 is not specified, it defaults to y1. These defaults facilitate sharing x or y coordinates between the baseline and topline. See also the implicit stack transform and shorthand x and y options supported by Plot.areaY and Plot.areaX.

By default, the data is assumed to represent a single series (i.e., a single value that varies over time). If the z channel is specified, data is grouped by z to form separate series. Typically z is a categorical value such as a series name. If z is not specified, it defaults to fill if a channel, or stroke if a channel.

The stroke defaults to none. The fill defaults to currentColor if the stroke is none, and to none otherwise. If the fill is defined as a channel, the area will be broken into contiguous overlapping segments when the fill color changes; the fill color will apply to the interval spanning the current data point and the following data point. This behavior also applies to the fillOpacity, stroke, strokeOpacity, strokeWidth, opacity, href, title, and ariaLabel channels. When any of these channels are used, setting an explicit z channel (possibly to null) is strongly recommended. The strokeLinecap and strokeLinejoin default to round, and the strokeMiterlimit defaults to 1.

Points along the baseline and topline are connected in input order. Likewise, if there are multiple series via the z, fill, or stroke channel, the series are drawn in input order such that the last series is drawn on top. Typically, the data is already in sorted order, such as chronological for time series; if sorting is needed, consider a sort transform.

The area mark supports curve options to control interpolation between points. If any of the x1, y1, x2, or y2 values are invalid (undefined, null, or NaN), the baseline and topline will be interrupted, resulting in a break that divides the area shape into multiple segments. (See d3-shape’s area.defined for more.) If an area segment consists of only a single point, it may appear invisible unless rendered with rounded or square line caps. In addition, some curves such as cardinal-open only render a visible segment if it contains

0.6.6

1 year ago

0.6.5

1 year ago

0.6.4

1 year ago