Change ColumnDataSource columns and get '...nonexistent field...'

Thank you! I follow your advice and add some other code to avoid the legend of the whole columns taking too much space by refering(Updating legend label using callback - #4 by p-himik). Now it’s great!

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from bokeh.layouts import column, row, layout
from bokeh.plotting import curdoc, figure
from bokeh.models import ColumnDataSource, Select, Legend, LegendItem



def load_source():
    data = {
        'time': pd.date_range('2021-10-1T00', periods=10, freq='D'),
        'asdsxasd': np.linspace(0, 10, 10),
        'basyda': np.linspace(10, 20, 10),
        'casxda': np.linspace(20, 30, 10),
        'dsyfsf': np.linspace(30, 40, 10)
    }
    df = pd.DataFrame(data)
    df.set_index('time', drop=True, inplace=True)
    return ColumnDataSource(data=df), df

def gen_colors(n):
    color_arr = plt.cm.Set3(np.linspace(0, 1, n)).tolist()
    for i in color_arr:
        i[0] = int(i[0]*255)
        i[1] = int(i[1]*255)
        i[2] = int(i[2]*255)
        i[3] = float(i[3]*1.0)
        i = tuple(i)
    return color_arr

def make_plot(source, title):
    p1 = figure(width=1000, height=600, title=title, x_axis_type='datetime') 
    color_list = gen_colors(len(source.column_names))
    leg_list = []
    for i, col in enumerate(source.column_names):
        if col != 'time':
            temp_name = p1.line(
                x='time', y=col, source=source, line_width=2,
                color=color_list[i], visible=False, name=col
            )
            leg_list.append(LegendItem(label=col, renderers=[temp_name]))
    return p1, leg_list
    

init_col = 'origin'

col_select = Select(title='type', value=init_col, width=200, 
    options=['origin', 'x', 'y'])

source, df = load_source()
plot, legend_list = make_plot(source, init_col)

legend = Legend(items=legend_list)

def update_plot(attr, old, new):
    col = col_select.value
    plot.title.text = col
    leg_list = []
    for i in df.columns:
        if col in i:
            plot.select_one(i).visible = True
            leg_list.append(LegendItem(label=i, renderers=[plot.select_one(i)]))
        else:
            plot.select_one(i).visible = False

    legend.items = leg_list
col_select.on_change('value', update_plot)


plot.add_layout(legend)
curdoc().add_root(row(plot, col_select))
1 Like