Using Bokeh I would appreciate some help to scale plots Y axis as a function of X range following a zoom event for instance. The idea is to have a number of plot strips showing for instance motors current over time. When zooming over a particular X range of one strip all the other strips would zoom to the same X range and on their Y axis scale their data to fit this range. For a given time window (from user zoom) all the plots would zoom in. I have this autoscale working with matplotlib and I would like now to have the equivalent in Bokeh. I’ve copied the matplotlib code which hopefully can clarify what I am after. With Bokeh I guess I will have to:
- link x range over the multiple plot strips
- call a piece of javascript with a callback on a change event of x_range like fig.x_range.callback = CustomJS( …
But that’s as far as I got to. I don’t really understand yet how to access all the parameters I would need to compute the scaling of all the plots. I’m new to Bokeh and JS so have to go through the learning curve. But if someone already has a good idea of how to proceed that would help a lot. In the meantime I will continue with some tentative coding.
import math
from matplotlib import pyplot as plt
from matplotlib import ticker as ticker
import numpy as np
def rescale_y(ax):
setmargin = 0.05
xmin, xmax = ax.get_xlim()
axes = ax.figure.get_axes()
for axis in axes:
lines = axis.get_lines()
ylo = math.inf
yhi = -math.inf
for line in lines:
x, y = line.get_data()
cond = (x >= xmin) & (x <= xmax)
yrest = y[cond]
margin = (yrest.max()-yrest.min())*setmargin
new_ylo = yrest.min()-margin
new_yhi = yrest.max()+margin
if new_ylo < ylo: ylo = new_ylo
if new_yhi > yhi: yhi = new_yhi
axis.set_ylim(ylo,yhi)
axis.figure.canvas.draw()
# Prepare dummy data to plot
x = np.arange(0,100)
y1 = x
y2 = np.power(x, 2)
y3 = x + 10
# Prepare plots
fig, ax = plt.subplots( 2, 1, squeeze=False, sharex='col' )
#plt.subplots_adjust( hspace=0.05, left=0.05, right=0.99, top=0.95, bottom=0.05 )
fig.suptitle( 'my example' )
ax[0,0].plot( x, y1, c='blue', linewidth=1, label='plot 1')
ax[0,0].plot( x, y2, c='red', linewidth=1, label='plot 2')
ax[1,0].plot( x, y3, c='green', linewidth=1, label='plot 3')
# Set callbacks on xlim changed
axes = fig.get_axes()
for i in axes:
i.callbacks.connect('xlim_changed', rescale_y)
# Display plots
plt.show()