Same input and output in a callback

Hi all,

My question is: is not possible to create a callback function with the same value as Input and Output?

To be a little more specific I have a slider whose value I only want changed if a specific condition (press of a button) is met. Otherwise, I want it to keep it’s value. For this, I have formulated my callbacks as follows:

start counter from 0 once button is clicked

@app.callback(
dash.dependencies.Output(‘interval-comp’, ‘n_intervals’),
[dash.dependencies.Input(‘button’, ‘n_clicks’)])
def btn_clicked(btn_click):
return 0

every 1 second change slider values - short demo

@app.callback(
dash.dependencies.Output(‘slider’, ‘value’),
[dash.dependencies.Input(‘button’, ‘n_clicks’),
dash.dependencies.Input(‘interval-comp’, ‘n_intervals’),
dash.dependencies.Input(‘slider’, ‘value’)])
def on_click(btn_click, count_interval, prev_value):
# don’t do this when application is loaded for the first time
if btn_click!=None and count_interval < 81:

    value = slider_vals[count_interval]
    return round(value, 2)
else:
    return prev_value

The problem is am getting an “Error loading layout” message on my browser after adding the Input slider and if I don’t include this, then None is returned as the new value of the slider (if the button hasn’t been clicked)!

Any ideas about how to go about dealing with this?

Thanks,
C.

I’m also interested in this. In my case I wanted to use a multi-dropdown and mouse selection on the graph to filter the same data with selections made on the graph showing up in the dropdown and vice-versa. It’s also not possible (as far as a can see) to have two callbacks with opposite input/output which would be the other natural way to achieve this.

Obviously there’s the possibility of recursion but it should be possible to catch this and prevent updates with an exception when the selection hasn’t actually changed, so if these options are being disallowed rather than being hard to do on the JS side I think there should be the option to allow them.

Okay, before I was only really responding to your post’s title. I’m not 100% sure what you’re trying to do, but maybe you want to your slider to output to holding Div, e.g.:

html.Div([], id='value-container', style={'display': 'none'})

and then pass that value to the button’s callback as a State (not Input) when you press it?

Going back to the title, I have some kind of workaround that might be useful to people. A callback with the same input as output is probably out of the question but you can sidestep the issue by having two callbacks that talk to each other indirectly.

import dash
from dash.exceptions import PreventUpdate
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# create a layout with two multi-select dropdowns
def get_dropdown(n, value=None):
    value = [] if value is None else value
    return html.Div(
        [dcc.Dropdown(
            id='dropdown'+n,
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': 'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
            multi=True,
            value=value
        )],
        id='dropdown-container'+n,

    )
app.layout = html.Div([
    get_dropdown('1'),
    get_dropdown('2'),
    html.Div([], id='previously-selected', style={'display': 'none'})
])


# Callback one recreates the other dropdown using new values
#   and updates the previously-selected value
@app.callback(
    [Output('dropdown-container2', 'children'), Output('previously-selected', 'children')],
    [Input('dropdown1', 'value')],
    [State('previously-selected', 'children')]
)
def update_via_children(value, prev_selected):
    print('callback one')

    if sorted(value) == sorted(prev_selected):
        raise PreventUpdate

    return get_dropdown('2', value=value), value

# Callback two updates the value of dropdown1 directly and so could be used to alter something
#   complicated like a Graph, hopefully. Does not update previously-selected, so callback one
#   will be called again, recreating dropdown2, triggering callback one a second time, but
#   this time previously-selected == value
@app.callback(
    Output('dropdown1', 'value'),
    [Input('dropdown2', 'value')],
    [State('previously-selected', 'children')]
)
def update_directly(value, prev_selected):
    print('callback two')
    if sorted(value) == sorted(prev_selected):
        raise PreventUpdate
    return value


app.run_server(debug=True)
1 Like

I found your post this afternoon, and it saved me a lot of time. Thanks for posting.