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))