Skip to content

Commit a1c43ca

Browse files
authored
Merge branch 'main' into fil/render-api-docs
2 parents a825a73 + e5fb68d commit a1c43ca

File tree

794 files changed

+55124
-40183
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

794 files changed

+55124
-40183
lines changed

.github/workflows/deploy.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ jobs:
1515
name: github-pages
1616
url: ${{ steps.deployment.outputs.page_url }}
1717
steps:
18-
- uses: actions/checkout@v3
19-
- uses: actions/setup-node@v3
18+
- uses: actions/checkout@v4
19+
- uses: actions/setup-node@v4
2020
with:
21-
node-version: 16
22-
cache: 'yarn'
21+
node-version: 20
22+
cache: yarn
2323
- run: yarn --frozen-lockfile
2424
- run: yarn prepublishOnly
2525
- run: yarn docs:build
26-
- uses: actions/configure-pages@v3
27-
- uses: actions/upload-pages-artifact@v1
26+
- uses: actions/configure-pages@v4
27+
- uses: actions/upload-pages-artifact@v3
2828
with:
2929
path: docs/.vitepress/dist
3030
- name: Deploy
3131
id: deployment
32-
uses: actions/deploy-pages@v1
32+
uses: actions/deploy-pages@v4

.github/workflows/publish.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Publish
2+
3+
on:
4+
workflow_dispatch: {}
5+
release:
6+
types: [published]
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: read
13+
packages: write
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: 20
19+
registry-url: 'https://registry.npmjs.org'
20+
cache: 'yarn'
21+
- run: yarn --frozen-lockfile
22+
- run: yarn test
23+
- run: npm publish
24+
env:
25+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/test.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ jobs:
1010
test:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v3
14-
- uses: actions/setup-node@v3
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-node@v4
1515
with:
16-
node-version: 16
17-
cache: 'yarn'
16+
node-version: 20
17+
cache: yarn
1818
- run: yarn --frozen-lockfile
1919
- run: yarn test:mocha
2020
- run: yarn test:tsc
@@ -24,7 +24,7 @@ jobs:
2424
- run: yarn test:prettier
2525
- run: yarn prepublishOnly
2626
- run: yarn docs:build
27-
- uses: actions/upload-artifact@v3
27+
- uses: actions/upload-artifact@v4
2828
if: failure()
2929
with:
3030
name: test-output-changes

.mocharc.json

Lines changed: 0 additions & 5 deletions
This file was deleted.

CHANGELOG-2021.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Observable Plot - Changelog [2021]
22

3-
Year: [Current (2023)](./CHANGELOG.md) · [2022](./CHANGELOG-2022.md) · **2021**
3+
Year: [Current (2024)](./CHANGELOG.md) · [2023](./CHANGELOG-2023.md) · [2022](./CHANGELOG-2022.md) · **2021**
44

55
## 0.3.2
66

CHANGELOG-2022.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Observable Plot - Changelog [2022]
22

3-
Year: [Current (2023)](./CHANGELOG.md) · **2022** · [2021](./CHANGELOG-2021.md)
3+
Year: [Current (2024)](./CHANGELOG.md) · [2023](./CHANGELOG-2023.md) · **2022** · [2021](./CHANGELOG-2021.md)
44

55
## 0.6.1
66

CHANGELOG-2023.md

Lines changed: 855 additions & 0 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 8 additions & 718 deletions
Large diffs are not rendered by default.

