In my last article , I presented a flowchart that can be useful for those trying to select the appropriate python library for a visualization task. Based on some comments from that article, I decided to use Bokeh to create waterfall charts and bullet graphs . The rest of this article shows how to use Bokeh to create these unique and useful visualizations.

Bullet Graphs

In the comments section of the last article, Bryan Van de Ven provided example code for creating a bullet graph in Bokeh. For those of you that do not know Bryan, he is a Senior Software Engineer at Anaconda and is one of the creators of Bokeh. It is safe to say he knows that library well so I figured I should listen to his comments!

I took his example and expand it a bit and included it here in order to compare to the matplotlib process. In the process of building these examples, I learned a lot more about how to use Bokeh and hope this article will show others how to use Bokeh. I’ll be honest, I do think the resulting code is simpler to understand than the matplotlib bullet graph example.

I have posted this notebook on github so feel free to download it and use it to follow along. Unfortunately the Bokeh charts do not render in github but if you wish to use this example, it should run on your system as long as the dependencies are installed.

First, let’s do the imports and enable Bokeh’s output to display in our notebook:

from bokeh.io import show , output_notebook from bokeh.palettes import PuBu4 from bokeh.plotting import figure from bokeh.models import Label output_notebook ()

For this example, we’ll populate the data with python lists. We could modify this to fit in a pandas dataframe but we will stick with simple python data types for this example:

data = [( "John Smith" , 105 , 120 ), ( "Jane Jones" , 99 , 110 ), ( "Fred Flintstone" , 109 , 125 ), ( "Barney Rubble" , 135 , 123 ), ( "Mr T" , 45 , 105 )] limits = [ 0 , 20 , 60 , 100 , 160 ] labels = [ "Poor" , "OK" , "Good" , "Excellent" ] cats = [ x [ 0 ] for x in data ]

The code is a pretty straightforward definition of the data. The one tricky code portion is building out a list of categories in the cats variable that will go on the y-axis.

The next step is to create the Bokeh figure and set a couple of options related to the way the x-axis and grid lines are displayed. As mentioned above, we use the cats variable to define all the categories in the y_range

p = figure ( title = "Sales Rep Performance" , plot_height = 350 , plot_width = 800 , y_range = cats ) p . x_range . range_padding = 0 p . grid . grid_line_color = None p . xaxis [ 0 ] . ticker . num_minor_ticks = 0

The next section will create the colored range bars using bokeh’s hbar . To make this work, we need to define the left and right range of each bar along with the color . We can use python’s zip function to create the data structure we need:

zip ( limits [: - 1 ], limits [ 1 :], PuBu4 [:: - 1 ])

[(0, 20, '#f1eef6'), (20, 60, '#bdc9e1'), (60, 100, '#74a9cf'), (100, 160, '#0570b0')]

Here’s how to pull it all together to create the color ranges:

for left , right , color in zip ( limits [: - 1 ], limits [ 1 :], PuBu4 [:: - 1 ]): p . hbar ( y = cats , left = left , right = right , height = 0.8 , color = color )

We use a similar process to add a black bar for each performance measure:

perf = [ x [ 1 ] for x in data ] p . hbar ( y = cats , left = 0 , right = perf , height = 0.3 , color = "black" )

The final marker we need to add is a segment that shows the the target value:

comp = [ x [ 2 ] for x in data ] p . segment ( x0 = comp , y0 = [( x , - 0.5 ) for x in cats ], x1 = comp , y1 = [( x , 0.5 ) for x in cats ], color = "white" , line_width = 2 )

The final step is to add the labels for each range. We can use zip to create the label structures we need and then add each label to the layout:

for start , label in zip ( limits [: - 1 ], labels ): p . add_layout ( Label ( x = start , y = 0 , text = label , text_font_size = "10pt" , text_color = 'black' , y_offset = 5 , x_offset = 15 ))

I think this solution is simpler to follow than the matplotlib example. Let’s see if the same is true for the waterfall chart.