3

I have recently started working in Bokeh, finished some quick course on datacamp and I got stuck on creating a DateRangeSlider. Slider itself looks ok to me, changing the values on the slider works, but I can't make it to change the plot.

Not sure what am I missing as I can't find proper tutorials / info on using this particular tool, so any help on that would be highly appreciated.

Here's the code:

data['periodFrom'] = pd.to_datetime(data['periodFrom']).dt.date
data = data.rename(columns={'MWh/h' : 'MWH'})
source = ColumnDataSource(data={
    'x'       : data.periodFrom,
    'y'       : data.MWH,
    'point'      : data.pointLabel,
    'direction'      : data.directionKey
})
xmin, xmax = min(data.periodFrom), max(data.periodFrom)
ymin, ymax = min(data['MWH']), max(data['MWH'])

plot = figure(title='Gas renomination', plot_height=400, plot_width=700,
              x_range=(xmin, xmax), y_range=(ymin, ymax))

plot.line(x='x', y='y', source=source)

plot.xaxis.axis_label ='Date'
plot.yaxis.axis_label = 'MWh/h'

def update_plot(attr, old, new):
    yr = slider.value
    new_data = {
    'x'       : data.loc[yr[0]:yr[1]].periodFrom,
    'y'       : data.loc[yr[0]:yr[1]].MWH,
    'point'      : data.loc[yr[0]:yr[1]].pointLabel,
    'direction'      : data.loc[yr[0]:yr[1]].directionKey
    }
    source.data = new_data

slider = DateRangeSlider(start=date(2016,1,1), end=date.today(), step=1, 
         value=(date(2016,1,1),date(2016,2,1)), title='Date', width=1000)

slider.on_change('value', update_plot)

curdoc().add_root(plot)
curdoc().add_root(slider)
show(plot)

And here's the error message I get in the commmand prompt every time I change slider's value:

2018-07-19 11:56:55,387 error handling message Message 'PATCH-DOC' (revision 1): KeyError(1451606400000,)

Best, Piotrek

EDIT:

I did some work on the slider, now not raising any errors, but the plot vanishes when I move the slider in any direction. Individually filtering works well (i.e. when I put 'data[data.index > yr[0]].periodFrom' in the console), but it seems like there's something wrong with updating the plot with new values.

data['periodFrom'] = pd.to_datetime(data['periodFrom'])
data.index = data['periodFrom'].astype(np.int64) // 10 ** 9
data.index = data.index.astype(np.float)

data = data.rename(columns={'MWh/h' : 'MWH'})
source = ColumnDataSource(data={
    'x'       : data.periodFrom,
    'y'       : data.MWH,
    'point'      : data.pointLabel,
    'direction'      : data.directionKey
})

xmin, xmax = min(data.periodFrom), max(data.periodFrom)
ymin, ymax = min(data['MWH']), max(data['MWH'])

# Create the figure: plot
plot = figure(title='Gas renomination', plot_height=400, plot_width=700,
              x_range=(xmin, xmax), y_range=(ymin, ymax))

plot.line(x='x', y='y', source=source)

plot.xaxis.axis_label ='Date'
plot.yaxis.axis_label = 'MWh/h'

#slider
def update_plot(attr, old, new):
    yr = slider.value
    yr=list(yr)
    [float(i) for i in yr]
    new_data = {
        'x' : data[(data.index > yr[0]) & (data.index < yr[1])].periodFrom,
        'y' : data[(data.index > yr[0]) & (data.index < yr[1])].MWH,
        'point' : data[(data.index > yr[0]) & (data.index < yr[1])].pointLabel,
        'direction' : data[(data.index > yr[0]) & (data.index < yr[1])].directionKey}

print(new_data)
source.data = new_data

slider = DateRangeSlider(start=datetime(2016,1,2).timestamp(), 
end=datetime.today().timestamp(), step=1, value= 
(datetime(2016,2,2).timestamp(),datetime(2016,3,3).timestamp()), title='Date', 
width=1000)
slider.on_change('value', update_plot)

#dropdown

def update_dropdown(attr, old, new):
    point_select = select.value
    data_selected ={
        'x' : data[data['pointLabel'] == point_select].periodFrom,
        'y' : data[data['pointLabel'] == point_select].MWH,
        'point' : data[data['pointLabel'] == point_select].pointLabel,
        'direction' : data[data['pointLabel'] == point_select].directionKey}

    source.data=data_selected

select = Select(title="Point", options=pointlabels, value='Kondratki')
select.on_change('value', update_dropdown)

curdoc().add_root(select)
curdoc().add_root(plot)
curdoc().add_root(slider)

My original dataframe is 40639 x 6, after printing new_data i get a dict:

dict image

I also added a Select widget in the second part of the code, data_selected is the same format as in DateRangeSlider (see: image). What's strange for me is that Select works perfectly, while DataRangeSlider makes the plot vanish every time I click it.

2 Answers 2

3

Although sliders can be initialized with datetime objects for convenience, the slider value is actually represented as a floating point timestamp, specificically, the number of milliseconds since epoch. That means your attempts to index your dataframe directly with the value are roughly equivalent to:

data.loc[1451606400000].periodFrom

Which does not work for obvious reasons.

Based on the name yr, it looks like you want to index your dataframe with values that are years? Then you need to convert the timestamp value to a real datetime and extra the year:

In [6]: from datetime import datetime

In [7]: datetime.fromtimestamp(1451606400000/1000).year
Out[7]: 2015

As an aside, there is never a reason to use or call show in a Bokeh server application.

4
  • Great, thanks a lot! I'm actually indexing with a full date, but I guess I can handle this myself from now on. Cheers!
    – Piotrek
    Commented Jul 20, 2018 at 11:28
  • could you please have a look at the updated post? your solution has helped a lot, but I'm still struggling with connecting slider values with plot.
    – Piotrek
    Commented Jul 24, 2018 at 10:53
  • 1
    I can't really say anything else without a complete example to run. But what I would do is add some print statements to the callback to examine the variable values to see that they are what I expect (or if they aren't) and you can do that as well.
    – bigreddot
    Commented Jul 24, 2018 at 16:57
  • sure, I added some code and a screenshot, if you want i can post the data somewhere so you can run the example. print statement in the mid of update_plot returns 4 times pandas series and 'Name: periodFrom, Length: 934, dtype: datetime64[ns]' after each series.
    – Piotrek
    Commented Jul 25, 2018 at 7:25
0

the DateRangeSlider has the attribute value_as_date which makes the tuple's elements on date format, you just have to make it:

yr = slider.value_as_date

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