SKILL.md
Data Chart
Render measured data as static charts in the shared editorial figure language: gridless ink axes, restrained direct labels, and one accent family per page. Titles and legends are optional content, not a fixed page frame. SVG is the primary artifact (text preserved as text); inspect a PNG proof before claiming success.
Routing: chart or diagram?
Decide by the figure's content, not its name:
- Measured data - real numbers, many points, true scales (log axes, distributions, time series) - this skill.
- Structure - boxes, arrows, layers, pipelines, or a few illustrative values inside a larger schematic - the sibling
technical-diagramskill. Usedrawio-diagramonly when native draw.io format is part of the request. - Borderline (3-8 bars): real measurements that may change → this skill (the chart regenerates from data); a decorative sketch inside a diagram → technical-diagram.
Quick start
- Read [
references/chart-language.md](references/chart-language.md) for the full rule set (anatomy, tokens, marks, dark mode). - Write a small script that imports the style module [
scripts/editorialmpl.py](scripts/editorialmpl.py):ed.use()→ plot with family colors →ed.monoticks/ed.axislabel→ optionaled.header→ed.save(fig, stem)(writesstem.svg+stem.png). The module reads the vendored canonical values from [assets/editorial-tokens.json](assets/editorial-tokens.json). [scripts/examplechart.py](scripts/examplechart.py) is a working reference for both a line chart and grouped bars; copy its margin setup (subplots_adjustwithtop≈0.80clears the header row). - Run it. No system matplotlib is assumed - use
uv run --with matplotlib python <script>.py(add other deps the same way).findfontwarnings about Inter/IBM Plex Mono are expected on machines without those fonts; fallbacks carry the voice and the SVG keeps the full stack. - Look at the PNG before finishing. Check: no clipped direct labels or tick text (widen margins, not the font), any required legend fits on one line, one accent family, and no gridlines or unrequested supporting text.
Non-negotiables
- Data values come from the user or their files - never invent or "smooth" numbers. Inspect the supplied data before asking. Preserve missing values as gaps when that representation is valid; if omission would change the requested comparison, ask about that series while preparing the supported chart parts. Disclose an omitted series rather than silently dropping it.
- Emphasis comes from color and direct labels, never thicker strokes or bigger fonts.
- Direct value labels on endpoints or one emphasized point only - never every point. Axis and tick text stays ink.
- One y-scale per chart. Two measures of different scale become two charts.
- Deterministic scripts: no RNG, no timestamps in output filenames.
- Do not add a title when the embedding document already names the chart. Do not add a legend when direct labels make every series clear. Never add a subtitle, takeaway strip, source footer, badge, or decorative inset merely to fill the canvas.
Brand safety
The look is modeled on openai.com editorial figures - geometry, palette, and typographic structure only. Never add the OpenAI logo, blossom mark, or wordmark; never label output as OpenAI-branded or imply affiliation. OpenAI Sans is proprietary - the Inter/IBM Plex Mono stacks in the style module are the approved substitutes.
Verification before claiming done
- The script ran cleanly and wrote both
.svgand.png. - You rendered and actually viewed the PNG (step 4 above).
- The SVG contains
<textelements (fonts preserved), not outlined paths. - Every number in the chart traces to user-provided data.
Once these checks pass at the intended display size, deliver the script, SVG, and PNG. Rerender after a data, label, or layout correction; do not create additional chart types or style variants merely to prolong visual review.
Gotchas
- matplotlib's default
svg.fonttypeispath: skippinged.use()(or saving before it runs) silently outlines all text and kills editability. Verification step 3 catches this. - Endpoint direct labels sit outside the axes and clip at the figure edge; reserve margin first (
subplots_adjust(right≈0.88)). Fix clipping with margins, never smaller fonts. - Coral mid (
#FF9365) fails 3:1 contrast on white - keep coral series dashed or direct-labeled, and set coral value labels in#804126. ed.header()draws the canvas to measure each legend label, so call it after the figure size and margins are final; latesubplots_adjustcalls shift the plot under a already-placed header.findfontwarnings for Inter/IBM Plex Mono are expected on machines without those fonts and are not a failure.