# Share an Altair Chart — Keep the Tooltips, Lose the Screenshot

Canonical: https://commareports.com/share-altair-chart
Published: 2026-08-25

> chart.save('chart.html') gives you an interactive Vega-Lite chart in a file nobody can open. Publish it to Comma: a link with the zoom, tooltips and selections intact, and comments on the outlier.

# 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.

```python
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

```bash
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](https://commareports.com/).

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](/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:

```python
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](/docs/routines) 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 →](https://commareports.com/)**

### Related

- [Share a Plotly chart](/share-plotly-html) · [Share a Bokeh plot](/share-bokeh-plot)
- [Share a Folium map](/share-folium-map) · [Interactive HTML reports](/interactive-html-reports)
- [Share a Jupyter notebook as HTML](/share-jupyter-notebook-html)
