Fill and stroke channel interpretation
If fill or stroke is set to a valid CSS color as a string, it is interpreted as a literal color constant. If it is a string that is not a valid CSS color, it is interpreted as a column name for a channel. If it is a function, it is interpreted as a channel.
Insets for rect-like marks
Rect-like marks support insets in pixels: inset (shorthand for all four), insetTop, insetRight, insetBottom, insetLeft. Positive insets move the side toward the opposing side (in); negative insets move away (out). Insets default to zero. Commonly used to create one-pixel gaps between bars. The bin transform provides default insets.
Channel scale override with value and scale properties
Any channel's associated scale can be overridden by specifying the channel as an object with a value property for channel values and a scale property for the scale name or null for an unscaled channel. Example: Plot.dot(data, {stroke: {value: "fieldName", scale: null}}) forces stroke to be unscaled, interpreting values as literal colors.
Mark types: dot, line, bar
The dot mark draws stroked circles by default. The line mark (lineY or lineX) draws connected line segments (polylines). The bar mark draws rectangular bars in either horizontal (barX) or vertical (barY) orientation.
Marks are geometric shapes
Plot does not have chart types. Instead, charts are constructed by layering marks. Marks are the visual vocabulary used to compose charts—geometric shapes such as circles from the dot mark, connected line segments from the line mark, and rectangular bars from the bar mark.
Channel value types: field names, functions, arrays
Channels can be specified as a field (column) name, an accessor function invoked for each element, or an array of values with the same length and order as the data. When accessor functions or arrays are used instead of field names, automatic axis labels are lost but can be restored using the label option on scales.
Marks use scales to encode data
Marks are positioned in data space, not literal pixels. Scales encode abstract values such as time and temperature into visual values such as position and color. The x and y options are typically bound to the x and y scales, while fill and stroke are typically bound to the color scale. Plot automatically creates axes and legends to document scale encodings.
Optional channels for all marks
All marks support optional channels: fill (bound to color scale), fillOpacity (bound to opacity scale), stroke (bound to color scale), strokeOpacity (bound to opacity scale), strokeWidth (pixels), opacity (bound to opacity scale), title (accessible short text), href (URL), ariaLabel (accessibility label).
Marks are layered in a single plot
Multiple marks of different types can be composed into a single plot by passing them in the marks array. Each mark supplies its own data. Array.map can be used to create multiple marks from nested data. Marks may also be a function returning an SVG element, or null/undefined to produce no output.
Style options for all marks
All marks support: fill, fillOpacity (0–1), stroke, strokeWidth (pixels), strokeOpacity (0–1), strokeLinejoin (bevel, miter, miter-clip, round), strokeLinecap (butt, round, square), strokeMiterlimit, strokeDasharray (comma-separated dash lengths), strokeDashoffset (pixels), opacity (0–1), mixBlendMode, imageFilter, shapeRendering, paintOrder, dx (pixels; defaults 0), dy (pixels; defaults 0), target, className, ariaDescription, ariaHidden, pointerEvents, clip, tip, pool.
Columnar data and Apache Arrow support
Plot supports columnar data for efficiency with larger datasets. Data can be specified as any array of appropriate length (or iterable compatible with Array.from), with separate arrays of values passed as options. Apache Arrow tables and vectors can also be passed directly, and parallel arrays of values can be passed to each channel.
Transform options for all marks
All marks support transform options: filter (apply filter transform), sort (apply sort transform), reverse (apply reverse transform), transform (apply custom transform), initializer (apply custom initializer). The sort option can also be used to impute ordinal scale domains when not specified as a channel value.
Tidy data format for marks
Plot favors tidy data structured as an array of objects, where each object represents an observation (a row) and each property represents an observed value. All objects should have the same property names (columns). For larger datasets, Apache Arrow tables can be used as a columnar data representation.
frameAnchor option values
For marks supporting frameAnchor, valid values are: top, right, bottom, left (four sides), top-left, top-right, bottom-right, bottom-left (four corners), or middle.
Plot.marks() convenience method
Plot.marks(...marks) is a convenience method for composing multiple marks. It takes a series of other marks as arguments and returns an array of marks that implements the mark.plot function. Example usage: Plot.marks(Plot.ruleY([0]), Plot.areaY(data, {...}), Plot.lineY(data, {...}))
Channel transform method
Channel values can be specified as an object with a transform method, which is passed the mark's entire array of data and must return the corresponding array of channel values. Unlike a channel function invoked for each element, the transform method is invoked only once. Example: Plot.dot(numbers, {x: {transform: (data) => data}}) passes mark data directly to the x channel.
Color channel default scale binding
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.
Missing and invalid data handling
Missing and invalid data are handled specifically for each mark type and channel. If a channel value is null, undefined, or NaN, the mark implicitly filters that datum and does not generate output. Some channels like radius must be positive. Line and area marks stop the path before invalid points and start again at the next valid point, creating interruptions. Titles are added only if non-empty.
Marks have options and channels
Marks take options as a second argument to change appearance. Options can be constants (same for all shapes) or channels (vary across shapes). Channels encode data and are typically bound to scales. Most mark options can vary with data, but some like strokeDasharray cannot be channels. Options are generally optional and Plot provides defaults.
Tip option for pointer tips
If tip is true, a tip mark with the pointer transform is derived and placed atop other marks, offering details on demand. If tip is an options object, those options are passed to the derived tip mark. If tip or its pointer option is x, y, or xy, pointerX, pointerY, or pointer will be used; otherwise the pointing mode is chosen automatically. Title channel is not applied as SVG title when tip is truthy.
Clip option values and behavior
The clip option controls whether and how to clip the mark. If clip is frame or true, the mark is clipped to frame dimensions. If clip is null or false, the mark is not clipped. If clip is sphere, the mark is clipped to the projected sphere (requires geographic projection). If clip is a GeoJSON object, the mark is clipped to the projected geometry.
Rounded corners for rect-like marks
Rect-like marks support rounded corners with options: r (all corners), rx1 (x1-y1 and x1-y2 corners), rx2 (x2-y1 and x2-y2 corners), ry1 (x1-y1 and x2-y1 corners), ry2 (x1-y2 and x2-y2 corners), rx1y1, rx1y2, rx2y1, rx2y2 (individual corners), rx (x-radius for elliptical corners), ry (y-radius for elliptical corners). Corner radii are in pixels or percentages/auto for rx and ry. Radii are reduced proportionally if too large.
Data type implications for marks
Different data types have different implications: quantitative or temporal values can be subtracted and interpolated; ordinal values can be ordered; nominal or categorical values can only be the same or different. Line marks require both x and y to be quantitative or temporal with meaningful ordering. For rectangles, use rect when both x and y are quantitative, barX when x is quantitative and y is ordinal, barY when x is ordinal and y is quantitative, and cell when both x and y are ordinal.
Title, href, and ariaLabel channel restrictions
The title, href, and ariaLabel options can only be specified as channels. When specified as a string, the string refers to a column name in the mark's data. To make every instance have the same value, specify as a function returning the desired value, e.g., () => "Hello, world!".
Plot.cell() two-dimensional shorthand with ordinal data
Plot.cell(matrix).plot() creates a matrix diagram from a two-dimensional array of string pairs, treating both x and y as ordinal. This is useful for visualizing which pairs exist in a dataset, such as code review relationships.
Plot.textX() one-dimensional shorthand
Plot.textX(numbers).plot() draws a label at each value in a one-dimensional array, though this is not particularly readable due to occlusion.
Marks without meaningful shorthand
The arrow and link marks both require start (x1, y1) and end (x2, y2) points, and the image mark requires a source URL (src), so these marks do not currently provide meaningful shorthand syntax.
Plot.text() two-dimensional shorthand
Plot.text(timeSeries).plot() creates a scatterplot with labels showing the zero-based index of each data point from a two-dimensional array.
Plot.vector() two-dimensional shorthand
Plot.vector(timeSeries).plot() creates a vector plot from a two-dimensional array of [x, y] tuples.
Plot.dot() two-dimensional shorthand
Plot.dot(timeSeries).plot() creates a scatterplot from a two-dimensional array of [x, y] tuples.
Plot.line() two-dimensional shorthand with temporal data
Plot.line(timeSeries).plot() creates a line chart from a two-dimensional array of [x, y] tuples. When x-values are dates, the x-axis shows the date rather than zero-based index, and non-uniform spacing is preserved (e.g., gaps on weekends).
Plot.dotX() with Plot.dodgeY() transform shorthand
Plot.dotX(numbers, Plot.dodgeY()).plot() creates a beeswarm plot from a one-dimensional array by applying the dodge transform to avoid occlusion.
Plot.barY() with Plot.groupX() transform shorthand
Plot.barY(gene, Plot.groupX()).plot() groups and counts ordinal data from a string (e.g., DNA bases). When passed a string, it groups by character and counts frequency of each character.
Plot.boxX() one-dimensional shorthand for boxplot
Plot.boxX(numbers).plot() creates a horizontal boxplot from a one-dimensional array. The gray band represents the interquartile range, black whiskers show the extrema (not including outliers), the thick black stroke represents the median, and outliers are drawn as dots.
Plot.vectorX() one-dimensional shorthand
Plot.vectorX(numbers).plot() draws little up-pointing arrows at each value in a one-dimensional array. Typically the vector mark is used with rotate and length options to control direction and magnitude.
Plot.ruleX() and Plot.tickX() one-dimensional shorthand
Plot.ruleX(numbers).plot() and Plot.tickX(numbers).plot() both draw vertical rules at each value in a one-dimensional array. Plot.ruleX behaves identically to Plot.tickX when there is no y channel. These are commonly used to annotate special x or y values in plots.
Plot.dotX() one-dimensional shorthand for distribution
Plot.dotX(numbers).plot() creates a scatterplot from a one-dimensional array when the order of data does not matter and you want to view the distribution of values.
Plot.cellX() one-dimensional shorthand encodes values as fill color
Plot.cellX(numbers).plot() creates a cell mark with ordinal x-scale where numeric values are encoded as the fill color using the default quantitative turbo color scheme: higher values are reddish, lower values blueish.
Plot.barY() one-dimensional shorthand uses ordinal x-scale
Plot.barY(numbers).plot() creates a bar chart where x is ordinal (band scale) rather than quantitative (linear). An ordinal axis labels every tick, which appear at the middle of each bar rather than between rects.
Plot.rectY() one-dimensional shorthand uses interval transform
Plot.rectY(numbers).plot() creates vertical bars from a one-dimensional array, implicitly using the interval transform so the first rect spans from x = 0 to x = 1, the second from x = 1 to x = 2, and so on, with horizontal inset to separate adjacent rects.
Plot.areaY() one-dimensional shorthand
Plot.areaY(numbers).plot() creates an area chart from a one-dimensional array with an implicit baseline at y = 0.
Plot.rectY() with Plot.binX() transform shorthand
Plot.rectY(numbers, Plot.binX()).plot() generates a histogram from a one-dimensional array to visualize the distribution by binning values and showing their frequencies.
Plot.lineY() one-dimensional shorthand
Plot.lineY(numbers).plot() creates a line chart from a one-dimensional array where values are encoded as y-coordinates and indices serve as x-coordinates.
Shorthand syntax with two-dimensional array of tuples
Plot shorthand also accepts a two-dimensional array of tuples [[x₀, y₀], [x₁, y₁], [x₂, y₂], …]. When passed to marks like Plot.line(), Plot.area(), Plot.dot(), or Plot.vector(), the first element of each tuple is encoded as x and the second as y.
Shorthand syntax with one-dimensional array
The most concise form of Plot shorthand syntax accepts a one-dimensional array of values [v₀, v₁, v₂, …]. When used with marks like Plot.lineY(), Plot.areaY(), Plot.rectY(), or Plot.barY(), the data values are encoded as the y-channel, and x-values are implicitly the zero-based index of each data point.
Plot.area() two-dimensional shorthand
Plot.area(timeSeries).plot() creates an area chart from a two-dimensional array with an implicit baseline at y = 0, with x and y encoded from the tuple elements.
crosshairX() function usage
Plot.crosshairX(data, options) is like crosshair but uses pointerX when x is the dominant dimension, such as time in a time-series chart.
Crosshair faceting support
The crosshair mark supports faceting, but most other mark options are ignored.
Crosshair options reference
Crosshair mark options: x (horizontal position, bound to x scale), y (vertical position, bound to y scale), color (shorthand for ruleStroke and textFill), opacity (shorthand for ruleStrokeOpacity), ruleStroke (rule stroke color), ruleStrokeOpacity (defaults to 0.2), ruleStrokeWidth (defaults to 1), textFill (text fill color), textFillOpacity (text fill opacity), textStroke (defaults to white), textStrokeOpacity (defaults to 1), textStrokeWidth (defaults to 5), maxRadius (maximum pointing distance in pixels, defaults to 40).
Crosshair format options not supported
The crosshair mark does not currently support any format options; values are displayed with the default format. A custom crosshair can be implemented using the pointer transform and a text mark.
Crosshair color option
The color option sets the fill color of the text and the stroke color of the rule. This option can be specified as a channel to reinforce a color encoding.
One-dimensional crosshair
If either x or y is not specified, the crosshair is one-dimensional.
crosshairX and crosshairY marks for dominant dimensions
Use crosshairX mark for charts with a dominant x dimension (such as time in time-series) with pointerX, and crosshairY mark for charts with a dominant y dimension with pointerY.
crosshairX example with time series
Plot.plot({ marks: [ Plot.lineY(aapl, {x: "Date", y: "Close"}), Plot.crosshairX(aapl, {x: "Date", y: "Close"}) ] })
Crosshair mark overview
The crosshair mark shows the x (horizontal) and y (vertical) values of the point closest to the pointer on the bottom and left sides of the frame respectively. It was introduced in version 0.6.7.
crosshairY() function usage
Plot.crosshairY(data, options) is like crosshair but uses pointerY when y is the dominant dimension.
Crosshair example with dot plot
Plot.plot({ marks: [ Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", stroke: "sex"}), Plot.crosshair(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm"}) ] })
crosshair() function usage
Plot.crosshair(data, options) returns a new crosshair for the given data and options, drawing horizontal and vertical rules. The corresponding x and y values are drawn just outside the bottom and left sides of the frame respectively, typically on top of the axes.
One-dimensional crosshairX example
Plot.plot({ marks: [ Plot.tickX(penguins, {x: "body_mass_g"}), Plot.crosshairX(penguins, {x: "body_mass_g"}) ] })
Crosshair with color channel example
Plot.plot({ marks: [ Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", stroke: "sex"}), Plot.crosshair(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", color: "sex", opacity: 0.5}) ] })