I have two callbacks that are clashing and causing a “Duplicate Callback Outputs” error. They both seek to change the data of a dcc.Store() under different circumstances.
@app.callback(
Output('df-memory', 'data'),
[Input('demo-dropdown', 'value')]
)
def switch_table(playlist_name):
if playlist_name is None:
raise PreventUpdate
else:
playlist = playlists[playlist_name]
data = playlist.to_dict('records')
return data
@app.callback(
Output('df-memory', 'data'),
[Input('search-term-button', 'n_clicks')],
[State('search_term_input', 'value'),
State('table', 'derived_virtual_indices'),
State('df-memory', 'data')]
)
def add_search_word_score(n_clicks, search_words, derived_virtual_indices, data):
if n_clicks and search_words:
scores = []
temp_df = pd.DataFrame.from_records(data)
track_ids = temp_df.loc[derived_virtual_indices, '_id'].tolist()
recs = recommend_tracks(search_words, min_occurences=1, tid_subset=track_ids)
for track_id in track_ids:
if track_id in recs:
scores.append(recs[track_id])
else:
scores.append(0)
temp_df.insert(7, 'Search Score', scores, True)
return temp_df.to_dict('records')
else:
raise PreventUpdate
My error is:
Duplicate callback outputs2:04:58 PM
In the callback for output(s):
df-memory.data
Output 0 (df-memory.data) is already in use.
Any given output can only have one callback that sets it.
To resolve this situation, try combining these into
one callback function, distinguishing the trigger
by using dash.callback_context if necessary.
Currently, it is not possible to have the same output in two different callbacks. You can either put them under same callback, and check from the callback context which one triggered the callback so you can decide which one to give as output, or you can check out the CallbackGrouper of the dash-extensions package which kind of does the same thing under the hood. Afaik the CallbackGrouper component is still in “beta” stage, but it might work in your situation.
Thanks, that’s really good information. A quick follow up:
I have multiple data frames that I want to display via the data table (only one at a time), selected via a dropdown menu. I also want to be able to modify the current dataframe, which is stored in a dcc.Store() component. Would you recommend putting this under one callback, or using the CallbackGrouper? Putting them both under one callback seems, well, clunky, to say the least, but I’m hesitant to use something that’s still in Beta.
I have no personal experience with the CallbackGrouper, I just know that this kind of component exists. So it’s up to you if you want to try it out
Even if you needed to use a common callback, you could make is less clunky by writing the logic into separate functions, and calling them when necessary, inside some if statement that checks for the callback context value.
Now, since your problem is very specific, almost like the “component -> data to Store -> calculate something based on Store -> output to somewhere else” -pattern, you might want take take a look at the CallbackCache of the dash-extensions package mentioned on this thread.
Or, reading you code more carefully, there is another wild idea: could you just save the data into some server-side dictionary-like cache? You could use session key for identifier between users. This would have the plus side that you would not have to send the data back and forth to browser so many times. I haven’t yet done it myself but since dash uses Flask you could try to find some caching mechanisms for Flask and use them.