Thank you @Bryan @Timo I will try to expand the information as well as to share with the community what I have found on this topic.
- My final purpose have been to build a multi line graph with interactive widgets capable to include or remove lines. Additionally my intention was to include a hover that show x and y data as well as the selected categories. On this respect I consulted several examples on this community. I started with Bokeh 2.2.3 and found that hover does not work, so I tried 2.4.3 and it worked. A finial short example is posted here, because I think could be useful for people with the same purpose.
import pandas as pd
from bokeh.layouts import row
from bokeh.models import MultiChoice, ColumnDataSource, CustomJS, CDSView, HoverTool, CustomJSFilter, MultiSelect
from bokeh.plotting import figure, show
from bokeh.palettes import Category20
df_ini = pd.DataFrame(data={'ILLUMINANT': {0: '01_CFL', 1: '01_CFL', 2: '03_D65', 3: '03_D65', 4: '01_CFL', 5: '01_CFL', 6: '03_D65', 7: '03_D65', 8: '01_CFL', 9: '01_CFL', 10: '03_D65', 11: '03_D65', 12: '01_CFL', 13: '01_CFL', 14: '03_D65', 15: '03_D65', 16: '01_CFL', 17: '01_CFL', 18: '03_D65', 19: '03_D65'},
'MONITOR': {0: '01_WPC', 1: '04_DWPC', 2: '01_WPC', 3: '04_DWPC', 4: '01_WPC', 5: '04_DWPC', 6: '01_WPC', 7: '04_DWPC', 8: '01_WPC', 9: '04_DWPC', 10: '01_WPC', 11: '04_DWPC', 12: '01_WPC', 13: '04_DWPC', 14: '01_WPC', 15: '04_DWPC', 16: '01_WPC', 17: '04_DWPC', 18: '01_WPC', 19: '04_DWPC'},
'WAVELENGTH': {0: 400, 1: 400, 2: 400, 3: 400, 4: 410, 5: 410, 6: 410, 7: 410, 8: 420, 9: 420, 10: 420, 11: 420, 12: 430, 13: 430, 14: 430, 15: 430, 16: 440, 17: 440, 18: 440, 19: 440},
'SRF': {0: 11.4083333, 1: 18.268, 2: 10.087, 3: 17.2156667, 4: 16.6256667, 5: 25.0633333, 6: 20.1476667, 7: 27.872, 8: 36.044000000000004, 9: 39.304, 10: 48.1666667, 11: 48.97, 12: 55.265666700000004, 13: 49.8693333, 14: 79.611, 15: 67.3716667, 16: 59.5793333, 17: 51.5753333, 18: 86.417, 19: 69.7326667}})
df_ini.reset_index(inplace=True)
df_ini['ALL_CATERGORIES'] = '-0-' + df_ini['ILLUMINANT'] + '-1-' + df_ini['MONITOR']
ALL_CATEGORIES_group = df_ini.ALL_CATERGORIES.unique()
df = pd.DataFrame()
df['all_categories'] = ALL_CATEGORIES_group
df['xs'] = [df_ini.loc[df_ini.ALL_CATERGORIES == i].WAVELENGTH for i in ALL_CATEGORIES_group]
df['ys'] = [df_ini.loc[df_ini.ALL_CATERGORIES == i].SRF for i in ALL_CATEGORIES_group]
df['color'] = (Category20[len(ALL_CATEGORIES_group)])[0:len(ALL_CATEGORIES_group)]
df['illuminant'] = df['all_categories'].str.extract('-0-(\w+)')
df['monitor'] = df['all_categories'].str.extract('-1-(\w+)')
df = df.astype('object')
source_01 = ColumnDataSource(data=df)
ILLUMINANTS_initial = 1
MONITOR_initial = 1
ILLUMINANTS_group = df['illuminant'].unique()
MONITOR_group = df.monitor.unique().tolist()
ILLUMINANT_select = MultiChoice(value=list(ILLUMINANTS_group[:ILLUMINANTS_initial]), options=list(ILLUMINANTS_group), title="Illuminants", width=200, placeholder='Please select one item')
MONITOR_select = MultiChoice(value=list(MONITOR_group[:MONITOR_initial]), options=list(MONITOR_group), title="Monitors")
illumi_filter = CustomJSFilter(args=dict(illumi_choice=ILLUMINANT_select), code="""
const indices = []
for (var i = 0; i < source.get_length(); i++) {
if (illumi_choice.value.includes(source.data['illuminant'][i], 0)) {
indices.push(i)
}
}
return indices
""")
monit_filter = CustomJSFilter(args=dict(monit_choice=MONITOR_select), code="""
const indices = []
for (var i = 0; i < source.get_length(); i++) {
indices.push(monit_choice.value.includes(source.data['monitor'][i], 0))
}
return indices
""")
view = CDSView(source=source_01,filters=[illumi_filter, monit_filter])
ILLUMINANT_update = CustomJS(args=dict(cb=ILLUMINANT_select,source=source_01,filt=illumi_filter)
,code='''
var active_lbls = cb.value
var new_filt = []
for (var i=0;i<source.data['illuminant'].length;i++){
if (active_lbls.includes(source.data['illuminant'][i])){
new_filt.push(i)
}
}
filt.indices = new_filt
source.change.emit()
'''
)
MONITOR_update = CustomJS(args=dict(cb=MONITOR_select,source=source_01,filt=monit_filter)
,code='''
var active_lbls = cb.value
var new_filt = []
for (var i=0;i<source.data['monitor'].length;i++){
if (active_lbls.includes(source.data['monitor'][i])){
new_filt.push(i)
}
}
filt.indices = new_filt
source.change.emit()
'''
)
ILLUMINANT_select.js_on_change('value', ILLUMINANT_update)
MONITOR_select.js_on_change('value', MONITOR_update)
p = figure(x_range=(395, 445), y_range=(0, 170))
hover_lines = HoverTool(
show_arrow=False,
line_policy='next',
tooltips=[
('Illuminant', '@illuminant'),
('Monitor', '@monitor'),
('SRF', '$y'),
('Wavelength', '$x')
]
)
p.add_tools(hover_lines)
p.multi_line("xs", "ys", line_width=2, source=source_01, view=view, line_color='color')
show(row([p, ILLUMINANT_select, MONITOR_select]))
- When I implemented a similar code as part of a Phyton-Flask web app, problems appeared. The initial post of this series recorded one of them. So, I tried several options and finally, in my case all problems gone with Bokeh 2.3.3, with that version hover works fine and there is no conflicts with other components and libraries in the web app.
Thank you. Regards, Rodrgo.