-
More details in this notebook. Is there a good way to get the transformed data value(s) from a Plot? I want to append an element onto a chart following a click event. Because a Plot exposes the data value ( A simple click event like this works well enough: clickEvent = (plotObject, value, columns) => {
// Get the scales
const xScale = plotObject.scale("x");
const yScale = plotObject.scale("y");
// Create circle
const circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
// Position it using the scales
circle.setAttribute(
"cx",
xScale.apply(value[columns.x]) + xScale.bandwidth / 2
);
circle.setAttribute("cy", yScale.apply(value[columns.y]));
circle.setAttribute("r", 5);
circle.setAttribute("fill", "red");
// Append
plotObject.appendChild(circle);
} But for a stacked chart, the transformed values aren't exposed, so the // Renamed the `spot` function from https://observablehq.com/@enjalot/plot-spot
getTransformed = (
data = [],
{ transform, ...channels },
facets = [Uint32Array.from(data, (d, i) => i)]
) => {
if (transform !== undefined) {
({ data, facets } = transform(data, facets));
}
return {
data,
facets,
...Object.fromEntries(
Object.entries(channels).map(([name, value]) => [
name,
Plot.valueof(data, value)
])
)
};
} However, we then need to identify the hovered value in the transformed data, as the Plot's // For finding the element in the transformed data
findTransformedIndex = (value, transformedData) =>
transformedData.findIndex((d) =>
Object.keys(value).every((key) => d[key] === value[key])
) Putting that all together looks something like this: rect.addEventListener("pointerdown", (event) => {
// Explicitly transform the data
const transformed = getTransformed(
tidy,
Plot.stackY({
x: "state",
y: "population",
fill: "age"
})
);
// Find the value
const index = findTransformedIndex(chart.value, transformed.data);
const hoverValue = { ...chart.value, y: transformed.y2[index] };
// Call the custom click event handler
clickEvent(chart, hoverValue, { x: "state", y: "y" });
}); So, all of this is to say, is there a simpler/clearer/more-reliable way to retrieve the stacked values from a Plot? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
Here's what I'd try: Plot.plot({
y: { tickFormat: "s" },
marks: [
Plot.barY(tidy, {
x: "state",
y: "population",
fill: "age",
sort: { x: "y", reverse: true },
render(index, scales, values, dimensions, context, next) {
const g = next(index, scales, values, dimensions, context);
g.addEventListener("pointerdown", (event) => {
const i = event.target.__data__;
d3.select(context.ownerSVGElement)
.append("circle")
.attr("r", 5)
.attr("fill", "red")
.attr("cx", values.x[i] + scales.scales.x.bandwidth / 2)
.attr("cy", values.y2[i]);
});
return g;
}
//tip: true
})
],
width
}) |
Beta Was this translation helpful? Give feedback.
-
@Fil any chance you know why you need to click twice on a pointer-transformed element to get the event listener to fire 😅 ? https://observablehq.com/d/2b8dd9674553809d |
Beta Was this translation helpful? Give feedback.
Here's what I'd try: