Providing data for a multi line from a dataframe? Having trouble figuring out how to restructure the dataframe / use multi_line's syntax

Alright, I’ve tried figuring out how to rebuild the data with JS from something @carolyn kindly helped me with a few months ago, and I think I’ve almost got it, but can’t quite figure out how to implement it.

In the for loop where we’re making the lines I’m unsure how to pass the source as subset_source while also keeping the data=df[df.option==cause] condition:

import pandas as pd
from bokeh.models import LinearColorMapper, ColumnDataSource, Slider, Select, CustomJSFilter, CDSView, CustomJS, GroupFilter
from bokeh.layouts import row, column, layout
from bokeh.plotting import figure, output_file, show
from bokeh.palettes import Viridis256, Category20_20

df = pd.read_excel('https://cjdixon.s3-ap-southeast-2.amazonaws.com/bokeh/heatmap_linegraph_datademo.xlsx', index_col=0)
df = df.reset_index()

df = df.rename(columns={n: str(n) for n in range(1,11)})

output_file('heatmap_linegraph.html', title='whatever', mode='inline')

df['period'] = df['period'].astype(str)
periods = df.period.unique().tolist()
causes = df.option.unique().tolist()
abilities = df.ability.unique().tolist()
df['active_column'] = df['5']

source = ColumnDataSource(data=df)

active = 5
color_mapper = LinearColorMapper(palette=Viridis256,
                                 low=0,
                                 high=0.02)

year_select = Slider(value=active, start=1, end=10, step=1)
ability_select = Select(value='noob', options=['l33t', 'noob'])

ability_filter = CustomJSFilter(args=dict(ability_select=ability_select), code='''
    var indices = []
    for (var i = 0; i < source.get_length(); i++){
        if (source.data['ability'][i] == ability_select.value){
                indices.push(true);
            } else {
                indices.push(false);
            }
        }
        return indices;
''')

subset_source = ColumnDataSource(data=source.data.copy())
fields_to_update = list(df.columns.values)
ability_callback = CustomJS(args=dict(source=source, subset_source=subset_source, ability_select=ability_select, fields_to_update=fields_to_update), code="""
    subset_source.clear();
    for (i = 0; i < source.data.x.length; i++) {
        if (source.data.ability[i] == ability_select.value) {
            for (j=0; j < fields_to_update.length; j++) {
                subset_source.data[fields_to_update[j]].push(source.data[fields_to_update[j]][i]);
            }
        }
    }'
    subset_source.change.emit();
""")

view = CDSView(source=source, filters=[ability_filter])
heatmap = figure(x_range=periods, y_range=causes,
                 x_axis_location="above", sizing_mode="stretch_both")

heatmap_renderer = heatmap.rect(x="period", y="option", width=1, height=0.95,
                                source=source, view=view,
                                fill_color={'field': str(active), 'transform': color_mapper},
                                line_color=None, name=str(active))
line_fig = figure(sizing_mode="stretch_both", y_range = (0, .03)
, x_range = (0, 60))
line_renderers = []
for cause, color in zip(causes, Category20_20):
    r = line_fig.line(x='period'
                      ,y=str(active)
                      ,color=color
                      ,line_width=3
                      ,source= ColumnDataSource(data=df[df.option==cause])
                      ,legend_label=str(cause))
    line_renderers.append(r)

ability_select.js_on_change('value', ability_callback)

year_select.js_on_change('value', CustomJS(args=dict(heatmap_renderer=heatmap_renderer, p=heatmap, year_select=year_select, source=source, ability_select=ability_select, line_fig=line_fig, line_renderers=line_renderers), code="""\
    const active = cb_obj.value;
    const data = heatmap_renderer.data_source.data[active];
    heatmap_renderer.name = String(active);
    const {transform} = heatmap_renderer.glyph.fill_color;
    heatmap_renderer.glyph.fill_color = {field: cb_obj.value, transform: transform};
    for (const lr of line_renderers) {
    lr.glyph.y = {field: active};
    }    
    source.data['active_column'] = source.data[year_select.value]
    source.change.emit()
    line_fig.reset.emit()
"""))

top_area = row(year_select, ability_select)
show(layout(column([top_area, heatmap, line_fig]), sizing_mode="stretch_both"))

Any ideas? We’re so close!