Another option if you don’t want to get into the lower levels of making a custom tool or modification is to try a periodic callback in Javascript. Something like this as a modification to what was posted earlier in the thread as a starting point.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
"""
import numpy as np
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, RangeTool
from bokeh.plotting import figure
from bokeh.sampledata.stocks import AAPL
from bokeh.events import MouseMove
from bokeh.models import CustomJS
dates = np.array(AAPL['date'], dtype=np.datetime64)
source = ColumnDataSource(data=dict(date=dates, close=AAPL['adj_close']))
p = figure(plot_height=300, plot_width=800, tools="xpan", toolbar_location=None,
x_axis_type="datetime", x_axis_location="above",
background_fill_color="#efefef", x_range=(dates[1500], dates[2500]))
p.line('date', 'close', source=source)
p.yaxis.axis_label = 'Price'
select = figure(title="Drag the middle and edges of the selection box to change the range above",
plot_height=130, plot_width=800, y_range=p.y_range,
x_axis_type="datetime", y_axis_type=None,
tools="", toolbar_location='right', background_fill_color="#efefef")
range_tool = RangeTool(x_range=p.x_range)
range_tool.overlay.fill_color = "navy"
range_tool.overlay.fill_alpha = 0.2
select.line('date', 'close', source=source)
select.ygrid.grid_line_color = None
select.add_tools(range_tool)
select.toolbar.active_multi = range_tool
cb = CustomJS(args=dict(rng=range_tool), code="""
if (!rng.name) {
rng.name = 'range_tool';
setInterval(function(){console.log('RANGE TOOL active state ' + rng.active);}, 1000)
}
""")
select.js_on_event(MouseMove, cb)
show(column(p, select))