Search code examples
pythonpandasbokeh

Can't initialize Bokeh dashboard with Select widget


This is my first Bokeh experience, so I apologize if I'm asking a very silly question here. So, here's the code. I have a dataframe that contains scores for several individuals. I want to plot a time series line with years on the x-axis, and scores on y-axis and a select menu to pick a player.

This is what I have so far, but I've hit the wall. What am I missing here?

import pandas as pd
import numpy as np
from bokeh.layouts import row, column
from bokeh.models import ColumnDataSource, Select
from bokeh.io import output_file, show
from bokeh.plotting import figure

players = {'AJ':'Alex Jones', 'CH':'Chris Humps', 'BH':'Brian Hill', 'CM':'Chris Matta',
                 'JB':'Jim Bellami'}

data = pd.DataFrame({'score_AJ':[6, 7, 5, 4, 3], 'score_CH':[4, 2, 4, 1, 3], 'score_BH':[7, 3, 2, 7, 6],
                     'score_CM':[1, 1, 3, 2, 4], 'score_JB':[2, 3, 3, 5, 6]})

data.index = pd.period_range(start='2015-01-01', end='2019-01-01', freq='A')

output_file("test.html")

player_select = Select(title='Player:', value="Chris Matta", options=sorted(players.values()))

def update_data(attr, old, new):
    player = [key for (key, value) in players.items() if value == player_select.value]
    df = pd.DataFrame({'year': data.index, 'score': data['score_'+ player]})
    return ColumnDataSource(data=df)

def plot_charts(source):
    chart = figure(width=600, plot_height = 300, x_axis_type ='datetime', title = 'Player score')
    chart.line('year', 'score', color='midnightblue', line_width=2, alpha=1, source = source)
    return chart

player_select.on_change('value', update_data)

chart = plot_charts(source)
main_row = row(chart, player_select)
show(main_row)

Thank you!


Solution

  • Using real Python callbacks, as you have done above, requires running your code as an application on a Bokeh server. That is because web browsers have no knowledge of, nor ability to run, Python code. Real Python callbacks imply there is some actually running Python process that can run the Python callback code. In this case, that process is the Bokeh server (that is what the Bokeh server exists to be).

    Now, the show function is for generating standalone (i.e. non-Bokeh server) output. Just pure HTML and JS in a static file. Given that, there is no way real Python callbacks can function with show.

    So you have two options:

    • Rework this as a Bokeh Server application, in which case you should first refer to Running a Bokeh Server in the User's Guide for necessary context. Then, here is a complete example of a Bokeh sever app that updates data from a Select you can emulate.
    • Alternatively, rework this to use only CustomJS callbacks, and no Python callbacks. It is definitely possible to do this sort of thing with only JS callbacks, in which case standalone output created with show will work. See JavaScript Callbacks for background and many examples of updating things from JS callbacks on widgets.

    Besides this, there are some other miscellaneous issues. Namely, this line:

    chart.line('year', 'score', ...)
    

    tells Bokeh "look in the data source for a column named 'year' for the x-values, and in a column named 'score' for the y-values". However, your data source has neither of these columns. It has columns named things like "score_AJ", etc, and no "year" column at all.