Quantcast
Channel: 🎛️ Dash - Plotly Community Forum
Viewing all articles
Browse latest Browse all 6271

Bypassing serialization of Dash graph objects for efficient server-side caching

$
0
0

I’m developing an application in which lots of graphs need to be rendered on every page. Some of these graphs are quite complex, and the callbacks that output them take 50-500ms on my high-end local development machine, even more so on the production server which is a carefully sized VM.

Server-side caching the graphs (via Redis or diskcache, for instance) is an excellent option in my case, but there is still an unnecessary cost that comes from JSON-loading the serialized graph object (via plotly.io.from_json) just to have it serialized it again by the callback that produces it (I bet that the decorated callback uses plotly.io.to_json to do that, internally). The code below is an example of how this could be done (nevermind the session-uuid store, it’s just a generic placeholder for inputs of any sort):

import plotly.io
from dash import Dash, dcc, html
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
from redis import Redis

redis = Redis(host="redis", port=6379)

app = Dash(__name__)
app.layout = html.Div([
    dcc.Store("session-uuid", storage_type="session"),
    dcc.Graph("costly-graph")
])


@app.callback(
    Output("costly-graph", "figure"),
    Input("session-uuid", "data")
)
def update_graph(session_uuid: str):
    if session_uuid is None:
        raise PreventUpdate()
    
    figure_key = f"some-key-depending-on-{session_uuid}-or-any-other-input-for-instance"
    figure_bytes = redis.get(figure_key)

    if figure_bytes:
        figure = plotly.io.from_json(figure_bytes.decode())
    else:
        figure = produce_costly_figure(session_uuid)
        redis.set(figure_key, plotly.io.to_json(figure).encode())

    return figure


def produce_costly_figure(session_uuid):
    """Some function that takes some 500+ms to complete."""
    pass

Therefore, I wonder if there’s a way (or any plans/quick hacks) for “bypassing” the serialization, so that I can return a JSON string (produced/retrieved in whatever way) as the content of the output graph object. Following the example above, something along the lines of (note the hypothetical raw_json argument to Input):

@app.callback(
    Output("costly-graph", "figure", raw_json=True),
    Input("session-uuid", "data")
)
def update_graph(session_uuid: str):
    if session_uuid is None:
        raise PreventUpdate()

    figure_key = f"some-key-depending-on-{session_uuid}-or-any-other-input-for-instance"
    figure_bytes = redis.get(figure_key)

    if not figure_bytes:
        figure = produce_costly_figure(session_uuid)
        figure_bytes = plotly.io.to_json(figure).encode()
        redis.set(figure_key, figure_bytes)

    return figure_bytes

By the way: I know about orjson and it does improve performance by a small margin, but I’m really concerned with squeezing every drop of juice by preventing a useless round trip!

Thanks in advance!

1 post - 1 participant

Read full topic


Viewing all articles
Browse latest Browse all 6271

Trending Articles