Skip to content

Commit 1c27551

Browse files
authored
revert brush (#748)
1 parent 5d06b6f commit 1c27551

11 files changed

+6
-5041
lines changed

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
*Not yet released. These are forthcoming changes in the main branch.*
66

7-
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.
8-
97
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.
108

119
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.

README.md

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,38 +1225,6 @@ Plot.vector(wind, {x: "longitude", y: "latitude", length: "speed", rotate: "dire
12251225

12261226
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₂*, …].
12271227

1228-
## Interactions
1229-
1230-
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).
1231-
1232-
### Brush
1233-
1234-
[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.
1235-
1236-
#### Plot.brush(*data*, *options*)
1237-
1238-
```js
1239-
Plot.brush(penguins, {x: "culmen_depth_mm", y: "culmen_length_mm"})
1240-
```
1241-
1242-
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₂*, …].
1243-
1244-
#### Plot.brushX(*data*, *options*)
1245-
1246-
```js
1247-
Plot.brushX(penguins, {x: "culmen_depth_mm"})
1248-
```
1249-
1250-
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₂*, …].
1251-
1252-
#### Plot.brushY(*data*, *options*)
1253-
1254-
```js
1255-
Plot.brushY(penguins, {y: "culmen_length_mm"})
1256-
```
1257-
1258-
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₂*, …].
1259-
12601228
## Decorations
12611229

12621230
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.

src/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ export {plot, Mark, marks} from "./plot.js";
22
export {Area, area, areaX, areaY} from "./marks/area.js";
33
export {Arrow, arrow} from "./marks/arrow.js";
44
export {BarX, BarY, barX, barY} from "./marks/bar.js";
5-
export {brush, brushX, brushY} from "./marks/brush.js";
65
export {Cell, cell, cellX, cellY} from "./marks/cell.js";
76
export {Dot, dot, dotX, dotY} from "./marks/dot.js";
87
export {Frame, frame} from "./marks/frame.js";
@@ -14,7 +13,6 @@ export {RuleX, RuleY, ruleX, ruleY} from "./marks/rule.js";
1413
export {Text, text, textX, textY} from "./marks/text.js";
1514
export {TickX, TickY, tickX, tickY} from "./marks/tick.js";
1615
export {Vector, vector} from "./marks/vector.js";
17-
export {selection} from "./selection.js";
1816
export {valueof} from "./options.js";
1917
export {filter, reverse, sort, shuffle} from "./transforms/basic.js";
2018
export {bin, binX, binY} from "./transforms/bin.js";

src/marks/brush.js

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

src/plot.js

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import {create, cross, difference, groups, InternMap, union} from "d3";
1+
import {create, cross, difference, groups, InternMap} from "d3";
22
import {Axes, autoAxisTicks, autoScaleLabels} from "./axes.js";
33
import {Channel, channelSort} from "./channel.js";
44
import {defined} from "./defined.js";
55
import {Dimensions} from "./dimensions.js";
66
import {Legends, exposeLegends} from "./legends.js";
7-
import {arrayify, isOptions, keyword, range, first, second, where, take} from "./options.js";
7+
import {arrayify, isOptions, keyword, range, first, second, where} from "./options.js";
88
import {Scales, ScaleFunctions, autoScaleRange, applyScales, exposeScales} from "./scales.js";
9-
import {selection} from "./selection.js";
109
import {applyInlineStyles, maybeClassName, styles} from "./style.js";
1110
import {basic} from "./transforms/basic.js";
1211

