Reset slider to initial values on Reset Click

On clicking the Reset Widget, I would like reset the range_slider to it initial values alongside the main chart. However all my attempts to reset it via Customjs have failed. I have tried all the variations that I could see;

drs.value[0]
drs.change.sender.properties.value.spec.value[0]
drs.exprchange.sender.properties.value.spec.value[0]
etc.
followed by drs.change.emit().

Also tried changing value_throttled.

Where am I going wrong? At worst I can make a call back to the server( I’m running the actual code in django ) to rebuild on reset but this will be wasteful. I’ve stripped down the issue with below script and some dummy data.

Bokeh version = 2.4.3
Python version = 3.8.4
Platform = Windows 11 Home / 21H2

"""
Problem: Cannot get date range slider to reset to initial values when ResetTool is clicked.
Attempting to do via Javascript.  

Standalone script with all extraneous code taken out to focus on issue.  
"""

from bokeh.models import layouts, Range1d
from bokeh.layouts import column, layout
from bokeh.plotting import figure, show, ColumnDataSource
from bokeh.transform import factor_cmap, factor_mark

from bokeh.io import show
from bokeh.models import (
    CustomJS,
    RangeSlider,
)

from random import randint, choices

if __name__ == "__main__":

#Generate some random data
    y = [randint(0, 20) for x in range(10) ]
    x = [x for x in range(10)]

# Some categorisation for scatter points
    PERSONS = ['Bob', 'Mary', 'Jo']
    MARKERS = ["hex", "circle", "triangle"]
    per = choices(population = PERSONS, k=10)

    p = figure(
        title = 'Range widget reset',
        tools="pan,box_zoom,reset,save",
        plot_width=1000,
        plot_height=500,
        y_axis_type="auto",
        x_axis_type="auto",
        x_axis_label="X axis",
        y_axis_label="y axis",
    )

    p.sizing_mode = "scale_both"

    p.x_range = Range1d(0, 10)
    p.y_range = Range1d(0, 20)

    source = ColumnDataSource(data={'xval': x, 'yval': y, 'person': per })
    #print(source.column_names)

    scat = p.scatter(
        x="xval",
        y="yval",
        legend_group="person",
        marker=factor_mark("person", MARKERS, PERSONS),
        color=factor_cmap("person", "Category10_3", PERSONS),
        size=11,
        source=source,
    )
    
    p.legend.location = "bottom_right"
    p.legend.click_policy = "hide"

    # Date Range Slider widget
    range_slider = RangeSlider(
        value=(0, 10),
        start=0,
        end=10,
        sizing_mode="scale_width",
        value_throttled=(0, 10),
    )

    xrange_callback = CustomJS(
        args=dict(xrange=p.x_range, plt=p, rs=range_slider),
        code="""

    xrange.start = this.value_throttled[0];
    xrange.end = this.value_throttled[1];
    xrange.change.emit();

    debugger;
    """,
    )

    # Update the x-axis based on the slider
    range_slider.js_on_change("value_throttled", xrange_callback)


# Try and reset the slider to initial positions after reset click
    p.js_on_event('reset', CustomJS(args=dict(drs=range_slider,), code="""
    console.log('Reset tool callback');
    console.log('Value throttled', drs.value_throttled[0])
    console.log('Value start', drs.start)
    console.log('Value value[0]', drs.value[0])
    // No variations of the below appear to work
    // drs.value_throttled[0] = drs.start;
    // drs.value[0] = drs.start;
    // drs.change.emit()
    debugger;
    """))

    layout = column([range_slider, p])
        
    show(layout)
    

Ah, I literally just learned/figured this out today :slight_smile: You basically already have the part I was missing i.e. it’s not a click of the ResetTool, it’s a Reset event on the figure, but what you’re missing is a means of informing the callback what value you want the “reset” value to be.

So just pass it into the callback as one of the args:

from bokeh.plotting import figure, show
from bokeh.models import CustomJS, Slider, ColumnDataSource
from bokeh.layouts import column

f = figure()

ini_val = 5
sl = Slider(value=ini_val,start=0,end=10)

cb = CustomJS(args=dict(ini_val=ini_val,sl=sl)
              ,code='''
              console.log('uhuh this happened')
              sl.value = ini_val
              ''')
f.js_on_event('reset',cb)

show(column([f,sl]))
1 Like