'Bokeh one slider for hiding multiple renderers
I am developing an application with Bokeh with multiple bar charts. Each chart has multiple renderers, one for each year of data, and all charts are embedded and run on Flask---code for one chart is shown below.
I want to add one slider that will show/hide bars corresponding to one or years of data but I could only find online how to make a slider change data shown by one renderer, not to completely get rid of it. I have tried both approaches shown here. They did not work because:
- I am using Flask rather than the Bokeh server (I am a high performance computing guy rather than web-anything, and Flask was already set up by someone else), and
- I cannot figure out the JS callback for multiple renderers.
Any suggestions? Thanks in advance.
import datetime
import pandas as pd
from bokeh.layouts import widgetbox, column
from bokeh.models import Slider, HoverTool
from bokeh.plotting import ColumnDataSource, figure, show
from bokeh.embed import components
from bokeh.transform import dodge
from bokeh import palettes
BAR_GROUP_WIDTH = 0.6
MONTHS = [
'January',
'Febuary',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
data = pd.DataFrame.from_dict(
{'Month': ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
'2017': [11.6124, 7.11175, 9.366717, 11.071917, 4.849774, 10.0885, 14.81031, 15.486875, 14.877268, 14.025417, 11.203527, 11.09575],
'2018': [10.480874, 11.042208, 11.874903, 12.120542, 15.4275, 19.12525, 16.546917, 9.330083, 6.740833, 2.145, 5.919208, 15.946958],
'2019': [11.521308, 7.023, 9.282109, 10.518875, 12.664917, 9.953042, 13.494, 11.729083, 14.696792, 10.704042, 8.468698, 13.1605],
'2020': [11.162708, 7.276667, 15.194272, 16.654917, 19.552996, 20.480625, 14.800629, 7.722917, 19.260708, 18.052994, 17.488208, 19.442917],
'2021': [18.712944, 17.520792, 18.69113, 17.505542, 21.687413, 20.725637, 10.538542, 19.516708, 17.576167, 20.552875, 13.38375, 17.651667],
'2022': [17.027417, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
)
now = datetime.datetime.now()
years = [str(y) for y in range(2017, 2022)]
title = 'Test Plot'
source = ColumnDataSource(data=data)
p = figure(
x_range=MONTHS,
y_range=(0, data[years].max().max() * 1.25),
height=350, width=900,
title=title.center(100)
)
renderers = []
for ix, y in enumerate(years):
# Here I generate one renderer for each group of twelve bars corresponding to all months in a year
d = -BAR_GROUP_WIDTH / 2 + BAR_GROUP_WIDTH / (len(years) - 1) * ix
r = p.vbar(x=dodge('Month', d, range=p.x_range), top=y, width=BAR_GROUP_WIDTH / len(years),
source=source, line_color="white",
color=palettes.Category10[len(years)][ix],
legend_label=y
)
tooltip = [
('YEAR', y),
('MONTH', '@Month'),
('TOTAL', f'@{y}')
]
p.add_tools(HoverTool(tooltips=tooltip, renderers=[r]))
renderers.append(r)
p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.legend.location = "top_left"
p.legend.orientation = "horizontal"
# How do I make this slider do what I want it to do?
slider = Slider(start=2017, end=now.year, value=now.year, step=1, title="Range")
layout = column(p, widgetbox(slider))
show(layout)
# # My application is running on Flask and I'm embedding Bokeh components, so I actually use components rather than show.
# script, div = components(layout)
# return (script, div)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
