1

I'm trying to add a slider via Bokeh to my plot which is connected to a pandas dataframe.

The plot is using the datetime index to show how Air Quality Index over one year.

I would like to add a slider for each month, January - December 2016. I'm not able to find a clear example with code that connects the slider to a plot which is connected to a pandas dataframe. Someone help please!

I was able to find the following code, but the plot was generated with random data. The output of this code is exactly what I'm looking to do but with time series data.

from bokeh.io import output_notebook, show, vform
from bokeh.plotting import figure, Figure
from bokeh.models import ColumnDataSource, Slider, CustomJS
import numpy as np

output_notebook()

x = np.sort(np.random.uniform(0, 100, 2000))

y = np.sin(x*10) + np.random.normal(scale=0.1, size=2000)
fig = Figure(plot_height=400, x_range=(0, 2))

source = ColumnDataSource(data={"x":x, "y":y})

line = fig.line(x="x", y="y", source=source)
callback = CustomJS(args=dict(x_range=fig.x_range), code="""
var start = cb_obj.get("value");
x_range.set("start", start);
x_range.set("end", start+2);
""")

slider = Slider(start=0, end=100, step=2, callback=callback)
show(vform(slider, fig))

I also found the source code of making this type of slider (below/linked here) but I am unsure how to implement it. As you can probably tell, I'm fairly new to Bokeh. Please help!

class DateRangeSlider(AbstractSlider):
""" Slider-based date range selection widget. """

@property
def value_as_datetime(self):
    ''' Convenience property to retrieve the value tuple as a tuple of
    datetime objects.

    '''
    if self.value is None:
        return None
    v1, v2 = self.value
    if isinstance(v1, numbers.Number):
        d1 = datetime.utcfromtimestamp(v1 / 1000)
    else:
        d1 = v1
    if isinstance(v2, numbers.Number):
        d2 = datetime.utcfromtimestamp(v2 / 1000)
    else:
        d2 = v2
    return d1, d2

value = Tuple(Date, Date, help="""
Initial or selected range.
""")

start = Date(help="""
The minimum allowable value.
""")

end = Date(help="""
The maximum allowable value.
""")

step = Int(default=1, help="""
The step between consecutive values.
""")

format = Override(default="%d %b %G")

2 Answers 2

1

I just worked through a similar situation with my project. I did not use the pandas datetime functionality as my dates were mixed format, but it was easy to update once I cleaned my data. The important part is to have your callback function adjust the .data attribute of your ColumnDataSource.

In the example you have, the callback function is written in Javascript. I used the code from the example Iain references, but I had to do a small workaround for panda dataframes. In the example below, data is a list of panda dataframes.

def callback(attrname, old, new):
    month = slider.value
    source.data = ColumnDataSource(data[month]).data

This replaces the current data for the graph with data from a different pandas dataframe. If, like me, all your data is in one data frame, you could also do some pandas filtering to return the data that you want to display.

data_to_use = data[data['Month'] == month[slider.value]]

Again, when I did that, I had to convert data_to_use to a ColumnDataSource and then replace the .data attribute of the source for my graph.

0

The Gapminder example from the Bokeh gallery does this using years, a similar approach should work for Months for your dataset. As you are only worried about months, you don't need to work with a datetime index, just get it as a list.

gapminder

Not the answer you're looking for? Browse other questions tagged or ask your own question.