I am aiming in the below code to make a stacked bar chart with bokeh, appended with sliders so I can increase or decrease the size of each bar segment and shift the others in turn.
My issue right now is that it will not update when running from a bokeh server. My guess is maybe bokeh does not run the calculations again after updating the source... Or I am getting a source conflict. (So far I have only implemented it for "Engineering". Wanted to get that to work before I sort the rest out.
Other things of note. I am using a depreciated technique of providing each glyph with bottom / top data as well as a source. This was done as it was the only way I could get the hovertool to show.
The only way I have got this to work was to redraw the graph completely, I would be ok with this option, but it was stacking the graphs on top of each other. Is there a way to clear all previous graphs in Bokeh? Obviously I would prefer a solution which just alters the data and doesn't completely redraw the graph.
from bokeh.plotting import figure, show, curdoc
from bokeh.models import NumeralTickFormatter
from bokeh.models import HoverTool
from bokeh.models import ColumnDataSource
from bokeh.layouts import widgetbox, column
from bokeh.models import CustomJS, Slider
from matplotlib import colors
import pandas as pd
import numpy as np
# Read Data
df=pd.read_csv('/home/mint/SAGD_Costs.csv')
# Master source
source = ColumnDataSource(df)
# Bar Tops Data
engtop = source.data['Engineering'][0]
equiptop = source.data['Engineering'][0] + source.data['Equipment'][0]
bulktop = source.data['Engineering'][0] + source.data['Equipment'][0] + source.data['Bulk_Materials'][0]
inditop = source.data['Engineering'][0] + source.data['Equipment'][0] + source.data['Bulk_Materials'][0] + source.data['Indirects'][0]
labtop = source.data['Engineering'][0] + source.data['Equipment'][0] + source.data['Bulk_Materials'][0] + source.data['Indirects'][0] + source.data['Labour'][0]
# Source for Stupid Hovertool
engsource = ColumnDataSource(data=dict(x=[0], y=[engtop], desc = ['Engineering']))
equipsource = ColumnDataSource(data=dict(x=[0], y=[equiptop-engtop], desc = ['Equipment']))
bulksource = ColumnDataSource(data=dict(x=[0], y=[bulktop-equiptop], desc = ['Bulk Materials']))
indisource = ColumnDataSource(data=dict(x=[0], y=[inditop-bulktop], desc = ['Indirects']))
labsource = ColumnDataSource(data=dict(x=[0], y=[labtop-inditop], desc = ['Labour']))
# HoverTool Label
hover = HoverTool(
tooltips=[
('Item', '@desc'),
('Cost', '@y{$ 0.00 a}'),
]
)
# Other Tools
TOOLS = 'box_zoom, box_select, resize, reset'
# Figure
p = figure(title="Capital Costs Breakdown", title_location="above", plot_width=600, plot_height=600, x_range=(-2, 2), tools=[TOOLS, hover])
# Plots
engbar = p.vbar(x=source.data['Year'][0], width=2, bottom=0,
top=engtop, alpha=0.75, color="darkslategrey", legend="Engineering", source=engsource)
equipbar = p.vbar(x=[source.data['Year'][0]], width=2, bottom=engtop,
top = equiptop, alpha=0.75, color="teal", legend="Equipment", source=equipsource)
bulkbar = p.vbar(x=[source.data['Year'][0]], width=2, bottom=equiptop,
top=bulktop, alpha=0.75, color="cyan", legend="Bulk Materials", source=bulksource)
indibar = p.vbar(x=[source.data['Year'][0]], width=2, bottom=bulktop,
top=inditop, alpha=0.75, color="powderblue", legend="Indirects", source=indisource)
labbar = p.vbar(x=[source.data['Year'][0]], width=2, bottom=inditop,
top=labtop, alpha=0.75, color="lavender", legend="Labour", source=labsource)
# Format
p.yaxis[0].formatter = NumeralTickFormatter(format="$0,000")
# Set up widgets
eng_slider = Slider(start=5000000, end=100000000, value=40000000, step=5000000, title="Engineering")
def update_data(attrname, old, new):
# Get the current slider values
a = eng_slider.value
# Generate the new curve
df['Engineering'][0] = a
source = ColumnDataSource(df)
#source.data = dict(x=x, y=y)
for w in [eng_slider]:
w.on_change('value', update_data)
# Set up layouts and add to document
inputs = widgetbox(eng_slider)
# Show!
curdoc().add_root(column(inputs, p))
curdoc().title = "Sliders"