Plotting Advisor
Rules engine for Python plotting. Use BEFORE writing any plotting code. Returns a structured checklist and a paste-ready YAML decision card. Library mechanics are delegated to scientific-skills:matplotlib, seaborn, or plotly.
When to Use This Skill
Use this skill when:
- A user asks to plot, visualize, chart, or graph any data
- Another agent (
bioinformatician, calculator, notebook-writer) is about to render a figure
- A figure already exists and the user asks "is this plot OK?" / "review this figure" / "make this better" → invokes the lint flow
- Intent is documented (compare, distribution, trend, composition, relation). If not, ask one question before recommending.
When NOT to Use This Skill
Do NOT use this skill when:
- The user only needs
matplotlib/seaborn/plotly syntax mechanics (e.g., "how do I set a log axis") → use scientific-skills:matplotlib
- The plot is a one-off exploratory glance during debugging (advisor overhead not justified)
- The output is a domain-specific established convention with no flexibility (e.g., a regulatory-required forest plot in clinical reporting) — note the convention and step aside
- The work is non-Python (R/ggplot, D3, etc.) — out of scope
Workflow
Two flows, sharing the rule base in references/.
Advisor flow (default)
Intake — gather from the caller:
- Data shape (variable types, n, dimensionality, missingness)
- Intent — one of
{compare, distribution, trend, composition, relation, ranking, geographic, network}
- Audience (print, slides, paper figure, dashboard)
- Constraints (caller-specified chart type, palette, B/W output, journal style)
- If intent is missing, ask one question, then proceed.
Chart selection — open references/chart-selection.md, walk the decision tree for (data shape × intent). Output: recommended chart + 1-2 alternatives + the rule that selected it.
Palette selection — open references/palettes.md:
- Categorical ≤8 → Okabe-Ito
- Continuous unipolar → viridis / cividis
- Diverging around meaningful midpoint → ColorBrewer RdBu / PuOr
- Decorative color → single neutral; reserve color for emphasis
Axis & scale (inline rules):
- Linear axis includes zero unless truncation is justified and annotated
- Log scale only when data spans ≥2 orders of magnitude OR the underlying process is multiplicative
- ~5-7 major ticks per axis
- Shared axes for small multiples
- Date axes redundantly labeled if range crosses years
Annotation & labels (inline rules):
- Axis labels with units in parentheses:
Time (h)
- Direct-label series when ≤5 (Tufte) instead of legend
- Title states the finding; subtitle states the context
- Annotate outliers, intervention points, baselines
Accessibility floor (inline rules, always apply):
- Colorblind-safe palette OR redundant encoding (shape / line style / position)
- Minimum font size: 8pt print / 14pt slide
- Avoid red/green as the only encoding distinction
- Test against deuteranopia simulation when categorical color count ≥3
Anti-pattern vetoes (inline, refuse outright; full list in references/anti-patterns.md):
- No 3D bar/pie/surface
- No dual y-axes
- No rainbow palette (
jet, gist_rainbow, hsv) on continuous data
- No truncated baseline without annotation
- No pie with >5 slices
Output — produce the structured checklist + decision card (formats below).
Lint flow (when the caller hands over a figure)
Input (mutually exclusive modes):
python3 scripts/style_lint.py --image figure.png
python3 scripts/style_lint.py --figure-spec figure.json (caller produces JSON via figure_spec.extract_spec(fig))
python3 scripts/style_lint.py --describe "<text description of the figure>"
Inspection — style_lint.py extracts properties from the input (image / spec / description) and applies the rule base.
Rule check — violations grouped by severity (critical / major / minor) with one-line fixes and reference anchors.
Exit code:
- Default: exit 0 (advisory)
--strict: exit 2 if any critical violation present
The skill never imports matplotlib to render anything.
Output Format
Advisor — Checklist + Decision card
## Plotting Advisor: [chart type recommendation, in one phrase]
### Intent & data
- Intent: compare across 4 conditions
- Data: continuous response, ~30 obs/group, balanced, no missing
- Audience: paper figure (300 dpi print)
### Recommended chart: dot plot with median bar
- Rule: Cleveland 1985 — position encodes more accurately than length/angle/area
- Alternatives considered: box plot (loses obs at n=30); violin (overstates smoothness); raincloud (complexity not justified)
### Palette: Okabe-Ito (categorical, 4 colors)
- Hex: #E69F00, #56B4E9, #009E73, #F0E442
- Why: colorblind-safe, ≤8 levels supported, perceptually balanced
- Reference: references/palettes.md#okabe-ito
### Axes & scale
- Y: linear, include zero (response is a count); 5 major ticks
- X: categorical, ordered by condition (control first)
- Units: `Response (counts/min)`
### Annotation
- Direct-label each group (n=4 ≤5 rule)
- Annotate sample size per group below x-axis
- Title states finding; subtitle states context
### Accessibility floor
- ✓ Colorblind-safe palette
- ✓ Redundant encoding (group also encoded by x-position)
- ✓ Font size 9pt (print floor 8pt)
- ✓ No red/green-only distinction
### Anti-pattern check
- ✓ No 3D, no dual axes, no rainbow, no truncated baseline, no pie
### Decision card
```yaml
chart: dot_plot_with_median
library: seaborn
palette:
type: categorical
name: okabe_ito
hex: ["#E69F00", "#56B4E9", "#009E73", "#F0E442"]
axes:
x: {type: categorical, order: [control, t1, t2, t3]}
y: {type: linear, include_zero: true, label: "Response (counts/min)"}
encoding:
position: condition
color: condition # redundant with position — fine
annotation:
direct_labels: true
sample_size_per_group: true
title: "<state finding>"
subtitle: "<state context>"
accessibility:
colorblind_safe: true
min_font_pt: 9
output:
dpi: 300
format: pdf
delegate_to: scientific-skills:seaborn
Every recommendation includes a rule citation (short tag like `[Cleveland 1985]` or a `references/<file>.md#anchor` pointer). Full bibliography lives in `references/sources.md`.
### Lint output
```markdown
## Plotting Advisor: figure check — N issues found
### Critical (n)
- <issue>. <impact>.
- Fix: <one-line fix>
- Rule: references/<file>.md#<anchor>
### Major (n)
- ...
### Minor (n)
- ...
Plus JSON to stdout for machine consumption (see scripts/style_lint.py --help).
Integration with Existing Skills
scientific-skills:matplotlib / seaborn / plotly — explicit delegate_to field in the decision card names the right software skill. This advisor never duplicates their syntax content.
bioinformatician — its visualization reference can point at references/scientific-conventions.md (follow-up PR).
notebook-writer — invoke this skill for every plotting cell.
editor / consistency-auditor — precedent for the rules-engine-as-skill pattern.
References
references/chart-selection.md — decision tree by intent × data shape (general only)
references/palettes.md — Okabe-Ito, viridis family, ColorBrewer, Tol bright
references/anti-patterns.md — 12-15 anti-patterns with citations
references/accessibility.md — WCAG, colorblind sim, fonts, journal overrides
references/interactive-adaptation.md — how rules shift for plotly/bokeh/altair
references/scientific-conventions.md — volcano, UMAP, Manhattan, forest, ROC, etc.
references/sources.md — full bibliography
Scripts
scripts/palettes.py — canonical hex lists, is_colorblind_safe_categorical(hex_list) helper
scripts/figure_spec.py — extract_spec(fig) for matplotlib Figure → JSON; CLI mode also accepts a pickled figure
scripts/style_lint.py — main CLI with three input modes; --strict for CI use
Run tests with:
python3 -m unittest discover -s claude-config/skills/plotting-advisor/scripts/tests -v
1---2name: plotting-advisor3version: 1.04last_updated: 2026-05-245description: "Use BEFORE writing any Python plotting code (matplotlib, seaborn, plotly) — recommends chart type, color palette, axis treatment, and accessibility choices using Tufte, Cleveland, Wong, and Wilke principles. Also lints existing figures on request. Triggers on 'plot', 'chart', 'figure', 'heatmap', or any mention of matplotlib/seaborn/plotly."6prerequisites:7 - Data shape known (variable types, n)8 - Plotting intent stated (compare, distribution, trend, composition, relation)9constraints:10 - Does NOT write plotting code — delegates syntax to scientific-skills:matplotlib / seaborn / plotly11 - Lint is passive — caller provides Figure object or PNG path; advisor never imports matplotlib to render12success_criteria:13 - Chart-type recommendation justified by data shape + intent14 - Palette selected is colorblind-safe OR exception flagged with reason15 - Axis treatment (scale, zero, breaks) explicitly addressed16 - Decision card produced as paste-ready block17 - Accessibility minimums met (font size, redundant encoding when color encodes a meaningful variable)18---1920# Plotting Advisor2122Rules engine for Python plotting. Use BEFORE writing any plotting code. Returns a structured checklist and a paste-ready YAML decision card. Library mechanics are delegated to `scientific-skills:matplotlib`, `seaborn`, or `plotly`.2324## When to Use This Skill2526Use this skill when:2728- A user asks to plot, visualize, chart, or graph any data29- Another agent (`bioinformatician`, `calculator`, `notebook-writer`) is about to render a figure30- A figure already exists and the user asks "is this plot OK?" / "review this figure" / "make this better" → invokes the lint flow31- Intent is documented (compare, distribution, trend, composition, relation). If not, ask one question before recommending.3233## When NOT to Use This Skill3435Do NOT use this skill when:3637- The user only needs `matplotlib`/`seaborn`/`plotly` syntax mechanics (e.g., "how do I set a log axis") → use `scientific-skills:matplotlib`38- The plot is a one-off exploratory glance during debugging (advisor overhead not justified)39- The output is a domain-specific established convention with no flexibility (e.g., a regulatory-required forest plot in clinical reporting) — note the convention and step aside40- The work is non-Python (R/ggplot, D3, etc.) — out of scope4142## Workflow4344Two flows, sharing the rule base in `references/`.4546### Advisor flow (default)47481. **Intake** — gather from the caller:49 - Data shape (variable types, n, dimensionality, missingness)50 - Intent — one of `{compare, distribution, trend, composition, relation, ranking, geographic, network}`51 - Audience (print, slides, paper figure, dashboard)52 - Constraints (caller-specified chart type, palette, B/W output, journal style)53 - If intent is missing, ask **one** question, then proceed.54552. **Chart selection** — open `references/chart-selection.md`, walk the decision tree for (data shape × intent). Output: recommended chart + 1-2 alternatives + the rule that selected it.56573. **Palette selection** — open `references/palettes.md`:58 - Categorical ≤8 → Okabe-Ito59 - Continuous unipolar → viridis / cividis60 - Diverging around meaningful midpoint → ColorBrewer RdBu / PuOr61 - Decorative color → single neutral; reserve color for emphasis62634. **Axis & scale** (inline rules):64 - Linear axis includes zero unless truncation is justified and annotated65 - Log scale only when data spans ≥2 orders of magnitude OR the underlying process is multiplicative66 - ~5-7 major ticks per axis67 - Shared axes for small multiples68 - Date axes redundantly labeled if range crosses years69705. **Annotation & labels** (inline rules):71 - Axis labels with units in parentheses: `Time (h)`72 - Direct-label series when ≤5 (Tufte) instead of legend73 - Title states the finding; subtitle states the context74 - Annotate outliers, intervention points, baselines75766. **Accessibility floor** (inline rules, always apply):77 - Colorblind-safe palette OR redundant encoding (shape / line style / position)78 - Minimum font size: 8pt print / 14pt slide79 - Avoid red/green as the only encoding distinction80 - Test against deuteranopia simulation when categorical color count ≥381827. **Anti-pattern vetoes** (inline, refuse outright; full list in `references/anti-patterns.md`):83 - No 3D bar/pie/surface84 - No dual y-axes85 - No rainbow palette (`jet`, `gist_rainbow`, `hsv`) on continuous data86 - No truncated baseline without annotation87 - No pie with >5 slices88898. **Output** — produce the structured checklist + decision card (formats below).9091### Lint flow (when the caller hands over a figure)92931. **Input** (mutually exclusive modes):94 - `python3 scripts/style_lint.py --image figure.png`95 - `python3 scripts/style_lint.py --figure-spec figure.json` (caller produces JSON via `figure_spec.extract_spec(fig)`)96 - `python3 scripts/style_lint.py --describe "<text description of the figure>"`97982. **Inspection** — `style_lint.py` extracts properties from the input (image / spec / description) and applies the rule base.991003. **Rule check** — violations grouped by severity (critical / major / minor) with one-line fixes and reference anchors.1011024. **Exit code**:103 - Default: exit 0 (advisory)104 - `--strict`: exit 2 if any critical violation present105106The skill never imports matplotlib to render anything.107108## Output Format109110### Advisor — Checklist + Decision card111112```markdown113## Plotting Advisor: [chart type recommendation, in one phrase]114115### Intent & data116- Intent: compare across 4 conditions117- Data: continuous response, ~30 obs/group, balanced, no missing118- Audience: paper figure (300 dpi print)119120### Recommended chart: dot plot with median bar121- Rule: Cleveland 1985 — position encodes more accurately than length/angle/area122- Alternatives considered: box plot (loses obs at n=30); violin (overstates smoothness); raincloud (complexity not justified)123124### Palette: Okabe-Ito (categorical, 4 colors)125- Hex: #E69F00, #56B4E9, #009E73, #F0E442126- Why: colorblind-safe, ≤8 levels supported, perceptually balanced127- Reference: references/palettes.md#okabe-ito128129### Axes & scale130- Y: linear, include zero (response is a count); 5 major ticks131- X: categorical, ordered by condition (control first)132- Units: `Response (counts/min)`133134### Annotation135- Direct-label each group (n=4 ≤5 rule)136- Annotate sample size per group below x-axis137- Title states finding; subtitle states context138139### Accessibility floor140- ✓ Colorblind-safe palette141- ✓ Redundant encoding (group also encoded by x-position)142- ✓ Font size 9pt (print floor 8pt)143- ✓ No red/green-only distinction144145### Anti-pattern check146- ✓ No 3D, no dual axes, no rainbow, no truncated baseline, no pie147148### Decision card149150```yaml151chart: dot_plot_with_median152library: seaborn153palette:154 type: categorical155 name: okabe_ito156 hex: ["#E69F00", "#56B4E9", "#009E73", "#F0E442"]157axes:158 x: {type: categorical, order: [control, t1, t2, t3]}159 y: {type: linear, include_zero: true, label: "Response (counts/min)"}160encoding:161 position: condition162 color: condition # redundant with position — fine163annotation:164 direct_labels: true165 sample_size_per_group: true166 title: "<state finding>"167 subtitle: "<state context>"168accessibility:169 colorblind_safe: true170 min_font_pt: 9171output:172 dpi: 300173 format: pdf174delegate_to: scientific-skills:seaborn175```176```177178Every recommendation includes a rule citation (short tag like `[Cleveland 1985]` or a `references/<file>.md#anchor` pointer). Full bibliography lives in `references/sources.md`.179180### Lint output181182```markdown183## Plotting Advisor: figure check — N issues found184185### Critical (n)186- <issue>. <impact>.187 - Fix: <one-line fix>188 - Rule: references/<file>.md#<anchor>189190### Major (n)191- ...192193### Minor (n)194- ...195```196197Plus JSON to stdout for machine consumption (see `scripts/style_lint.py --help`).198199## Integration with Existing Skills200201- **`scientific-skills:matplotlib` / `seaborn` / `plotly`** — explicit `delegate_to` field in the decision card names the right software skill. This advisor never duplicates their syntax content.202- **`bioinformatician`** — its visualization reference can point at `references/scientific-conventions.md` (follow-up PR).203- **`notebook-writer`** — invoke this skill for every plotting cell.204- **`editor` / `consistency-auditor`** — precedent for the rules-engine-as-skill pattern.205206## References207208- `references/chart-selection.md` — decision tree by intent × data shape (general only)209- `references/palettes.md` — Okabe-Ito, viridis family, ColorBrewer, Tol bright210- `references/anti-patterns.md` — 12-15 anti-patterns with citations211- `references/accessibility.md` — WCAG, colorblind sim, fonts, journal overrides212- `references/interactive-adaptation.md` — how rules shift for plotly/bokeh/altair213- `references/scientific-conventions.md` — volcano, UMAP, Manhattan, forest, ROC, etc.214- `references/sources.md` — full bibliography215216## Scripts217218- `scripts/palettes.py` — canonical hex lists, `is_colorblind_safe_categorical(hex_list)` helper219- `scripts/figure_spec.py` — `extract_spec(fig)` for matplotlib Figure → JSON; CLI mode also accepts a pickled figure220- `scripts/style_lint.py` — main CLI with three input modes; `--strict` for CI use221222Run tests with:223224```bash225python3 -m unittest discover -s claude-config/skills/plotting-advisor/scripts/tests -v226```