I have a plot that is connected to a CDS. When I now update the data I would like the data to be shown as if it were set from the beginning (autoscaled). However it seems like that this is very much dependent on the previous zoom state.
No zoom before data update: works as desired.
Zoom before data update: zoom is kept despite data update
Additionally I noticed that autoscaling does not seem to trigger any RangeUpdate event. Is there any option to get a callback post autoscaling?
import numpy as np
from bokeh import events
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, Button, PanTool, BoxZoomTool, ResetTool
from bokeh.plotting import figure
from bokeh.layouts import row, column
doc = curdoc()
n_samples = 100
x = np.linspace(0, 1000, n_samples)
x2 = np.linspace(0, 1500, n_samples)
y = np.random.rand(n_samples)
source = ColumnDataSource({"x": x2, "y": y})
p1 = figure(width=400, height=400)
p1.line("x", "y", source=source)
def update_data():
source.data["x"] = x
button_update_data = Button()
button_update_data.on_click(update_data)
def range_updated(event):
print(f"range start {event.x0}, range end {event.x1}")
p1.on_event(events.RangesUpdate, range_updated)
doc.add_root(column(p1, button_update_data))
it seems like that this is very much dependent on the previous zoom state.
This is working as intended and expected. Anytime the range extents are explicitly set, the new manual values take precedence over auto-ranging until a plot reset (e.g. via a ResetTool). Explicitly setting range extents can mean programmatically, e.g. by executing range.start = 10 in a callback, but also includes range values being updated as a result of panning/zooming or other UI interactions.
This precedence order has to be defined one way or the other. We judged that more users would complain if their carefully constructed new viewports were reset out from under them without asking, than the converse. Yours is the first comment I can recall about this in ~12 years so I think we made the right call. I doubt we would change it, but offering additional explicit ways to trigger plot resets, especially from Python, seems like a reasonable ask, so feel free to open a feature request.
My wording was probably not precise enough. The choice for the current behavior is probably required in 99% of the cases.
I’m mainly looking for existing options that are less clunky than using CustomJS callback on dummy divs to achieve a reasonable callback chain. Based on your answer they don’t exist yet.
Regarding the autoscaling: the RangeUpdate event will trigger when caused by reset. However it will not trigger if the autoscaling is the result of a data update.