PJW PJW - 2 months ago 15
Python Question

Bokeh Ray glyph not displaying when length defined

I am attempting to use the Bokeh Ray glyph to display wind direction data. My x-data is datetime (at 1-day resolution). I have a Pandas dataframe that includes a datetime-indexed column of wind direction data (one entry per day, ranges 0-360 degrees). The Ray function seems like it should be perfect, however when I define

length
the ray segments do not render. If I set
length=0
(which forces the ray segment to span the entire plot window), then the rendering is successful.

Relevant code:

def make_avewindspddir_fig(df):

fig = figure(
title="Average Wind Speed & Direction",
name="avewindspddir_fig",
x_axis_type='datetime',
y_axis_label='wind speed (mph)',
width=900, height=250
)

newcds = create_avewindspddir_cds(df, 'summit', start, end)

avewinddirrays = fig.ray(x='Date', y='y_zeros', length=0,
length_units='data', angle='avewinddir', angle_units='deg',
color='black', line_width=2, source=newcds)

fig.y_range = Range1d(-20, 100)

return fig


The Pandas dataframe I pass to the 'create_avewindspddir_cds' function (which creates the newcds) contains a datetime index, average wind speed, max wind gust, ave wind direction (degrees), and 'y_zeros' (a column of zeros that I use as the origin point for each ray, equal in length to all other columns). The date range is input by the user and define 'start' and 'end'.

The code above (along with code for plotting wind speed and gust lines) produces the following figure. This is a single panel among many other panels in my layout, so I will just use a screenshot (click for zoomed view):
enter image description here

The rays are rendering the angle data correctly, and the plot essentially seems perfect if I could get control of the length parameter. The idea here is to have small wind direction vectors plotting for each day, displaying below the average wind speed and max gust lines (each ray has origin at y=0). If I change the ray plotting code to this (changing the
length
parameter to 10):

avewinddirrays = fig.ray(x='Date', y='y_zeros', length=10,
length_units='data', angle='avewinddir', angle_units='deg',
color='black', line_width=2, source=newcds)


...the rays simply do not plot (and I get no error messages in my terminal). I have tried length values from 0.1 to 1000, and I have tried using length units of 'screen' and 'data'.

Likely, this is a problem related to having datetime values for my x-axis, and integers for my y-axis (do 'length' units in the data-space refer to x-axis units or y-axis units?).

As a follow-up question, is there a way to put an arrow symbol on one end of the ray?

EDIT: In response to @bigreddot....
One additional piece that is key to making this work:
If using wind direction data (with compass directions in degrees), the data must first be rotated for Ray to plot it correctly. Note that Ray rotates angles up from the horizontal x-axis. To convert compass directions, the following code works:

# a: 0-90
a = winddir.ix[(winddir > 0) & (winddir <= 90)]
a_rotate = (a - 90)*-1
a_rotate.name = 'a_rotate'

# b: 90-180
b = winddir.ix[(winddir > 90) & (winddir <= 180)]
b_rotate = (b - 450)*-1
b_rotate.name = 'b_rotate'

# c: 180-360
c_d = winddir.ix[(winddir > 180) & (winddir <= 360)]
c_d_rotate = 360 - c_d + 90
c_d_rotate.name = 'c_d_rotate'

# retain the nulls!
nulls = winddir[winddir.isnull()==True]
nulls.name = 'nulls'

# put it back together:
avewinddir_rotate = pd.concat([a_rotate, b_rotate, c_d_rotate, nulls])
avewinddir_rotate.sort_index(inplace=True)


Also, because arrows are not possible, I achieved the same effect using circles:

circles = fig.circle(x='Date', y='y_zeros',size=4, line_color='black',
fill_color='white', line_width=2, source=newcds)


All that is needed is a symbol to orient one end of the Ray. In this case, the Ray rotates around the circle and indicates where the wind is from (as is standard with wind barbs). Here is my resulting figure:

enter image description here

Answer Source

Ray length is currently measured only according to the x-axis scale. In your case, the x-axis is measuring datetimes, which are expressed in milliseconds since epoch. With data units, you'd probably need to make the length values be tens of millions or more before they become visible on the scale of months.

I would expect things to show up with screen units, however (length measured in pixels). Perhaps there's a bug, so I'd suggest filing a GitHub issue. You might also suggest (in a separate issue) adding a property to make it configurable which direction the measurement happens along (an easy addition, already available for circle radii)

Finally, this looks like an interesting example. If it is something you can pare down to bare basics and share, please consider contributing an example(s) for the gallery or docs.