Colorbar not updating range

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)