I am plotting a complex interactive donut chart in bokeh. The code below is a simplification of a component of this chart.
I have a function which compiles a dataframe of data for the donut, and then converts it to a CDS. This data is then plotted as annular wedges. A radiobutton group should trigger a switch to a different dataframe (as CDS), and replot the annular wedge glyphs.
The example provide (for Jupyter Lab) works in one direction. When initially plotted the button.active == 0
(outer_1). When outer_2 is selected, the chart correctly changes to plot the second dataframe (cds).
But when the outer_1 button is pressed, the glyphs do not change back. The callback is triggered - as the title changes. But the glyphs do not change.
Why are the glyphs not changing in subsequent button presses / callbacks?
I've read a few similar SO posts, and also reviewed a number of bokeh examples (the weather example here is similar)
import pandas as pd
from math import pi
from bokeh.plotting import figure
from bokeh.layouts import column, row
from bokeh.models.widgets import RadioButtonGroup
from bokeh.io import curdoc
from bokeh.models.sources import ColumnDataSource
from bokeh.layouts import column, row
from bokeh.plotting import show, output_notebook
output_notebook()
df = pd.DataFrame({'start':[pi/2, pi, 3*pi/2],
'end' :[pi/2+1.5, pi+1.5, (3*pi/2)+1.5],
'inner': [100,100,100],
'outer': [200,200,200],
'color':['red','green','blue']})
df_2 = pd.DataFrame({'start':[pi/2, pi, 3*pi/2],
'end' :[pi/2+1, pi+1, (3*pi/2)+1],
'inner': [100,100,100],
'outer': [250,300,350],
'color':['orange','gray','purple']})
data_1 = ColumnDataSource(data=df)
data_2 = ColumnDataSource(data=df_2)
def create_doc(doc):
button = RadioButtonGroup(labels=["outer_1", "outer_2"], active=0)
inputs = column(button)
p = figure(plot_width=600, plot_height=600, title="data_1",
x_axis_type=None, y_axis_type=None,
x_range=(-300, 300), y_range=(-300, 300),
min_border=0, outline_line_color=None,
background_fill_color='white', toolbar_location="above")
circle = p.circle(0,0, radius=100, fill_alpha=0, line_color='grey', line_alpha=0.4)
source = [data_1, data_2][button.active]
segments = p.annular_wedge(0,0,'inner', 'outer', 'start', 'end', color='color', alpha=0.6, source=source, name='segments')
r = row (inputs,p)
def callback(attr, old, new):
if button.active == 1:
p.title.text = 'data_2 {}'.format(button.active)
source.data.update(data_2.data)
elif button.active == 0:
p.title.text = 'data_1 {}'.format(button.active)
source.data.update(data_1.data)
button.on_change('active', callback)
doc.add_root(r)
show(create_doc)
The glpyhs change successfully once, but not again, although the changing title text (on button presses) indicate that the buttons & callback continue to work partially.
Why converting to
DataFrame
knowing that internally the data of ColumnDataSource is a dictionary? The following code works fine for Bokeh v1.1.0