Share an Altair chart
The reason to use Altair rather than matplotlib is the interaction — the tooltip, the brush selection, the linked view that filters the other panel. Every one of those is destroyed by the way charts usually get shared, which is a PNG pasted into a channel.
import altair as alt
chart = alt.Chart(df).mark_circle().encode(
x="week:O", y="latency_p95:Q", color="service:N",
tooltip=["service", "week", "latency_p95"],
).interactive()
chart.save("chart.html")
Publish the file
curl -X POST https://commareports.com/api/v1/reports \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html chart.html \
'{title: "p95 latency by service", html: $html}')"
Or drag chart.html into the app.
The chart keeps working at the link. Report HTML renders with scripts
enabled inside a sandboxed iframe (allow-scripts, no
allow-same-origin), so the Vega runtime initialises and the zoom,
tooltips and selections behave exactly as they do in your notebook —
see interactive HTML reports.
Online vs. self-contained
chart.save() writes a page that loads Vega, Vega-Lite and vega-embed
from jsDelivr, which is allow-listed — the chart renders at the link
without further work.
Use chart.save("chart.html", inline=True) (with vl-convert-python
installed) when the audience might be offline or on a locked-down
network. The file gets larger; it stops depending on anything.
Chart plus narrative
A chart on its own answers a question nobody asked. Build the page in Python and publish that instead:
html = f"""
<h1>p95 latency, weeks 20–40</h1>
<p>Two services regressed after the connection-pool change in week 32.</p>
{chart.to_html()}
"""
Then POST html. The same trick works for a composed view —
(chart1 | chart2) keeps the selections linked across both panels.
Keeping it current
PATCH the same report id when the data refreshes, or run the script on a routine so the URL you pasted into the wiki three months ago still shows this week's numbers. Each refresh appends a revision, so the change is inspectable rather than silent.
Limits
- Entry HTML: 5 MB. Altair inlines the data by default, so a chart over a large frame can pass that — aggregate before plotting, or reference the data as an asset URL.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.
Publish an interactive chart →