Repository navigation
Conversation
Since plotly#3882 the plotly_relayout handler copies user edits (zoom, pan, ...) into the figure prop. The graph then re-plots with them as figure input, so plotly.js takes them as the new starting point and drops them from its uirevision bookkeeping. The next figure that leaves them out resets the view, even with the same uirevision. Remember the value each synced layout key had before the edit, and while the figure still holds the synced value under the same uirevision, give that value to plotly.js instead, so plotly.js keeps the edit itself. Only do this for edits that plotly.js keeps under uirevision, so other edits are not undone. Fixes plotly#4093
|
|
A note on the red checks here, since none of them comes from this change:
A re-run of the first one should be enough. |
T4rk1n
left a comment
There was a problem hiding this comment.
The approach is right, and the fix holds for the case reported in #4093. I'd block on one thing: the restored layout now also goes to Plotly.animate. animate doesn't apply uirevision, so with animate=True it moves the axes back to the pre-zoom range (inline on line 229). The other inline is about matching at the top-level key. That one is a gap in the fix, not a regression from 4.4.1, so I'm fine with a follow-up if it's not cheap to do here.
| configClone.typesetMath = mathjax; | ||
|
|
||
| const layout = this.getLayout(figure?.layout, responsive); | ||
| this.restoreGuiEditOrigins(layout); |
There was a problem hiding this comment.
With animate=True this restored layout is passed to Plotly.animate as well, and plots.transition doesn't run applyUIRevisions. It just moves the axes to whatever range the layout holds. Scenario: a figure with xaxis.range=[0, 9], uirevision=True and animate=True. The user zooms, the relayout sync updates the figure prop, plot() takes the animate branch with xaxis.range=[0, 9] restored, and the zoom snaps back. On 4.4.1 that call is a no-op because it animates to the synced range. Can you restore only on the Plotly.react path and add a test with animate=True and an explicit initial range?
| keptByPlotly && | ||
| uirevision && | ||
| getUirevision(layout, key) === uirevision && | ||
| equals(layout[key], synced) |
There was a problem hiding this comment.
This compares the whole top-level key, so a Patch that touches anything else under xaxis drops the entry. Scenario: the user zooms, a callback does p.layout.xaxis.title.text = "...", then a later callback returns a new figure. On the Patch, layout.xaxis is {range: zoomed, title: ...}, which isn't equal to synced. The entry gets deleted and plotly.js takes the zoomed range as input, so the new figure resets the zoom, same as on 4.4.1. Updating an axis title or tick format with a Patch is common. Could you track the edited sub-paths (the eventKeys) and restore only those, as long as they still match the synced values?



Fixes #4093
Since #3882, the
plotly_relayouthandler copies user edits (zoom, pan, ...) into thefigureprop so that a laterPatchdoesn't revert them. That prop change makes the graph re-plot with the edits as figure input. plotly.js then treats them as the new starting point and drops them from its uirevision bookkeeping (_preGUI), so the next figure that leaves them out resets the view, even whenuirevisionhasn't changed.So with
uirevision=True, zooming and then returning a new figure from a callback loses the zoom (the report in #4093). Zooming, applying aPatch, and then returning a new figure loses it too.Fix
When a layout key is synced, remember the value it had before the edit and the uirevision at that time. When the graph plots a figure that still holds the synced value under the same uirevision, it gives plotly.js the value from before the edit instead. plotly.js then sees an unchanged input and keeps the edit itself, as it did before #3882. The
figureprop keeps the synced edits, so #3810 stays fixed.This is only done for edits that plotly.js keeps under uirevision (
layoutUIControlPatternsin plotly.jsplot_api.js: axis ranges, shapes, annotations, dragmode, map center, ...). For other edits, like an edited legend title, putting the old value back would undo the user's edit right away, so those keys keep the current behavior.Testing
test_grbs013: zoom with a real mouse drag, then return a new figure, thenPatchand return a new figure again; the zoom stays. It fails ondev(range back to autorange) and passes with the change.test_grbs014: an edit that uirevision does not track (legend title) is not undone by the sync or by a laterPatch. I checked that it fails if the "edits plotly keeps" check is removed.tests/integration/graph: 53 passed, 1 skipped, run twice. Jest in dash-core-components: 85 passed.I also ran user journeys in headless Chrome against the published 4.4.0 and 4.4.1 wheels and against this branch. All with
uirevision=Trueunless noted. Every zoom and pan is a real mouse drag:On this branch, switching to pan from the modebar and panning a
scattermap(map center) also survive a new figure and aPatchfollowed by a new figure.The added work per plot is one
equalson each key the user edited. It costs less than theclonethatgetLayoutalready does on the same layout: about 1.5 us for an axis, and about 1 ms for 1000 edited shapes.Contributor Checklist
optionals
CHANGELOG.md