Hello,
How can I link elements like vbar
colored with factor_cmap
(e.g. here) with ColorPicker?
The only way I’ve found is to create a separate ColumnDataSource
for each bar (without using factor_map
at all).
Hello,
How can I link elements like vbar
colored with factor_cmap
(e.g. here) with ColorPicker?
The only way I’ve found is to create a separate ColumnDataSource
for each bar (without using factor_map
at all).
@dinya Actually I do not see any reason to have multiple CDS, one for each bar. One way to achieve what you want is to have a fruit Selector
and one ColorPicker
. Add a CustomJS
callback to each of those widgets. Example below is based on using factor_cmap
for fill_color
of the vbar
. If instead one is using a specific field in the CDS for color of the bars, then one can easily change callbacks for that case.
The CustomJS
callback for the Selector
is used to update the color
property of the ColorPicker
in order to display the current color of the selected fruit (bar) .
CustomJS
callback for the ColorPicker
is used to update the palette
in the factor_cmap
that is used to map fill_color
to the fruits.
from bokeh.models import ColumnDataSource, ColorPicker, CustomJS, Select
from bokeh.palettes import Bright6
from bokeh.plotting import figure, show
from bokeh.transform import factor_cmap
from bokeh.layouts import column, row
fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
counts = [5, 3, 4, 2, 4, 6]
source = ColumnDataSource(data=dict(fruits=fruits, counts=counts))
p = figure(
x_range = fruits, height = 350,
toolbar_location = None,
title = "Fruit Counts"
)
r_vbar = p.vbar(
x = 'fruits', top = 'counts', width=0.9,
source = source, legend_field = "fruits",
line_color = 'white',
fill_color = factor_cmap('fruits', palette=Bright6, factors=fruits)
)
p.xgrid.grid_line_color = None
p.y_range.start = 0
p.y_range.end = 9
p.legend.orientation = "horizontal"
p.legend.location = "top_center"
select = Select(
title = 'Fruit',
value = fruits[0],
options = fruits
)
color_picker = ColorPicker(
title = 'Bar color specific fruit',
color = r_vbar.glyph.fill_color.transform.palette[fruits.index(select.value)]
)
# add callbacks to widgets
# update color picker with current color of selected fruit
select.js_on_change(
"value",
CustomJS(
args = {
'vbar': r_vbar,
'color_picker': color_picker
},
code="""
const idx = this.options.indexOf(this.value);
const color = vbar.glyph.fill_color.transform.palette[idx];
color_picker.color = color;
"""
)
)
# update vbar color mapper
color_picker.js_on_change(
'color',
CustomJS(
args = {
'select': select,
'vbar': r_vbar,
'plot': p
},
code="""
const idx = select.options.indexOf(select.value);
const {transform} = vbar.glyph.fill_color;
transform.palette[idx] = this.color;
vbar.glyph.fill_color = {field: 'fruits', transform: transform};
plot.reset.emit();
"""
)
)
show(column(p, row(select, color_picker)))