Skip to content

Commit

Permalink
revert pointer scale changes; CHANGELOG
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed May 23, 2023
1 parent 4aebcd7 commit 8d705b9
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 57 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG-2021.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Observable Plot - Changelog [2021]

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

## 0.3.2

Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG-2022.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Observable Plot - Changelog [2022]

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

## 0.6.1

Expand Down
118 changes: 73 additions & 45 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
# Observable Plot - Changelog

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

## 0.6.7

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

The new [tip mark](https://observablehq.com/plot/marks/tip) renders annotations in a floating box anchored to a given position in **x** and **y**. Like the text mark, it supports soft-wrapping and multi-line text, and can be used to draw attention to points of interest and add commentary.
The new [tip mark](https://observablehq.com/plot/marks/tip) displays text, or a name-value pair for each channel, in a floating box anchored to a given position in **x** and **y**. The tip mark is often paired with the new [pointer interaction](https://observablehq.com/plot/interactions/pointer) such that only the point closest to the pointer is rendered, allowing the tip mark to reveal details interactively by hovering the chart.

<img src="./img/tip-line.webp" width="640" alt="A line chart of Apple stock price from 2013 to 2018, with an annotation on May 12, 2016, showing the two-year low closing price of $90.34.">

```js
Plot.lineY(aapl, {x: "Date", y: "Close", tip: true}).plot()
```

The new **tip** mark option adds an implicit tip mark with pointer interaction derived from the current mark. The line chart above can be written more explicitly as:

```js
Plot.plot({
marks: [
Plot.lineY(aapl, {x: "Date", y: "Close"}),
Plot.tip(aapl, Plot.pointerX({x: "Date", y: "Close"}))
]
})
```

The tip mark can be also used to draw attention to points of interest and add commentary. When used with the **title** channel, the tip mark supports text wrapping and multi-line text.

<img src="./img/tip-title.png" width="640" alt="A line chart of Apple stock price from 2013 to 2018, with an annotation describing the decline from 2015 through mid-2016, followed by a recovery.">

Expand All @@ -15,6 +34,10 @@ Plot.plot({
y: {grid: true},
marks: [
Plot.lineY(aapl, {x: "Date", y: "Close"}),
Plot.tip(
[`Apple stock reaches a new high of $133 on Feb. 23, 2015. The release of the first Apple Watch, slated for April, is hotly anticipated.`],
{x: new Date("2015-02-23"), y: 133, dy: -3, anchor: "bottom"}
),
Plot.tip(
[`Apple stock drops 8% after the company misses Q2 revenue targets and reports declining iPhone sales. It reaches a two-year low of $90.34 on May 12.`],
{x: new Date("2016-05-12"), y: 90.34, dy: 3, anchor: "top"}
Expand All @@ -23,39 +46,26 @@ Plot.plot({
})
```

If the **title** channel is omitted, the tip mark automatically shows the name and value of all channels.
The pointer interaction can be paired with any mark, not just a tip: a red dot, say, to emphasize the focused point, or a rule to highlight its *x* or *y* position. You can independently control the target position from the display using the **px** and **py** channels, say to show the currently-focused point’s value in the top-left corner of the chart with a text mark.

<img src="./img/tip.png" width="640" alt="A line chart of Apple stock price from 2013 to 2018, with an annotation on May 12, 2016, showing the two-year low closing price of $90.34.">
<img src="./img/pointer-text.webp" width="640" alt="A line chart of Apple stock price from 2013 to 2018; as the pointer moves over the chart, the date and close are shown in the top-left corner, while a red rule and dot highlights the focused point.">

```js
Plot.plot({
y: {grid: true},
height: 160,
y: {axis: "right", grid: true, nice: true},
marks: [
Plot.lineY(aapl, {x: "Date", y: "Close"}),
Plot.tip({length: 1}, {x: new Date("2016-05-12"), y: 90.34, dy: 3, anchor: "top"})
Plot.ruleX(aapl, Plot.pointerX({x: "Date", py: "Close", stroke: "red"})),
Plot.dot(aapl, Plot.pointerX({x: "Date", y: "Close", stroke: "red"})),
Plot.text(aapl, Plot.pointerX({px: "Date", py: "Close", dy: -17, frameAnchor: "top-left", fontVariant: "tabular-nums", text: (d) => [`Date ${Plot.formatIsoDate(d.Date)}`, `Close ${d.Close.toFixed(2)}`].join(" ")}))
]
})
```

The tip mark is often paired with the new [pointer interaction](https://observablehq.com/plot/interactions/pointer), which dynamically filters a mark such that only the instance closest to the pointer is rendered. This allows the tip mark to reveal more information about the datum closest to the pointer, say when hovering a scatterplot or line chart.

The pointer interaction can also be paired with any mark: a red dot, say, to emphasize the focused point, or a rule to highlight its *x* or *y* position. You can also independently control the target position from the display, say to show the currently-focused point’s value in the top-left corner of the chart with a text mark.

[TODO Example of a text mark driven by the pointer interaction.]

The pointer interaction supports “click-to-stick”: if you click on the chart, the currently-focused point will remain focused until you click again. By temporarily locking the focused point, you can select text from the tip for copy and paste.

The new **tip** mark option adds an implicit tip mark with pointer interaction derived from the current mark.

[TODO Animated tip + pointer example]

```js
Plot.lineY(aapl, {x: "Date", y: "Close", tip: true}).plot({y: {grid: true}})
```

When the **tip** option is truthy, the **title** channel is no longer applied using an SVG title element; it is instead rendered via the tip mark. The auto mark sets the **tip** option to true by default.

The pointer interaction also powers the new crosshair mark, which provides an alternative strategy for showing the *x* (horizontal↔︎ position) and *y* (vertical↕︎ position) of the closest point to the pointer.
The pointer interaction also powers the new [crosshair mark](https://observablehq.com/plot/interactions/crosshair) which shows the *x* (horizontal↔︎ position) and *y* (vertical↕︎ position) value of the point closest to the pointer on the bottom and left sides of the frame, respectively.

<img src="./img/crosshair.png" width="640" alt="A line chart of Apple stock price from 2013 to 2018, with a crosshair centered over May 12, 2016, showing a closing price of $90.34.">

Expand All @@ -64,52 +74,70 @@ Plot.plot({
marginLeft: 50,
marks: [
Plot.lineY(aapl, {x: "Date", y: "Close"}),
Plot.crosshair(aapl, {x: "Date", y: "Close"}) // TODO crosshairX
Plot.crosshairX(aapl, {x: "Date", y: "Close"})
]
})
```

The new **labelArrow** axis mark option and implicit arrow behavior for axis labels.
In addition to these exciting new interaction features, Plot 0.6.7 includes a variety of improvements and bug fixes.

Ordinal scales are now smarter about choosing a default time format when the **interval** option is a yearly interval: the four-digit year is (YYYY) shown instead of year, month, and day (YYYY-01-01).
The **sort** mark option now supports *-channel* descending shorthand for [imputed scales domains](https://observablehq.com/plot/features/scales#sort-mark-option) and the [sort transform](https://observablehq.com/plot/transforms/sort). For example, sorting *x* by *-y* orders a bar chart by descending value:

Color scales now default to a *categorical* scale when a categorical color scheme is specified. (This avoids an “unknown quantitative scheme” error.)
<img src="./img/bar-sort.png" width="640" alt="A bar chart showing English letters by descending frequency, starting with E (12.7%), T (9.1%), down to Z (0.7%).">

Time intervals can now be specified as integer multiples of a base time interval, such as *3 months* or *10 years*.
```js
Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "-y"}}).plot()
```

The new **imageFilter** mark option.
This is equivalent to:

The new **render** transform mark option.
```js
Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", order: "descending"}}).plot()
```

Mark transforms are now passed the plot’s *options* as a third argument. This allows the group, bin, and stack transforms (and other transforms) to check if the scale has a declared **interval** option, and if so, apply that interval before grouping.
The **sort** option for imputed channel domains now also takes an **order** option which can be *ascending*, *descending*, a custom comparator, or null. (This more closely matches the **order** option for the sort transform.) The **reverse** option now reverses the order rather than using descending natural order, placing nulls first instead of last.

The autoSpec method now returns the name of the explicit mark and transform implementations as **markImpl** and **transformImpl** respectively, along with the **markOptions** and **transformOptions** needed to instantiate them.
Previously setting the scale **label** option would disable Plot’s automatic directional arrow in axis labels (↑, →, ↓, or ←); now Plot implicitly adds an arrow to the label you provide, unless the label already has a arrow or you set the **labelArrow** option to null or false. You can also force an arrow by setting this option to true, or *up*, *right*, *down*, or *bottom*. In Plot’s code base, we were able to remove 161 Unicode arrows thanks to this change!

The normalize and window transforms now accept two-argument “index-aware” reducers. The map transform now accepts a two-argument index-aware map method, too.
Color scales now default to a *categorical* scale when a categorical color scheme is specified. For example, this no longer throws a “unknown quantitative scheme” error:

Fix a bug where the *opacity* channel didn’t automatically opt-out of the *opacity* scale when all values are in the interval [0,1].
<img src="./img/cell-categorical.png" width="640" alt="A row of 10 rectangular swatches showing the Tableau10 color scheme.">

Fix a bug where the frame mark would crash if a channel-eligible option such as **fill** were specified as an invalid CSS color string, such as *bluez*. The frame mark now supports channel-eligible options to be specified as abstract values, in which case the abstract values will be encoded using a scale; for example, setting **fill** to *Biscoe* would apply an *ordinal* *color* scale.
```js
Plot.cellX(d3.range(10)).plot({color: {scheme: "Tableau10"}})
```

Fix a bug when filtering facets and computing facet anchors with non-primitive facet domains, such as dates.
Ordinal scales are now smarter about choosing a default time format when the **interval** option is a yearly interval: the four-digit year is (YYYY) shown instead of year, month, and day (YYYY-01-01). Time intervals can now be specified as integer multiples of a base time interval, such as *3 months* or *10 years*.

Fix a bug where the position defaults for the rectX, rectY, barX, and barY marks were only applied if the *options* object was strictly undefined; now the position defaults apply if the relevant position options are undefined.
Mark transforms are now passed the plot’s *options* as a third argument; this allows the group, bin, and stack transforms (and other transforms) to check if the scale has a declared **interval** option, and if so, apply that interval before grouping. For example, to count athletes by age at 5-year intervals:

<img src="./img/group-interval.png" width="640" alt="A bar chart showing the frequency of athletes by age, grouped at 5-year intervals; the chart peaks at 1990 with more than 4,500 athletes, following a skewed bell curve.">

```js
Plot.barY(olympians, Plot.groupX({y: "count"}, {x: "date_of_birth"})).plot({x: {interval: "5 years"}})
```

Fix *z*-order across facets. Fix *z*-order of facet axes, which should be drawn below rather than above other marks, as with other axes.
The new **imageFilter** mark option applies a [CSS filter effect](https://developer.mozilla.org/en-US/docs/Web/CSS/filter) to the mark, such as a drop shadow or blur. The [rule](https://observablehq.com/plot/marks/rule) and [tick](https://observablehq.com/plot/marks/tick) marks now support **marker** options.

Fix the auto mark to chose the rect mark instead of rectX or rectY when appropriate, and likewise choose correctly between line, lineX, and lineY, and areaX and areaY.
The normalize and window transforms now accept two-argument “index-aware” reducers; the map transform now also accepts a two-argument index-aware map method. The mapX transform now defaults **x** to identity if none of **x**, **x1**, and **x2** are specified; the mapY transform does the same for **y**.

The mapX transform now defaults **x** to identity if none of **x**, **x1**, and **x2** are specified; the mapY transform does the same for **y**.
When faceting, the plot dimensions now includes **facet**.**width** and **facet**.**height** for the plot’s outer dimensions. The plot context now includes the ownerSVGElement.

Fix a bug where the *opacity* channel didn’t automatically opt-out of the *opacity* scale when all values are in the interval [0,1].

Fix a bug where the frame mark would crash if a channel-eligible option such as **fill** were specified as an invalid CSS color string, such as *bleu*. The frame mark now supports channel-eligible options to be specified as abstract values, in which case the abstract values will be encoded using a scale; for example, setting **fill** to *Biscoe* would apply an *ordinal* *color* scale.

Fix a bug where the position defaults for the rectX, rectY, barX, and barY marks were only applied if the *options* object was strictly undefined; now the position defaults apply if the relevant position options are undefined.

TODO Change to maybeOptionalZero when **x** is strictly null?
Fix a bug when filtering facets and computing facet anchors with non-primitive facet domains, such as dates. Fix *z*-order across facets: each mark now draws atop all earlier marks across facets. Fix *z*-order of facet axes, which should be drawn below rather than above other marks, as other axes do.

The plot context now exposes the ownerSVGElement.
Fix the auto mark to chose the rect mark instead of rectX or rectY when appropriate, and likewise choose correctly between line, lineX, and lineY, and areaX and areaY. Also, the autoSpec method now returns the name of the explicit mark and transform implementations as **markImpl** and **transformImpl** respectively, along with the **markOptions** and **transformOptions** needed to instantiate them.

The text mark now positions multi-line text using the *dy* attribute instead of the *y* attribute.
<!-- The text mark now positions multi-line text using the *dy* attribute instead of the *y* attribute. -->

When faceting, the plot dimensions now includes **facet**.**width** and **facet**.**height** for the plot’s outer dimensions.
<!-- The new **render** transform mark option. -->

Derived channels can now declare **source** and **hint** options which are used by the tip mark.
<!-- Derived channels can now declare **source** and **hint** options which are used by the tip mark. -->

## 0.6.6

Expand Down
2 changes: 1 addition & 1 deletion docs/features/marks.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ All marks support the following style options:

If the **clip** option is *frame* (or equivalently true), the mark is clipped to the frame’s dimensions; if the **clip** option is null (or equivalently false), the mark is not clipped. If the **clip** option is *sphere*, then a [geographic projection](./projections.md) is required and the mark will be clipped to the projected sphere (_e.g._, the front hemisphere when using the orthographic projection).

If the **tip** option is true, a [tip mark](../marks/tip.md) with the [pointer transform](../interactions/pointer.md) will be derived from this mark and placed atop all other marks, offering details on demand. If the **tip** option is set to *x*, *y*, or *xy*, [pointerX](../interactions/pointer.md#pointerx-options), [pointerY](../interactions/pointer.md#pointery-options), or [pointer](../interactions/pointer.md#pointer-options) will be used, respectively; otherwise the pointing mode will be chosen automatically.
If the **tip** option is true, a [tip mark](../marks/tip.md) with the [pointer transform](../interactions/pointer.md) will be derived from this mark and placed atop all other marks, offering details on demand. If the **tip** option is set to *x*, *y*, or *xy*, [pointerX](../interactions/pointer.md#pointerx-options), [pointerY](../interactions/pointer.md#pointery-options), or [pointer](../interactions/pointer.md#pointer-options) will be used, respectively; otherwise the pointing mode will be chosen automatically. (If the **tip** mark option is truthy, the **title** channel is no longer applied using an SVG title element as this would conflict with the tip mark.)

For all marks except [text](../marks/text.md), the **dx** and **dy** options are rendered as a transform property, possibly including a 0.5px offset on low-density screens.

Expand Down
4 changes: 2 additions & 2 deletions docs/marks/tip.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ onMounted(() => {

# Tip mark

The **tip mark** displays text, or several name-value pairs, in a floating box anchored for a given position in **x** and **y**. The tip mark is often paired with the [pointer transform](../interactions/pointer.md) to reveal details on demand when hovering over a chart, as in this line chart of Apple stock price:
The **tip mark** displays text, or several name-value pairs, in a floating box anchored to a given position in **x** and **y**. The tip mark is often paired with the [pointer transform](../interactions/pointer.md) to reveal details on demand when hovering over a chart, as in this line chart of Apple stock price:

:::plot defer
```js
Expand Down Expand Up @@ -103,7 +103,7 @@ Plot.rectY(olympians, Plot.binX({y: "sum"}, {x: "weight", y: (d) => d.sex === "m
```
:::

The tip mark does not provide options for formatting channel names or values. When a channel is bound to a scale, the scale’s label is shown instead of the channel name. If you are interested in this feature, please upvote [#1612](https://github.com/observablehq/plot/issues/1612).
The tip mark does not provide options for formatting channel names or values. When a channel is bound to a scale, the scale’s label is shown instead of the channel name. If you desire greater customization, please upvote [#1612](https://github.com/observablehq/plot/issues/1612).

The tip mark supports nine different orientations specified by the **anchor** option: the four sides (*top*, *right*, *bottom*, *left*), the four corners (*top-left*, *top-right*, *bottom-right*, *bottom-left*), and *middle*. Note that when *middle* is used, the tip will obscure its anchor point.

Expand Down
Binary file added img/bar-sort.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cell-categorical.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/group-interval.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/pointer-text.webp
Binary file not shown.
Binary file added img/tip-line.webp
Binary file not shown.
Binary file modified img/tip-title.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/interactions/pointer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export interface PointerOptions {
/**
* The maximum radius in pixels to determine whether to render the closest
* point; if no point is within this radius to the pointer, nothing will be
* rendered. Defaults to 40 pixels. (For pointerX and pointerY, this refers to
* scaled distance; the actual distance may be 10× this amount.)
* rendered. Defaults to 40 pixels. On pointerX and pointerY, only the *x* and
* *y* distance is considered, respectively.
*/
maxRadius?: number;

Expand Down
4 changes: 2 additions & 2 deletions src/interactions/pointer.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ export function pointer(options) {
}

export function pointerX(options) {
return pointerK(10, 0.1, options);
return pointerK(1, 0.01, options);
}

export function pointerY(options) {
return pointerK(0.1, 10, options);
return pointerK(0.01, 1, options);
}

export function anchorX({x1: X1, x2: X2, x: X = X1}, cx) {
Expand Down
Loading

0 comments on commit 8d705b9

Please sign in to comment.