✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Callback/Rangeslider

Is there a way to trigger a callback only when a RangeSlider is moved?

Background: I have a range slider in a div with a datatable. I would like to use that range slider to update both the table and some bar/scatter plots in other divs. I have most of this working with the following code:

@app.callback(Output('bar-graph','children'),
                [Input('range_slider','value')])
def update_bar(slider_range):
         things get updated

The problem I am having is that the interactive controls on the plots in other divs become unusable as the callback is continually triggered. I think I could use a button to trigger, but space is at a premium, and the user interface would be better if it just worked off the slider.

I am looking for something like:

@app.callback(Output('bar-graph','children'),
                [Input('submit-button','nclicks')],
                [State('number-in', 'value')]
def update_bar(slider_range):

but I can’t seem to find the property similar to nclicks.

Thanks

Hi @Bill_M, the default updatemode of a dcc.Slider is mouseup (see https://dash.plot.ly/dash-core-components/slider), so that the callback should only be triggered when the mouse is released. Therefore it’s not so different from the behaviour of a button and n_clicks. Could it happen that you set the updatemode to drag?

@Emmanuelle: Thanks for the note. No and I explicitly set it to “mouseup” after reading the docs (though I guess I could have trusted the defaults.)

But even if I did that, wouldn’t the callback trigger every time I tried to use a zoom (or any other) tool?

This probably isn’t the way Dash was intended to be used, but my hope was to use the slider and a drop down in one div to generate all callbacks and the modebarbuttons to allow individual graphs to be zoomed and examined without changing the underlying data (effectively just a visual zoom.)

Hum I’m not sure I understand. The callback you provided will only be triggered when the slider is moved (on mouseup), not when graphs are zoomed etc. Do you have another callback modifying the slider value from Python?
Please provide more code with how the graphs are generated, ideally you would include a standalone code using dummy data or adapted from one of the dash tutorials.

This might make things as clear as mud…but picture a page that has two rows. First row, 3 divs: data table/rangeslider, barchart, map.
Second Row, full width scatter plot.

setup
Initiate and slice various dfs for later use. These dfs are copied and resliced as appropriate on callbacks. Individual divs from #above rerendered.


app.layout = html.Div([

# First Row
html.Div(children = [

# Data Table
html.Div(id='summary_table',children = [
        html.H1('Boston',style={...}),

        dash_table.DataTable(id='table',
        columns=[{"name": i, "id": i} for i in table_df.columns],
        data=table_df.to_dict('records'),
        style_cell={...},
        style_as_list_view=True,
        style_cell_conditional=[
        {},
        {},
        {}
        ]),

    html.Div(children=[dcc.RangeSlider(id='range_slider',
        ...
        updatemode='mouseup')],
    style={}),  #End Div 1

html.Div(id='bar-graph',children = [\
dcc.Graph(figure=,
    config={'modeBarButtonsToRemove': ['toggleSpikelines',
    ...]},
    style={}), #End Div 2

html.Div(children = [an Iframe]),

# set the sizing of the first row parent div
style = {'display': 'inline-block',
}),#<--End Div3 and First Row
html.Hr(),

#4 Readings per year
html.Div(id='yearly-scatter',children = [
dcc.Graph(figure=...,
            config={'modeBarButtonsToRemove': ['toggleSpikelines',
            "select2d", "lasso2d","hoverCompareCartesian"]},

             style={})])#End second Row

])

@app.callback(Output(‘summary_table’,‘children’),
[Input(‘range_slider’,‘value’)])
def update_value(slider_range):

....

table_df=func.make_summary_table(all_days_df,bf_slope)
child=[
        html.H1('Boston',style={...}),
        dash_table.DataTable(id='table',
        columns=[{"name": i, "id": i} for i in table_df.columns],
        data=table_df.to_dict('records'),
        style_cell={...},
        style_as_list_view=True,
        style_cell_conditional=[
        {},
        {},
        {}
        ])

    html.Div(children=[dcc.RangeSlider(id='range_slider',
        min=xnew, max=ynew, step=10,
        marks={i: i for i in range()},
        updatemode='mouseup',
        value=[slider_range[0],slider_range[1]])],
    style={'margin-top':'15px','vertical-align':'bottom'}),

        ]
return child

@app.callback(Output(‘bar-graph’,‘children’),
[Input(‘range_slider’, ‘value’)])#,
#[State(‘range_slider’,‘value’)])
def update_bar(slider_range):

.etc

if name == ‘main’:
app.run_server()

So without the mess above, this will functionally do what I want:

@app.callback(Output(‘bar-graph’,‘children’),
[Input(‘update-plots’, ‘n_clicks’)],
[State(‘range_slider’,‘value’)])
def update_bar(n_clicks,slider_range):

where:
update-plots is the id of a button

but:
a) I don’t ever use n_clicks in the update_bar portion
b) The plots do update everytime I move the slider, however, I can use the built in interactive controls from Plotly, so this OK functionally
c) I am never using the update-plots button (though it is functional, but because the plots update on slider movement, it doesn’t really do anything.)

So this isn’t perfect, but it would work if I could hide the button in the background. Is there a way to turn off the button display? I changed the text and background to match the div it resides in, but I can’t seem to kill the shadows.

Thanks