Updating a bokeh renderer's field in a notebook application

31 Views Asked by At

I want to change the color of my plot during runtime by selecting the data sources column name from a dropdown list.

Here is my code:

import pandas as pd
from bokeh.models import Dropdown, ColumnDataSource, CustomJS 
from bokeh.transform import factor_cmap
from bokeh.layouts import column 
from bokeh.plotting import show,figure


plot = figure(tools='tap, pan, wheel_zoom', width=1500, height=700 )
node_df = pd.DataFrame(data=dict(x=[1, 2, 3], y=[4, 5, 6], Option_A=['red', 'green', 'blue'], Option_B=['green', 'blue','red']))

node_source = ColumnDataSource(node_df)
mapper = factor_cmap(field_name='Option_A', palette=['red', 'green', 'blue'], factors = ['red','green','blue'])
node_renderer = plot.circle('x', 'y', source=node_source, size=10, color=mapper, selection_color=mapper, 
                              nonselection_color=mapper, selection_alpha=1, nonselection_alpha=0.2, line_color="black", 
                              selection_line_color="black", nonselection_line_color="black")
Dropdown_node_color = Dropdown(button_type="warning", menu = ['Option_A','Option_B'])

callback_node_color = CustomJS(args=dict(renderer=node_renderer, source=node_source),code="""
    renderer.glyph.field = this.item;
    renderer.change.emit();
""")
Dropdown_node_color.js_on_event("menu_item_click", callback_node_color)

layout = column(
    Dropdown_node_color,
    plot
    )
show(layout)

A possible work around is the following:

import pandas as pd
from bokeh.models import Dropdown, ColumnDataSource, CustomJS 
from bokeh.transform import factor_cmap
from bokeh.layouts import column 
from bokeh.plotting import show,figure


plot = figure(tools='tap, pan, wheel_zoom', width=1500, height=700 )
node_df = pd.DataFrame(data=dict(x=[1, 2, 3], y=[4, 5, 6], Option_A=['red', 'green', 'blue'], Option_B=['green', 'blue','red']))

node_source = ColumnDataSource(node_df)
mapper = factor_cmap(field_name='Fillcolor', palette=['red', 'green', 'blue'], factors = ['red','green','blue'])
node_renderer = plot.circle('x', 'y', source=node_source, size=10, color=mapper, selection_color=mapper, 
                              nonselection_color=mapper, selection_alpha=1, nonselection_alpha=0.2, line_color="black", 
                              selection_line_color="black", nonselection_line_color="black")
Dropdown_node_color = Dropdown(button_type="warning", menu = ['Option_A','Option_B'])

callback_node_color = CustomJS(args=dict(renderer=node_renderer, source=node_source),code="""
    //renderer.glyph.field = this.item;
    //renderer.change.emit();
    var selected_column_data = source.data[this.item];
    source.data['Fillcolor'] = selected_column_data;
    source.change.emit();
""")
Dropdown_node_color.js_on_event("menu_item_click", callback_node_color)

layout = column(
    Dropdown_node_color,
    plot
    )
show(layout)

I have only found examples of how to do this by updating the values in the ColumnDataSource, but I'd like to avoid this copying work around.

How could I solve this without using a server application? I'd be very grateful for tips (also in general about using bokeh).

0

There are 0 best solutions below