diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c868f8b4f..f00c6fc15c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,6 @@ *Not yet released. These are forthcoming changes in the main branch.* -Plot now supports [interaction marks](./README.md#interactions)! An interaction mark defines an interactive selection represented as a subset of the mark’s data. For example, the [brush mark](./README.md#brush) allows rectangular selection by clicking and dragging; you can use a brush to select points of interest from a scatterplot and show them in a table. The interactive selection is exposed as *plot*.value. When the selection changes during interaction, the plot emits *input* events. This allows plots to be [Observable views](https://observablehq.com/@observablehq/introduction-to-views), but you can also [listen to *input* events](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) directly. - The [text mark](./README.md#text) now supports automatic wrapping! The new **lineWidth** option specifies the desired length of a line in ems. The line breaking, wrapping, and text metrics implementations are all rudimentary, but they should be acceptable for text that is mostly ASCII. (For more control, you can hard-wrap text manually.) The **monospace** option now provides convenient defaults for monospaced text. Plot now supports ARIA attributes for improved accessibility: aria-label, aria-description, aria-hidden. The top-level **ariaLabel** and **ariaDescription** options apply to the root SVG element. The new **ariaLabel** and **ariaDescription** scale options apply to axes; the label defaults to *e.g.* “y-axis” and the description defaults to the scale’s label (*e.g.*, “↑ temperature”). Marks define a group-level aria-label (*e.g.*, “dot”). There is also an optional **ariaLabel** channel for labeling data (*e.g.*, “E 12.7%”), and a group-level **ariaDescription** option for a human-readable description. The **ariaHidden** mark option allows the hiding of decorative elements from the accessibility tree. diff --git a/README.md b/README.md index 0d747958ea..8a4fa9ea31 100644 --- a/README.md +++ b/README.md @@ -1225,38 +1225,6 @@ Plot.vector(wind, {x: "longitude", y: "latitude", length: "speed", rotate: "dire Returns a new vector with the given *data* and *options*. If neither the **x** nor **y** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. -## Interactions - -Interactions are special marks that handle user input and define interactive selections. When a plot has an interaction mark, the returned *plot*.value represents the current selection as an array subset of the interaction mark’s data. As the user modifies the selection through interaction with the plot, *input* events are emitted. This design is compatible with [Observable’s viewof operator](https://observablehq.com/@observablehq/introduction-to-views), but you can also listen to *input* events directly via the [EventTarget interface](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). - -### Brush - -[Source](./src/marks/brush.js) · [Examples](https://observablehq.com/@observablehq/plot-brush) · Selects points within a single contiguous rectangular region, such as nearby dots in a scatterplot. - -#### Plot.brush(*data*, *options*) - -```js -Plot.brush(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"}) -``` - -Returns a new brush with the given *data* and *options*. If neither the **x** nor **y** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. - -#### Plot.brushX(*data*, *options*) - -```js -Plot.brushX(penguins, {x: "culmen_depth_mm"}) -``` - -Equivalent to [Plot.brush](#plotbrushdata-options) except that if the **x** option is not specified, it defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. - -#### Plot.brushY(*data*, *options*) - -```js -Plot.brushY(penguins, {y: "culmen_length_mm"}) -``` - -Equivalent to [Plot.brush](#plotbrushdata-options) except that if the **y** option is not specified, it defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. - ## Decorations Decorations are static marks that do not represent data. Currently this includes only [Plot.frame](#frame), although internally Plot’s axes are implemented as decorations and may in the future be exposed here for more flexible configuration. diff --git a/src/index.js b/src/index.js index 3d282cd381..7ac7a63778 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,6 @@ export {plot, Mark, marks} from "./plot.js"; export {Area, area, areaX, areaY} from "./marks/area.js"; export {Arrow, arrow} from "./marks/arrow.js"; export {BarX, BarY, barX, barY} from "./marks/bar.js"; -export {brush, brushX, brushY} from "./marks/brush.js"; export {Cell, cell, cellX, cellY} from "./marks/cell.js"; export {Dot, dot, dotX, dotY} from "./marks/dot.js"; export {Frame, frame} from "./marks/frame.js"; @@ -14,7 +13,6 @@ export {RuleX, RuleY, ruleX, ruleY} from "./marks/rule.js"; export {Text, text, textX, textY} from "./marks/text.js"; export {TickX, TickY, tickX, tickY} from "./marks/tick.js"; export {Vector, vector} from "./marks/vector.js"; -export {selection} from "./selection.js"; export {valueof} from "./options.js"; export {filter, reverse, sort, shuffle} from "./transforms/basic.js"; export {bin, binX, binY} from "./transforms/bin.js"; diff --git a/src/marks/brush.js b/src/marks/brush.js deleted file mode 100644 index d319d6b732..0000000000 --- a/src/marks/brush.js +++ /dev/null @@ -1,87 +0,0 @@ -import {brush as brusher, brushX as brusherX, brushY as brusherY, create, select} from "d3"; -import {identity, maybeTuple} from "../options.js"; -import {Mark} from "../plot.js"; -import {selection, selectionEquals} from "../selection.js"; -import {applyDirectStyles, applyIndirectStyles} from "../style.js"; - -const defaults = { - ariaLabel: "brush", - fill: "#777", - fillOpacity: 0.3, - stroke: "#fff" -}; - -export class Brush extends Mark { - constructor(data, {x, y, ...options} = {}) { - super( - data, - [ - {name: "x", value: x, scale: "x", optional: true}, - {name: "y", value: y, scale: "y", optional: true} - ], - options, - defaults - ); - this.activeElement = null; - } - render(index, {x, y}, {x: X, y: Y}, dimensions) { - const {ariaLabel, ariaDescription, ariaHidden, ...options} = this; - const {marginLeft, width, marginRight, marginTop, height, marginBottom} = dimensions; - const brush = this; - const g = create("svg:g") - .call(applyIndirectStyles, {ariaLabel, ariaDescription, ariaHidden}) - .call((X && Y ? brusher : X ? brusherX : brusherY)() - .extent([[marginLeft, marginTop], [width - marginRight, height - marginBottom]]) - .on("start brush end", function(event) { - const {type, selection: extent} = event; - // For faceting, when starting a brush in a new facet, clear the - // brush and selection on the old facet. In the future, we might - // allow independent brushes across facets by disabling this? - if (type === "start" && brush.activeElement !== this) { - if (brush.activeElement !== null) { - select(brush.activeElement).call(event.target.clear, event); - brush.activeElement[selection] = null; - } - brush.activeElement = this; - } - let S = null; - if (extent) { - S = index; - if (X) { - let [x0, x1] = Y ? [extent[0][0], extent[1][0]] : extent; - if (x.bandwidth) x0 -= x.bandwidth(); - S = S.filter(i => x0 <= X[i] && X[i] <= x1); - } - if (Y) { - let [y0, y1] = X ? [extent[0][1], extent[1][1]] : extent; - if (y.bandwidth) y0 -= y.bandwidth(); - S = S.filter(i => y0 <= Y[i] && Y[i] <= y1); - } - } - if (!selectionEquals(this[selection], S)) { - this[selection] = S; - this.dispatchEvent(new Event("input", {bubbles: true})); - } - })) - .call(g => g.selectAll(".selection") - .attr("shape-rendering", null) // reset d3-brush - .call(applyIndirectStyles, options) - .call(applyDirectStyles, options)) - .node(); - g[selection] = null; - return g; - } -} - -export function brush(data, {x, y, ...options} = {}) { - ([x, y] = maybeTuple(x, y)); - return new Brush(data, {...options, x, y}); -} - -export function brushX(data, {x = identity, ...options} = {}) { - return new Brush(data, {...options, x, y: null}); -} - -export function brushY(data, {y = identity, ...options} = {}) { - return new Brush(data, {...options, x: null, y}); -} diff --git a/src/plot.js b/src/plot.js index a26ba715cf..d8412d7748 100644 --- a/src/plot.js +++ b/src/plot.js @@ -1,12 +1,11 @@ -import {create, cross, difference, groups, InternMap, union} from "d3"; +import {create, cross, difference, groups, InternMap} from "d3"; import {Axes, autoAxisTicks, autoScaleLabels} from "./axes.js"; import {Channel, channelSort} from "./channel.js"; import {defined} from "./defined.js"; import {Dimensions} from "./dimensions.js"; import {Legends, exposeLegends} from "./legends.js"; -import {arrayify, isOptions, keyword, range, first, second, where, take} from "./options.js"; +import {arrayify, isOptions, keyword, range, first, second, where} from "./options.js"; import {Scales, ScaleFunctions, autoScaleRange, applyScales, exposeScales} from "./scales.js"; -import {selection} from "./selection.js"; import {applyInlineStyles, maybeClassName, styles} from "./style.js"; import {basic} from "./transforms/basic.js"; @@ -96,21 +95,12 @@ export function plot(options = {}) { .call(applyInlineStyles, style) .node(); - let initialValue; for (const mark of marks) { const channels = markChannels.get(mark) ?? []; const values = applyScales(channels, scales); const index = filter(markIndex.get(mark), channels, values); const node = mark.render(index, scales, values, dimensions, axes); - if (node != null) { - if (node[selection] !== undefined) { - initialValue = markValue(mark, node[selection]); - node.addEventListener("input", () => { - figure.value = markValue(mark, node[selection]); - }); - } - svg.appendChild(node); - } + if (node != null) svg.appendChild(node); } // Wrap the plot in a figure with a caption, if desired. @@ -129,7 +119,6 @@ export function plot(options = {}) { figure.scale = exposeScales(scaleDescriptors); figure.legend = exposeLegends(scaleDescriptors, options); - figure.value = initialValue; return figure; } @@ -200,10 +189,6 @@ function markify(mark) { return mark instanceof Mark ? mark : new Render(mark); } -function markValue(mark, selection) { - return selection === null ? mark.data : take(mark.data, selection); -} - class Render extends Mark { constructor(render) { super(); @@ -279,7 +264,7 @@ class Facet extends Mark { return {index, channels: [...channels, ...subchannels]}; } render(I, scales, _, dimensions, axes) { - const {data, channels, marks, marksChannels, marksIndexByFacet} = this; + const {marks, marksChannels, marksIndexByFacet} = this; const {fx, fy} = scales; const fyDomain = fy && fy.domain(); const fxDomain = fx && fx.domain(); @@ -287,8 +272,7 @@ class Facet extends Mark { const fxMargins = fx && {marginRight: 0, marginLeft: 0, width: fx.bandwidth()}; const subdimensions = {...dimensions, ...fxMargins, ...fyMargins}; const marksValues = marksChannels.map(channels => applyScales(channels, scales)); - let selectionByFacet; - const parent = create("svg:g") + return create("svg:g") .call(g => { if (fy && axes.y) { const axis1 = axes.y, axis2 = nolabel(axis1); @@ -332,25 +316,10 @@ class Facet extends Mark { const values = marksValues[i]; const index = filter(marksFacetIndex[i], marksChannels[i], values); const node = marks[i].render(index, scales, values, subdimensions); - if (node != null) { - if (node[selection] !== undefined) { - if (marks[i].data !== data) throw new Error("selection must use facet data"); - if (selectionByFacet === undefined) selectionByFacet = facetMap(channels); - selectionByFacet.set(key, node[selection]); - node.addEventListener("input", () => { - selectionByFacet.set(key, node[selection]); - parent[selection] = facetSelection(selectionByFacet); - }); - } - this.appendChild(node); - } + if (node != null) this.appendChild(node); } })) .node(); - if (selectionByFacet !== undefined) { - parent[selection] = facetSelection(selectionByFacet); - } - return parent; } } @@ -393,20 +362,6 @@ function facetTranslate(fx, fy) { : ky => `translate(0,${fy(ky)})`; } -// If multiple facets define a selection, then the overall selection is the -// union of the defined selections. As with non-faceted plots, we assume that -// only a single mark is defining the selection; if multiple marks define a -// selection, generally speaking the last one wins, although the behavior is not -// explicitly defined. -function facetSelection(selectionByFacet) { - let selection = null; - for (const value of selectionByFacet.values()) { - if (value === null) continue; - selection = selection === null ? value : union(selection, value); - } - return selection; -} - function facetMap(channels) { return new (channels.length > 1 ? FacetMap2 : FacetMap); } @@ -424,9 +379,6 @@ class FacetMap { set(key, value) { return this._.set(key, value), this; } - values() { - return this._.values(); - } } // A Map-like interface that supports paired keys. @@ -445,9 +397,4 @@ class FacetMap2 extends FacetMap { else super.set(key1, new InternMap([[key2, value]])); return this; } - *values() { - for (const map of this._.values()) { - yield* map.values(); - } - } } diff --git a/src/selection.js b/src/selection.js deleted file mode 100644 index 228a22743c..0000000000 --- a/src/selection.js +++ /dev/null @@ -1,18 +0,0 @@ -// This symbol is used by interactive marks to define which data are selected. A -// node returned by mark.render may expose a selection as node[selection], whose -// value may be an array of numbers (e.g., [0, 1, 2, …]) representing an -// in-order subset of the rendered index, or null if the selection is undefined. -// The selection can be updated during interaction by emitting an input event. -export const selection = Symbol("selection"); - -// Given two (possibly null, possibly an index, but not undefined) selections, -// returns true if the two represent the same selection, and false otherwise. -// This assumes that the selection is a in-order subset of the original index. -export function selectionEquals(s1, s2) { - if (s1 === s2) return true; - if (s1 == null || s2 == null) return false; - const n = s1.length; - if (n !== s2.length) return false; - for (let i = 0; i < n; ++i) if (s1[i] !== s2[i]) return false; - return true; -} diff --git a/test/output/gistempAnomalyBrush.svg b/test/output/gistempAnomalyBrush.svg deleted file mode 100644 index 4f7b3e8ac3..0000000000 --- a/test/output/gistempAnomalyBrush.svg +++ /dev/null @@ -1,1742 +0,0 @@ - - - - - - −0.6 - - - - −0.4 - - - - −0.2 - - - - +0.0 - - - - +0.2 - - - - +0.4 - - - - +0.6 - - - - +0.8 - - - - +1.0 - - - - +1.2 - ↑ Temperature anomaly (°C) - - - - 1880 - - - 1900 - - - 1920 - - - 1940 - - - 1960 - - - 1980 - - - 2000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/output/penguinCulmenBrush.html b/test/output/penguinCulmenBrush.html deleted file mode 100644 index 59a710f28f..0000000000 --- a/test/output/penguinCulmenBrush.html +++ /dev/null @@ -1,3036 +0,0 @@ - - - - - Adelie - - - Chinstrap - - - Gentoo - species - - - - FEMALE - - - MALE - - - - sex - - - - - - 35 - - - - 40 - - - - 45 - - - - 50 - - - - 55 - - ↑ culmen_length_mm - - - - - - 35 - - - - 40 - - - - 45 - - - - 50 - - - - 55 - - - - - - - - 35 - - - - 40 - - - - 45 - - - - 50 - - - - 55 - - - - - - - - 15 - - - - 20 - - - - - - - - 15 - - - - 20 - - - - - - - - 15 - - - - 20 - - culmen_depth_mm → - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 344 \ No newline at end of file diff --git a/test/plots/gistemp-anomaly-brush.js b/test/plots/gistemp-anomaly-brush.js deleted file mode 100644 index 3a3b2f97d8..0000000000 --- a/test/plots/gistemp-anomaly-brush.js +++ /dev/null @@ -1,22 +0,0 @@ -import * as Plot from "@observablehq/plot"; -import * as d3 from "d3"; - -export default async function() { - const data = await d3.csv("data/gistemp.csv", d3.autoType); - return Plot.plot({ - y: { - label: "↑ Temperature anomaly (°C)", - tickFormat: "+f", - grid: true - }, - color: { - type: "diverging", - reverse: true - }, - marks: [ - Plot.ruleY([0]), - Plot.dot(data, {x: "Date", y: "Anomaly", stroke: "Anomaly"}), - Plot.brush(data, {x: "Date", y: "Anomaly"}) - ] - }); -} diff --git a/test/plots/index.js b/test/plots/index.js index 6d2be5cb14..b2ee127e33 100644 --- a/test/plots/index.js +++ b/test/plots/index.js @@ -48,7 +48,6 @@ export {default as footballCoverage} from "./football-coverage.js"; export {default as fruitSales} from "./fruit-sales.js"; export {default as fruitSalesDate} from "./fruit-sales-date.js"; export {default as gistempAnomaly} from "./gistemp-anomaly.js"; -export {default as gistempAnomalyBrush} from "./gistemp-anomaly-brush.js"; export {default as gistempAnomalyMoving} from "./gistemp-anomaly-moving.js"; export {default as gistempAnomalyTransform} from "./gistemp-anomaly-transform.js"; export {default as googleTrendsRidgeline} from "./google-trends-ridgeline.js"; @@ -91,7 +90,6 @@ export {default as musicRevenue} from "./music-revenue.js"; export {default as ordinalBar} from "./ordinal-bar.js"; export {default as penguinCulmen} from "./penguin-culmen.js"; export {default as penguinCulmenArray} from "./penguin-culmen-array.js"; -export {default as penguinCulmenBrush} from "./penguin-culmen-brush.js"; export {default as penguinIslandUnknown} from "./penguin-island-unknown.js"; export {default as penguinMass} from "./penguin-mass.js"; export {default as penguinMassSex} from "./penguin-mass-sex.js"; diff --git a/test/plots/penguin-culmen-brush.js b/test/plots/penguin-culmen-brush.js deleted file mode 100644 index 4f08af205e..0000000000 --- a/test/plots/penguin-culmen-brush.js +++ /dev/null @@ -1,39 +0,0 @@ -import * as Plot from "@observablehq/plot"; -import * as d3 from "d3"; -import {html} from "htl"; - -export default async function() { - const data = await d3.csv("data/penguins.csv", d3.autoType); - const plot = Plot.plot({ - height: 600, - grid: true, - facet: { - data, - x: "sex", - y: "species", - marginRight: 80 - }, - marks: [ - Plot.frame(), - Plot.dot(data, { - facet: "exclude", - x: "culmen_depth_mm", - y: "culmen_length_mm", - r: 2, - fill: "#ddd" - }), - Plot.dot(data, { - x: "culmen_depth_mm", - y: "culmen_length_mm" - }), - Plot.brush(data, { - x: "culmen_depth_mm", - y: "culmen_length_mm" - }) - ] - }); - const output = html``; - plot.oninput = () => output.value = plot.value.length; - plot.oninput(); - return html`${plot}${output}`; -}