Reputation: 273
I have a dataframe with multiple columns as below:
data = pd.DataFrame({'Year': ['2016', '2017', '2018', '2019', '2020'],
'A1 Qty': [743.85, 608.75, 1099.14, 1253.50, 239.45],
'A2 Qty': [0.0, 0.0, 0.0, 1280.78, 1138.66],
'B1 Qty': [153.3, 213.04, 125.85, 0.0, 0.0],
'B2 Qty': [832.93, 1080.74, 1188.46, 0.0, 0.0],
'C1 Qty': [11.47, 9.52, 11.57, 10.1, 1.52],
'C2 Qty': [14.33, 15.88, 2.53, 9.98, 1.87]
})
I want to plot multiple bar graphs in different plots and i managed to do it one by one using the code below:
src = ColumnDataSource(data)
y_max = max(src.data['A1 Qty'].max(), src.data['A2 Qty'].max())
y_max*=1.50
y_max1 = max(src.data['B1 Qty'].max(), src.data['B2 Qty'].max())
y_max1*=1.50
y_max2 = max(src.data['C1 Qty'].max(), src.data['C2 Qty'].max())
y_max2*=1.50
#if loop what change? y_range, title,
s = figure(x_range=src.data['Year'], y_range=(0, y_max), plot_height=250, title="A1 vs A2 by Year",
toolbar_location=None, tools="")
s.vbar(x=dodge('Year', -0.25, range=s.x_range), top='A1 Qty', width=0.2, source=src,
color="gold", legend="Actual")#, legend_label="Actual")
s.vbar(x=dodge('Year', 0, range=s.x_range), top='A2 Qty', width=0.2, source=src,
color="indianred", legend="Recommended")#, legend_label="Recommended")
s1 = figure(x_range=src.data['Year'], y_range=(0, y_max1), plot_height=250, title="B1 vs B2 by Year",
toolbar_location=None, tools="")
s1.vbar(x=dodge('Year', -0.25, range=s1.x_range), top='B1 Qty', width=0.2, source=src,
color="gold", legend="Actual")#, legend_label="Actual")
s1.vbar(x=dodge('Year', 0, range=s1.x_range), top='B2 Qty', width=0.2, source=src,
color="indianred", legend="Recommended")#, legend_label="Recommended")
s2 = figure(x_range=src.data['Year'], y_range=(0, y_max2), plot_height=250, title="C1 vs C2 by Year",
toolbar_location=None, tools="")
s2.vbar(x=dodge('Year', -0.25, range=s2.x_range), top='C1 Qty', width=0.2, source=src,
color="gold", legend="Actual")#, legend_label="Actual")
s2.vbar(x=dodge('Year', 0, range=s2.x_range), top='C2 Qty', width=0.2, source=src,
color="indianred", legend="Recommended")#, legend_label="Recommended")
layout = row(s,s1,s2)
show(layout)
As you can see, this is very ineffective way because i need to repetitively define y_max, figure, and vbar. How do i do this using loop because I have more than 20 columns to plot.
Upvotes: 0
Views: 416
Reputation: 10652
You don't need to set the ranges manually - just specify the start value and the span. Bokeh will compute the end value for you.
import pandas as pd
from bokeh.io import show
from bokeh.layouts import row
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.transform import dodge
data = pd.DataFrame({'Year': ['2016', '2017', '2018', '2019', '2020'],
'A1 Qty': [743.85, 608.75, 1099.14, 1253.50, 239.45],
'A2 Qty': [0.0, 0.0, 0.0, 1280.78, 1138.66],
'B1 Qty': [153.3, 213.04, 125.85, 0.0, 0.0],
'B2 Qty': [832.93, 1080.74, 1188.46, 0.0, 0.0],
'C1 Qty': [11.47, 9.52, 11.57, 10.1, 1.52],
'C2 Qty': [14.33, 15.88, 2.53, 9.98, 1.87]})
src = ColumnDataSource(data)
def mk_plot(label1, label2):
s = figure(x_range=src.data['Year'], plot_height=250, title=f"{label1} vs {label2} by Year",
toolbar_location=None, tools="")
s.y_range.start = 0
# 1 instead of 0.5 because it gets divided by half, but the "start" half
# is not taken into account because we set the start manually.
s.y_range.range_padding = 1
s.vbar(x=dodge('Year', -0.25, range=s.x_range), top=f'{label1} Qty', width=0.2, source=src,
color="gold", legend_label="Actual")
s.vbar(x=dodge('Year', 0, range=s.x_range), top=f'{label2} Qty', width=0.2, source=src,
color="indianred", legend_label="Recommended")
return s
show(row([mk_plot(f'{l}1', f'{l}2') for l in 'ABC']))
Upvotes: 2