Plotly in apps: Dash, Streamlit and widgets

Plotly · Advanced · 12 min

Most production Plotly charts live inside an app or a web page, not in a notebook.

Because a figure is JSON for plotly.js, you can deliver it anywhere JavaScript runs.

Dash (from Plotly) builds web apps in pure Python. A figure goes into dcc.Graph(figure=fig), and callbacks regenerate figures when inputs change or when users click, select or zoom (Input("graph", "clickData")).

Streamlit renders a figure with st.plotly_chart(fig); widgets above it rerun the script with new inputs. Selections can be returned with on_select="rerun".

Jupyter: figures display inline by default. go.FigureWidget(fig) makes a live widget that Python can update in place and listen to.

Any web stack: send fig.to_json() from an API and call Plotly.newPlot(div, fig.data, fig.layout) in the browser, or embed fig.to_html(full_html=False, include_plotlyjs="cdn") in a server-rendered template. plotly.io.from_json and pio.read_json load a figure back.

Practical concerns:

  • Size: large arrays bloat JSON; aggregate on the server before sending.
  • Versions: the plotly.js version in the page must match what the Python library generated; mixing a very old CDN version with a new figure causes missing features.
  • Responsiveness: set config={"responsive": True} and avoid fixed width so charts resize with their container.
  • Updates: in apps, regenerate or patch figures rather than creating new ones per tiny change (Dash has Patch for partial updates).

Example

import json
import plotly.express as px
import plotly.io as pio

fig = px.line(x=[1, 2, 3], y=[3, 1, 2], title="API chart")

payload = fig.to_json()                  # send from your web API
spec = json.loads(payload)
print(sorted(spec))                      # ['data', 'layout']

restored = pio.from_json(payload)        # e.g. in a test or another service
print(restored.layout.title.text)        # API chart

snippet = fig.to_html(full_html=False, include_plotlyjs="cdn",
                      config={"responsive": True, "displaylogo": False})
print("cdn.plot.ly" in snippet)          # True: loads plotly.js from the CDN

# Browser side:  Plotly.newPlot("chart", spec.data, spec.layout)
# Dash:          dcc.Graph(figure=fig)
# Streamlit:     st.plotly_chart(fig, on_select="rerun")

Remember

  • A figure is JSON: send it to any page that loads plotly.js
  • Dash (dcc.Graph) and Streamlit (st.plotly_chart) embed figures in Python apps
  • Keep payloads small and plotly.js versions consistent

Watch out for

  • Shipping a figure with a million raw points through a web API instead of aggregating first.

Check yourself

  1. Your FastAPI backend should give a React front end a chart. What is the simplest contract?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: plotly.com/python/figurewidget/