Gotcha. No need to create new data sources, you just have to filter the values. One issue - you will get a warning: “CDSView filters are not compatible with glyphs with connected topology such as Line or Patch”. But in your case, you can just ignore it.
from pandas import *
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import LinearColorMapper, CustomJS, Slider, ColumnDataSource, CDSView, GroupFilter
from bokeh.palettes import Viridis256
from bokeh.plotting import figure
df = DataFrame({'attribute': ['Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z']
, 'period': [100, 200, 300, 400, 100, 200, 300, 400]
, '1': [1, 37, 44, 13, 41, 51, 18, 14]
, '2': [10, 3, 44, 53, 20, 9, 18, 14]
, '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()
selectable_columns = ['1', '2', '3']
source = ColumnDataSource(df)
active = 1
values_select = Slider(title="Values", start=1, end=3, step=1, value=active)
color_mapper = LinearColorMapper(palette=Viridis256, low=df[str(active)].min(), high=df[str(active)].max())
heatmap_fig = figure(x_range=periods, y_range=attributes)
heatmap_renderer = heatmap_fig.rect(x="period", y="attribute", width=1, height=1, line_color=None, source=source,
name=str(active),
fill_color={'field': str(active), 'transform': color_mapper})
line_fig = figure()
line_renderers = []
for a in attributes:
r = line_fig.line(x='period'
, y=str(active)
, legend_label=str(a)
, view=CDSView(source=source,
filters=[GroupFilter(column_name='attribute',
group=a)])
, source=source)
line_renderers.append(r)
values_select.js_on_change('value',
CustomJS(args=dict(heatmap_renderer=heatmap_renderer,
line_renderers=line_renderers,
heatmap_fig=heatmap_fig, line_fig=line_fig), code="""\
const active = cb_obj.value.toString();
const data = heatmap_renderer.data_source.data[active];
heatmap_renderer.name = active;
const {transform} = heatmap_renderer.glyph.fill_color;
heatmap_renderer.glyph.fill_color = {field: cb_obj.value, transform: transform};
heatmap_fig.reset.emit();
for (const lr of line_renderers) {
lr.glyph.y = {field: active};
}
line_fig.reset.emit();
"""))
show(column(values_select, heatmap_fig, line_fig))