diff --git a/docs/community.md b/docs/community.md
index 7ff2f5ced7..af5e1cba01 100644
--- a/docs/community.md
+++ b/docs/community.md
@@ -14,7 +14,7 @@ And of course, follow us on [Observable](https://observablehq.com/@observablehq?
We recommend asking for help on the [Observable forum](https://talk.observablehq.com/c/help/6). Or if you prefer chat, join the [Observable community Slack](https://observable-community.slack.com/ssb/redirect).
-We encourage you to share your work, no matter how messy, on [Observable](https://observablehq.com). Sharing live code is the easiest way to let people see what you see, and to debug your problem. Strive for a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)—it helps people hone in on your problem more quickly.
+We encourage you to share your work, no matter how messy, on [Observable](https://observablehq.com). Sharing live code is the easiest way to let people see what you see, and to debug your problem. Strive for a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) — it helps people hone in on your problem more quickly.
When asking for help, don’t just post your code and ask people to fix it. Provide context, and say what you want help with. For example:
@@ -23,7 +23,7 @@ When asking for help, don’t just post your code and ask people to fix it. Prov
- What behavior are you currently seeing?
- Is the current behavior not what you expect?
-If you think you’ve found a bug in Plot, please file a [GitHub issue](https://github.com/observablehq/plot/issues). But don’t use an issue to ask for help—you’ll have better luck on the forum or Slack.
+If you think you’ve found a bug in Plot, please file a [GitHub issue](https://github.com/observablehq/plot/issues). But don’t use an issue to ask for help — you’ll have better luck on the forum or Slack.
## Getting involved
diff --git a/docs/features/marks.md b/docs/features/marks.md
index e7819609de..63b6265c85 100644
--- a/docs/features/marks.md
+++ b/docs/features/marks.md
@@ -58,7 +58,7 @@ Plot doesn’t have chart types; instead, you construct charts by layering **mar
## Marks are geometric shapes
-Plot provides a variety of mark types. Think of marks as the “visual vocabulary”—the painter’s palette 🎨, but of shapes instead of colors—that you pull from when composing a chart. Each mark type produces a certain type of geometric shape.
+Plot provides a variety of mark types. Think of marks as the “visual vocabulary” — the painter’s palette 🎨, but of shapes instead of colors — that you pull from when composing a chart. Each mark type produces a certain type of geometric shape.
For example, the [dot mark](../marks/dot.md) draws stroked circles (by default).
@@ -157,7 +157,7 @@ Plot.plot({
## Marks use scales
-Marks are (typically) not positioned in literal pixels, or colored in literal colors, as in a conventional graphics system. Instead you provide abstract values such as time and temperature—marks are drawn “in data space”—and [scales](./scales.md) encode these into visual values such as position and color. And best of all, Plot automatically creates [axes](../marks/axis.md) and [legends](./legends.md) to document the scales’ encodings.
+Marks are (typically) not positioned in literal pixels, or colored in literal colors, as in a conventional graphics system. Instead you provide abstract values such as time and temperature — marks are drawn “in data space” — and [scales](./scales.md) encode these into visual values such as position and color. And best of all, Plot automatically creates [axes](../marks/axis.md) and [legends](./legends.md) to document the scales’ encodings.
Data is passed through scales automatically during rendering; the mark controls which scales are used. The **x** and **y** options are typically bound to the *x* and *y* scales, respectively, while the **fill** and **stroke** options are typically bound to the *color* scale. Changing a scale’s definition, say by overriding its **domain** (the extent of abstract input values) or **type**, affects the appearance of all marks that use the scale.
@@ -178,7 +178,7 @@ Plot.plot({
## Marks have tidy data
-A single mark can draw multiple shapes. A mark generally produces a shape—such as a rectangle or circle—for each element in the data.
+A single mark can draw multiple shapes. A mark generally produces a shape — such as a rectangle or circle — for each element in the data.
:::plot defer https://observablehq.com/@observablehq/plot-tidy-data
```js
@@ -194,7 +194,7 @@ Plot.lineY(aapl, {x: "Date", y: "Close"}).plot()
```
:::
-And a line mark isn’t even guaranteed to produce a single polyline—there can be multiple polylines, as in a line chart with multiple series (using **z**).
+And a line mark isn’t even guaranteed to produce a single polyline — there can be multiple polylines, as in a line chart with multiple series (using **z**).
:::plot defer https://observablehq.com/@observablehq/plot-multiple-series-line-chart
```js
@@ -258,10 +258,10 @@ Note that when accessor functions or parallel arrays are used instead of field n
Data comes in different types: quantitative (or temporal) values can be subtracted, ordinal values can be ordered, and nominal (or categorical) values can only be the same or different.
:::info
-Because nominal values often need some arbitrary order for display purposes—often alphabetical—Plot uses the term *ordinal* to refer to both ordinal and nominal data.
+Because nominal values often need some arbitrary order for display purposes — often alphabetical — Plot uses the term *ordinal* to refer to both ordinal and nominal data.
:::
-Some marks work with any type of data, while other marks have certain requirements or assumptions of data. For example, a line should only be used when both *x* and *y* are quantitative or temporal, and when the data is in a meaningful order (such as chronological). This is because the line mark will interpolate between adjacent points to draw line segments. If *x* or *y* is nominal—say the names of countries—it doesn’t make sense to use a line because there is no half-way point between two nominal values.
+Some marks work with any type of data, while other marks have certain requirements or assumptions of data. For example, a line should only be used when both *x* and *y* are quantitative or temporal, and when the data is in a meaningful order (such as chronological). This is because the line mark will interpolate between adjacent points to draw line segments. If *x* or *y* is nominal — say the names of countries — it doesn’t make sense to use a line because there is no half-way point between two nominal values.
:::plot https://observablehq.com/@observablehq/plot-dont-do-this
```js
@@ -357,7 +357,7 @@ Channels are mark options that can be used to encode data. These options allow t
* an accessor function, or
* an array of values of the same length and order as the data.
-Not all mark options can be expressed as channels. For example, **stroke** can be a channel but **strokeDasharray** cannot. This is mostly a pragmatic limitation—it would be harder to implement Plot if every option were expressible as a channel—but it also serves to guide you towards options that are intended for encoding data.
+Not all mark options can be expressed as channels. For example, **stroke** can be a channel but **strokeDasharray** cannot. This is mostly a pragmatic limitation — it would be harder to implement Plot if every option were expressible as a channel — but it also serves to guide you towards options that are intended for encoding data.
:::tip
To vary the definition of a constant option with data, create multiple marks with your different constant options, and then filter the data for each mark to achieve the desired result.
diff --git a/docs/features/projections.md b/docs/features/projections.md
index e34168d98d..0035809f00 100644
--- a/docs/features/projections.md
+++ b/docs/features/projections.md
@@ -56,7 +56,7 @@ Plot.plot({
Above, a [geo mark](../marks/geo.md) draws polygons representing land and a [sphere mark](../marks/geo.md#sphere-options) draws the outline of the globe. A [dot mark](../marks/dot.md) draws earthquakes as circles sized by magnitude.
-The geo mark is “projection aware” so that it can handle all the nuances of projecting spherical polygons to the screen—leaning on [d3-geo](https://d3js.org/d3-geo) to provide [adaptive sampling](https://observablehq.com/@d3/adaptive-sampling) with configurable precision, [antimeridian cutting](https://observablehq.com/@d3/antimeridian-cutting), and clipping. The dot mark is not; instead, Plot applies the projection in place of the *x* and *y* scales. Hence, projections work with any mark that consumes continuous **x** and **y** channels—as well as marks that use **x1** & **y1** and **x2** & **y2**. Each mark implementation decides whether to handle projections specially or to treat the projection as any other position scale. (For example, the [line mark](../marks/line.md) is projection-aware to draw geodesics.)
+The geo mark is “projection aware” so that it can handle all the nuances of projecting spherical polygons to the screen — leaning on [d3-geo](https://d3js.org/d3-geo) to provide [adaptive sampling](https://observablehq.com/@d3/adaptive-sampling) with configurable precision, [antimeridian cutting](https://observablehq.com/@d3/antimeridian-cutting), and clipping. The dot mark is not; instead, Plot applies the projection in place of the *x* and *y* scales. Hence, projections work with any mark that consumes continuous **x** and **y** channels — as well as marks that use **x1** & **y1** and **x2** & **y2**. Each mark implementation decides whether to handle projections specially or to treat the projection as any other position scale. (For example, the [line mark](../marks/line.md) is projection-aware to draw geodesics.)
:::info
Marks that require *band* scales (bars, cells, and ticks) cannot be used with projections. Likewise one-dimensional marks such as rules cannot be used, though see [#1164](https://github.com/observablehq/plot/issues/1164).
diff --git a/docs/features/scales.md b/docs/features/scales.md
index 8516599124..36376e1d76 100644
--- a/docs/features/scales.md
+++ b/docs/features/scales.md
@@ -76,7 +76,7 @@ Plot.ruleX(gistemp, {x: "Date", stroke: "Anomaly"}).plot()
```
:::
-While the resulting chart looks different, the *color* scale here behaves similarly to the `y` function above—the only difference is that it interpolates colors (using [d3.interpolateTurbo](https://d3js.org/d3-scale-chromatic/sequential#interpolateTurbo)) instead of numbers (the top and bottom sides of the plot frame):
+While the resulting chart looks different, the *color* scale here behaves similarly to the `y` function above — the only difference is that it interpolates colors (using [d3.interpolateTurbo](https://d3js.org/d3-scale-chromatic/sequential#interpolateTurbo)) instead of numbers (the top and bottom sides of the plot frame):
```js
function color(anomaly) {
@@ -163,7 +163,7 @@ Plot.plot({x: {type: "utc", domain: [1609459200000, 1640995200000], grid: true}}
```
:::
-If the scale **type** is *time*, the ticks will be in local time—as with the dates below—rather than UTC.
+If the scale **type** is *time*, the ticks will be in local time — as with the dates below — rather than UTC.
:::plot https://observablehq.com/@observablehq/plot-continuous-scales
```js
@@ -241,7 +241,7 @@ Plot
```
:::
-While *point* and *band* scales appear visually similar when only the grid is visible, the two are not identical—they differ respective to padding. Play with the options below to get a sense of their effect on the scale’s behavior.
+While *point* and *band* scales appear visually similar when only the grid is visible, the two are not identical — they differ respective to padding. Play with the options below to get a sense of their effect on the scale’s behavior.
@@ -707,7 +707,7 @@ The default range depends on the scale: for position scales (*x*, *y*, *fx*, and
The behavior of the **unknown** scale 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 [**interval** option](#scale-transforms) 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 time interval, or a skip interval consisting of a number followed by the interval name (possibly pluralized), such as *3 months* or *10 years*. 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.
+For data at regular intervals, such as integer values or daily samples, the [**interval** option](#scale-transforms) 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 time interval, or a skip interval consisting of a number followed by the interval name (possibly pluralized), such as *3 months* or *10 years*. 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:
@@ -732,7 +732,7 @@ Plot.plot({
### Color scale 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:
+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* - like *ordinal*, but defaults to *tableau10*
* *sequential* - like *linear*
@@ -921,7 +921,7 @@ Similarly, the *y* and *fy* scales support asymmetric insets with:
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 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.
Ordinal position scales support additional options, all specified as proportions in [0, 1]:
diff --git a/docs/features/shorthand.md b/docs/features/shorthand.md
index 539640ca5d..121483171c 100644
--- a/docs/features/shorthand.md
+++ b/docs/features/shorthand.md
@@ -75,7 +75,7 @@ const gene = "AAAAGAGTGAAGATGCTGGAGACGAGTGAAGCATTCACTTTAGGGAAAGCGAGGCAAGAGCGTTTC
# Shorthand
-The most concise form of Plot is its **shorthand** syntax where no options are specified—only data. To use this shorthand, the data must have a specific structure: either a one-dimensional array of values [*v₀*, *v₁*, *v₂*, …] or a two-dimensional array of tuples [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …].
+The most concise form of Plot is its **shorthand** syntax where no options are specified — only data. To use this shorthand, the data must have a specific structure: either a one-dimensional array of values [*v₀*, *v₁*, *v₂*, …] or a two-dimensional array of tuples [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …].
While none of these charts are particularly groundbreaking, we hope you find this shorthand convenient the next time you want a quick look at some data. And if the shorthand view is useful, you can then enhance it by adding options!
@@ -180,7 +180,7 @@ Plot.boxX(numbers).plot()
```
:::
-Some of Plot’s transforms support shorthand syntax, too. For example, we can use Plot.rectY with [Plot.binX](../transforms/bin.md) to generate a histogram—another common way to visualize a one-dimensional distribution.
+Some of Plot’s transforms support shorthand syntax, too. For example, we can use Plot.rectY with [Plot.binX](../transforms/bin.md) to generate a histogram — another common way to visualize a one-dimensional distribution.
:::plot https://observablehq.com/@observablehq/plot-shorthand-histogram
```js
diff --git a/docs/features/transforms.md b/docs/features/transforms.md
index 4b9ce620ba..5393a4f77e 100644
--- a/docs/features/transforms.md
+++ b/docs/features/transforms.md
@@ -72,7 +72,7 @@ Plot.plot({
Plot includes many useful transforms! For example, you can compute a [rolling average](../transforms/window.md) to smooth a noisy signal, [stack layers](../transforms/stack.md) for a streamgraph, or [dodge dots](../transforms/dodge.md) for a beeswarm. Plot’s various built-in transforms include: [bin](../transforms/bin.md), [centroid](../transforms/centroid.md), [dodge](../transforms/dodge.md), [filter](../transforms/filter.md), [group](../transforms/group.md), [hexbin](../transforms/hexbin.md), [interval](../transforms/interval.md), [map](../transforms/map.md), [normalize](../transforms/normalize.md), [reverse](../transforms/sort.md#reverse-options), [select](../transforms/select.md), [shuffle](../transforms/sort.md#shuffle-options), [sort](../transforms/sort.md), [stack](../transforms/stack.md), [tree](../transforms/tree.md), and [window](../transforms/window.md). If these don’t meet your needs, you can even implement a [custom transform](#custom-transforms).
-Transforms are never required—you can always aggregate and derive data yourself outside of Plot, and then pass in the binned values. For example, we could use [d3.bin](https://d3js.org/d3-array/bin) to compute a histogram of athletes’ weights as an array of {*x0*, *x1*, *length*} objects.
+Transforms are never required — you can always aggregate and derive data yourself outside of Plot, and then pass in the binned values. For example, we could use [d3.bin](https://d3js.org/d3-array/bin) to compute a histogram of athletes’ weights as an array of {*x0*, *x1*, *length*} objects.
```js
bins = d3.bin().thresholds(80).value((d) => d.weight)(olympians)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 898fd5f224..86f2075a98 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -78,7 +78,7 @@ div.append(plot);
```
:::
-Plot returns a detached DOM element—either an [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) or [HTML figure](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure) element. In vanilla web development, this means you need to insert the generated plot into the page to see it. Typically this is done by selecting a DOM element (such as a DIV with a unique identifier, like `myplot` above), and then calling [*element*.append](https://developer.mozilla.org/en-US/docs/Web/API/Element/append).
+Plot returns a detached DOM element — either an [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) or [HTML figure](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure) element. In vanilla web development, this means you need to insert the generated plot into the page to see it. Typically this is done by selecting a DOM element (such as a DIV with a unique identifier, like `myplot` above), and then calling [*element*.append](https://developer.mozilla.org/en-US/docs/Web/API/Element/append).
If you’d prefer to run Plot locally (or entirely offline), you can download the UMD bundle of Plot along with its dependency, D3, here:
diff --git a/docs/marks/auto.md b/docs/marks/auto.md
index 582108a154..6d2e0cd0d6 100644
--- a/docs/marks/auto.md
+++ b/docs/marks/auto.md
@@ -17,7 +17,7 @@ onMounted(() => {
# 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](https://observablehq.com/@observablehq/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:
+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](https://observablehq.com/@observablehq/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:
:::plot https://observablehq.com/@observablehq/plot-auto-mark-scatterplot
```js
diff --git a/docs/marks/cell.md b/docs/marks/cell.md
index 2e098009e2..1672c5613b 100644
--- a/docs/marks/cell.md
+++ b/docs/marks/cell.md
@@ -26,7 +26,7 @@ The cell mark is one of several marks in Plot for drawing rectangles; it should
The **cell mark** draws rectangles positioned in two ordinal dimensions. Hence, the plot’s *x* and *y* scales are [band scales](../features/scales.md). Cells typically also have a **fill** color encoding.
-For example, the heatmap below shows the decline of *The Simpsons* after Season 9: high IMDb ratings are dark green, while low ratings are dark pink. (The worst episode ever—cue Comic Book Guy—is season 23’s [“Lisa Goes Gaga”](https://en.wikipedia.org/wiki/Lisa_Goes_Gaga).)
+For example, the heatmap below shows the decline of *The Simpsons* after Season 9: high IMDb ratings are dark green, while low ratings are dark pink. (The worst episode ever — cue Comic Book Guy — is season 23’s [“Lisa Goes Gaga”](https://en.wikipedia.org/wiki/Lisa_Goes_Gaga).)
:::plot defer https://observablehq.com/@observablehq/plot-simpsons-ratings
```js
diff --git a/docs/marks/density.md b/docs/marks/density.md
index 0358e7832f..52d8cf1bc6 100644
--- a/docs/marks/density.md
+++ b/docs/marks/density.md
@@ -165,7 +165,7 @@ Plot.plot({
```
:::
-
+
The **weight** channel specifies the contribution of each data point to the estimated density; it defaults to 1, weighing each point equally. This can be used to give some points more influence than others. Try adjusting the skew slider below to transition between female- and male-weighted density.
diff --git a/docs/marks/geo.md b/docs/marks/geo.md
index 8a6e8553a1..761515e982 100644
--- a/docs/marks/geo.md
+++ b/docs/marks/geo.md
@@ -32,7 +32,7 @@ onMounted(() => {
# Geo mark
-The **geo mark** draws geographic features—polygons, lines, points, and other geometry—often as thematic maps. It works with Plot’s [projection system](../features/projections.md). For example, the [choropleth map](https://en.wikipedia.org/wiki/Choropleth_map) below shows unemployment by county in the United States.
+The **geo mark** draws geographic features — polygons, lines, points, and other geometry — often as thematic maps. It works with Plot’s [projection system](../features/projections.md). For example, the [choropleth map](https://en.wikipedia.org/wiki/Choropleth_map) below shows unemployment by county in the United States.
:::plot defer https://observablehq.com/@observablehq/plot-us-choropleth
```js
@@ -151,7 +151,7 @@ Plot.plot({
This uses the [**interval** scale option](../features/scales.md#scale-transforms) to bin temporal data into facets by decade.
:::
-Lastly, the geo mark is not limited to spherical geometries! [Plot’s projection system](../features/projections.md) includes planar projections, which allow you to work with shapes—such as contours—generated on an arbitrary flat surface.
+Lastly, the geo mark is not limited to spherical geometries! [Plot’s projection system](../features/projections.md) includes planar projections, which allow you to work with shapes — such as contours — generated on an arbitrary flat surface.
## Geo options
diff --git a/docs/marks/grid.md b/docs/marks/grid.md
index fad2456c16..830717c2ae 100644
--- a/docs/marks/grid.md
+++ b/docs/marks/grid.md
@@ -61,7 +61,7 @@ See the [axis mark](./axis.md) for more details and examples.
## Grid options
-The optional *data* is an array of tick values—it defaults to the scale’s ticks. The grid mark draws a line for each tick value, across the whole frame.
+The optional *data* is an array of tick values — it defaults to the scale’s ticks. The grid mark draws a line for each tick value, across the whole frame.
The following options are supported:
diff --git a/docs/marks/image.md b/docs/marks/image.md
index 5c4e0c356b..68240b8308 100644
--- a/docs/marks/image.md
+++ b/docs/marks/image.md
@@ -111,7 +111,7 @@ Plot.plot({
```
:::
-If—*for reasons*—you want to style the plot with a background image, you can do that using the top-level **style** option rather than an image mark. Below, Kristen Gorman’s penguins dataset is visualized atop her photograph of sea ice near Palmer Station on the Antarctic peninsula, where she collected the measurements.
+If — *for reasons* — you want to style the plot with a background image, you can do that using the top-level **style** option rather than an image mark. Below, Kristen Gorman’s penguins dataset is visualized atop her photograph of sea ice near Palmer Station on the Antarctic peninsula, where she collected the measurements.
:::plot defer https://observablehq.com/@observablehq/plot-background-image
```js
diff --git a/docs/marks/line.md b/docs/marks/line.md
index f93a7637bb..5689b34dc1 100644
--- a/docs/marks/line.md
+++ b/docs/marks/line.md
@@ -81,7 +81,7 @@ Plot.lineY(d3.shuffle(aapl.slice()), {x: "Date", y: "Close", sort: "Date"}).plot
```
:::
-While the *x* scale of a line chart often represents time, this is not required. For example, we can plot the elevation profile of a Tour de France stage—and imagine how tiring it must be to start a climb after riding 160km! ⛰🚴💦
+While the *x* scale of a line chart often represents time, this is not required. For example, we can plot the elevation profile of a Tour de France stage — and imagine how tiring it must be to start a climb after riding 160km! ⛰🚴💦
:::plot defer https://observablehq.com/@observablehq/plot-tour-de-france-elevation-profile
```js
diff --git a/docs/marks/link.md b/docs/marks/link.md
index a04c6055bb..081991fc76 100644
--- a/docs/marks/link.md
+++ b/docs/marks/link.md
@@ -20,7 +20,7 @@ onMounted(() => {
# Link mark
-The **link mark** draws straight lines between two points [**x1**, **y1**] and [**x2**, **y2**] in quantitative dimensions. It is similar to the [arrow mark](./arrow.md), except it draws a straight line—or geodesic when used with a [spherical projection](../features/projections.md).
+The **link mark** draws straight lines between two points [**x1**, **y1**] and [**x2**, **y2**] in quantitative dimensions. It is similar to the [arrow mark](./arrow.md), except it draws a straight line — or geodesic when used with a [spherical projection](../features/projections.md).
For example, the chart below shows the rising inequality (and population) in various U.S. cities from 1980 to 2015. Each link represents two observations of a city: the city’s population (**x**) and inequality (**y**) in 1980, and the same in 2015. The link’s **stroke** redundantly encodes the change in inequality: red indicates rising inequality, while blue (there are only four) indicates declining inequality.
diff --git a/docs/marks/raster.md b/docs/marks/raster.md
index 3f9e3ebb8a..f84bdd4131 100644
--- a/docs/marks/raster.md
+++ b/docs/marks/raster.md
@@ -30,7 +30,7 @@ function mandelbrot(x, y) {
To produce contours instead of a heatmap, see the [contour mark](./contour.md).
:::
-The **raster mark** renders a [raster image](https://en.wikipedia.org/wiki/Raster_graphics)—that is, an image formed by discrete pixels in a grid, not a vector graphic like other marks. And whereas the [image mark](./image.md) shows an *existing* image, the raster mark *creates* one from abstract data, either by [interpolating spatial samples](#spatial-interpolators) (arbitrary points in **x** and **y**) or by sampling a function *f*(*x*,*y*) along the grid.
+The **raster mark** renders a [raster image](https://en.wikipedia.org/wiki/Raster_graphics) — that is, an image formed by discrete pixels in a grid, not a vector graphic like other marks. And whereas the [image mark](./image.md) shows an *existing* image, the raster mark *creates* one from abstract data, either by [interpolating spatial samples](#spatial-interpolators) (arbitrary points in **x** and **y**) or by sampling a function *f*(*x*,*y*) along the grid.
For example, the heatmap below shows the topography of the [Maungawhau volcano](https://en.wikipedia.org/wiki/Maungawhau), produced from a {{volcano.width}}×{{volcano.height}} grid of elevation samples.
diff --git a/docs/marks/text.md b/docs/marks/text.md
index c66a0c28f6..58346ba82f 100644
--- a/docs/marks/text.md
+++ b/docs/marks/text.md
@@ -170,9 +170,9 @@ Plot.plot({
marks: [
Plot.text(
[
- "Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before cof\xadfin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.",
- "There now is your insular city of the Manhattoes, belted round by wharves as Indian isles by coral reefs—commerce surrounds it with her surf. Right and left, the streets take you waterward. Its extreme downtown is the battery, where that noble mole is washed by waves, and cooled by breezes, which a few hours previous were out of sight of land. Look at the crowds of water-gazers there.",
- "Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears Hook to Coenties Slip, and from thence, by Whitehall, northward. What do you see?—Posted like silent sentinels all around the town, stand thousands upon thousands of mortal men fixed in ocean reveries. Some leaning against the spiles; some seated upon the pier-heads; some looking over the bulwarks of ships from China; some high aloft in the rigging, as if striving to get a still better seaward peep. But these are all landsmen; of week days pent up in lath and plaster—tied to counters, nailed to benches, clinched to desks. How then is this? Are the green fields gone? What do they here?"
+ "Call me Ishmael. Some years ago — never mind how long precisely — having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before cof\xadfin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off — then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.",
+ "There now is your insular city of the Manhattoes, belted round by wharves as Indian isles by coral reefs — commerce surrounds it with her surf. Right and left, the streets take you waterward. Its extreme downtown is the battery, where that noble mole is washed by waves, and cooled by breezes, which a few hours previous were out of sight of land. Look at the crowds of water-gazers there.",
+ "Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears Hook to Coenties Slip, and from thence, by Whitehall, northward. What do you see? — Posted like silent sentinels all around the town, stand thousands upon thousands of mortal men fixed in ocean reveries. Some leaning against the spiles; some seated upon the pier-heads; some looking over the bulwarks of ships from China; some high aloft in the rigging, as if striving to get a still better seaward peep. But these are all landsmen; of week days pent up in lath and plaster — tied to counters, nailed to benches, clinched to desks. How then is this? Are the green fields gone? What do they here?"
],
{
x: (d, i) => 1 + i, // paragraph number
diff --git a/docs/marks/tip.md b/docs/marks/tip.md
index 26b99de327..c73fdb08a5 100644
--- a/docs/marks/tip.md
+++ b/docs/marks/tip.md
@@ -93,7 +93,7 @@ Plot.plot({
```
:::
-If no **title** channel is supplied, the tip mark displays all channel values. You can supply additional name-value pairs by registering extra channels using the **channels** mark option. In the scatterplot of Olympic athletes below, you can hover to see the *name* and *sport* of each athlete. This is helpful for noticing patterns—tall basketball players, giant weightlifters and judoka, diminutive gymnasts—and for seeing individuals.
+If no **title** channel is supplied, the tip mark displays all channel values. You can supply additional name-value pairs by registering extra channels using the **channels** mark option. In the scatterplot of Olympic athletes below, you can hover to see the *name* and *sport* of each athlete. This is helpful for noticing patterns — tall basketball players, giant weightlifters and judoka, diminutive gymnasts — and for seeing individuals.
:::plot defer https://observablehq.com/@observablehq/plot-tips-additional-channels
```js
diff --git a/docs/transforms/bin.md b/docs/transforms/bin.md
index 417fd80145..2fa707d4b7 100644
--- a/docs/transforms/bin.md
+++ b/docs/transforms/bin.md
@@ -20,7 +20,7 @@ onMounted(() => {
The bin transform is for aggregating quantitative or temporal data. For ordinal or nominal data, use the [group transform](./group.md). See also the [hexbin transform](./hexbin.md).
:::
-The **bin transform** groups quantitative or temporal data—continuous measurements such as heights, weights, or temperatures—into discrete bins. You can then compute summary statistics for each bin, such as a count, sum, or proportion. The bin transform is most often used to make histograms or heatmaps with the [rect mark](../marks/rect.md).
+The **bin transform** groups quantitative or temporal data — continuous measurements such as heights, weights, or temperatures — into discrete bins. You can then compute summary statistics for each bin, such as a count, sum, or proportion. The bin transform is most often used to make histograms or heatmaps with the [rect mark](../marks/rect.md).
For example, here is a histogram showing the distribution of weights of Olympic athletes.
diff --git a/docs/transforms/centroid.md b/docs/transforms/centroid.md
index 409704c29d..419e1e131b 100644
--- a/docs/transforms/centroid.md
+++ b/docs/transforms/centroid.md
@@ -43,7 +43,7 @@ Plot.voronoi(counties, Plot.centroid()).plot({projection: "albers"})
While the centroid transform computes the centroid of a geometry _after_ projection, the geoCentroid transform computes it _before_ projection, then projects the resulting coordinates. This difference has a few implications, as follows.
-As an [initializer](../features/transforms.md#custom-initializers), the centroid transform operates _after_ the geometries have been projected to screen coordinates. The resulting **x** and **y** channels reference the pixel coordinates of the planar centroid of the _projected_ shapes. No assumption is made about the geometries: they can be in any coordinate system, and the returned value is in the frame—as long as the projected geometry returns at least one visible point.
+As an [initializer](../features/transforms.md#custom-initializers), the centroid transform operates _after_ the geometries have been projected to screen coordinates. The resulting **x** and **y** channels reference the pixel coordinates of the planar centroid of the _projected_ shapes. No assumption is made about the geometries: they can be in any coordinate system, and the returned value is in the frame — as long as the projected geometry returns at least one visible point.
:::plot defer https://observablehq.com/@observablehq/plot-centroid-dot
```js
@@ -52,7 +52,7 @@ Plot.dot(counties, Plot.centroid()).plot({projection: "albers-usa"})
:::
-The geoCentroid transform is more specialized as the **x** and **y** channels it derives represent the longitudes and latitudes of the centroids of the given GeoJSON geometries, before projection. It expects the geometries to be specified in _spherical_ coordinates. It is more correct, in a geospatial sense—for example, the spherical centroid always represents the center of mass of the original shape, and it will be rotated exactly in line with the projection’s rotate argument. However, this also means that it might land outside the frame if only a part of the land mass is visible, and might be clipped by the projection. In practice, the difference is generally imperceptible.
+The geoCentroid transform is more specialized as the **x** and **y** channels it derives represent the longitudes and latitudes of the centroids of the given GeoJSON geometries, before projection. It expects the geometries to be specified in _spherical_ coordinates. It is more correct, in a geospatial sense — for example, the spherical centroid always represents the center of mass of the original shape, and it will be rotated exactly in line with the projection’s rotate argument. However, this also means that it might land outside the frame if only a part of the land mass is visible, and might be clipped by the projection. In practice, the difference is generally imperceptible.
:::plot defer https://observablehq.com/@observablehq/plot-centroid-dot
```js
@@ -60,7 +60,7 @@ Plot.dot(counties, Plot.geoCentroid()).plot({projection: "albers-usa"})
```
:::
-The geoCentroid transform is slightly faster than the centroid initializer—which might be useful if you have tens of thousands of features and want to show their density on a [hexbin map](../transforms/hexbin.md):
+The geoCentroid transform is slightly faster than the centroid initializer — which might be useful if you have tens of thousands of features and want to show their density on a [hexbin map](../transforms/hexbin.md):
:::plot defer https://observablehq.com/@observablehq/plot-centroid-hexbin
```js
diff --git a/docs/transforms/filter.md b/docs/transforms/filter.md
index 4eaca5aff1..da2a36d794 100644
--- a/docs/transforms/filter.md
+++ b/docs/transforms/filter.md
@@ -50,7 +50,7 @@ As an alternative to the filter transform here, you could set the **text** chann
The filter transform can be applied either via the **filter** [mark option](../features/marks.md#mark-options), as above, or as an explicit [filter transform](#filter-test-options). The latter is generally only needed when composing multiple transforms.
-To highlight the vowels in a bar chart of English letter frequency, you can use a filtered bar with a red stroke. A filtered mark allows you to set options on a subset of the data, even if those options—such as mark insets—are not expressible as a channels.
+To highlight the vowels in a bar chart of English letter frequency, you can use a filtered bar with a red stroke. A filtered mark allows you to set options on a subset of the data, even if those options — such as mark insets — are not expressible as a channels.
:::plot https://observablehq.com/@observablehq/plot-filtered-bars
```js{8}
diff --git a/docs/transforms/group.md b/docs/transforms/group.md
index df85aea289..3f88eea20c 100644
--- a/docs/transforms/group.md
+++ b/docs/transforms/group.md
@@ -19,7 +19,7 @@ onMounted(() => {
The group transform is for aggregating ordinal or nominal data. For quantitative or temporal data, use the [bin transform](./bin.md).
:::
-The **group transform** groups ordinal or nominal data—discrete values such as name, type, or category. You can then compute summary statistics for each group, such as a count, sum, or proportion. The group transform is most often used to make bar charts with the [bar mark](../marks/bar.md).
+The **group transform** groups ordinal or nominal data — discrete values such as name, type, or category. You can then compute summary statistics for each group, such as a count, sum, or proportion. The group transform is most often used to make bar charts with the [bar mark](../marks/bar.md).
For example, the bar chart below shows a distribution of Olympic athletes by sport.
diff --git a/docs/transforms/hexbin.md b/docs/transforms/hexbin.md
index 9d223d29a1..051b75bc82 100644
--- a/docs/transforms/hexbin.md
+++ b/docs/transforms/hexbin.md
@@ -23,7 +23,7 @@ onMounted(() => {
# Hexbin transform
-The **hexbin transform** groups two-dimensional quantitative or temporal data—continuous measurements such as heights, weights, or temperatures—into discrete hexagonal bins. You can then compute summary statistics for each bin, such as a count, sum, or proportion. The hexbin transform is most often used to make heatmaps with the [dot mark](../marks/dot.md).
+The **hexbin transform** groups two-dimensional quantitative or temporal data — continuous measurements such as heights, weights, or temperatures — into discrete hexagonal bins. You can then compute summary statistics for each bin, such as a count, sum, or proportion. The hexbin transform is most often used to make heatmaps with the [dot mark](../marks/dot.md).
For example, the heatmap below shows the weights and heights of Olympic athletes. The color of each hexagon represents the number (*count*) of athletes with similar weight and height.
diff --git a/docs/transforms/interval.md b/docs/transforms/interval.md
index 40964702aa..7b19052a83 100644
--- a/docs/transforms/interval.md
+++ b/docs/transforms/interval.md
@@ -38,7 +38,7 @@ Plot.plot({
```
:::
-In contrast, a [rectY mark](../marks/rect.md) with the **interval** option and the *day* interval produces a temporal (*utc*) *x* scale. This allows Plot to compute ticks at meaningful intervals: here weekly boundaries, UTC midnight on Sundays. Furthermore, we can see that this isn’t truly daily data—it’s missing weekends and holidays when the stock market was closed.
+In contrast, a [rectY mark](../marks/rect.md) with the **interval** option and the *day* interval produces a temporal (*utc*) *x* scale. This allows Plot to compute ticks at meaningful intervals: here weekly boundaries, UTC midnight on Sundays. Furthermore, we can see that this isn’t truly daily data — it’s missing weekends and holidays when the stock market was closed.
:::plot https://observablehq.com/@observablehq/plot-temporal-interval-option
```js
diff --git a/docs/transforms/map.md b/docs/transforms/map.md
index c2b6f739a9..2e859520f5 100644
--- a/docs/transforms/map.md
+++ b/docs/transforms/map.md
@@ -20,7 +20,7 @@ function bollinger(N, K) {
# Map transform
-The **map transform** groups data into series and then transforms each series’ values, say to normalize them relative to some basis or to apply a moving average. For example, below the map transform computes a cumulative sum (*cumsum*) of a series of random numbers sampled from a normal distribution—in other words, a random walk.
+The **map transform** groups data into series and then transforms each series’ values, say to normalize them relative to some basis or to apply a moving average. For example, below the map transform computes a cumulative sum (*cumsum*) of a series of random numbers sampled from a normal distribution — in other words, a random walk.
:::plot https://observablehq.com/@observablehq/plot-random-walk-cumsum-map
```js
diff --git a/docs/transforms/normalize.md b/docs/transforms/normalize.md
index 984214e9f0..f8979ecd02 100644
--- a/docs/transforms/normalize.md
+++ b/docs/transforms/normalize.md
@@ -27,7 +27,7 @@ onMounted(() => {
# Normalize transform
-The **normalize transform** is a specialized [map transform](./map.md) that normalizes series values relative to some basis, say to convert absolute values into relative values. For example, here is an index chart—a type of multi-series line chart—showing the return of several stocks relative to their closing price on a particular date.
+The **normalize transform** is a specialized [map transform](./map.md) that normalizes series values relative to some basis, say to convert absolute values into relative values. For example, here is an index chart — a type of multi-series line chart — showing the return of several stocks relative to their closing price on a particular date.
:::plot defer https://observablehq.com/@observablehq/plot-index-chart
```js
diff --git a/docs/transforms/stack.md b/docs/transforms/stack.md
index c991dffd4f..d833cab894 100644
--- a/docs/transforms/stack.md
+++ b/docs/transforms/stack.md
@@ -53,7 +53,7 @@ const likert = Likert([
The **stack transform** comes in two orientations: [stackY](#stacky-stack-options) replaces **y** with **y1** and **y2** to form vertical↑ stacks grouped on **x**, while [stackX](#stackx-stack-options) replaces **x** with **x1** and **x2** for horizontal→ stacks grouped on **y**. In effect, stacking transforms a *length* into *lower* and *upper* positions: the upper position of each element equals the lower position of the next element in the stack. Stacking makes it easier to perceive a total while still showing its parts.
-For example, below is a stacked area chart of [deaths in the Crimean War](https://en.wikipedia.org/wiki/Florence_Nightingale#Crimean_War)—predominantly from disease —using Florence Nightingale’s data.
+For example, below is a stacked area chart of [deaths in the Crimean War](https://en.wikipedia.org/wiki/Florence_Nightingale#Crimean_War) — predominantly from disease — using Florence Nightingale’s data.
:::plot https://observablehq.com/@observablehq/plot-crimean-war-casualties
```js
diff --git a/docs/why-plot.md b/docs/why-plot.md
index fc3116463a..236e62a935 100644
--- a/docs/why-plot.md
+++ b/docs/why-plot.md
@@ -19,7 +19,7 @@ function arealineY(data, {color, fillOpacity = 0.1, ...options} = {}) {
**Observable Plot** is for exploratory data visualization. It’s for finding insights quickly. Its API, while expressive and configurable, optimizes for conciseness and memorability. We want the time to first chart to be as fast as possible.
-And the speed doesn’t stop there: Plot helps you quickly pivot and refine your views of data. Our hope with Plot is that you’ll spend less time reading the docs, searching for code to copy-paste, and debugging—and more time asking questions of data.
+And the speed doesn’t stop there: Plot helps you quickly pivot and refine your views of data. Our hope with Plot is that you’ll spend less time reading the docs, searching for code to copy-paste, and debugging — and more time asking questions of data.
Compared to other visualization tools, including low-level tools such as D3 and less expressive high-level tools such as chart templates, we think you’ll be more productive exploring data with Plot. You’ll spend more time “using vision to think” and less time wrangling the machinery of programming.
@@ -35,7 +35,7 @@ Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", stroke: "specie
```
:::
-What makes Plot concise? In a word: *defaults*. If you specify the semantics—your data and the desired encodings—Plot will figure out the rest.
+What makes Plot concise? In a word: *defaults*. If you specify the semantics — your data and the desired encodings — Plot will figure out the rest.
The beauty of defaults is that you can override them as needed. This is ideal for exploring: you invest minimally in the initial chart, and as you start to see something interesting, you progressively customize to improve the display. Perhaps the plot above would be easier to read with an aspect ratio proportional to the data, a grid, and a legend?
@@ -163,7 +163,7 @@ We’ve long said that *D3 makes things possible, not necessarily easy.* And tha
**Plot’s goal is to make the easy things easy, and fast, and then some.**
:::tip
-Whether or not Plot succeeds at this goal is up to you—so we’d love [your feedback](https://talk.observablehq.com/c/site-feedback/3) on what you find easy or hard to do with Plot. And we encourage you to [ask for help](https://talk.observablehq.com/c/help/6) when you get stuck. We learn a lot from helping!
+Whether or not Plot succeeds at this goal is up to you — so we’d love [your feedback](https://talk.observablehq.com/c/site-feedback/3) on what you find easy or hard to do with Plot. And we encourage you to [ask for help](https://talk.observablehq.com/c/help/6) when you get stuck. We learn a lot from helping!
:::
Since Plot and D3 have different goals, they make different trade-offs. Plot is more efficient: you can make charts quickly. But it is also necessarily less expressive: bespoke visualizations with extensive animation and interaction, advanced techniques like force-directed graph layout, or even developing your own charting library, are better done with D3’s low-level API.