Skip to main content

Async Dash

async-dash is an async port of Plotly Dash library, created by replacing its Flask backend with its async counterpart Quart.

It started with my need to be able to create realtime dashboards with dash, specifically with event-driven architecture. Using async-dash with components from dash-extensions such as WebSocket, EventSource, etc. you can create truly event-based or realtime dashboards.

Table Of Contents

Installation

pip install async-dash

Usage

from async_dash import Dash
from dash import html, dcc

Examples

Basic Async Callback

import asyncio
import time

from dash import Input, Output, html
from quart import Quart

from async_dash import Dash

server = Quart(__name__)
app = Dash(__name__, server=server)

app.layout = html.Div([
    html.Button("Async Request (2s delay)", id="async-btn", n_clicks=0),
    html.Div(id="async-output"),
])


@app.callback(
    Output("async-output", "children"),
    Input("async-btn", "n_clicks"),
    prevent_initial_call=True,
)
async def async_callback(n_clicks):
    """Async callback that simulates a slow async operation.

    This could be an API call, a database query, etc.
    """
    start = time.time()
    # This is non-blocking - other requests can be processed during this sleep
    await asyncio.sleep(2)
    elapsed = time.time() - start
    return f"Async callback #{n_clicks} completed in {elapsed:.2f}s (non-blocking!)"


if __name__ == "__main__":
    app.run(debug=True, port=8050)

Sync Callbacks Still Work

from dash import Input, Output, html
from quart import Quart

from async_dash import Dash

server = Quart(__name__)
app = Dash(__name__, server=server)

app.layout = html.Div([
    html.Button("Sync Request", id="sync-btn", n_clicks=0),
    html.Div(id="sync-output"),
])


@app.callback(
    Output("sync-output", "children"),
    Input("sync-btn", "n_clicks"),
    prevent_initial_call=True,
)
def sync_callback(n_clicks):
    """Sync callback - still works with async-dash."""
    return f"Sync callback #{n_clicks} completed instantly!"


if __name__ == "__main__":
    app.run(debug=True, port=8050)

WebSocket Example

Using websockets for real-time updates with dash-extensions:

import asyncio
import random

from dash import Input, Output, dcc, html
from dash_extensions import WebSocket
from quart import Quart, json, websocket

from async_dash import Dash

server = Quart(__name__)
app = Dash(__name__, server=server)

app.layout = html.Div([
    WebSocket(id="ws", url="/ws"),
    html.H3("Live Random Data (via WebSocket)"),
    dcc.Graph(id="graph"),
])

app.clientside_callback(
    """
function(msg) {
    if (msg) {
        const data = JSON.parse(msg.data);
        return {data: [{y: data, type: "scatter"}]};
    } else {
        return {};
    }
}""",
    Output("graph", "figure"),
    [Input("ws", "message")],
)


@server.websocket("/ws")
async def random_data():
    while True:
        output = json.dumps([random.random() for _ in range(10)])
        await websocket.send(output)
        await asyncio.sleep(1)


if __name__ == "__main__":
    app.run()

Running with Uvicorn

For production, use an ASGI server like uvicorn:

uvicorn example:server --host 0.0.0.0 --port 8050

Motivation

In addition to all the advantages of writing async code, async-dash enables you to:

  1. Run truly asynchronous callbacks
  2. Use websockets, server sent events, etc. without needing to monkey patch the Python standard library
  3. Use quart / fastapi / starlette frameworks with your dash apps side by side
  4. Use HTTP/2 (especially server push) if you use an HTTP/2 enabled server such as hypercorn

Caveats

I'm maintaining this library as a proof of concept for now. It should not be used for production. If you do decide to use it, I'd love to hear your feedback.

TODO

  1. Gather reviews and feedback from the Dash Community.

Metadata

Release files for async-dash 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for async-dash 0.1.0
File Size Uploaded
async_dash-0.1.0.tar.gz 26.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for async-dash 0.1.0
File Interpreter ABI Platform
async_dash-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.9 kB

Release files / async_dash-0.1.0.tar.gz

Download URL async_dash-0.1.0.tar.gz
Size 26.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6edfdc55a9d58b5faa6453b8efcd5e99c7489e683f0094d0af31640482c940a5
BLAKE2b-256 checksum
How to use checksums
a8be3958492c17c9c377ae3e751a617c1f29724a7139d5f0763e0c3c85d9fbed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.5

Release files / async_dash-0.1.0-py3-none-any.whl

Download URL async_dash-0.1.0-py3-none-any.whl
Size 5.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e7f53b28e9690eca5c17d1c441ca22ed4d3b3283779f25d27ed5b56b00ddf055
BLAKE2b-256 checksum
How to use checksums
cb5cd6e37f6710e335ea539159cbe6233f69dac182553de9a0e3320f0bd11f42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page