Jess
January 31, 2025, 9:25am
1
Hi all,
I am trying to implement a circular callback that would recursively process elements in a list (stored in a Store component).
For some reason the callback is only fired once. Am I doing something wrong? Is it possible to achieve what I have in mind?
from dash import Dash, dcc, callback, Input, Output, State
app = Dash(__name__)
app.layout = [
dcc.Store(
id='store',
data=[1, 2, 3]
),
dcc.Store(
id='even-store',
data=[]
),
dcc.Store(
id='odd-store',
data=[]
)
]
@callback(
Output('store', 'data'),
Output('even-store', 'data'),
Output('odd-store', 'data'),
Input('store', 'data'),
State('even-store', 'data'),
State('odd-store', 'data')
)
def classify(remaining, evens, odds):
if remaining:
n = remaining[0]
if n % 2 == 0:
print(f"even: {len(remaining)}")
return remaining[1:], evens + [n], odds
else:
print(f"odd: {len(remaining)}")
return remaining[1:], evens, odds + [n]
else:
print(f"nothing")
return []
debug = True
if __name__ == '__main__':
app.run(debug=debug, use_reloader=debug)
Output:
* Serving Flask app 'test_app'
* Debug mode: on
odd: 3
Expected output:
* Serving Flask app 'test_app'
* Debug mode: on
odd: 3
even: 2
odd: 1
nothing
Hello @Jess ,
Welcome to the community!
I don’t think you can do this, since the callback is updating itself it’s not going to work.
You could update a button or some other component.
Actually, remove the output to itself, and instead use set_props, to itself. This will bypass the check for the circular output.
Jess
January 31, 2025, 9:53am
3
I was trying to follow the example in Advanced Callbacks | Dash for Python Documentation | Plotly where Input and Output are effectively the same.
I have never tried set_props (or clientside_callback for that matter). Will have a look now.
Thanks!
For your example, I’d do this:
from dash import Dash, dcc, callback, Input, Output, State
app = Dash(__name__)
app.layout = [
dcc.Store(
id='store',
data=[1, 2, 3]
),
dcc.Store(
id='even-store',
data=[]
),
dcc.Store(
id='odd-store',
data=[]
)
]
@callback(
Output('even-store', 'data'),
Output('odd-store', 'data'),
Input('store', 'data'),
State('even-store', 'data'),
State('odd-store', 'data')
)
def classify(remaining, evens, odds):
if remaining:
n = remaining[0]
dash.set_props('store': {'data': remaining[1:]})
if n % 2 == 0:
print(f"even: {len(remaining)}")
return evens + [n], odds
else:
print(f"odd: {len(remaining)}")
return evens, odds + [n]
print(f"nothing")
return [], []
debug = True
if __name__ == '__main__':
app.run(debug=debug, use_reloader=debug)
1 Like
Jess
January 31, 2025, 10:19am
5
Thanks, it looks like this works. I wasn’t aware set_props was available directly from dash.
FYI, you have a typo in
dash.set_props('store': {'data': remaining[1:]}
It should be
dash.set_props('store', {'data': remaining[1:]}
Not sure if you want to edit or if I should accept the solution as is?
Updated.
And yes, set_props
is available in python and the clientside. The caveat is that its not subject to Dash restraints.
Jess
February 1, 2025, 7:45am
7
Thanks, I just came back to Python Dash and I had missed this. If I may ask, the .set_props
looks pretty much like what a regular callback with an Output
does, so why don’t we use .set_props
everywhere? I’m guessing there is a good reason, .set_props
just looks like cheating.
Jess
February 1, 2025, 7:49am
8
Ah never mind, just read https://dash.plotly.com/advanced-callbacks#setting-properties-directly and it’s very clear already. Thanks for your support!
2 Likes