Repository navigation
[BUG]: deserialization of xrange of box select in figure with multiple subplots broken #5703
Copy link
Copy link
Open
Labels
Description
Activity
Let me know if this is actually a solara bug.
@flpi-sun would you be able to investigate if this a bug related to solara?
It seems to be related to solara, because I can't replicate the bug using dash.
I couldn't replicate the bug using dash so I at first thought its a solara issue but its actually inside Plotly widgetbundle.js.Here's the dash example anyway (where the bug does not occur):
import json from collections.abc import Mapping, Sequence import plotly.graph_objects as go from dash import Dash, Input, Output, dcc, html from plotly.subplots import make_subplots def build_figure() -> go.Figure: fig = make_subplots(rows=1, cols=2, subplot_titles=("Scatter", "Bar")) fig.add_trace( go.Scatter( x=[1, 2, 3, 4, 5, 6], y=[2, 1, 3, 5, 4, 6], mode="markers", name="Series A", ), row=1, col=1, ) fig.add_trace(go.Bar(x=["A", "B", "C"], y=[3, 1, 2], name="Series B"), row=1, col=2) fig.update_layout(dragmode="select") return fig app = Dash(__name__) app.layout = html.Div( [ dcc.Graph(id="selection-graph", figure=build_figure()), html.Pre(id="selection-debug", style={"whiteSpace": "pre-wrap"}), ] ) @app.callback(Output("selection-debug", "children"), Input("selection-graph", "selectedData")) def on_selection(selected_data): return "selectedData:\n\n" + json.dumps(selected_data, indent=2) if __name__ == "__main__": app.run(debug=True)

Here's my proposed patch that I verified using the first example above.
Index: js/src/widget.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/src/widget.ts b/js/src/widget.ts --- a/js/src/widget.ts (revision a5974ced8c177bb23bd51d65a5461aa7562c9f82) +++ b/js/src/widget.ts (revision 9721bf3db12464f43f14e633344e21b800d0bdd9) @@ -109,9 +109,7 @@ type Selector = { type: "box" | "lasso"; - selector_state: - | { xrange: number[]; yrange: number[] } - | { xs: number[]; ys: number[] }; + selector_state: Record<string, any>; }; // Model @@ -1149,22 +1147,30 @@ var selectorObject: Selector; if (data.hasOwnProperty("range")) { - // Box selection + // Box selection - preserve all subplot-specific axis keys (x, x2, x3, ... and y, y2, y3, ...) + var rangeData = data["range"]; + // Verify we have at least an x and y range (in any subplot) + var hasXRange = Object.keys(rangeData || {}).some((key: string) => /^x\d*$/.test(key)); + var hasYRange = Object.keys(rangeData || {}).some((key: string) => /^y\d*$/.test(key)); + if (!hasXRange || !hasYRange) { + return null; + } selectorObject = { type: "box", - selector_state: { - xrange: data["range"]["x"], - yrange: data["range"]["y"], - }, + selector_state: rangeData, }; } else if (data.hasOwnProperty("lassoPoints")) { - // Lasso selection + // Lasso selection - preserve all subplot-specific axis keys + var lassoData = data["lassoPoints"]; + // Verify we have at least an x and y coordinate array (in any subplot) + var hasXCoords = Object.keys(lassoData || {}).some((key: string) => /^x\d*$/.test(key)); + var hasYCoords = Object.keys(lassoData || {}).some((key: string) => /^y\d*$/.test(key)); + if (!hasXCoords || !hasYCoords) { + return null; + } selectorObject = { type: "lasso", - selector_state: { - xs: data["lassoPoints"]["x"], - ys: data["lassoPoints"]["y"], - }, + selector_state: lassoData, }; } else { selectorObject = null;
It passes all xNrange, yNrange attributes which solves the issue described above.
@camdecoster Please let me know if it is worth pursuing this idea then I can create a fork and PR.
@camdecoster heres the corresponding PR #5710Reacted by Robert Claus- added a commit that references this issue
on Sep 3, 2026
Description
When you do a box (or lasso) select in a figure with multiple subplots (not the first subplot) the selection x/yrange is not a list/dict but a plain python object.
The gif above was created with this example:
Steps to reproduce