Reputation: 11
I am trying to draw vbar_stacked (y-axis) with nested categories (x-axis). I used MultiIndex from Pandas and pass to ColumnDataSource, but don't know how to specify 'x' in vbar_stack. Below is the code I am working on now.
Thanks in advance
import pandas as pd
from bokeh.models import ColumnDataSource, FactorRange
from bokeh.io import show, output_file
import numpy as np
from bokeh.plotting import figure, curdoc, output_file, show
output_file("stacked.html")
second_x = ['A', 'B', 'C', 'D']
first_x = ['one','two']
stacks = ["q", "w", "e"]
iterable = [first_x, second_x]
index = pd.MultiIndex.from_product(iterable, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(len(stacks),len(first_x)*len(second_x)), index = stacks, columns= index)
source = ColumnDataSource(df)
h_index = df.columns.tolist()
p=figure(x_range=FactorRange(*h_index))
p.vbar_stack(x=WHAT SHOULD I PUT?, width=0.9, stackers=['q','w','e'], source = source)
This is the chart I want to generate it (I draw using Excel)
Upvotes: 1
Views: 888
Reputation: 17037
here is a solution following what you want: i have just modified your random dataframe
import pandas as pd
from bokeh.models import ColumnDataSource, FactorRange
from bokeh.core.properties import value
from bokeh.io import show, output_file
import numpy as np
from bokeh.plotting import figure, curdoc, output_file, show
output_file("stacked.html")
second_x = ['A', 'B', 'C', 'D']
first_x = ['one', 'two']
stacks = ["q", "w", "e"]
iterable = [first_x, second_x]
index = pd.MultiIndex.from_product(iterable, names=['first', 'second'])
#new randomn generator to avoid negative numbers
df = pd.DataFrame(np.random.randint(5, size=(len(stacks), len(first_x) * len(second_x))), index=stacks, columns=index)
print(df)
# this creates the double axis
factors = [(f_x, s_x) for f_x in first_x for s_x in second_x]
source = ColumnDataSource(data=dict(
x = factors,
q = df.loc['q'].tolist(),
w = df.loc['w'].tolist(),
e = df.loc['e'].tolist()
))
h_index = df.columns.tolist()
p = figure(x_range=FactorRange(*h_index), title='Chart')
p.vbar_stack(stacks, x='x', width = 0.9, color=["blue", "red", "grey"], source = source,
legend=[value(x) for x in stacks])
p.yaxis.axis_label = "Axis Title"
p.xgrid.grid_line_color = None
p.legend.location = "top_center"
p.legend.orientation = "horizontal"
show(p)
output df:
first one two
second A B C D A B C D
q 2 0 3 4 2 4 1 2
w 4 3 4 1 1 3 3 1
e 3 3 4 4 4 0 0 3
graph result:
Upvotes: 2
Reputation: 1795
There are some nice examples in the Bokeh documentation that make it easy to create these charts. I used this one to create this example.
from bokeh.core.properties import value
from bokeh.models import ColumnDataSource, FactorRange
from bokeh.io import show, output_file
from bokeh.plotting import figure, output_file, show
output_file("stacked.html")
second_x = ['A', 'B', 'C', 'D']
first_x = ['one','two']
q = [1, 2, 3, 4, 5, 6, 7, 8]
w = [8, 7, 6, 5, 4, 3, 2, 1]
e = [2, 4, 6, 8, 7, 5, 3, 1]
stacks = ['q', 'w', 'e']
factors = []
for first in first_x:
for second in second_x:
factors.append((first, second))
source = ColumnDataSource(data=dict(
x=factors,
q=q,
w=w,
e=e
))
p=figure(x_range=FactorRange(*factors), title='Chart')
p.yaxis.axis_label = "Axis Title"
p.xgrid.grid_line_color = None
p.vbar_stack(stacks, x='x', width=0.9, color=['blue', 'orange', 'gray'], source = source, legend=[value(x) for x in stacks])
show(p)
Upvotes: 1