Bokeh and Jupyter Notebook

In [1]:
from bokeh.io import output_notebook, show
In [2]:
output_notebook()
Loading BokehJS ...

plotting interface - figure

In [3]:
from bokeh.plotting import figure
In [4]:
p = figure(width=300, height=300)
show(p)
In [5]:
p = figure(width=300, height=300)
p.circle(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
show(p)
In [6]:
p = figure(width=300, height=300)
p.line(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
show(p)
In [7]:
p = figure(width=300, height=300)
p.line(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
p.circle(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5])
show(p)

Bokeh and Pandas - Introducing ColumnDataSource

In [8]:
from bokeh.sampledata.iris import flowers as data
In [9]:
data.head()
Out[9]:
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
In [10]:
from bokeh.models import ColumnDataSource
In [11]:
source = ColumnDataSource(data)
In [12]:
p = figure(width=600, height=600)

p.circle(x=data['sepal_length'], y=data['sepal_width'])

show(p)
In [13]:
from bokeh.models import ColumnDataSource
from bokeh.models import palettes
In [14]:
p = figure(width=600, height=600)

colors = {s: palettes.Viridis3[i]  for i, s in enumerate(data['species'].unique())}
data['color'] = data['species'].apply(lambda x: colors[x])
p.circle(x=data['sepal_length'], y=data['sepal_width'], fill_color=data['color'], size=10)

show(p)
In [15]:
from bokeh.models import CategoricalColorMapper
cmapper = CategoricalColorMapper(factors=list(data['species'].unique()), palette=palettes.Viridis3)
In [16]:
output_notebook()
Loading BokehJS ...
In [17]:
p = figure(width=600, height=600)

p.circle(source=source,
         x='sepal_length', 
         y='sepal_width', 
         fill_color={'field': 'species', 'transform': cmapper}, 
         size=10)

show(p)

Multiple plots

In [18]:
from bokeh.models import Row
from bokeh.models import BoxSelectTool, LassoSelectTool
In [19]:
p1 = figure(width=450, height=300, tools=[BoxSelectTool(), LassoSelectTool()])

p1.circle(source=source,
         x='sepal_length', 
         y='sepal_width', 
         # fill_color={'field': 'species', 'transform': cmapper}, 
         size=10)

p2 = figure(width=450, height=300, tools=[BoxSelectTool(), LassoSelectTool()])

p2.circle(source=source,
         x='petal_length', 
         y='petal_width', 
         # fill_color={'field': 'species', 'transform': cmapper}, 
         size=10)


p1.xaxis.axis_label = 'Sepal Length'
p1.yaxis.axis_label = 'Sepal Width'

p2.xaxis.axis_label = 'Petal Length'
p2.yaxis.axis_label = 'Petal Width'

show(Row(p1, p2))

A little bit of Javascript can go a long way

In [20]:
from bokeh.models import Label, CustomJS
In [29]:
p1 = figure(width=450, height=300, tools=[BoxSelectTool(), LassoSelectTool()])

p1.circle(source=source,
         x='sepal_length', 
         y='sepal_width', 
         fill_color={'field': 'species', 'transform': cmapper}, 
         size=10)

p2 = figure(width=450, height=300, tools=[BoxSelectTool(), LassoSelectTool()])

p2.circle(source=source,
         x='petal_length', 
         y='petal_width', 
         fill_color={'field': 'species', 'transform': cmapper}, 
         size=10)

p1.xaxis.axis_label = 'Sepal Length'
p1.yaxis.axis_label = 'Sepal Width'

p2.xaxis.axis_label = 'Petal Length'
p2.yaxis.axis_label = 'Petal Width'

text1 = Label(x=7, y=4, text='')
text1.text_font_size = '10px'
text1.text_align = 'center'
p1.add_layout(text1)
text2 = Label(x=7, y=4.25, text='')
text2.text_font_size = '10px'
text2.text_align = 'center'
p1.add_layout(text2)
text3 = Label(x=2.75, y=2, text='')
text3.text_font_size = '10px'
text3.text_align = 'center'
p2.add_layout(text3)
text4 = Label(x=2.75, y=2.25, text='')
text4.text_font_size = '10px'
text4.text_align = 'center'
p2.add_layout(text4)

callback = CustomJS(args=dict(
                            text1=text1,
                            text2=text2,
                            text3=text3,
                            text4=text4
                             ), code="""

var inds = cb_obj.selected['1d'].indices;
var d = cb_obj.data;
var m_sl = 0
var m_sw = 0
var m_pl = 0
var m_pw = 0

if (inds.length == 0) { return; }

for (i = 0; i < inds.length; i++) {
    m_sl += d['sepal_length'][inds[i]]
    m_sw += d['sepal_width'][inds[i]]
    m_pl += d['petal_length'][inds[i]]
    m_pw += d['petal_width'][inds[i]]
}

m_sl /= inds.length
m_sw /= inds.length
m_pl /= inds.length
m_pw /= inds.length

var t = 'Avg. Sepal Length = ' + m_sl.toFixed(2).toString();
text1.text = t
var t = 'Avg. Sepal Width = ' + m_sw.toFixed(2).toString();
text2.text = t
var t = 'Avg. Petal Length = ' + m_pl.toFixed(2).toString();
text3.text = t
var t = 'Avg. Petal Width = ' + m_pw.toFixed(2).toString();
text4.text = t

""")

source.callback = callback

show(Row(p1, p2))
In [30]:
from bokeh.models import PanTool
In [31]:
p1.x_range = p2.x_range
p1.add_tools(PanTool())
p2.add_tools(PanTool())

show(Row(p1, p2))