docs/.vitepress/config.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default defineConfig({
3030
["script", {}, "window.dataLayer=window.dataLayer||[];\nfunction gtag(){dataLayer.push(arguments);}\ngtag('js',new Date());\ngtag('config','G-9B88TP6PKQ');"]
3131
],
3232
sitemap: {
33-
hostname: 'https://observablehq.com/plot'
33+
hostname: 'https://observablehq.com/plot/'
3434
},
3535
themeConfig: {
3636
// https://vitepress.dev/reference/default-theme-config
@@ -88,6 +88,7 @@ export default defineConfig({
8888
{text: "Contour", link: "/marks/contour"},
8989
{text: "Delaunay", link: "/marks/delaunay"},
9090
{text: "Density", link: "/marks/density"},
91+
{text: "Difference", link: "/marks/difference"},
9192
{text: "Dot", link: "/marks/dot"},
9293
{text: "Frame", link: "/marks/frame"},
9394
{text: "Geo", link: "/marks/geo"},
@@ -121,6 +122,7 @@ export default defineConfig({
121122
{text: "Map", link: "/transforms/map"},
122123
{text: "Normalize", link: "/transforms/normalize"},
123124
{text: "Select", link: "/transforms/select"},
125+
{text: "Shift", link: "/transforms/shift"},
124126
{text: "Sort", link: "/transforms/sort"},
125127
{text: "Stack", link: "/transforms/stack"},
126128
{text: "Tree", link: "/transforms/tree"},
@@ -142,8 +144,7 @@ export default defineConfig({
142144
},
143145
socialLinks: [
144146
{icon: "github", link: "https://github.com/observablehq/plot"},
145-
{icon: "twitter", link: "https://twitter.com/observablehq"},
146-
{icon: "mastodon", link: "https://vis.social/@observablehq"},
147+
{icon: "x", link: "https://twitter.com/observablehq"},
147148
{icon: "slack", link: "https://observablehq.com/slack/join"},
148149
{icon: "linkedin", link: "https://www.linkedin.com/company/observable"},
149150
{icon: "youtube", link: "https://www.youtube.com/c/Observablehq"}

docs/.vitepress/theme/index.ts

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,60 +17,16 @@ export default {
1717
}
1818
};
1919

20-
function enableAnalytics(router) {
20+
async function enableAnalytics(router) {
2121
if (typeof location === "undefined" || location.origin !== "https://observablehq.com") return;
22-
22+
const {pageLoad, routeChanged} = await import("https://events.observablehq.com/client.js");
2323
let pageLoaded;
24-
let queue: any[] | null = [];
25-
let user;
26-
2724
watch(router.route, () => {
2825
if (pageLoaded) {
29-
emit({
30-
type: "routeChanged",
31-
event_version: 2,
32-
data: {},
33-
tags: {}
34-
});
26+
routeChanged();
3527
} else {
36-
emit({
37-
type: "pageLoad",
38-
event_version: 1,
39-
data: {referrer: document.referrer.replace(/\?.*/, "")},
40-
tags: {}
41-
});
28+
pageLoad();
4229
pageLoaded = true;
4330
}
4431
});
45-
46-
fetch("https://api.observablehq.com/user", {credentials: "include"})
47-
.then((response) => (response.ok ? response.json() : null))
48-
.then(
49-
(u) => (user = u),
50-
() => (user = null)
51-
)
52-
.then(() => (sendEvents(queue), (queue = null)));
53-
54-
function emit(event) {
55-
event.time = new Date().toISOString();
56-
event.location = `${location.origin}${location.pathname}${location.search}`; // drop hash
57-
if (queue) queue.push(event);
58-
else sendEvents([event]);
59-
}
60-
61-
function sendEvents(events) {
62-
if (!events.length) return;
63-
navigator.sendBeacon(
64-
"https://events.observablehq.com/beacon-events",
65-
JSON.stringify({
66-
events: events.map((event) => ({
67-
...event,
68-
release: null,
69-
user_id: user?.id ?? null,
70-
user_agent: navigator.userAgent
71-
})),
72-
send_time: new Date().toISOString()
73-
})
74-
);
75-
}
76-
}
32+
}

docs/features/facets.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const olympians = shallowRef([
1313
{weight: 170, height: 2.21, sex: "male"}
1414
]);
1515

16+
const scheme = Plot.scale({color: {type: "categorical"}}).range;
17+
1618
onMounted(() => {
1719
d3.csv("../data/athletes.csv", d3.autoType).then((data) => (olympians.value = data));
1820
});
@@ -23,7 +25,7 @@ onMounted(() => {
2325

2426
Faceting partitions data by ordinal or categorical value and then repeats a plot for each partition (each **facet**), producing [small multiples](https://en.wikipedia.org/wiki/Small_multiple) for comparison. Faceting is typically enabled by declaring the horizontal↔︎ facet channel **fx**, the vertical↕︎ facet channel **fy**, or both for two-dimensional faceting.
2527

26-
For example, below we recreate the Trellis display (“reminiscent of garden trelliswork”) of [Becker *et al.*](https://hci.stanford.edu/courses/cs448b/papers/becker-trellis-jcgs.pdf) using the dot’s **fy** channel to declare vertical↕︎ facets, showing the yields of several varieties of barley across several sites for the years <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[0]}`}">1931</span> and <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[1]}`}">1932</span>.
28+
For example, below we recreate the Trellis display (“reminiscent of garden trelliswork”) of [Becker *et al.*](https://hci.stanford.edu/courses/cs448b/papers/becker-trellis-jcgs.pdf) using the dot’s **fy** channel to declare vertical↕︎ facets, showing the yields of several varieties of barley across several sites for the years <span :style="{borderBottom: `solid 2px ${scheme[0]}`}">1931</span> and <span :style="{borderBottom: `solid 2px ${scheme[1]}`}">1932</span>.
2729

2830
:::plot https://observablehq.com/@observablehq/plot-trellis
2931
```js
@@ -57,7 +59,7 @@ This plot uses the [**sort** mark option](./scales.md#sort-mark-option) to order
5759
Use the [frame mark](../marks/frame.md) for stronger visual separation of facets.
5860
:::
5961

60-
The chart above reveals a likely data collection error: the years appear to be reversed for the Morris site as it is the only site where the yields in <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[1]}`}">1932</span> were higher than in <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[0]}`}">1931</span>. The anomaly in Morris is more obvious if we use directed arrows to show the year-over-year change. The [group transform](../transforms/group.md) groups the observations by site and variety to compute the change.
62+
The chart above reveals a likely data collection error: the years appear to be reversed for the Morris site as it is the only site where the yields in <span :style="{borderBottom: `solid 2px ${scheme[1]}`}">1932</span> were higher than in <span :style="{borderBottom: `solid 2px ${scheme[0]}`}">1931</span>. The anomaly in Morris is more obvious if we use directed arrows to show the year-over-year change. The [group transform](../transforms/group.md) groups the observations by site and variety to compute the change.
6163

6264
:::plot defer https://observablehq.com/@observablehq/plot-trellis-anomaly
6365
```js

docs/features/markers.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ A **marker** defines a graphic drawn on vertices of a [line](../marks/line.md) o
3030
</label>
3131
</p>
3232

33-
:::plot https://observablehq.com/d/cfc5b4e46aa18b57?intent=fork
33+
:::plot https://observablehq.com/@observablehq/plot-line-chart-with-markers?intent=fork
3434
```js-vue
3535
Plot.plot({
3636
marks: [
@@ -56,9 +56,9 @@ The following named markers are supported:
5656
* *dot* - a filled *circle* without a stroke and 2.5px radius
5757
* *circle*, equivalent to *circle-fill* - a filled circle with a white stroke and 3px radius
5858
* *circle-stroke* - a hollow circle with a colored stroke and a white fill and 3px radius
59-
* *tick* - a small opposing line
60-
* *tick-x* - a small horizontal line
61-
* *tick-y* - a small vertical line
59+
* *tick* <VersionBadge version="0.6.12" pr="1872" /> - a small opposing line
60+
* *tick-x* <VersionBadge version="0.6.12" pr="1872" /> - a small horizontal line
61+
* *tick-y* <VersionBadge version="0.6.12" pr="1872" /> - a small vertical line
6262

6363
If **marker** is true, it defaults to *circle*. If **marker** is a function, it will be called with a given *color* and must return an [SVG marker element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/marker).
6464

docs/features/scales.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const align = ref(0.5);
1111
const radius = ref(8);
1212
const schemeq = ref("turbo");
1313
const schemed = ref("rdbu");
14-
const schemeo = ref("Tableau10");
14+
const schemeo = ref("Observable10");
1515
const interpolateq = ref("rgb");
1616
const anomaly = gistemp.map((d) => d.Anomaly);
1717
const aapl = shallowRef([]);
@@ -457,6 +457,7 @@ Plot also provides color schemes for discrete data. Use the *categorical* type f
457457
<option>Accent</option>
458458
<option>Category10</option>
459459
<option>Dark2</option>
460+
<option>Observable10</option>
460461
<option>Paired</option>
461462
<option>Pastel1</option>
462463
<option>Pastel2</option>
@@ -730,7 +731,7 @@ Plot.plot({
730731

731732
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:
732733

733-
* *categorical* - like *ordinal*, but defaults to *tableau10*
734+
* *categorical* - like *ordinal*, but defaults to *observable10*
734735
* *sequential* - like *linear*
735736
* *cyclical* - like *linear*, but defaults to *rainbow*
736737
* *threshold* - discretizes using thresholds given as the **domain**; defaults to *rdylbu*
@@ -878,6 +879,7 @@ Plot.plot({
878879
["Accent", d3.schemeAccent],
879880
["Category10", d3.schemeCategory10],
880881
["Dark2", d3.schemeDark2],
882+
["Observable10", Plot.scale({color: {type: "categorical"}}).range],
881883
["Paired", d3.schemePaired],
882884
["Pastel1", d3.schemePastel1],
883885
["Pastel2", d3.schemePastel2],
@@ -1011,19 +1013,35 @@ Note: when the value of the sort option is a string or a function, it is interpr
10111013

10121014
## scale(*options*) <VersionBadge version="0.4.0" /> {#scale}
10131015

1014-
You can also create a standalone scale with Plot.**scale**(*options*). The *options* object must define at least one scale; see [Scale options](#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*:
1016+
You can also create a standalone scale with Plot.**scale**(*options*). The *options* object must define at least one scale; see [Scale options](#scale-options) for how to define a scale. For example, here is a categorical color scale with the *Tableau10* color scheme and a domain of fruits:
10151017

10161018
```js
1017-
const color = Plot.scale({color: {type: "linear"}});
1019+
const color = Plot.scale({color: {scheme: "Tableau10", domain: ["apple", "orange", "pear"]}});
10181020
```
10191021

10201022
Both [*plot*.scale](./plots.md#plot_scale) and [Plot.scale](#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.
10211023

1022-
To reuse a scale across plots, pass the corresponding scale object into another plot specification:
1023-
10241024
```js
1025-
const plot1 = Plot.plot(options);
1026-
const plot2 = Plot.plot({...options, color: plot1.scale("color")});
1025+
color.domain // ["apple", "orange", "pear"]
10271026
```
10281027

10291028
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.
1029+
1030+
```js
1031+
color.apply("apple") // "#4e79a7"
1032+
```
1033+
1034+
To apply a standalone scale object to a plot, pass it to Plot.plot as the corresponding scale options, such as **color**:
1035+
1036+
:::plot
1037+
```js
1038+
Plot.cellX(["apple", "apple", "orange", "pear", "orange"]).plot({color})
1039+
```
1040+
:::
1041+
1042+
As another example, below are two plots with different options where the second plot uses the *color* scale from the first plot:
1043+
1044+
```js
1045+
const plot1 = Plot.plot({...options1});
1046+
const plot2 = Plot.plot({...options2, color: plot1.scale("color")});
1047+
```

docs/features/transforms.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const olympians = shallowRef([]);
1010
const traffic = shallowRef(["Saarbrücken-Neuhaus", "Oldenburg (Holstein)", "Holz", "Göttelborn", "Riegelsberg", "Kastel", "Neustadt i. H.-Süd", "Nettersheim", "Hasborn", "Laufeld", "Otzenhausen", "Nonnweiler", "Kirschheck", "AS Eppelborn", "Bierfeld", "Von der Heydt", "Illingen", "Hetzerath", "Groß Ippener", "Bockel", "Ladbergen", "Dibbersen", "Euskirchen/Bliesheim", "Hürth", "Lotte", "Ascheberg", "Bad Schwartau", "Schloss Burg", "Uphusen", "HB-Silbersee", "Barsbüttel", "HB-Mahndorfer See", "Glüsingen", "HB-Weserbrücke", "Hengsen", "Köln-Nord", "Hagen-Vorhalle", "Unna"].map((location, i) => ({location, date: new Date(Date.UTC(2000, 0, 1, i)), vehicles: (10 + i) ** 2.382})));
1111
const bins = computed(() => d3.bin().thresholds(80).value((d) => d.weight)(olympians.value));
1212

13+
const scheme = Plot.scale({color: {type: "categorical"}}).range;
14+
1315
onMounted(() => {
1416
d3.csv("../data/athletes.csv", d3.autoType).then((data) => (olympians.value = data));
1517
d3.csv("../data/bls-metro-unemployment.csv", d3.autoType).then((data) => (bls.value = data));
@@ -116,7 +118,7 @@ If a transform isn’t doing what you expect, try inspecting the options object
116118

117119
Transforms can derive channels (such as **y** above) as well as changing the default options. For example, the bin transform sets default insets for a one-pixel gap between adjacent rects.
118120

119-
Transforms are composable: you can pass *options* through more than one transform before passing it to a mark. For example, above it’s a bit difficult to compare the weight distribution by sex because there are fewer <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[0]}`}">female</span> than <span :style="{borderBottom: `solid 2px ${d3.schemeTableau10[1]}`}">male</span> athletes in the data. We can remove this effect using the [normalize transform](../transforms/normalize.md) with the *sum* reducer.
121+
Transforms are composable: you can pass *options* through more than one transform before passing it to a mark. For example, above it’s a bit difficult to compare the weight distribution by sex because there are fewer <span :style="{borderBottom: `solid 2px ${scheme[0]}`}">female</span> than <span :style="{borderBottom: `solid 2px ${scheme[1]}`}">male</span> athletes in the data. We can remove this effect using the [normalize transform](../transforms/normalize.md) with the *sum* reducer.
120122

121123
:::plot defer https://observablehq.com/@observablehq/plot-overlapping-relative-histogram
122124
```js-vue

docs/marks/axis.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ Plot.plot({
279279
marks: [
280280
Plot.frame(),
281281
Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", fx: "sex", fy: "species"}),
282-
Plot.axisX({color: "red", anchor, facetAnchor: facetAnchor === "auto" ? undefined : facetAnchor}),
282+
Plot.axisX({color: "red", anchor, facetAnchor: facetAnchor === "auto" ? undefined : facetAnchor === "null" ? null : facetAnchor}),
283283
Plot.axisFx({color: "blue", anchor: anchor === "top" ? "bottom" : "top"}) // place fx axis opposite x
284284
]
285285
})

0 commit comments

Comments
 (0)