From ee6982e19163b172232a486f2267253691fed1f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sun, 12 Nov 2023 16:06:02 +0100 Subject: [PATCH 1/7] differenceX --- docs/marks/difference.md | 10 +++- src/index.js | 2 +- src/marks/difference.d.ts | 50 +++++++++++++++++- src/marks/difference.js | 46 ++++++++++------ test/output/differenceX.svg | 102 ++++++++++++++++++++++++++++++++++++ test/plots/difference.ts | 8 +++ 6 files changed, 199 insertions(+), 19 deletions(-) create mode 100644 test/output/differenceX.svg diff --git a/docs/marks/difference.md b/docs/marks/difference.md index 9480ef259b..4149c942de 100644 --- a/docs/marks/difference.md +++ b/docs/marks/difference.md @@ -142,4 +142,12 @@ These options are passed to the underlying area and line marks; in particular, w Plot.differenceY(gistemp, {x: "Date", y: "Anomaly"}) ``` -Returns a new difference with the given *data* and *options*. The mark is a composite of a positive area, negative area, and line. The positive area extends from the bottom of the frame to the line, and is clipped by the area extending from the comparison to the top of the frame. The negative area conversely extends from the top of the frame to the line, and is clipped by the area extending from the comparison to the bottom of the frame. +Returns a new vertical difference with the given *data* and *options*. The mark is a composite of a positive area, negative area, and line. The positive area extends from the bottom of the frame to the line, and is clipped by the area extending from the comparison to the top of the frame. The negative area conversely extends from the top of the frame to the line, and is clipped by the area extending from the comparison to the bottom of the frame. + +## differenceX(*data*, *options*) {#differenceY} + +```js +Plot.differenceX(gistemp, {y: "Date", x: "Anomaly"}) +``` + +Returns a new horizontal difference with the given *data* and *options*. diff --git a/src/index.js b/src/index.js index 9fde7ce2d5..1d6b205762 100644 --- a/src/index.js +++ b/src/index.js @@ -12,7 +12,7 @@ export {Contour, contour} from "./marks/contour.js"; export {crosshair, crosshairX, crosshairY} from "./marks/crosshair.js"; export {delaunayLink, delaunayMesh, hull, voronoi, voronoiMesh} from "./marks/delaunay.js"; export {Density, density} from "./marks/density.js"; -export {differenceY} from "./marks/difference.js"; +export {differenceX, differenceY} from "./marks/difference.js"; export {Dot, dot, dotX, dotY, circle, hexagon} from "./marks/dot.js"; export {Frame, frame} from "./marks/frame.js"; export {Geo, geo, sphere, graticule} from "./marks/geo.js"; diff --git a/src/marks/difference.d.ts b/src/marks/difference.d.ts index 3e4b634cbb..b01eb2cfbf 100644 --- a/src/marks/difference.d.ts +++ b/src/marks/difference.d.ts @@ -3,7 +3,7 @@ import type {CurveOptions} from "../curve.js"; import type {Data, MarkOptions, RenderableMark} from "../mark.js"; /** Options for the difference mark. */ -export interface DifferenceOptions extends MarkOptions, CurveOptions { +export interface DifferenceYOptions extends MarkOptions, CurveOptions { /** * The comparison horizontal position channel, typically bound to the *x* * scale; if not specified, **x** is used. @@ -69,6 +69,52 @@ export interface DifferenceOptions extends MarkOptions, CurveOptions { z?: ChannelValue; } +export interface DifferenceXOptions extends DifferenceYOptions { + /** + * The comparison vertical position channel, typically bound to the *y* + * scale; if not specified, **y** is used. + */ + y1?: ChannelValueSpec; + + /** + * The primary vertical position channel, typically bound to the *y* scale; + * if not specified, **y1** is used. + */ + y2?: ChannelValueSpec; + + /** The vertical position channel, typically bound to the *y* scale. */ + y?: ChannelValueSpec; + + /** + * The comparison horizontal position channel, typically bound to the *x* scale; + * if not specified, **x** is used. For differenceY, defaults to zero if only + * one *x* and *y* channel is specified. + */ + x1?: ChannelValueSpec; + + /** + * The primary horizontal position channel, typically bound to the *x* scale; + * if not specified, **x1** is used. + */ + x2?: ChannelValueSpec; + + /** The horizontal position channel, typically bound to the *x* scale. */ + x?: ChannelValueSpec; +} + +/** + * Returns a new horizontal difference mark for the given the specified *data* + * and *options*. + * + * The mark is a composite of a positive area, negative area, and line. The + * positive area extends from the left of the frame to the line, and is clipped + * by the area extending from the comparison to the right of the frame. The + * negative area conversely extends from the right of the frame to the line, and + * is clipped by the area extending from the comparison to the left of the + * frame. + */ +export function differenceX(data?: Data, options?: DifferenceXOptions): Difference; + /** * Returns a new vertical difference mark for the given the specified *data* and * *options*, as in a time-series chart where time goes right→ (or ←left). @@ -80,7 +126,7 @@ export interface DifferenceOptions extends MarkOptions, CurveOptions { * and is clipped by the area extending from the comparison to the bottom of the * frame. */ -export function differenceY(data?: Data, options?: DifferenceOptions): Difference; +export function differenceY(data?: Data, options?: DifferenceYOptions): Difference; /** The difference mark. */ export class Difference extends RenderableMark {} diff --git a/src/marks/difference.js b/src/marks/difference.js index 551207067c..eeba6a4cf1 100644 --- a/src/marks/difference.js +++ b/src/marks/difference.js @@ -6,15 +6,23 @@ import {getClipId} from "../style.js"; import {area} from "./area.js"; import {line} from "./line.js"; -export function differenceY( +export function differenceX(data, options) { + return differenceK("x", data, options); +} +export function differenceY(data, options) { + return differenceK("y", data, options); +} + +function differenceK( + k, data, { x1, x2, y1, y2, - x = x1 === undefined && x2 === undefined ? indexOf : undefined, - y = y1 === undefined && y2 === undefined ? identity : undefined, + x = x1 === undefined && x2 === undefined ? (k === "y" ? indexOf : identity) : undefined, + y = y1 === undefined && y2 === undefined ? (k === "x" ? indexOf : identity) : undefined, fill, // ignored positiveFill = "#3ca951", negativeFill = "#4269d0", @@ -32,8 +40,11 @@ export function differenceY( ) { [x1, x2] = memoTuple(x, x1, x2); [y1, y2] = memoTuple(y, y1, y2); - if (x1 === x2 && y1 === y2) y1 = memo(0); - ({tip} = withTip({tip}, "x")); + if (x1 === x2 && y1 === y2) { + if (k === "y") y1 = memo(0); + else x1 = memo(0); + } + ({tip} = withTip({tip}, k === "y" ? "x" : "y")); return marks( !isNoneish(positiveFill) ? Object.assign( @@ -45,7 +56,7 @@ export function differenceY( z, fill: positiveFill, fillOpacity: positiveFillOpacity, - render: composeRender(render, clipDifferenceY(true)), + render: composeRender(render, clipDifference(k, true)), clip, ...options }), @@ -62,7 +73,7 @@ export function differenceY( z, fill: negativeFill, fillOpacity: negativeFillOpacity, - render: composeRender(render, clipDifferenceY(false)), + render: composeRender(render, clipDifference(k, false)), clip, ...options }), @@ -110,15 +121,20 @@ function memo(v) { return {transform: (data) => V || (V = valueof(data, value)), label}; } -function clipDifferenceY(positive) { +function clipDifference(k, positive) { + const f = k === "x" ? "y" : "x"; // f is the flipped dimension + const f1 = `${f}1`; + const f2 = `${f}2`; + const k1 = `${k}1`; + const k2 = `${k}2`; return (index, scales, channels, dimensions, context, next) => { - const {x1, x2} = channels; - const {height} = dimensions; - const y1 = new Float32Array(x1.length); - const y2 = new Float32Array(x2.length); - (positive === inferScaleOrder(scales.y) < 0 ? y1 : y2).fill(height); - const oc = next(index, scales, {...channels, x2: x1, y2}, dimensions, context); - const og = next(index, scales, {...channels, x1: x2, y1}, dimensions, context); + const {[f1]: F1, [f2]: F2} = channels; + const K1 = new Float32Array(F1.length); + const K2 = new Float32Array(F2.length); + const m = dimensions[k === "y" ? "height" : "width"]; + (positive === inferScaleOrder(scales[k]) < 0 ? K1 : K2).fill(m); + const oc = next(index, scales, {...channels, [f2]: F1, [k2]: K2}, dimensions, context); + const og = next(index, scales, {...channels, [f1]: F2, [k1]: K1}, dimensions, context); const c = oc.querySelector("g") ?? oc; // applyClip const g = og.querySelector("g") ?? og; // applyClip for (let i = 0; c.firstChild; i += 2) { diff --git a/test/output/differenceX.svg b/test/output/differenceX.svg new file mode 100644 index 0000000000..5aab5cc941 --- /dev/null +++ b/test/output/differenceX.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 95 + 90 + 85 + 80 + 75 + 70 + 65 + 60 + 55 + 50 + 45 + 40 + 35 + 30 + 25 + 20 + 15 + 10 + 5 + 0 + + + + + + + + + + + + + + −10 + −8 + −6 + −4 + −2 + 0 + 2 + 4 + 6 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/plots/difference.ts b/test/plots/difference.ts index 5ee4ea3690..b2e4df40ba 100644 --- a/test/plots/difference.ts +++ b/test/plots/difference.ts @@ -189,3 +189,11 @@ export async function differenceFilterY2() { const y2 = aapl.map((d, i, data) => d.Close / data[0].Close); return Plot.differenceY(aapl, {x, y1, y2}).plot(); } + +export async function differenceX() { + const random = d3.randomNormal.source(d3.randomLcg(22))(); + return Plot.differenceX({length: 100}, Plot.mapX("cumsum", {x1: random, x2: random, curve: "basis"})).plot({ + height: 600, + y: {reverse: true} + }); +} From 6ee2806c16e601dd281aa1838d6de258eab1b4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sun, 12 Nov 2023 16:10:47 +0100 Subject: [PATCH 2/7] shiftY --- docs/transforms/shift.md | 10 + src/index.js | 2 +- src/transforms/shift.d.ts | 7 + src/transforms/shift.js | 4 + test/output/shiftY.svg | 1341 +++++++++++++++++++++++++++++++++++++ test/plots/shift.ts | 5 + 6 files changed, 1368 insertions(+), 1 deletion(-) create mode 100644 test/output/shiftY.svg diff --git a/docs/transforms/shift.md b/docs/transforms/shift.md index 8ab45d3a73..7e71713658 100644 --- a/docs/transforms/shift.md +++ b/docs/transforms/shift.md @@ -46,3 +46,13 @@ Plot.shiftX("7 days", {x: "Date", y: "Close"}) Derives an **x1** channel from the input **x** channel by shifting values by the given *interval*. The *interval* may be specified as: a name (*second*, *minute*, *hour*, *day*, *week*, *month*, *quarter*, *half*, *year*, *monday*, *tuesday*, *wednesday*, *thursday*, *friday*, *saturday*, *sunday*) with an optional number and sign (*e.g.*, *+3 days* or *-1 year*); or as a number; or as an implementation — such as d3.utcMonth — with *interval*.floor(*value*), *interval*.offset(*value*), and *interval*.range(*start*, *stop*) methods. The shiftX also transform aliases the **x** channel to **x2** and applies a domain hint to the **x2** channel such that by default the plot shows only the intersection of **x1** and **x2**. For example, if the interval is *+1 year*, the first year of the data is not shown. + +## shiftY(*interval*, *options*) {#shiftY} + +```js +Plot.shiftY("7 days", {y: "Date", x: "Close"}) +``` + +Derives a **y1** channel from the input **y** channel by shifting values by the given *interval*. (See shiftX above for details.) + +The shiftY also transform aliases the **y** channel to **y2** and applies a domain hint to the **y2** channel such that by default the plot shows only the intersection of **y1** and **y2**. For example, if the interval is *+1 year*, the first year of the data is not shown. diff --git a/src/index.js b/src/index.js index 1d6b205762..470bc7b321 100644 --- a/src/index.js +++ b/src/index.js @@ -39,7 +39,7 @@ export {find, group, groupX, groupY, groupZ} from "./transforms/group.js"; export {hexbin} from "./transforms/hexbin.js"; export {normalize, normalizeX, normalizeY} from "./transforms/normalize.js"; export {map, mapX, mapY} from "./transforms/map.js"; -export {shiftX} from "./transforms/shift.js"; +export {shiftX, shiftY} from "./transforms/shift.js"; export {window, windowX, windowY} from "./transforms/window.js"; export {select, selectFirst, selectLast, selectMaxX, selectMaxY, selectMinX, selectMinY} from "./transforms/select.js"; export {stackX, stackX1, stackX2, stackY, stackY1, stackY2} from "./transforms/stack.js"; diff --git a/src/transforms/shift.d.ts b/src/transforms/shift.d.ts index 14327aadee..82848e7967 100644 --- a/src/transforms/shift.d.ts +++ b/src/transforms/shift.d.ts @@ -7,3 +7,10 @@ import type {Transformed} from "./basic.js"; * *x* channel according to the specified *interval*. */ export function shiftX(interval: Interval, options?: T): Transformed; + +/** + * Groups data into series using the first channel of *z*, *fill*, or *stroke* + * (if any), then derives *y1* and *y2* output channels by shifting the input + * *y* channel according to the specified *interval*. + */ +export function shiftY(interval: Interval, options?: T): Transformed; diff --git a/src/transforms/shift.js b/src/transforms/shift.js index 03f1c1171e..3027542404 100644 --- a/src/transforms/shift.js +++ b/src/transforms/shift.js @@ -7,6 +7,10 @@ export function shiftX(interval, options) { return shiftK("x", interval, options); } +export function shiftY(interval, options) { + return shiftK("y", interval, options); +} + function shiftK(x, interval, options = {}) { let offset; let k = 1; diff --git a/test/output/shiftY.svg b/test/output/shiftY.svg new file mode 100644 index 0000000000..aa1ddca410 --- /dev/null +++ b/test/output/shiftY.svg @@ -0,0 +1,1341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Oct2013 + Jan2014 + Apr + Jul + Oct + Jan2015 + Apr + Jul + Oct + Jan2016 + Apr + Jul + Oct + Jan2017 + Apr + Jul + Oct + Jan2018 + Apr + + + + + + + + + + + + 60 + 80 + 100 + 120 + 140 + 160 + 180 + + + Close → + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/plots/shift.ts b/test/plots/shift.ts index 3fb1bc61cc..97d6f920bb 100644 --- a/test/plots/shift.ts +++ b/test/plots/shift.ts @@ -5,3 +5,8 @@ export async function shiftX() { const aapl = await d3.csv("data/aapl.csv", d3.autoType); return Plot.arrow(aapl, Plot.shiftX("quarter", {x: "Date", y: "Close", bend: true})).plot(); } + +export async function shiftY() { + const aapl = await d3.csv("data/aapl.csv", d3.autoType); + return Plot.arrow(aapl, Plot.shiftY("quarter", {y: "Date", x: "Close", bend: true})).plot(); +} From 8ad1faf7c475d7a8b5408983b3c8d51ffc6d5215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sun, 12 Nov 2023 16:17:08 +0100 Subject: [PATCH 3/7] anchor --- docs/marks/difference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/marks/difference.md b/docs/marks/difference.md index 4149c942de..e6ef543849 100644 --- a/docs/marks/difference.md +++ b/docs/marks/difference.md @@ -144,7 +144,7 @@ Plot.differenceY(gistemp, {x: "Date", y: "Anomaly"}) Returns a new vertical difference with the given *data* and *options*. The mark is a composite of a positive area, negative area, and line. The positive area extends from the bottom of the frame to the line, and is clipped by the area extending from the comparison to the top of the frame. The negative area conversely extends from the top of the frame to the line, and is clipped by the area extending from the comparison to the bottom of the frame. -## differenceX(*data*, *options*) {#differenceY} +## differenceX(*data*, *options*) {#differenceX} ```js Plot.differenceX(gistemp, {y: "Date", x: "Anomaly"}) From b2a096471db565a6f7599a3d0890c26799ef1c6a Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 13 Jun 2024 22:02:25 -0700 Subject: [PATCH 4/7] consolidate DifferenceOptions --- src/marks/difference.d.ts | 44 ++++++--------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/src/marks/difference.d.ts b/src/marks/difference.d.ts index b01eb2cfbf..eceda57bfd 100644 --- a/src/marks/difference.d.ts +++ b/src/marks/difference.d.ts @@ -3,10 +3,11 @@ import type {CurveOptions} from "../curve.js"; import type {Data, MarkOptions, RenderableMark} from "../mark.js"; /** Options for the difference mark. */ -export interface DifferenceYOptions extends MarkOptions, CurveOptions { +export interface DifferenceOptions extends MarkOptions, CurveOptions { /** * The comparison horizontal position channel, typically bound to the *x* - * scale; if not specified, **x** is used. + * scale; if not specified, **x** is used. For differenceX, defaults to zero + * if only one *x* and *y* channel is specified. */ x1?: ChannelValueSpec; @@ -69,42 +70,9 @@ export interface DifferenceYOptions extends MarkOptions, CurveOptions { z?: ChannelValue; } -export interface DifferenceXOptions extends DifferenceYOptions { - /** - * The comparison vertical position channel, typically bound to the *y* - * scale; if not specified, **y** is used. - */ - y1?: ChannelValueSpec; - - /** - * The primary vertical position channel, typically bound to the *y* scale; - * if not specified, **y1** is used. - */ - y2?: ChannelValueSpec; - - /** The vertical position channel, typically bound to the *y* scale. */ - y?: ChannelValueSpec; - - /** - * The comparison horizontal position channel, typically bound to the *x* scale; - * if not specified, **x** is used. For differenceY, defaults to zero if only - * one *x* and *y* channel is specified. - */ - x1?: ChannelValueSpec; - - /** - * The primary horizontal position channel, typically bound to the *x* scale; - * if not specified, **x1** is used. - */ - x2?: ChannelValueSpec; - - /** The horizontal position channel, typically bound to the *x* scale. */ - x?: ChannelValueSpec; -} - /** * Returns a new horizontal difference mark for the given the specified *data* - * and *options*. + * and *options*, as in a time-series chart where time goes down↓ (or up↑). * * The mark is a composite of a positive area, negative area, and line. The * positive area extends from the left of the frame to the line, and is clipped @@ -113,7 +81,7 @@ export interface DifferenceXOptions extends DifferenceYOptions { * is clipped by the area extending from the comparison to the left of the * frame. */ -export function differenceX(data?: Data, options?: DifferenceXOptions): Difference; +export function differenceX(data?: Data, options?: DifferenceOptions): Difference; /** * Returns a new vertical difference mark for the given the specified *data* and @@ -126,7 +94,7 @@ export function differenceX(data?: Data, options?: DifferenceXOptions): Differen * and is clipped by the area extending from the comparison to the bottom of the * frame. */ -export function differenceY(data?: Data, options?: DifferenceYOptions): Difference; +export function differenceY(data?: Data, options?: DifferenceOptions): Difference; /** The difference mark. */ export class Difference extends RenderableMark {} From 223af91e928cd7059e2d5b258341641253f7f182 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 13 Jun 2024 22:08:06 -0700 Subject: [PATCH 5/7] update docs --- docs/marks/difference.md | 4 ++-- docs/transforms/shift.md | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/marks/difference.md b/docs/marks/difference.md index 46a7a13ffd..4ebde0a96c 100644 --- a/docs/marks/difference.md +++ b/docs/marks/difference.md @@ -144,10 +144,10 @@ Plot.differenceY(gistemp, {x: "Date", y: "Anomaly"}) Returns a new vertical difference with the given *data* and *options*. The mark is a composite of a positive area, negative area, and line. The positive area extends from the bottom of the frame to the line, and is clipped by the area extending from the comparison to the top of the frame. The negative area conversely extends from the top of the frame to the line, and is clipped by the area extending from the comparison to the bottom of the frame. -## differenceX(*data*, *options*) {#differenceX} +## differenceX(*data*, *options*) {#differenceX} ```js Plot.differenceX(gistemp, {y: "Date", x: "Anomaly"}) ``` -Returns a new horizontal difference with the given *data* and *options*. +Returns a new horizontal difference with the given *data* and *options*. See [differenceY](#differenceY) for more. diff --git a/docs/transforms/shift.md b/docs/transforms/shift.md index 696dd36902..ae01113720 100644 --- a/docs/transforms/shift.md +++ b/docs/transforms/shift.md @@ -43,16 +43,16 @@ When looking at year-over-year growth, the chart is mostly green, implying that Plot.shiftX("7 days", {x: "Date", y: "Close"}) ``` -Derives an **x1** channel from the input **x** channel by shifting values by the given *interval*. The *interval* may be specified as: a name (*second*, *minute*, *hour*, *day*, *week*, *month*, *quarter*, *half*, *year*, *monday*, *tuesday*, *wednesday*, *thursday*, *friday*, *saturday*, *sunday*) with an optional number and sign (*e.g.*, *+3 days* or *-1 year*); or as a number; or as an implementation — such as d3.utcMonth — with *interval*.floor(*value*), *interval*.offset(*value*), and *interval*.range(*start*, *stop*) methods. +Derives an **x1** channel from the input **x** channel by shifting values by the given [*interval*](../features/intervals.md). The *interval* may be specified as: a name (*second*, *minute*, *hour*, *day*, *week*, *month*, *quarter*, *half*, *year*, *monday*, *tuesday*, *wednesday*, *thursday*, *friday*, *saturday*, *sunday*) with an optional number and sign (*e.g.*, *+3 days* or *-1 year*); or as a number; or as an implementation — such as d3.utcMonth — with *interval*.floor(*value*), *interval*.offset(*value*), and *interval*.range(*start*, *stop*) methods. -The shiftX also transform aliases the **x** channel to **x2** and applies a domain hint to the **x2** channel such that by default the plot shows only the intersection of **x1** and **x2**. For example, if the interval is *+1 year*, the first year of the data is not shown. +The shiftX transform also aliases the **x** channel to **x2** and applies a domain hint to the **x2** channel such that by default the plot shows only the intersection of **x1** and **x2**. For example, if the interval is *+1 year*, the first year of the data is not shown. -## shiftY(*interval*, *options*) {#shiftY} +## shiftY(*interval*, *options*) {#shiftY} ```js Plot.shiftY("7 days", {y: "Date", x: "Close"}) ``` -Derives a **y1** channel from the input **y** channel by shifting values by the given *interval*. (See shiftX above for details.) +Derives a **y1** channel from the input **y** channel by shifting values by the given [*interval*](../features/intervals.md). See [shiftX](#shiftX) for more. -The shiftY also transform aliases the **y** channel to **y2** and applies a domain hint to the **y2** channel such that by default the plot shows only the intersection of **y1** and **y2**. For example, if the interval is *+1 year*, the first year of the data is not shown. +The shiftY transform also aliases the **y** channel to **y2** and applies a domain hint to the **y2** channel such that by default the plot shows only the intersection of **y1** and **y2**. For example, if the interval is *+1 year*, the first year of the data is not shown. From 6338eeb4724c4ff2a2abc4ae33d75e01c322ee86 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 13 Jun 2024 22:08:52 -0700 Subject: [PATCH 6/7] update test snapshots --- test/output/differenceX.svg | 10 +++++----- test/output/shiftY.svg | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/output/differenceX.svg b/test/output/differenceX.svg index 5aab5cc941..a6fe21f02c 100644 --- a/test/output/differenceX.svg +++ b/test/output/differenceX.svg @@ -1,6 +1,6 @@ - + - +