Easy Data Visualization Techniques with Bokeh | by Ilya Hopkins | Towards Data Science

Any story would be dead without proper visualizations. Only a few known (not always from trustworthy sources though) super-humans referred to as ‘Guru’, ‘Saint’, ‘Teacher’, sometimes ‘Lord’, and quite often ‘Martyr’, have found their immortal fame for being able to tell an inspirational story without proper visual support. Others have to use different support techniques to convey their stories.
There is a great number of make your story interesting and attractive to the audience. You may use verbal and non-verbal techniques in any combination, but only one things is truly essential — a good picture. Exactly the one that is worth a thousand words! And data science is definitely not an exception. That’s why most of us are learning basic visualization libraries (Matplotlib, Plotly, Seaborn — and it is just to start with) from the very beginning.
I have recently come across a library called Bokeh and I simply loved it! It is very intuitive, quite simple, with a very gentle learning curve. But from the very beginning, one starts creating cool interactive visualization. This article is the beginning of my Bokeh love story. The full story (including Jupyter notebooks and all files) is on my Github.
Most of us have seen and loved photographs where lots of bright colors in the front of the picture are combined with some blurred background. That is called ‘bokeh’ (sometimes spelt as ‘boke’) — a Japanese word meaning ‘blur’. It is quite popular in photography as a way to make a picture more visiually appealing. And it has also become a great name for a Python interactive visualization library!
Let’s look at the Top 5 Bokeh simplest visualization techniques that represent a gentle and gradual Bokeh learning curve. I have found a relatively small dataset on world’s socio-economic development available at the United Nations Open Data source. Among other indicators, it represents data on the infectious deceases prevalence across the globe for 2000–2015, the good old pre-COVID-19 era.
For everyone familiar with Python basics the code will look truly simple. For the sake of simplicity, I have included only meaningful chunks, omitting auxiliary and technical parts (importing libraries, etc.).
#Initializing our plot with the 400x400 dimensions and standard tools (zoom, save, etc.)p = figure(plot_width=400, plot_height=400, tools=TOOLS)#We need to set the axis and pass the values from the dataset.#Our horizontal axis X will be years, and our vertical axis Y will be life expectancyx = data[data['country']=='Afghanistan']['year']y = data[data['country']=='Afghanistan']['life expectancy']#Initializing our glyph. Only two parameters are necessary - x and yp.line(x,                            #horizontal axis       y,                            #vertical axis      line_alpha = .7,               #line opacity                         line_color = 'red',            #line color      line_width = 4,                #line width      line_dash = 'dashdot',         #line type(dotted,dashed, etc)       legend_label='Afghanistan'    #line legend      )#Additional visualization parametersp.xaxis.axis_label = "Year"                #horizontal axis' labelp.yaxis.axis_label = "Life Expectancy"     #vertical axis' labelp.legend.location = "center"               #legend's locationp.xgrid.grid_line_color = 'green'          #horizontal axis' colorp.xgrid.grid_line_alpha = .3               #horizontal axis opacityp.ygrid.grid_line_color = 'blue'           #vertical axis' colorp.ygrid.grid_line_alpha = .3               #vertical axis' opacity#Finally, we want to see our visual and we need to ask Bokeh to show it to us.show(p)
And the outcome:
As simple as that, and code comments are longer than the code itself!
Again, the coding part is truly straight-forward and intuitive. Let’s look at several random countries’ live expectancy data over 2000–2015.
#Initializing our plotp = figure(plot_width=600, plot_height=600, tools=TOOLS)#Horizontal axis - yearx = data[data['country']=='Afghanistan']['year']#Vertical axis for several countries' life expectanciesy = data[data['country']=='Afghanistan']['life expectancy']y1 = data[data['country']=='Romania']['life expectancy']y2 = data[data['country']=='France']['life expectancy']y3 = data[data['country']=='Japan']['life expectancy']y4 = data[data['country']=='Chad']['life expectancy']#Drawing our 5 curves. Each line has its own style and labelp.line(x , y,        line_alpha = .7, line_color = 'red', line_width = 4, line_dash = 'dashdot',       legend_label="Afghanistan")p.line(x , y1,        line_alpha = .7, line_color = 'green', line_width = 4, line_dash = 'dotdash',       legend_label="Romania")p.line(x , y2,        line_alpha = .7, line_color = 'blue', line_width = 4, line_dash = 'dashed',        legend_label='France')p.line(x , y3,       line_alpha = .7, line_color = 'orange', line_width = 4, line_dash = 'dotted',       legend_label='Japan')p.line(x , y4,        line_alpha = .7, line_color = 'magenta', line_width = 4,        legend_label='Chad')#Additional visualization parametersp.xaxis.axis_label = "Year"p.yaxis.axis_label = "Life Expectancy"p.legend.location = "center_right"       #Choosing legend's location#Showing the visualizationshow(p)
And the rendered result:
Again, very simple. We could also choose different styles for our plots and different glyphs. A glyph in Bokeh is one of the available symbols (pictograph) for representing data. Look at the following code and plot for life expectancy data for different random countries over the same timespan.
#Initializing the plotp = figure(plot_width=800, plot_height=500,      #plot size           background_fill_color='lightblue',    #background color           background_fill_alpha=.2,             #background opacity           title = 'Life expectancy 2000-2015',  #visual's title           title_location='above',               #title's location           tools=TOOLS                           #standard tools           )#Horizontal axisx = data[data['country']=='Afghanistan']['year']#Vertical axis for several countries' life expectanciesy = data[data['country']=='Brazil']['life expectancy']y1 = data[data['country']=='India']['life expectancy']y2 = data[data['country']=='Italy']['life expectancy']y3 = data[data['country']=='Egypt']['life expectancy']y4 = data[data['country']=='Cuba']['life expectancy']#Drawing our 5 curves. Each line has its own style and labelp.diamond(x , y, size =15, fill_alpha = .5, fill_color = 'red',          line_alpha = .5, line_color = 'green', line_width = 1.5,           legend_label="Brazil")p.circle(x , y1, size =15, fill_alpha = .5, fill_color = 'green',         line_alpha = .5, line_color = 'red', line_width = 1.5,          legend_label="India")p.asterisk(x , y2, size =15,  line_color = 'blue', line_width = 1.5,           legend_label="Italy")p.triangle(x , y3, size =15, fill_alpha = .5, fill_color = 'orange',           line_alpha = .5, line_color = 'blue', line_width = 1.5,            legend_label="Egypt")p.cross(x , y4, size =15,  line_color = 'magenta', line_width = 2,         legend_label="Cuba")#Additional visualization parametersp.xaxis.axis_label = "Year"p.yaxis.axis_label = "Life Expectancy"p.legend.location = "top_left"#Showing the visualizationshow(p)
And the result:
Simple, intuitive, straight-forward.
The beauty of Bokeh’s functionality is that we could pass Panda’s groupby structures (among many others) as arguments for plotting. We could also intuitively combine multiply styles for the same graphs. Let’s illustrate it on the example of average polio rates comparison for the developed and developing countries.
#Plotting a line for developing countries by passing Pandas groupby aggregate structure#directly to the plotting finctionp.line(        data[data['status']=='Developing'].groupby(['year']).mean()[['polio']].index,       data[data['status']=='Developing'].groupby(['year']).mean()['polio'],        line_color='blue',        line_width = 3        )#Plotting datapoint circles for developing countries p.circle(        data[data['status']=='Developing'].groupby(['year']).mean()[['polio']].index,       data[data['status']=='Developing'].groupby(['year']).mean()['polio'],        size = 15,        fill_color='azure',        legend_label = 'Developing countries'        )#Plotting a line for developed countries p.line(        data[data['status']=='Developed'].groupby(['year']).mean()[['polio']].index,       data[data['status']=='Developed'].groupby(['year']).mean()['polio'],        line_color='red',        line_width = 3        )#Plotting datapoint circles for developed countries p.circle(        data[data['status']=='Developed'].groupby(['year']).mean()[['polio']].index,       data[data['status']=='Developed'].groupby(['year']).mean()['polio'],        size = 15,        fill_color='salmon',        legend_label = 'Developed countries'        )#Setting the legend's locationp.legend.location = 'bottom_right'#Showing the visualizationshow(p)
And here we are:
Easy, simple, hassle-free. We could technically draw an endless number of graps on the same plot by using any possible combination of available Bokeh glyphs, colors and styles and this “superset” technique.
Bokeh also provides us with the ways to reduce the amount of code required for plotting multiple dependencies on the same plot using a multiline plotting function. Let’s look how that works on the example of aggregated measles statistics for developed and developing countries.
Multi-line plotting function works accorring to the following scheme:
p.milti-line([x[0]:x[i]], #list of horizontal values for each curve            [y[0]:y[i]],  #list of vertical values for each curve            ...........,  #lists of properties for the lines)
And the code looks like this:
p.multi_line(            [data[data['status']=='Developing'].groupby(['year']).mean()[['measles']].index,            data[data['status']=='Developing'].groupby(['year']).mean()[['measles']].index],                [data[data['status']=='Developing'].groupby(['year']).mean()['measles'],            data[data['status']=='Developed'].groupby(['year']).mean()['measles']],                color=['blue','red'],                width=[3,3]                          )
Here’s the result:
Again, simple and intuitive. And there’s a myriad of methods to enhance the visual’s details.
For many visualization libraries simultaneous creating a number of plots and arranging them in a grid is quite a tough task. Not for Bokeh. Let’s look at several random countries and their infant aged 0–5 y.o mortality rates over the years.
#Choosing the datay1 = data[data['country']=='Turkey']['under-five deaths']y2 = data[data['country']=='Brazil']['under-five deaths']y3 = data[data['country']=='Thailand']['under-five deaths']#Creating the first plotp1 = figure(width=250, height=250)p1.triangle(x, y1, size=10, color="firebrick", fill_alpha=0.25)p1.line(x,y1, color='salmon', line_width=2, legend_label='Turkey')p1.title.text='Mortality rates for infants 0-5 years 2000-2015'#Creating the second onep2 = figure(width=250, height=250)p2.square(x, y2, size=10, color="orange", fill_alpha=0.25)p2.line(x,y2, color='pink', line_width=2, legend_label='Brazil')#Create another onep3 = figure(width=250, height=250)p3.circle(x, y3, size=10, color="olive", fill_alpha=0.25)p3.line(x,y3, color='lightgreen', line_width=2, legend_label='Thailand')#Arranging all the plots in a gridplotp = gridplot([[p1, None], [ p2, p3]], toolbar_location=None)#Showing the resultsshow(p)
And the result is here:
We could keep experimenting with Bokeh’s simple techniques forever. The package provides a truly unlimited number of ways to create attractive and interactive visuals.
The next part of this story will be on of some Bokeh’s intermediate techniques.