Figure.add_layout() [bug]

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

Hi @www I’m sorry but there is not enough information about:

  • what you have tried (i.e. code)
  • what happened
  • what you expected

to really say anything at all. Ideally, to get help, you should provide a minimal complete example that demonstrates the specific thing you are having an issue with.

I edited the post with complete and runnable code and a detailed explanation of what happens. I really appreciate your help.

Doesn’t the solution of your other thread already solve this problem? :thinking:

yes, but this may still mean bugs in the library