From aa1f85f5aec2b0c6164c7a6ea3dbc7516d3c50da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sat, 27 May 2023 16:39:54 +0200 Subject: [PATCH 1/2] avoid double application of a scale transform when using a derived mark (such as a tip) --- src/plot.js | 7 +++- test/output/tipTransform.html | 75 +++++++++++++++++++++++++++++++++++ test/plots/tip.ts | 8 ++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 test/output/tipTransform.html diff --git a/src/plot.js b/src/plot.js index bf9b5020ed..9f5db52b6f 100644 --- a/src/plot.js +++ b/src/plot.js @@ -388,14 +388,17 @@ function applyScaleTransforms(channels, options) { // Note: mutates channel.value to apply the scale transform, if any. function applyScaleTransform(channel, options) { const {scale} = channel; - if (scale == null) return; + if (scale == null || channel.transformed) return; const { type, percent, interval, transform = percent ? (x) => x * 100 : maybeIntervalTransform(interval, type) } = options[scale] ?? {}; - if (transform != null) channel.value = map(channel.value, transform); + if (transform != null) { + channel.value = map(channel.value, transform); + channel.transformed = true; + } } // An initializer may generate channels without knowing how the downstream mark diff --git a/test/output/tipTransform.html b/test/output/tipTransform.html new file mode 100644 index 0000000000..f3e1362aec --- /dev/null +++ b/test/output/tipTransform.html @@ -0,0 +1,75 @@ +
+ + + + + + 0 + + + + 20 + + + + 40 + + + + 60 + + + + 80 + + + + 100 + + + + + + + + + + + 0.0 + 0.5 + 1.0 + + + + + + + + +
\ No newline at end of file diff --git a/test/plots/tip.ts b/test/plots/tip.ts index 417a740df8..3e645005af 100644 --- a/test/plots/tip.ts +++ b/test/plots/tip.ts @@ -194,3 +194,11 @@ export async function tipRuleAnchored() { ] }); } + +export async function tipTransform() { + return Plot.plot({ + width: 245, + color: {percent: true, legend: true}, + marks: [Plot.dotX([0, 0.1, 0.3, 1], {fill: Plot.identity, r: 10, frameAnchor: "middle", tip: true})] + }); +} From 987008522298b545532c6477f3abf00e93d95141 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 27 May 2023 10:12:04 -0700 Subject: [PATCH 2/2] transform instead of transformed --- src/channel.d.ts | 3 +++ src/plot.js | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/channel.d.ts b/src/channel.d.ts index 5ffad5b4a7..e88bb77c2a 100644 --- a/src/channel.d.ts +++ b/src/channel.d.ts @@ -109,6 +109,9 @@ export interface Channel { */ filter?: ((value: any) => boolean) | null; + /** Whether to apply the scale’s transform, if any; defaults to true. */ + transform?: boolean; + /** * An internal hint to affect the default construction of scales. For example, * the dot mark uses a channel hint to affect the default range of the diff --git a/src/plot.js b/src/plot.js index 9f5db52b6f..f99c4afd62 100644 --- a/src/plot.js +++ b/src/plot.js @@ -385,20 +385,20 @@ function applyScaleTransforms(channels, options) { return channels; } -// Note: mutates channel.value to apply the scale transform, if any. +// Note: mutates channel.value to apply the scale transform, if any. Also sets +// channel.transform to false to prevent duplicate transform application. function applyScaleTransform(channel, options) { - const {scale} = channel; - if (scale == null || channel.transformed) return; + const {scale, transform: t = true} = channel; + if (scale == null || !t) return; const { type, percent, interval, transform = percent ? (x) => x * 100 : maybeIntervalTransform(interval, type) } = options[scale] ?? {}; - if (transform != null) { - channel.value = map(channel.value, transform); - channel.transformed = true; - } + if (transform == null) return; + channel.value = map(channel.value, transform); + channel.transform = false; } // An initializer may generate channels without knowing how the downstream mark