I have 2 linked plots with the same datasource: one showing scatter points, another patches. As per my last post (Use a slider to create selection, customjs), I am altering the selection via a slider (or sliders) that move a selection box up/down/left/right.
I have implemented this as desired and am now trying to add a radiogroup widget that will allow changing the color theme of the patches. I’ve successfully implemented the callback for the radiogroup (it works as intended if you never touch the slider), however as soon as I move the slider to filter the selection, the color theme reverts back to its original theme and the radio group no longer functions.
Here is my working reproducible example, built mostly off my last one:
from bokeh.io import output_notebook, show
import numpy as np
from bokeh.layouts import gridplot
from bokeh.models import ColumnDataSource, Patches, Slider, Quad,CustomJS,RadioGroup
from bokeh.plotting import figure
import bokeh
output_notebook()
#points
x = list(range(-20, 21))
y = [abs(xx) for xx in x]
#making patches
N =41
xp = np.linspace(-2, 2, N)
yp = xp**2
xpts = np.array([-.09, -.12, .0, .12, .09])
ypts = np.array([-.1, .02, .1, .02, -.1])
source = ColumnDataSource(dict(x=x,y=y,
xs=[xpts*(1+i/10.0)+xx for i, xx in enumerate(xp)],
ys=[ypts*(1+i/10.0)+yy for i, yy in enumerate(yp)],
cvalsA = list(range(0,41)),
cvalsB = list(np.geomspace(0.1,41,41))
))
#colortheming dictionary
Amap = bokeh.models.LinearColorMapper(palette='Spectral11', low = 0, high = 41)
Bmap = bokeh.models.LinearColorMapper(palette='Turbo256', low = 0, high = 41)
cdict = {0:{'field':'cvalsA','transform':Amap},1:{'field':'cvalsB','transform':Bmap}}
TOOLS = "box_select,lasso_select"
# create a new plot and add a renderer
left = figure(tools=TOOLS, plot_width=300, plot_height=300, title=None)
left.circle('x', 'y', source=source)
# create another new plot and add a renderer
right = figure(tools=TOOLS, plot_width=300, plot_height=300, title=None)
glyph = Patches(xs="xs", ys="ys", fill_color=cdict[0])
patchrenderer = right.add_glyph(source, glyph)
#create the selection "quad"
qsource = ColumnDataSource({'bottom':[0],'top':[20],'left':[-20],'right':[20]})
selector = Quad(bottom='bottom',top='top',left='left',right='right',fill_color='green',fill_alpha=0.05)
renderer = left.add_glyph(qsource,selector)
hslider = Slider(start=-20, end=20, value=-20, step=1, title="hselector")
hcallback = CustomJS(args=dict(renderer=renderer), code="""
renderer.glyph.left = cb_obj.value;
""")
hslider.js_on_change('value',hcallback)
rbutton = RadioGroup(labels=['A theme','B theme'], active=0)
selcallback = CustomJS(args=dict(source=source,rbutton=rbutton,r=patchrenderer,cdict=cdict), code="""
var indices = [];
for (var i = 0; i <= source.data['x'].length; i++){
if (source.data['x'][i] > cb_obj.value) {
indices.push(i)
}
};
var l_selected = source.selected;
l_selected.indices = indices;
source.selected = l_selected;
r.glyph.fill_color = cdict[rbutton.active];
console.log(r.glyph.fill_color)
r.change.emit();
""")
hslider.js_on_change('value',selcallback)
rbutton_callback = CustomJS(args=dict(r=patchrenderer,cdict=cdict),code="""
r.glyph.fill_color = cdict[this.active]""")
rbutton.js_on_click(rbutton_callback)
p = gridplot([[left, right],[hslider,rbutton]])
show(p)
See the console.log(r.glyph.fill_color) in the slider callback? Looking at it… it actually shows it as updating correctly… i.e. it returns the correct dictionary entry when i move the slider, then change the radiogroup, then move the slider again:
I’m missing something with how bokeh handles the selections…I think. Any help much appreciated.