Using the example here
http://docs.bokeh.org/en/latest/docs/gallery/stacked_bar_chart.html
along with the interaction example here:
http://docs.bokeh.org/en/latest/docs/user_guide/interaction.html#userguide-interaction
It seems like it should be pretty straightforward to have a slider change the visualization of the stacked barchart. However, the problem is the Bar
object from the bokeh.charts
library does not expose where the data that is rendered in the bargraph is sourced. As far as I can tell, this is because the charts
module does not maintain this data.
Is it possible to have an interaction as described above using the Bar
object. I'm stuck as to where to source the data so the barchart can be updated when the slider moves. I really don't want to have to rebuild the entire barchart from primitives explicitly every time the slider moves.
Any help appreciated. My hail-mary attempt is isted below:
from collections import OrderedDict
import pandas as pd
from bokeh.charts import Bar, output_file, show
from bokeh.sampledata.olympics2014 import data
from bokeh.io import vform
from bokeh.models import Callback, ColumnDataSource, Slider
from bokeh.plotting import figure
output_file("callback_bar_graph.html")
df = pd.io.json.json_normalize(data['data'])
# filter by countries with at least one medal and sort
df = df[df['medals.total'] > 0]
df = df.sort("medals.total", ascending=False)
# get the countries and we group the data by medal type
countries = df.abbr.values.tolist()
gold = df['medals.gold'].astype(float).values
silver = df['medals.silver'].astype(float).values
bronze = df['medals.bronze'].astype(float).values
# build a dict containing the grouped data
medals = OrderedDict(bronze=bronze, silver=silver, gold=gold)
# any of the following commented are also alid Bar inputs
medals = pd.DataFrame(medals)
source = ColumnDataSource(data=dict(medals=medals, countries=countries))
bar = Bar(medals, countries, title="Stacked bars", stacked=True)
callback = Callback(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
medals = data['medals']
countries = data['countries']
for (i = 0; i < medals.bronze.length; i++) {
medals.bronze[i] = 2*medals.bronze[i]
}
source.trigger('change');
""")
slider = Slider(start=-2, end=2, value=1, step=.1,
title="value", callback=callback)
layout = vform(slider, bar)
show(layout)
BarChart
object, I've found no way to modify the plot object in a(n obvious) way that would facilitate what you're looking for. The reason for this is that theBarChart
stores all of it's chart data in its renderers. This wouldn't be a problem if you could pass anotherBarChart
's renderers to the callback, but callbacks can only receivePlotObject
s as arguments, and thus your list of renderers is immediately disqualified... – StevieP