Bokeh combine line and bar chart with hover


I want to create a combined bar and line chart with a hover tool. As I wanted to add a hover tool I initially created a figure and then tried to add the bars with vbar and the line with line_glyph.
This doesnt work, as it only creates a blank white canvas.

from bokeh.charts import Bar, output_file, show
from bokeh.plotting import figure
from bokeh.models.ranges import Range1d

from bokeh.models import ColumnDataSource, HoverTool
from bokeh.models.glyphs import Line as Line_glyph

import pandas as pd
import numpy as np

    'volume_neutral_promo': [420,430,440,400,2000],

        ( 'Date',   '@yw'            ),
        ( 'Volume (in kg)',  '@volume_neutral_promo' ), # use @{ } for field names with spaces
        ( 'Promo', '@Promo'      ),
        ( 'Product', '@Product'      )

p = figure(plot_width=1000, plot_height=800, tools=[hover],
           title="Weekly Sales 2015-2016",toolbar_location="below")

source = ColumnDataSource(data=data_2015_2016)

#Bar Chart
#This worked however I donno how to combine it with a hoover 
#p.Bar = Bar(data_2015_2016, label='yw', values='volume_promo', title="Sales",legend=False,plot_width=1000, plot_height=800)

p.vbar(x='yw', width=0.5, bottom=0,top='volume_promo', color="firebrick",source=source)

# create a line glyph object which references columns from source data
glyph = Line_glyph(x='yw', y='volume_neutral', line_color='green', line_width=2)

# add the glyph to the chart
p.add_glyph(source, glyph)

p.xaxis.axis_label = "Week and Year"

# change just some things about the y-axes
p.yaxis.axis_label = "Volume"
p.yaxis.major_label_orientation = "vertical"

p.y_range = Range1d(0, max(data_2015_2016.volume_neutral_promo))

Asked By: S.K.



There are a few things wrong with your code:

  • You’ve mixed up some of your column names, e.g. volume_neutral_promo is what is actually in your data source, but instead you have the glyphs mistakenly reference volume_promo_neutral

  • If you want to use a categorical range with bokeh.plotting plots, you have to explicitly tell that:

    p = figure(plot_width=1000, plot_height=800, tools=[hover],
               title="Weekly Sales 2015-2016",toolbar_location="below",
               # this part is new

Here is your complete code updated. I have removed the parts about bokeh.charts as I would not recommend using that API anymore (it’s basically unmaintained at this point). Also I used the simpler p.line instead of the low level Line glyph:

from numpy import nan
import pandas as pd

from import output_file, show
from bokeh.models import ColumnDataSource, HoverTool
from bokeh.plotting import figure

data_2015_2016 = pd.DataFrame({
    'year': [2015, 2015, 2015, 2015, 2015],
    'volume_neutral': [420, 430, 440, 400, nan],
    'volume_promo': [nan, nan, nan, nan, 2000],
    'volume_neutral_promo': [420, 430, 440, 400, 2000],
    'Promo': ['No', 'No', 'No', 'No', 'Yes'],
    'Product': ['Lemonade', 'Lemonade', 'Lemonade', 'Lemonade', 'Lemonade'],
    'yw': ['2015-W01', '2015-W02', '2015-W03', '2015-W04', '2015-W05']

source = ColumnDataSource(data=data_2015_2016)

    ( 'Date',           '@yw'                   ),
    ( 'Volume (in kg)', '@volume_neutral_promo' ),
    ( 'Promo',          '@Promo'                ),
    ( 'Product',        '@Product'              ),

p = figure(plot_width=1000, plot_height=800, tools=[hover],
           title="Weekly Sales 2015-2016",toolbar_location="below",
           x_range=['2015-W01', '2015-W02', '2015-W03', '2015-W04', '2015-W05'])

p.vbar(x='yw', width=0.5, bottom=0, top='volume_promo', color="firebrick", source=source)
p.line(x='yw', y='volume_neutral', line_color='green', line_width=2, source=source)

p.xaxis.axis_label = "Week and Year"
p.yaxis.axis_label = "Volume"
p.yaxis.major_label_orientation = "vertical"

p.y_range.start = 0
p.y_range.range_padding = 0



This results in the following plot with hover tool:

enter image description here

Answered By: bigreddot
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.