In a bokeh dashboard, I am trying to programmatically change the x-axis range while changing the data source.
See the following example, in which I want two datasets (data1_0
and data1_1
) to be displayed with one x-range (x_range1
), two other datasets (data2_0
and data2_1
) with another range (x_range2
).
import bokeh.io
from bokeh.io import curdoc
import bokeh.layouts
from bokeh.plotting import figure, show
from bokeh.models import Range1d, DataRange1d, Select
# Define data:
data1_0 = {'x-values': [1, 2, 3, 4, 5],
'y-values': [1, 2, 3, 4, 5]}
data1_1 = {'x-values': [2, 3, 4],
'y-values': [2, 3, 4]}
data2_0 = {'x-values': [4, 5, 6, 7, 8],
'y-values': [1, 2, 3, 4, 5]}
data2_1 = {'x-values': [6, 7],
'y-values': [3, 4]}
# Define x ranges:
x_range1 = [0.9, 5.1]
x_range2 = [3.9, 8.1]
# Also tested with Range1d and DataRange1d:
# x_range1 = DataRange1d(start=0.9, end=5.1)
# x_range2 = DataRange1d(start=3.9, end=8.1)
# x_range1 = Range1d(start=0.9, end=5.1)
# x_range2 = Range1d(start=3.9, end=8.1)
# Set up figure:
p = figure(y_range=(0.9, 5.1))
line = p.line(source=data1_0, x='x-values', y='y-values')
print('Initial setting of x_range1...')
# p.x_range = x_range1
p.x_range.start = x_range1[0]
p.x_range.end = x_range1[1]
print('x_range1 has been set.')
# Introduce an "on_change" callback to see if a change of the x axis range takes place:
def x_range_callback(attr, old, new):
print('x_range_callback called:', p.x_range.start, ' ', p.x_range.end)
p.x_range.on_change('end', x_range_callback)
# Build a selector:
selector = Select(title='Data source', value="data1_0", options=["data1_0", "data1_1", "data2_0", "data2_1"])
# Set up the selector callback:
def select_callback(attr, old, new):
print('New data source selected, setting', new, 'as new data source.')
line.data_source.data = eval(new) # <-- Without this line, scaling works well!
if new=='data1_0' or new=='data1_1':
print('Setting range1:')
p.x_range.start = x_range1[0]
p.x_range.end = x_range1[1]
# p.x_range = x_range1
print('Finished setting range1.')
else:
print('Setting range2:')
p.x_range.start = x_range2[0]
p.x_range.end = x_range2[1]
# p.x_range = x_range2
print('Finished setting range2.')
print('select_callback() ended.')
selector.on_change('value', select_callback)
# Set up layout:
my_layout = bokeh.layouts.row(children = [p, bokeh.layouts.Spacer(width=20), selector])
curdoc().add_root(my_layout)
The initial setting of the x_range works well, but any attempt to change it to other values afterwards will be directly overrode by my initial values.
Here is the log of the print()
commands I introduced to see what happens:
Initial setting of x_range1...
x_range1 has been set.
New data source selected, setting data2_0 as new data source.
Setting range2:
x_range_callback called: 3.9 8.1 <---- This is what should be set.
Finished setting range2.
select_callback() ended.
x_range_callback called: 0.9 5.1 <---- This comes automatically and overrides the previous setting.
New data source selected, setting data2_1 as new data source.
Setting range2:
x_range_callback called: 3.9 8.1 <---- This is what should be set.
Finished setting range2.
select_callback() ended.
x_range_callback called: 0.9 5.1 <---- This comes automatically and overrides the previous setting.
A important observation is that when I comment out the line:
line.data_source.data = eval(new)
then rescaling works as expected.
Additional observations:
If I comment out the initial setting of x_range, the later settings have no effect, automatic scaling is always applied.
If after setting x_range1
I directly set x_range2
before displaying the plot, then x_range2
always comes back.
So it seems that the range applied when first displaying the plot is “burned” into the plot and cannot be changed afterwards.
Am I missing something?
What can I do to have the expected behavior?
Also, is there a possibility to programmatically set back the default automatic scaling of the x-axis if the fixing is not needed anymore?
If this is a bug, where exactly should I report it?
This topic seems to be related to following topics:
and others…
Here are the used versions:
python version: 3.11.0
bokeh version: 3.1.0
Behaves the same with:
Python 3.9.12
bokeh 2.4.2
Keywords: x_range, y_range, dashboard, scaling, scale, rescale