Skip to content
On this page

Auto mark

The magic ✨ auto mark automatically selects a mark type that best represents the given dimensions of the data according to some simple heuristics. The auto mark—which powers Observable’s chart cell—is intended to support fast exploratory analysis where the goal is to get a useful plot as quickly as possible. For example, two quantitative dimensions make a scatterplot:

175180185190195200205210215220225230↑ flipper_length_mm3,0003,5004,0004,5005,0005,5006,000body_mass_g →Fork
js, {x: "body_mass_g", y: "flipper_length_mm"}).plot()


The auto mark is supposed to be fast and fluid, so don’t overthink it. If you need precise control, use explicit marks instead.


While the auto mark will respect the options you provide, you shouldn’t rely on its behavior being stable over time. The auto mark may get smarter and take advantage of new features. Because its heuristics are likely to evolve, they are not explicitly documented; see the source code for details.

A monotonically increasing dimension (here Date, as the data is ordered chronologically), paired with a numeric column (Close), makes a line chart:

60708090100110120130140150160170180190↑ Close20142015201620172018Fork
js, {x: "Date", y: "Close"}).plot()

Given only one dimension of data, it makes a histogram:

js, {x: "weight"}).plot()
020406080100120140160↑ FrequencyBiscoeDreamTorgersenislandFork
js, {x: "island"}).plot()

This is easier than deciding whether to use bin and rect, or group and bar: the auto mark chooses the right one based on whether the data is quantitative or ordinal.

If you’d like to explicitly avoid grouping the data, you can opt out of the reducer, and get a one-dimensional plot:

3,0003,5004,0004,5005,0005,5006,000body_mass_g →Fork
js, {x: "body_mass_g", y: {reduce: null}}).plot()

As you can see from that reduce property, the auto mark has some special syntax that lets you specify a reducer without explicitly specifying a transform. For example, the scatterplot above can be made into a heatmap by adding a color reducer. You can pass the name of a reducer to that property, or pass a shorthand string:

js, {x: "weight", y: "height", color: "count"}).plot()

That’s equivalent to this:

Plot.rect(olympians, Plot.bin({fill: "count"}, {x: "weight", y: "height"})).plot()

Notice that the code above makes you think about nested functions and two different options objects, which the auto mark flattens. The auto mark infers that it should use a rect; that it should bin on x and y; that the kind of color should be a fill; and that fill is an “output” of the reducer, whereas x and y are “inputs”.

This saves you a little bit of typing, but, more importantly, it means that switching from showing one dimension to another only involves changing one thing. In the code above, if you change y from weight to sex, it’ll break, because sex is ordinal instead of quantitative. (You’d also have to change rect to barX, and bin to binX.) With the auto mark, it just works:

js, {x: "weight", y: "sex", color: "count"}).plot()

Similarly, with explicit marks and transforms, changing a vertical histogram to a horizontal histogram involves switching rectY to rectX, binX to binY, x to y, and y to x. With the auto mark, just specify y instead of x:

BiscoeDreamTorgersenisland020406080100120140160Frequency →Fork
js, {y: "island"}).plot()

For the sake of seamless switching, the auto mark has just one color channel, which it assigns to either fill or stroke depending on the mark. We can see that clearly by overriding a line chart with the mark option to make an area chart:

2004006008001,0001,2001,4001,6001,8002,0002,2002,400↑ unemployed20002001200220032004200520062007200820092010Fork
js, {x: "date", y: "unemployed", color: "industry"}).plot()
02,0004,0006,0008,00010,00012,00014,000↑ unemployed20002001200220032004200520062007200820092010
js, {x: "date", y: "unemployed", color: "industry", mark: "area"}).plot()

The mark override option supports dot, line, area, rule, and bar (which automatically chooses among barX, barY, rectX, rectY, rect, and cell).

You can get a more elaborate aggregated chart by passing an object with both a value (the input dimension) and a reduce (the reducer). For example, here’s the average heights of Olympians over time by sex:

  .auto(olympians, {x: "date_of_birth", y: {value: "height", reduce: "mean"}, color: "sex", mark: "line"})
  .plot({color: {legend: true}})

You can similarly pass a zero option to indicate that zero is meaningful for either x or y. This adds a corresponding rule to the returned mark.

02004006008001,0001,2001,4001,6001,8002,0002,2002,400↑ unemployed20002001200220032004200520062007200820092010Fork
js, {x: "date", y: {value: "unemployed", zero: true}, color: "industry"}).plot()

The auto mark has a size channel, which (currently) always results in a dot. For now, it’s an alias for the dot’s r channel; in the future it will also represent a vector’s length channel.

60708090100110120130140150160170180190↑ Close20142015201620172018Fork
js, {x: "Date", y: "Close", size: "Volume"}).plot()

Like with any other mark, you can also use fx or fy, and pass additional global options in the plot method.

js, {
  x: "body_mass_g",
  y: "culmen_length_mm",
  fx: "island",
  fy: "species"
  grid: true,
  x: {ticks: 5},
  marginRight: 70


You can combine the auto mark with other marks, but the combination may be brittle because the auto mark may pick encodings that don’t play well with others.

Auto options

The auto mark currently supports only a subset of the standard mark options. You must provide at least one position channel:

  • x - horizontal position
  • y - vertical position

You may also provide one or more visual encoding channels:

  • color - corresponds to stroke or fill (depending on the chosen mark type)
  • size - corresponds to r (and in future, possibly length)

And you may specify the standard mark-level facet channels:

  • fx - horizontal facet position (column)
  • fy - vertical facet position (row)

In addition to channel values, the x, y, color, and size options may specify reducers. Setting a reducer on x implicitly groups or bins on y, and likewise setting a reducer on y implicitly groups or bins on x. Setting a reducer on color or size groups or bins in both x and y. Setting a reducer on both x and y throws an error. To specify a reducer, simply pass the reducer name to the corresponding option. For example:

js, {x: "body_mass_g", y: "count"})

To pass both a value and a reducer, or to disambiguate whether the given string represents a field name or a reducer name, the x, y, color, and size options can also be specified as an object with separate value and reduce properties. For example, to compute the total weight of the penguins in each bin:

js, {x: "body_mass_g", y: {value: "body_mass_g", reduce: "sum"}})

If the color channel is specified as a string that is also a valid CSS color, it is interpreted as a constant color. For example, for red bars:

js, {x: "body_mass_g", color: "red"})

This is shorthand for:

js, {x: "body_mass_g", color: {color: "red"}})

To reference a field name instead as a variable color encoding, specify the color option as an object with a value property:

js, {x: "body_mass_g", color: {value: "red"}})

Alternatively, you can specify a function of data or an array of values, as with a standard mark channel.

The auto mark chooses the mark type automatically based on several simple heuristics. For more control, you can specify the desired mark type using the mark option, which supports the following names:

  • area - areaY or areaX (or sometimes area)
  • bar - barY or barX; or rectY, rectX, or rect; or cell
  • dot - dot
  • line - lineY or lineX (or sometimes line)
  • rule - ruleY or ruleX

The chosen mark type depends both on the options you provide (e.g., whether you specified x or y or both) and the inferred type of the corresponding data values (whether the associated dimension of data is quantitative, categorical, monotonic, etc.).

auto(data, options)

js, {x: "weight", y: "height", color: "count"}) // equivalent to rect + bin, say

Returns an automatically-chosen mark with the given data and options, suitable for a quick view of the data.

autoSpec(data, options)

Plot.autoSpec(olympians, {x: "weight", y: "height", color: "count"})

Returns an auto mark options object with no option undefined; the mark type, reducers, and other options are all populated.

Library released under ISC License.