In [Bokeh 0.12.6+], you can use visual evasion :
from bokeh.core.properties import value from bokeh.io import show, output_file from bokeh.models import ColumnDataSource from bokeh.plotting import figure from bokeh.transform import dodge df.index = df.index.str.split('Q', expand=True) df = df.sort_index(level=[1,0]) df.index = df.index.map('Q'.join)
output_file("dodged_bars.html") df = df.reset_index().rename(columns={'index':'qrange'}) data = df.to_dict(orient='list') idx = df['qrange'].tolist() source = ColumnDataSource(data=data) p = figure(x_range=idx, y_range=(0, df[['A','B','C','D']].values.max() + 5), plot_height=250, title="Report", toolbar_location=None, tools="") p.vbar(x=dodge('qrange', -0.3, range=p.x_range), top='A', width=0.2, source=source, color="#c9d9d3", legend=value("A")) p.vbar(x=dodge('qrange', -0.1, range=p.x_range), top='B', width=0.2, source=source, color="#718dbf", legend=value("B")) p.vbar(x=dodge('qrange', 0.1, range=p.x_range), top='C', width=0.2, source=source, color="#e84d60", legend=value("C")) p.vbar(x=dodge('qrange', 0.3, range=p.x_range), top='D', width=0.2, source=source, color="#ddb7b1", legend=value("D")) p.x_range.range_padding = 0.2 p.xgrid.grid_line_color = None p.legend.location = "top_left" p.legend.orientation = "horizontal" show(p)
