5

I want to add BoxAnnotation to a plot that has a datetime x-axis. How can I set the left and right limits of of the BoxAnnotation to a datetime or date object. This is what I'm aiming for but it doesn't work.

from bokeh.sampledata.glucose import data
from bokeh.models import BoxAnnotation
from datetime import *

# output_file("box_annotation.html", title="box_annotation.py example")

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"

#reduce data size
data = data.ix['2010-10-06':'2010-10-13']

p = figure(x_axis_type="datetime", tools=TOOLS)

p.line(data.index.to_series(), data['glucose'],
       line_color="gray", line_width=1, legend="glucose")

left_box = BoxAnnotation(plot=p, right=date(2010,10,7), fill_alpha=0.1, fill_color='blue')
mid_box = BoxAnnotation(plot=p, left=date(2010,10,8), right=date(2010,10,9), fill_alpha=0.1, fill_color='yellow')
right_box = BoxAnnotation(plot=p, left=date(2010,10,10), fill_alpha=0.1, fill_color='blue')

p.renderers.extend([left_box, mid_box, right_box])

p.title = "Glucose Range"
p.xgrid[0].grid_line_color=None
p.ygrid[0].grid_line_alpha=0.5
p.xaxis.axis_label = 'Time'
p.yaxis.axis_label = 'Value'

show(p)
DrJMcAuliffe
  • 348
  • 4
  • 15

2 Answers2

6

The current BoxAnnotation implementation only accepts NumberSpec types (floats and ints) as inputs. The current work around would be to convert your datetime object to a timestamp (and scale it by 1e3 because Bokeh internally uses microsecond precision, no millisecond)

So it'd like: (uses python3 datetime.timestamp method)

from datetime import datetime as dt

...
left_box = BoxAnnotation(plot=p, right=dt(2010,10,7).timestamp()*1000, fill_alpha=0.1,   fill_color='blue')
mid_box = BoxAnnotation(plot=p, left=date(2010,10,8).timestamp()*1000,   right=date(2010,10,9).timestamp()*1000, fill_alpha=0.1, fill_color='yellow')
right_box = BoxAnnotation(plot=p, left=date(2010,10,10).timestamp()*1000, fill_alpha=0.1, fill_color='blue')

p.renderers.extend([left_box, mid_box, right_box])
...

It does seem like a valuable feature, to add support for datetime objects as a parameter. I've opened a Github issue that you can comment on/follow:

https://github.com/bokeh/bokeh/issues/2944

Luke Canavan
  • 2,107
  • 12
  • 13
  • Thanks Luke, you pointed me in the right direction. But since I'm on python 2.7 I had to use a little hack to get the timestamp (found it here: http://stackoverflow.com/questions/8777753/converting-datetime-date-to-utc-timestamp-in-python) `from __future__ import division from datetime import datetime, timedelta def totimestamp(dt, epoch=datetime(1970,1,1)): td = dt - epoch # return td.total_seconds() return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6` – DrJMcAuliffe Oct 05 '15 at 19:20
3

Bokeh now supports timestamps for box annotations!

import pandas as pd
...
left_box = BoxAnnotation(plot = p, right = pd.to_datetime('2010-10-07'), fill_alpha=0.1,   fill_color='blue')
...

This works with bokeh 0.12.9, and Python >2.7.

s3b4s
  • 93
  • 6
  • This seems to be broken currently (using **BokehJS version 3.0.2** here)? I get, for example : `ValueError: failed to validate BoxAnnotation(id='p5934', ...).left: expected an element of either Null, Float or Factor(Either(String, Tuple(String, String), Tuple(String, String, String))), got (Timestamp('1944-06-06 00:00:00'),)`. – Nikos Alexandris Dec 02 '22 at 23:26
  • Support re-added in 3.1, see : https://discourse.bokeh.org/t/does-boxannotation-not-support-timestamps/9799/2?u=nikosalexandris – Nikos Alexandris Dec 04 '22 at 10:28