it doesn’t update properly in the callback function and I have heard that I need to take everything out of the layout and refill it? how is that achieved, any hints or examples? thanks
Here is a concrete example. Once the website is created from the code, it is expected each time I enter something in the textbox and hit enter, it will create a new line and a legend corresponding to it. Specifically, the creation of the new line and the legend should be sync. However, in reality, it will always create the new line in the first callback and in the next callback it will create a second line and the legend corresponding to the first line, which is weird given the add_glyph and add_layout is altogether in the same callback function. Anyway to solve this? I really appreciate your help. [Hint: suggested input, enter “a” in the textbox and hit enter and then “b” and enter and then “c” …]
The code is here:
import numpy as np
import pandas as pd
from bokeh.models import ColumnDataSource, Select, CustomJS, TextInput, Legend, LegendItem
from bokeh.plotting import figure
from bokeh.layouts import row
from bokeh.io import curdoc,show
from bokeh.models.glyphs import Line
doc = curdoc()
table = [[1,2,3,4,1],[2,3,4,5,2],[3,4,5,6,3],[4,5,6,7,4]]
df = pd.DataFrame(table, columns=['a','b','c','d','e'])
colors = ["navy", "firebrick", "red", "darkorchid", "hotpink", "black", "pink"]
next_group = 1
source = ColumnDataSource(data = {'x':[], 'y':[]})
plot = figure(width=400, plot_height=300, title=None, tools='pan')
# plot.legend.location = "top_left"
# plot.legend.click_policy="mute"
# menu = Select(options=['ab', 'ac', 'bc','abc','abd','abcd'],
# value='ab', title='Type')
text_input = TextInput(value="ab", title="Label:")
legends = []
def update_plot(attrname, old, new):
# choice = menu.value
global next_group, legends
source1 = ColumnDataSource(data = {'x':[], 'y':[]})
choice = text_input.value
n = len(df['e'])
cl = [char for char in choice]
source1.data['x'] = df['e'].tolist() * len(cl)
source1.data['y'] = [x for e in cl for x in df[e].tolist()]
# plot.line(x='x', y= 'y', source = source1, legend_label = choice, line_width=2, color=colors[next_group], muted_alpha = 0.1)
# plot.legend.location = "top_left"
# plot.legend.click_policy="mute"
glyph1 = Line(x="x", y="y", line_color=colors[next_group], line_width=2, line_alpha=0.6, name = choice)
plot.add_glyph(source1, glyph1)
print(glyph1)
li1 = LegendItem(label=choice, renderers=[plot.renderers[next_group-1]])
legends.append(li1)
legend1 = Legend(items=legends, location='top_left')
print(legend1)
plot.add_layout(legend1)
print(plot.renderers)
# plot.renderers.append(legend1)
# plot.renderers.extend(li1.renderers)
# plot.renderers = plot.renderers.copy()
# print(plot.layout)
next_group += 1
text_input.on_change('value', update_plot)
doc.add_root(row(plot, text_input))