Share a pydeck map
pydeck gives Python a real WebGL mapping stack: hexagon aggregation over millions of points, arc layers, 3D extrusion, a camera you fly around. It is the output that most obviously loses its meaning as a screenshot, because the insight is usually "look at this when you rotate it".
import pydeck as pdk
layer = pdk.Layer(
"HexagonLayer", data=df,
get_position=["lon", "lat"],
radius=200, elevation_scale=4, extruded=True, pickable=True,
)
deck = pdk.Deck(
layers=[layer],
initial_view_state=pdk.ViewState(latitude=51.50, longitude=-0.12, zoom=11, pitch=45),
tooltip={"text": "{elevationValue} rides"},
)
deck.to_html("map.html")
to_html gives you a file. Which then does the usual thing: too big to paste,
downloads instead of opening when attached, and unpreviewable in chat.
Publish it
Drag map.html into the app, or POST it:
curl -fsS -X POST "https://commareports.com/api/v1/reports" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html map.html \
--arg t "Ride density — London, Q3" '{title: $t, html: $html}')"
Report HTML renders with scripts enabled inside a sandboxed iframe
(allow-scripts, no allow-same-origin), and WebGL is available inside it. So
the reader gets the map: pan, zoom, pitch, the tooltip on hover, and the layer
controls if you added them.
If to_html emitted the data as a sibling file rather than inlining it, publish
the folder instead of the single file — the JSON uploads as an asset and its
relative reference is rewritten to the uploaded copy, which is the step a
file:// origin cannot perform.
Check the token before you publish
This is the pydeck-specific trap. If you use a Mapbox base map, to_html
embeds your access token in the page:
pdk.Deck(..., map_provider="mapbox", api_keys={"mapbox": MAPBOX_KEY})
Publish that with public access and the token is public. Three ways out, in order of preference:
- Use a carto base map (
map_provider="carto"), which needs no token. - Restrict the token by URL in the Mapbox dashboard.
- Keep the report private — team, domain-gated or named reviewers. See the sharing model.
The same applies to any base map provider with a key.
Aggregate before you publish
A ScatterplotLayer over two million raw points produces an enormous HTML file
and a map that reads as a solid blob. HexagonLayer or GridLayer with
server-side aggregation produces a smaller file and a more readable map — the
constraint and the design advice point the same way here.
Refreshing maps
python build_map.py # regenerates map.html from the warehouse
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html map.html \
--arg t "Ride density — week $(date +%V)" '{title: $t, html: $html}')"
One URL per map, a revision per refresh — see scheduled HTML reports.
What review adds
- Anchored threads on a region or a spike — see commenting on HTML.
- Revisions, so week-over-week change is visible.
- Access per report — location data is frequently personal data. Set this deliberately.
Limits
- Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.