The support for Bokeh is incredibly frustrating. We are encountering so many problems that appear to be bugs. However your response is always “we’re not going to investigate the problem unless you supply an MRE”.
Our application is very large and complex, it’s not possible to just give you an MRE.
So we seem to be at an impasse where Bokeh has lots of bugs but you won’t even look at them.
we’re not going to investigate the problem unless you supply an MRE
What, exactly, are we supposed to investigate? I provided all the suggestion above that it is possible for me to give without actually running code. Did you try it?
Our application is very large and complex, it’s not possible to just give you an MRE.
Over the years, many users with large and complex applications have been able to supply MREs in order to help obtain better support. In such cases such as this, the onus is on you to create a “toy” MRE that is distilled down to just the code necessary to display the problem at hand.
from bokeh.layouts import column
from bokeh.models import Legend, LegendItem
from bokeh.plotting import figure, curdoc
from bokeh.sampledata.autompg import autompg
from bokeh.transform import jitter
years = sorted(autompg.yr.unique())
# Some example graphs from example on web
p1 = figure(width=600, height=300, title="Years vs mpg without jittering")
p1.xgrid.grid_line_color = None
p1.xaxis.ticker = years
p1.scatter(x='yr', y='mpg', size=9, alpha=0.4, source=autompg)
p2 = figure(width=600, height=300, title="Years vs mpg with jittering")
p2.xgrid.grid_line_color = None
p2.xaxis.ticker = years
scatter = p2.scatter(x=jitter('yr', 0.4), y='mpg', size=9, alpha=0.4, source=autompg)
# Add a legend
legend_items = []
legend_items.append(LegendItem(label='line X', renderers=[scatter]))
legend = Legend(items=legend_items)
p2.add_layout(legend,place='right')
# Add a label to the legend
p2.legend.items.insert(0, LegendItem(label="label", tags=['legend_label']))
# Add a callback which changes the label on the legend
def _on_x_range_end_changed(attr, old, new):
print("change:", attr, old, new)
p2.legend.items[0].label['value'] = f"{attr} {old}->{new}"
p1.x_range.on_change('end', _on_x_range_end_changed)
# add column - need to run this with bokeh --serve
curdoc().add_root(column(p1, p2))
However this doesn’t work with Bokeh 3.6.0. Get “TypeError: ‘Value’ object does not support item assignment”.
You need to set the actual property value itself, as I suggested originally, but because strings are ambiguous in this context (they can either be the label value itself, or the name of a CDS field to group from) you need to be explicit that you intend the string to be a value and not a field:
from bokeh.core.properties import value
p2.legend.items[0].label = value(f"{attr} {old}->{new}")
Sometimes Bokeh can auto-magically infer the (usually) right thing to do. Maybe this could or should be one of those times. Now that there is an MRE to focus discussions, feel free to open a GitHub development discussion if you’d like something to be considered further.
Regarding the ["value"] version AFAIK that is not anything that was ever demonstrated in our docs or examples. I think you just got “lucky” with some undefined and/or undocumented behavior.
Lastly, not to belabor the point, but this is why MREs are crucial, and required. I was able to answer this within five minutes of running actual code. There are hundred of thousands of users, a handful of us devs, and zero millions in VC funding. In true volunteer open-source contexts, users must meet devs in the middle, nothing else is sustainable. If you require a higher level of support than that, then you might want to consider commercial products with paid support offerings (that’s a sincere suggestion, not snark).