I’m going slightly crazy trying to debug this. I am using Patches to highlight area under the curve. The patches are rendered fine on app load (bokeh server 0.12.4).
The plot has a slider. When this is updated, the vertical line and the point on the curve are updated to new locations as expected, but the patches are not. Not only that but I am getting this warning: “Supplying a user-defined data source AND iterable values to glyph methods is deprecated”. This is definitely connected to the patches but cannot work out why.
A few things I’ve double checked (bolded areas in the code below):
-
I am ensuring that plot.patches uses string references ‘x’ and ‘y’ associated with ColumnDataSource **ppf_plot_auc_source (**so I cannot see the reason for the warning above?!).
-
I am ensuring that auc_x and auc_y are “lists of lists” by wrapping the 1d numpy arrays into a list. Printing shape shows that they are always the same shape, even when the slider is updated. Printing also shows that patches coordinates are correctly recalculated on slider update.
Any thoughts or pointers would be greatly appreciated? It feels like I’m missing something really obvious! (code is fully reproducible for those who would be willing to take a couple of minutes to run this)
import numpy as np
import scipy
from scipy import stats
from bokeh.io import curdoc
from bokeh.layouts import gridplot
from bokeh.plotting import figure
from bokeh.models import ResetTool, HoverTool, LassoSelectTool
from bokeh.models import PolySelectTool, BoxSelectTool
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider
from bokeh.models.widgets import Div
OPTIONS
we will create a distribution with these moments
MOMENTS = dict(loc=0, scale=1)
params for creating evenly spaced probabilities between 0.0001 and 0.9999
LO_PROB = 0.01
HI_PROB = 0.99
N_PROBS = 100
lower tail probability
P = 0.025
create a distribution
mydist = scipy.stats.norm(**MOMENTS)
generate probabilities
PROBS = np.linspace(start=LO_PROB, stop=HI_PROB, num=N_PROBS)
calculate quantiles of given list of probabilities
QUANTILES = mydist.ppf(PROBS)
*** INTERACTIONS
slider to control the lower tail probability
slider_lower_tail_prob = Slider(title=‘Lower Tail Probability’,
start=0,
end=1,
step=0.01,
value=P)
tools = [
BoxSelectTool(),
HoverTool(),
PolySelectTool(),
LassoSelectTool(),
ResetTool()
]
def gen_ppf_plot_data(mydist, p):
"""
Generate data for PPF plot curve, vertical line, area
under the curve and point on the curve
"""
# quantile associated with lower tail probability
p = np.array([p])
q = mydist.ppf(p)
# print "p: {0}".format(p.shape)
# print "q: {0}".format(q.shape)
# *** DATA FOR AREA UNDER THE CURVE
# patches xs coordinates is made up of 2 concatenated arrays
# first is x axis positions and
# the second is x positions reversed
auc_x_ = np.linspace(start=QUANTILES[0], stop=q, num=N_PROBS)
auc_x = np.append(auc_x_, auc_x_[::-1])
print "auc_x.shape: {0}".format(auc_x.shape)
# print "\n\nauc_x: {0}\n".format(auc_x)
auc_x = [auc_x]
# patches ys coordinates is made up of 2 concatenated arrays,
# first is zeroes (as we want the shading to start at y=0)
# the second is f(<x positions reversed>)
auc_y = np.append(np.zeros(auc_x_.shape[0]),
1 - mydist.sf(auc_x_[::-1]))
print "auc_y.shape: {0}".format(auc_y.shape)
# print "auc_y: {0}\n".format(auc_y)
auc_y = [auc_y]
# *** DATA FOR FUNCTION CURVE
f_x = QUANTILES
f_y = PROBS
# *** DATA FOR VERTICAL LINE (from quantile to curve)
l_x = np.array([q, q])
l_y = np.array([[0], p])
# *** POINT ON CURVE (corresponding lower tail probability)
p_x = np.array([q])
p_y = np.array([p])
return {
'p': p,
'q': q,
'auc_x': auc_x,
'auc_y': auc_y,
'f_x': f_x,
'f_y': f_y,
'l_x': l_x,
'l_y': l_y,
'p_x': p_x,
'p_y': p_y
}
def update_lower_tail_prob(attr, old, new):
p = slider_lower_tail_prob.value
# update data source objects
# PPF plot
ppf_plot_data = gen_ppf_plot_data(mydist, p)
ppf_plot_qp.data = {'x': ppf_plot_data['q'],
'y': ppf_plot_data['p']}
ppf_plot_auc_source.data = {'x': ppf_plot_data['auc_x'],
'y': ppf_plot_data['auc_y']}
ppf_plot_f_source.data = {'x': ppf_plot_data['f_x'],
'y': ppf_plot_data['f_y']}
ppf_plot_l_source.data = {'x': ppf_plot_data['l_x'],
'y': ppf_plot_data['l_y']}
ppf_plot_p_source.data = {'x': ppf_plot_data['p_x'],
'y': ppf_plot_data['p_y']}
“”"
PPF Plot (Quantile Function)
“”"
create data source objects
ppf_plot_data = gen_ppf_plot_data(mydist, P)
ppf_plot_qp = ColumnDataSource(
data={'x': ppf_plot_data['q'],
'y': ppf_plot_data['p']})
ppf_plot_auc_source = ColumnDataSource(
data={'x': ppf_plot_data['auc_x'],
'y': ppf_plot_data['auc_y']})
ppf_plot_f_source = ColumnDataSource(
data={'x': ppf_plot_data['f_x'],
'y': ppf_plot_data['f_y']})
ppf_plot_l_source = ColumnDataSource(
data={'x': ppf_plot_data['l_x'],
'y': ppf_plot_data['l_y']})
ppf_plot_p_source = ColumnDataSource(
data={'x': ppf_plot_data['p_x'],
'y': ppf_plot_data['p_y']})
quantile associated with lower tail probability
q = max(ppf_plot_qp.data[‘x’])
p = max(ppf_plot_qp.data[‘y’])
construct plot elements
plot = figure(plot_width=600,
plot_height=400,
title='Quantiles ~ Lower Tail Probabilities (PPF)',
tools=tools)
*** AREA UNDER THE CURVE
plot.patches(xs=‘x’, ys=‘y’,
fill_color=[‘LightSteelBlue’],
line_color=None,
alpha=0.6,
source=ppf_plot_auc_source)
*** FUNCTION CURVE
plot.line(x=‘x’, y=‘y’,
line_color='SteelBlue',
line_width=3,
source=ppf_plot_f_source)
*** VERTICAL LINE
plot.line(x=‘x’, y=‘y’,
line_color='black',
line_width=3,
source=ppf_plot_l_source)
*** POINT ON CURVE
plot.circle(x=‘x’, y=‘y’,
line_color='black',
fill_color='black',
line_width=3,
source=ppf_plot_p_source)
text = “”"Quantile corresponding to lower tail probability {p} is {q:.3f} (the quantile below which {pct:.2f}% of values are likely to be lower than)
""".format(p=p,
q=q,
pct=p * 100.0)
div = Div(text=text, width=600, css_classes=[“customdiv”])
slider_lower_tail_prob.on_change(‘value’, update_lower_tail_prob)
grid = gridplot([[slider_lower_tail_prob], [plot], [div]])
curdoc().add_root(grid)
``
Thank you!