In [22]:
import numpy as np
import pandas as pd
from IPython.html.widgets import interact

from bokeh.layouts import column
from bokeh.models import (
    ColumnDataSource, 
    Plot, 
    CategoricalAxis, 
    LinearAxis, 
    Rect, 
    Range1d, 
    FactorRange, 
    Select, 
    CustomJS,
    Title
)
from bokeh.io import output_notebook, show, vplot
from bokeh.io import vplot
 
output_notebook()


Loading BokehJS ...

In [12]:
data = {
    'primary_term': ['python', 'python', 'java'],
    'secondary_term': ['R', 'java', 'maven'],
    'frequency': [60, 10, 70],
}
df = pd.DataFrame(data)
df['y'] = df['frequency'] / 2
df.head()


Out[12]:
frequency primary_term secondary_term y
0 60 python R 30
1 10 python java 5
2 70 java maven 35

Basic


In [13]:
s1 = ColumnDataSource(df)
p1 = Plot(
    x_range=FactorRange(factors=data['secondary_term']), 
    y_range=Range1d(0, 100), 
    title=Title(text='Simple'), plot_height=250)
p1.add_layout(CategoricalAxis(), 'below')
p1.add_layout(LinearAxis(), 'left')
rect = Rect(x='secondary_term', y='y', width=0.8, height='frequency')
p1.add_glyph(s1, rect)
show(p1)


Out[13]:

<Bokeh Notebook handle for In[13]>

IPython widget


In [14]:
initial_value = 'python'

all_data_source = ColumnDataSource(df)
selected_df = df[df.primary_term == initial_value]
selected_data_source = ColumnDataSource(selected_df)
selected_df.head()


Out[14]:
frequency primary_term secondary_term y
0 60 python R 30
1 10 python java 5

In [16]:
x_range = FactorRange(factors=list(df['secondary_term'].values))
p2 = Plot(x_range=x_range, y_range=Range1d(0, 100), title=Title(text='IPython Update'), plot_height=250)
p2.add_layout(CategoricalAxis(), 'below')
p2.add_layout(LinearAxis(), 'left')
p2.add_glyph(selected_data_source, rect)
show(p2)


Out[16]:

<Bokeh Notebook handle for In[16]>


In [17]:
def update(primary):
    new_selected_df = df[df.primary_term == primary]
    s = ColumnDataSource(new_selected_df)
    selected_data_source.data = s.data
    selected_data_source.push_notebook()

interact(update, primary=['python', 'java'])


/Users/caged/miniconda3/envs/bokeh_miscellany/lib/python3.5/site-packages/ipykernel/__main__.py:5: BokehDeprecationWarning: bokeh.models.sources.push_notebook was deprecated in Bokeh 0.11.0; please use bokeh.io.push_notebook instead
Out[17]:
<function __main__.update>

JS Callback


In [18]:
factors_dict = {
    'python': ['R', 'java'],
    'java': ['maven']
}

python = pd.Series([60, 10], name='python', index=factors_dict['python'])
java = pd.Series([70], name='java', index=factors_dict['java'])
js_df = pd.DataFrame([python, java]).transpose()
js_df['python_y'] = js_df.python / 2
js_df['java_y'] = js_df.java / 2
js_df


Out[18]:
python java python_y java_y
R 60 NaN 30 NaN
java 10 NaN 5 NaN
maven NaN 70 NaN 35

In [23]:
all_source = ColumnDataSource(js_df)
selected_df = js_df[['python', 'python_y']]
selected_df = selected_df.rename(columns={
        'python_y': 'y',
        'python': 'height'
    })
selected_source = ColumnDataSource(selected_df)

# set up the plot
p3 = Plot(
    x_range=FactorRange(factors=factors_dict[initial_value]),
    y_range=Range1d(0, 100),
    title=Title(text='JS Callback'), plot_height=250
)
p3.add_layout(CategoricalAxis(), 'below')
p3.add_layout(LinearAxis(), 'left')
p3.add_glyph(selected_source, Rect(x='index', height='height', y='y', width=0.8))

# set up the select w/callback
code = """
    var val = cb_obj.get('value'),
        factors = %s,
        data = selected_source.get('data');
    x_range.set('factors', factors[val]);
    data['height'] = all_source.get('data')[val];
    data['y'] = all_source.get('data')[val + '_y'];
    selected_source.trigger('change');
""" % factors_dict

callback = CustomJS(
    args={'x_range': p3.x_range, 'selected_source': selected_source, 'all_source': all_source},
    code=code
)
select = Select(options=list(factors_dict.keys()), callback=callback, value=initial_value)

show(column(select, p3))


Out[23]:

<Bokeh Notebook handle for In[23]>


In [ ]:


In [ ]: