The last mile of analysis — charts, captions, and the executive summary — is where AI saves hours and where it invents percentages.
Tier: Foundation · Workflow area: Visualization & communication
This playbook covers both halves: generating publication-quality matplotlib/plotly code fast, and drafting narrative with the numbers-pinned method, where every figure in the prose is injected by you from verified tables and the model is never the source of a single number.
Skip elaborate generation for quick-look plots — df.plot() needs no assistant.
Generate chart code from a chart spec, not a vibe:
Matplotlib chart from df_conv (columns: month, channel, conversion_rate,
n_trials). Spec:
- Line chart, one line per channel, monthly conversion (already 0-1 floats;
format axis as %). Annotate the March-2026 pricing change with a vertical
reference line + label.
- Suppress months where n_trials < 100 (draw as gap, note in caption).
- Style: 900x500, no top/right spines, direct line labels at right edge
instead of a legend, title states the takeaway ("Paid-social conversion
fell 6pp after March"), subtitle states the population and window.
- Return a function make_conversion_chart(df) -> Figure. No plt.show().
Takeaway-as-title and small-n suppression are the two spec habits that most improve real-world charts.
Render and critique in a loop. Show the rendered chart (paste the image to a multimodal model or describe issues): overlapping labels, unreadable rotation, misleading truncated axis. Two or three critique rounds beats one mega-prompt. For axis choices, be explicit: bar charts start at zero; line-chart y-ranges are a judgment you make, stated in the caption if truncated.
Build the numbers block — the only source of truth for prose. From your verified tables, assemble every number the narrative may use:
NUMBERS (verified, use ONLY these; if a claim needs a number not listed,
write [MISSING] instead of computing or estimating it):
- overall trial→paid conversion: Mar 18.2% → Jun 14.1% (−4.1pp)
- mix-shift contribution: −3.2pp; within-channel: −0.9pp
- paid-social share of signups: 22% → 41%
- n = 48,300 trials, Mar-Jun 2026
Draft narrative against the block:
Using ONLY the numbers block, draft: (1) a 3-sentence executive TL;DR,
(2) a caption for each chart (1-2 sentences: what it shows, the takeaway,
the population/window), (3) a 200-word findings section ordered by decision
relevance. Plain language, no "delve", no unexplained jargon; state
uncertainty where the block does (n, windows). Every numeric claim must
match the block verbatim.
Audit the draft mechanically. Check every number in the prose against the block (a regex for digits makes this fast: each match must appear in the block). Hunt the subtler failures: derived numbers the model computed itself ("a 23% relative decline" — did you verify that division?), causal language exceeding the analysis ("caused" vs "coincided with"), and superlatives with no basis ("dramatic"). Any [MISSING] markers route back to you for a verified value or deletion of the claim.
Package per audience. Same numbers block, different renderings: 3 bullets for the exec channel, the full memo for the team, speaker notes for the review meeting. Regenerating per audience from the same block keeps versions consistent — the block is your single source of truth.
The model writes sentences; it never writes numbers. Every digit in shipped prose traces to the numbers block you assembled from verified tables.
subplots yourself.