I'm using Bokeh to create scatter plots by passing a ColumnDataSource
to the figure.circle
function. The data source has columns that designate certain colors for each point, with a hex code in each row, because the coloring scheme I want to use is somewhat plicated.
Is there a way to change the column used to color the circles in the callback of a widget? I'm imagining a dropdown menu allowing users to choose various coloring schemes for the points.
I'm using Bokeh to create scatter plots by passing a ColumnDataSource
to the figure.circle
function. The data source has columns that designate certain colors for each point, with a hex code in each row, because the coloring scheme I want to use is somewhat plicated.
Is there a way to change the column used to color the circles in the callback of a widget? I'm imagining a dropdown menu allowing users to choose various coloring schemes for the points.
Share Improve this question edited Jan 21, 2017 at 3:06 James Draper 5,3105 gold badges41 silver badges63 bronze badges asked Dec 14, 2016 at 16:51 user5182786user51827862 Answers
Reset to default 6Here is an example of a solution using a models.Select
widget and models.CustomJS
to select out of two coloring schemes defined in the ColumnDataSource
of Figure.circle
:
import bokeh
import bokeh.plotting
p = bokeh.plotting.figure(x_range=(0,4), y_range=(0,4), plot_height=200 )
csource = bokeh.models.ColumnDataSource(data=dict(
x=[1,2,3],
y=[1,2,1],
colors1=["#ff0000","#00ff00","#0000ff"],
colors2=["#ff00ff","#ffff00","#00ffff"]))
cir = p.circle(x="x",y="y",fill_color="colors1",line_color="colors1",
size=20,source=csource)
cb_cselect = bokeh.models.CustomJS(args=dict(cir=cir,csource=csource), code ="""
var selected_color = cb_obj.value;
cir.glyph.line_color.field = selected_color;
cir.glyph.fill_color.field = selected_color;
csource.trigger("change")
""")
color_select = bokeh.models.Select(title="Select colors", value="colors1",
options = ["colors1","colors2"], callback = cb_cselect)
layout = bokeh.layouts.gridplot([[p],[color_select]])
bokeh.io.output_file("output.html")
bokeh.io.show(layout)
The output looks like
I've updated the excellent answer provided by Pablo Reyes for Bokeh 2.4.1:
import bokeh
import bokeh.plotting
p = bokeh.plotting.figure(x_range=(0,4), y_range=(0,4), plot_height=200 )
csource = bokeh.models.ColumnDataSource(data=dict(
x=[1,2,3],
y=[1,2,1],
colors1=["#ff0000","#00ff00","#0000ff"],
colors2=["#ff00ff","#ffff00","#00ffff"]))
cir = p.circle(x="x",y="y",fill_color="colors1",line_color="colors1",
size=20,source=csource)
cb_cselect = bokeh.models.CustomJS(args=dict(cir=cir,csource=csource), code ="""
var selected_color = cb_obj.value;
cir.glyph.line_color.field = selected_color;
cir.glyph.fill_color.field = selected_color;
csource.change.emit();
""")
color_select = bokeh.models.Select(title="Select colors", value="colors1",
options = ["colors1","colors2"])
color_select.js_on_change('value', cb_cselect)
layout = bokeh.layouts.gridplot([[p],[color_select]])
bokeh.io.output_file("output.html")
bokeh.io.show(layout)
Essentially, the JavaScript csource.trigger("change")
triggered an error in JavaScript:
Uncaught TypeError: csource.trigger is not a function
Replacing it with csource.change.emit()
produces the desired result. While source.change.emit()
is not well documented, some examples exist here.