@@ -96,21 +95,12 @@ export function plot(options = {}) {
9695
.call(applyInlineStyles, style)
9796
.node();
9897

99-
let initialValue;
10098
for (const mark of marks) {
10199
const channels = markChannels.get(mark) ?? [];
102100
const values = applyScales(channels, scales);
103101
const index = filter(markIndex.get(mark), channels, values);
104102
const node = mark.render(index, scales, values, dimensions, axes);
105-
if (node != null) {
106-
if (node[selection] !== undefined) {
107-
initialValue = markValue(mark, node[selection]);
108-
node.addEventListener("input", () => {
109-
figure.value = markValue(mark, node[selection]);
110-
});
111-
}
112-
svg.appendChild(node);
113-
}
103+
if (node != null) svg.appendChild(node);
114104
}
115105

116106
// Wrap the plot in a figure with a caption, if desired.
@@ -129,7 +119,6 @@ export function plot(options = {}) {
129119

130120
figure.scale = exposeScales(scaleDescriptors);
131121
figure.legend = exposeLegends(scaleDescriptors, options);
132-
figure.value = initialValue;
133122
return figure;
134123
}
135124

@@ -200,10 +189,6 @@ function markify(mark) {
200189
return mark instanceof Mark ? mark : new Render(mark);
201190
}
202191

203-
function markValue(mark, selection) {
204-
return selection === null ? mark.data : take(mark.data, selection);
205-
}
206-
207192
class Render extends Mark {
208193
constructor(render) {
209194
super();
@@ -279,16 +264,15 @@ class Facet extends Mark {
279264
return {index, channels: [...channels, ...subchannels]};
280265
}
281266
render(I, scales, _, dimensions, axes) {
282-
const {data, channels, marks, marksChannels, marksIndexByFacet} = this;
267+
const {marks, marksChannels, marksIndexByFacet} = this;
283268
const {fx, fy} = scales;
284269
const fyDomain = fy && fy.domain();
285270
const fxDomain = fx && fx.domain();
286271
const fyMargins = fy && {marginTop: 0, marginBottom: 0, height: fy.bandwidth()};
287272
const fxMargins = fx && {marginRight: 0, marginLeft: 0, width: fx.bandwidth()};
288273
const subdimensions = {...dimensions, ...fxMargins, ...fyMargins};
289274
const marksValues = marksChannels.map(channels => applyScales(channels, scales));
290-
let selectionByFacet;
291-
const parent = create("svg:g")
275+
return create("svg:g")
292276
.call(g => {
293277
if (fy && axes.y) {
294278
const axis1 = axes.y, axis2 = nolabel(axis1);
@@ -332,25 +316,10 @@ class Facet extends Mark {
332316
const values = marksValues[i];
333317
const index = filter(marksFacetIndex[i], marksChannels[i], values);
334318
const node = marks[i].render(index, scales, values, subdimensions);
335-
if (node != null) {
336-
if (node[selection] !== undefined) {
337-
if (marks[i].data !== data) throw new Error("selection must use facet data");
338-
if (selectionByFacet === undefined) selectionByFacet = facetMap(channels);
339-
selectionByFacet.set(key, node[selection]);
340-
node.addEventListener("input", () => {
341-
selectionByFacet.set(key, node[selection]);
342-
parent[selection] = facetSelection(selectionByFacet);
343-
});
344-
}
345-
this.appendChild(node);
346-
}
319+
if (node != null) this.appendChild(node);
347320
}
348321
}))
349322
.node();
350-
if (selectionByFacet !== undefined) {
351-
parent[selection] = facetSelection(selectionByFacet);
352-
}
353-
return parent;
354323
}
355324
}
356325

@@ -393,20 +362,6 @@ function facetTranslate(fx, fy) {
393362
: ky => `translate(0,${fy(ky)})`;
394363
}
395364

396-
// If multiple facets define a selection, then the overall selection is the
397-
// union of the defined selections. As with non-faceted plots, we assume that
398-
// only a single mark is defining the selection; if multiple marks define a
399-
// selection, generally speaking the last one wins, although the behavior is not
400-
// explicitly defined.
401-
function facetSelection(selectionByFacet) {
402-
let selection = null;
403-
for (const value of selectionByFacet.values()) {
404-
if (value === null) continue;
405-
selection = selection === null ? value : union(selection, value);
406-
}
407-
return selection;
408-
}
409-
410365
function facetMap(channels) {
411366
return new (channels.length > 1 ? FacetMap2 : FacetMap);
412367
}
@@ -424,9 +379,6 @@ class FacetMap {
424379
set(key, value) {
425380
return this._.set(key, value), this;
426381
}
427-
values() {
428-
return this._.values();
429-
}
430382
}
431383

432384
// A Map-like interface that supports paired keys.
@@ -445,9 +397,4 @@ class FacetMap2 extends FacetMap {
445397
else super.set(key1, new InternMap([[key2, value]]));
446398
return this;
447399
}
448-
*values() {
449-
for (const map of this._.values()) {
450-
yield* map.values();
451-
}
452-
}
453400
}

src/selection.js

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

0 commit comments

Comments
 (0)