Search code examples
pythonbokeh

bokeh: retrieve axis ticker interval of BasicTicker


I am trying to calculate a (cross-sectional) average for each major interval on an x-axis, in order to do this I have to retrieve the label interval. My X-axis p.axis.ticker ticker is a BasicTicker object. This object has a base=10 and mantissas=[1, 2, 5].

I see on the x-axis that the labels show with an interval of 20 units (this number is what I am after), but another complication is that the figure is dynamic. The variable used for the X-axis can be changed, and therefore the interval automatically changes due to scaling (some variables are in the range of 0.1-0.5, others 5-10 e.g.). For this reason I need to gain access to the interval variable.

from bokeh.io import curdoc
from bokeh.layouts import column, layout
from bokeh.models import ColumnDataSource, Select
from bokeh.plotting import figure

axis_map = {
    "Return": "ret",
    "Holding period": "holdp",
    "Data source": "source",
}
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="Holding period")
y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="Return")

source = ColumnDataSource(data=dict(x=[], y=[]))

p = figure(plot_height=600, plot_width=700, title="", sizing_mode="scale_both")
scatter = p.scatter(x="x", y="y", source=source, size=4, color="color", fill_alpha="alpha", marker="marker")

def update_data()
   ...
   interval = p.axis.ticker.*get_interval()*
   df['interval_group'] = df[x_name].apply(lambda x: interval*round(x/interval))
   y_avg = df.groupby('interval_group')[y_name].mean()
   source.data = dict(x=..,
                      y=..,
                      y_avg=y_avg
                      )

controls = [x_axis, y_axis]
for control in controls:
     control.on_change('value', lambda attr, old, new: update())

inputs = column(*controls, width=320, height=1000)
inputs.sizing_mode = "fixed"
l = layout([
    [inputs, p, h],
], sizing_mode="scale_both")
            
update()
            
doc = curdoc()
doc.add_root(l)
doc.title = "Test"

Solution

  • In BokehJS, ContinuousTicker (a parent class of BasicTicker) has an abstract get_interval method - seems like it's exactly what you need. But neither this method nor anything that uses it is exposed on the Python side. Well, at least as far as I can tell.

    To get the required value, I would either recreate the body of the get_interval method in Python or create a custom ticker (or an axis, likely) where the only custom behavior is to send the computed value to the Python side.