✊🏿 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!

Multiple callbacks for an output

From version 0.0.47, a new MultiplexerTransform is included in dash-extensions. It makes it possible to target an output by multiple callbacks (which is otherwise problematic in Dash) with nearly zero code changes,

import dash_html_components as html
from dash_extensions.enrich import Output, DashProxy, Input, MultiplexerTransform

app = DashProxy(prevent_initial_callbacks=True, transforms=[MultiplexerTransform()])
app.layout = html.Div([html.Button("left", id="left"), html.Button("right", id="right"), html.Div(id="log")])


@app.callback(Output("log", "children"), Input("left", "n_clicks"))
def left(_):
    return "left"


@app.callback(Output("log", "children"), Input("right", "n_clicks"))
def right(_):
    return "right"


if __name__ == '__main__':
    app.run_server()

For details on the implementation, see the dash-extensions docs or this thread. The core logic of the implementation was proposed by dwelch91 :slight_smile:

7 Likes

This is great! Thanks for sharing. Would it be possible to, eventually, combine the individual callbacks into a single callback instead? Or is that not the usecase this feature is intended for?

I am not sure I understand what you mean; you can always combine callbacks in Dash? (:

It seems like this Multiplexer allows you to “split” the callbacks such that you can target the same output but via different inputs. I’m unclear in what scenario you’d want to do something like this when the “combined callbacks” is already a thing with Dash.

Could you provide some more context behind why this is needed and how it’s supposed to be used?

It is an issue that is rather common to encounter is Dash**. The “standard” solution is to create one combined callback, which will typically require mixing the logic of otherwise unrelated functions along with not-so-nice dispatch logic (a lot of conditional statements based on inspection of which component triggered the callback).

As a concreate example, consider logging. Say that you have “create”, “save”, “update”, “load”, etc. buttons that perform separate actions, but all needs to write some logging information (e.g. if an error occurs) to the same output. With MultiplexerTransform you can create an a callback for each button with their respective logic. Without it, you would have to create one callback to handle all actions, which will become rather messy (:

** Here are just a few threads on the topic,

Is this different from the GroupTransform from the previous version of the extension?

Yes. You don’t need to add groups anymore. And the callbacks are no longer grouped :slight_smile:

Thanks @Emil for your great works with dash-extension. I love your ServersideOutputTransform which helps me to speed up my app dramatically.

I’m still searching for a way to fine-tune the speed of my app even further. Currently, my app has a giant callback with a long list of inputs to update a single output ( I didn’t use dash.callback_context.ctx.trigger yet, as proposed by others to check which input was changed before updating the output). I’m wondering if I’m using MultiplexerTransform instead, would it help to boost my app’s performance as compared to the giant callback with a dash.callback_context.ctx.triggered approach?

It is hard to say without seeing the code . Generally, if you just refactor into many ‘small’ callbacks, the performance will probably be the same. However, if you can avoid doing expensive operations in some of the callbacks, performance will improve (:

Awesome! Thanks for the valuable work in packaging this together. Hopefully this will get integrated into core Dash library itself :slight_smile:

1 Like