Cannot get customJS to trigger off changes to RangeTool or Range1d objects

I am trying to filter data using the RangeTool object. My plan is to trigger some custom JS to perform the selection I want when the RangeTool range is changed, however nothing I have tried seems to respond to such changes. Here is a simple example:

# Test customJS on RangeTool range change

import numpy as np
from bokeh.plotting import figure, show
from bokeh.models import RangeTool, Range1d, ColumnDataSource, CustomJS, CustomJSFilter

select = figure(title="Range selection",
                height=200, width=1000)

x = np.arange(0, 10, 0.1)
y = x**2
data = ColumnDataSource(data=dict(x=x, y=y))
select.scatter('x', 'y', source=data)

x_range = Range1d(x.min(), x.max())
range_tool = RangeTool(start_gesture="pan", x_range=x_range)

custom_js = CustomJS(code="""
console.log("range changed!");
""")
x_range.js_on_change("start", custom_js)
x_range.js_on_change("end", custom_js)

select.add_tools(range_tool)

show(select)

So here my idea was to look for changes to the underlying Range1d object and trigger on those, but I get zero console messages from the above code. I have also tried e.g. range_tool.js_on_change("x_range", custom_js), and on range_tool.overlay, and various others I have forgotten already. Nothing causes the JS to trigger when changing the range overlay in the plot window.

Am I fundamentally misunderstanding something here? Does js_on_change not work how I am thinking? How can I trigger code to run when I change the RangeTool range?

There is an alternative described here: How do I get a "Range Select Tool"? - #10 by bevoorrading, however it seems parts of the solution have been deprecated in the last two years. The _clone() function in particular seems to be gone.

There is also this feature request which maybe was originally supposed to do what I want, [FEATURE] Support BoxSelectTool-like range-setting for the RangeTool · Issue #13646 · bokeh/bokeh · GitHub, but it looks like the way it was implemented it just modifies plot ranges, it doesn’t perform any actual selection on the underlying data like a BoxSelectTool does.

Well it seems that BoxSelectTool pretty much does what I want already. I just added one to my “minimap” figure with dimensions=‘width’ and it works nicely:

      bsel = BoxSelectTool(dimensions='width')
      bsel.continuous = True
      fig.add_tools(bsel)

I can then trigger my customJS off the change in the ‘selected’ attribute of the ColumnDataSource underlying the figure, which is probably the best way to do it anyway:

     source.selected.js_on_change('indices', custom_js)

It’s a little less cool than RangeTool but seems to work for the task more naturally.

@bjfar IMO your original code should work as you expected, so this seems like it might be a bug with the way the range tool updates its ranges. Notably, setting the exact same callback on select.x_range does trigger the console message.

Can you please file a bug report in a GitHub Issue with these details?