If you change the dimension and open the JavaScript console, you will see there a very clear error indicating what’s wrong with your code.
With that being said, there’s a better way to do it - without shuffling the data around. You can just change the field
, transform.low
, and transform.high
:
from pandas import *
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import LinearColorMapper, Select, CustomJS
from bokeh.palettes import Viridis256
from bokeh.plotting import figure
df = DataFrame({'attribute': ['Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z']
, 'period': [1, 2, 3, 4, 1, 2, 3, 4]
, 'dimension_1': [1, 37, 44, 13, 41, 51, 18, 14]
, 'dimension_2': [10, 3, 44, 53, 20, 9, 18, 14]
, 'dimension_3': [80, 37, 22, 13, 13, 44, 18, 14]})
df['period'] = df['period'].astype(str)
periods = df.period.unique().tolist()
attributes = df.attribute.unique().tolist()
active = 'dimension_1'
values_select = Select(title="Values:", options=["dimension_1", "dimension_2", 'dimension_3'], value=active)
color_mapper = LinearColorMapper(palette=Viridis256, low=df[active].min(), high=df[active].max())
p = figure(x_range=periods, y_range=attributes)
renderer = p.rect(x="period", y="attribute", width=1, height=1, line_color=None, source=df,
fill_color={'field': 'dimension_1', 'transform': color_mapper})
values_select.js_on_change('value', CustomJS(args=dict(renderer=renderer, p=p), code="""\
const active = cb_obj.value;
const data = renderer.data_source.data[active];
const {transform} = renderer.glyph.fill_color;
transform.low = Math.min(...data);
transform.high = Math.max(...data);
renderer.glyph.fill_color = {field: cb_obj.value, transform: transform};
p.reset.emit()
"""))
show(column([values_select, p]))