I have a Parameterized class which is going to create an interactive Bokeh contour plot, using image()
function. A colorbar is associated to the contour data, using a LinearColorMapper
. This is a sample of the code to create the plot:
# these are 2D numpy arrays. `s` is a custom object
x, y, z = s.get_data()
x, y, zz = [t.flatten() for t in [x, y, z]]
minx, miny, minz = min(x), min(y), min(zz)
maxx, maxy, maxz = max(x), max(y), max(zz)
fig.image(image=[z], x=minx, y=miny,
dw=abs(maxx - minx), dh=abs(maxy - miny),
palette=colormap)
colormapper = LinearColorMapper(palette=colormap, low=minz, high=maxz)
colorbar = ColorBar(color_mapper=colormapper, title="test")
fig.add_layout(colorbar, 'right')
The following is a sample of the code to update the data:
x, y, z = s.get_data()
fig.renderers[0].data_source.data.update({"image": [z]})
zz = z.flatten()
colorbar.color_mapper.update(low = min(zz), high=max(zz))
At this point:
- the contour plot gets updated correctly.
- the values of the color mapper gets updated correctly. If I print them on the screen, I see the updated values.
- the colorbar doesn’t update. It’s like its not being rendered with the new values.
What can I do to fix the problem?
I’m going to post a ful basic example illustrating the problem. Run this in Jupyter Notebook.
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import LinearColorMapper, ColorBar
from bokeh.layouts import column, row
from bokeh.io import curdoc
import numpy as np
output_notebook(hide_banner=True)
def test(doc):
x = y = np.linspace(-5, 5, 200)
xx, yy = np.meshgrid(x, y)
f = lambda a, x, y: a * np.cos(a * x**2 + y**2)
z = f(2, xx, yy)
minx, miny, minz = min(x), min(y), np.amin(z)
maxx, maxy, maxz = max(x), max(y), np.amax(z)
fig = figure(plot_width=600, plot_height=400)
fig.image(image=[z], x=minx, y=miny,
dw=abs(maxx - minx), dh=abs(maxy - miny),
palette="Viridis256")
color_mapper = LinearColorMapper(palette="Viridis256", low=minz, high=maxz)
colorbar = ColorBar(color_mapper=color_mapper)
fig.add_layout(colorbar, 'right')
def update_data(attrname, old, new):
z = f(freq.value, xx, yy)
fig.renderers[0].data_source.data.update({"image": [z]})
colorbar.color_mapper.update(low = np.amin(z), high = np.amax(z))
print(colorbar.color_mapper.low, colorbar.color_mapper.high)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1, step=0.1)
freq.on_change('value', update_data)
doc.add_root(column(freq, fig))
show(test)