first commit

This commit is contained in:
2026-06-11 03:33:14 +08:00
commit 5f555bf342
599 changed files with 142347 additions and 0 deletions

View File

@@ -0,0 +1,318 @@
---
name: publication-chart-skill
description: This skill should be used when the user asks for a publication-quality scientific figure or table, wants help choosing the right chart for results, needs a paper-ready pubfig or pubtab workflow, wants a figure + companion table for a results section, wants an Excel sheet turned into publication-ready LaTeX, or wants an existing scientific figure/table reviewed and upgraded.
version: 0.2.0
---
# Publication Chart Skill
## Goal
Use this skill to turn research results into **publication-grade figures and tables** with an end-to-end workflow.
Primary production stack:
- **`pubfig`** for figures
- **`pubtab`** for publication tables
This skill covers the full delivery chain:
1. understand the scientific communication goal,
2. choose the right artifact type,
3. map the task to `pubfig`, `pubtab`, or both,
4. generate concrete runnable instructions,
5. export paper-ready assets,
6. run publication QA,
7. propose targeted revisions.
## Use this skill when
Trigger this skill for requests like:
- “make a publication-quality figure”
- “choose the right chart for these results”
- “turn these results into a paper-ready figure”
- “make a benchmark / ablation / calibration / forest / heatmap / scatter / line / bar figure”
- “make a benchmark / appendix / ablation table from Excel”
- “convert this Excel table into publication-ready LaTeX”
- “prepare one summary figure plus one companion table for the results section”
- “review and improve this scientific figure/table”
- “I already have a weak chart / screenshot / draft plot — make it publication-ready”
- “export panels for a paper figure”
## Do not use this skill for
Do **not** use this skill when the task is mainly:
- manuscript prose writing,
- statistical testing without artifact design,
- raw exploratory analysis with no publication deliverable,
- Figma-first layout work before the figure/table content is solid.
For simple composite assembly after the figure content is already strong, use the optional secondary workflow in `references/composite-assembly.md`.
## Primary contract
### Inputs
Expect some combination of:
- the scientific communication goal,
- available data shape,
- venue or style constraints,
- whether the artifact is a figure, table, or mixed deliverable,
- optional existing assets such as code, spreadsheets, `.tex`, screenshots, or draft plots,
- whether the user needs a first draft, a publication-ready artifact, or a review/revision pass.
### Outputs
The minimum useful output is:
- the recommended figure/table form,
- the recommended `pubfig` / `pubtab` route,
- a minimal runnable code snippet or CLI command,
- explicit export filenames and formats,
- a publication QA summary,
- and, when needed, a revision plan.
## Default workflow
### 0. Probe the environment and artifact state
Before generating anything, identify:
- whether `pubfig` or `pubtab` is actually available,
- whether the user already has code / spreadsheets / `.tex` / screenshots,
- whether the deliverable is a fresh build or a revision,
- whether the result needs exact values, fast visual perception, or both.
Prefer the smallest environment check that helps execution. When the bundled helper script is available, use it first:
- `python3 scripts/ensure_publication_tooling.py --require pubfig --json`
- `python3 scripts/ensure_publication_tooling.py --require pubtab --json`
Equivalent manual checks are still acceptable when needed:
- `python -c "import pubfig; print(pubfig.__version__)"`
- `python -c "import pubtab; print(pubtab.__version__)"`
- `pubtab --help`
Report the result clearly as **available** or **missing**.
If a dependency is missing and the task requires runnable execution:
- **auto-install it by default**,
- prefer the users active environment instead of guessing a random global interpreter,
- use `python3 scripts/ensure_publication_tooling.py --require ...` as the default bundled route when the script is present,
- let that helper choose `uv` vs `python -m pip` against the active interpreter,
- re-run the availability probe after installation,
- and only then continue with the artifact workflow.
Equivalent concrete commands include:
- `python3 scripts/ensure_publication_tooling.py --require pubfig`
- `python3 scripts/ensure_publication_tooling.py --require pubtab`
- `uv pip install pubfig`
- `uv pip install pubtab`
- `python -m pip install pubfig`
- `python -m pip install pubtab`
If auto-install fails, report the exact failure and then degrade gracefully.
Do not block on a full environment audit.
### 1. Classify the task
Classify the request along these axes:
- **artifact type**: figure / table / mixed deliverable
- **maturity**: exploratory draft / publication-ready generation / revision of an existing artifact
- **structure**: single panel / multi-panel / figure-plus-table package
- **evidence mode**: pattern perception / exact value lookup / both
Do not jump into plotting code before the communication target is clear.
Before plotting research results, lock the evidence contract:
- primary scientific claim,
- unit of analysis,
- primary metric and metric direction,
- whether repeated rows are independent,
- missing cells or incomplete comparison blocks,
- error-bar basis: subject, subject-task, fold, seed, run, or bootstrap sample,
- whether exact values need a companion table,
- whether the current evidence allows a winner/significance claim.
If these are unclear, ask or produce an audit recommendation instead of a polished figure. Do not create a paper-ready plot while the unit of analysis, missing-cell handling, or error-bar basis is unresolved.
### 2. Choose the representation
Choose the representation based on the scientific claim, not novelty or visual flair.
Common families:
- **comparison** — grouped scatter, bar, line comparison, benchmark summary, companion table
- **ablation** — grouped comparison, dumbbell, paired comparison, compact table
- **distribution** — box, violin, raincloud, histogram, density, ECDF, QQ
- **relationship** — scatter, bubble, contour2d, hexbin
- **trend** — line, area
- **evaluation / diagnostic** — calibration, ROC, PR, BlandAltman, forest plot, volcano
- **composition / hierarchy** — UpSet, stacked ratio, donut, radial hierarchy, circular grouped or stacked bars
- **table** — benchmark table, ablation table, dataset summary, appendix table, error breakdown
Avoid weak defaults:
- avoid pie/donut when exact comparison matters and a bar/table is clearer,
- avoid radar unless the comparison is genuinely profile-like and low-cardinality,
- avoid 3D, decorative gradients, and dense legends used only for style,
- avoid forcing every result into a figure when a publication table communicates the evidence better.
If the request is ambiguous, explicitly state what scientific claim the artifact is supposed to support.
### 3. Map to the toolchain
Default mapping:
- **Figures** → `pubfig`
- **Tables** → `pubtab`
- **Mixed deliverables** → use both, with each artifact carrying a distinct role
Tool roles:
- `pubfig` is the default figure engine for scientific plots and paper-ready export.
- `pubtab` is the default table engine for Excel ↔ LaTeX workflows, preview, and publication-ready table export.
- Figma/composite assembly is an **optional secondary branch** for multi-panel finishing.
Route selection rules:
- prefer **Python** for `pubfig` figure generation,
- prefer **CLI** for `pubtab` when the task is file-driven,
- prefer **Python** for `pubtab` when the task is already inside a notebook or scripted pipeline,
- keep the figure and table responsibilities separate in mixed requests.
### 4. Generate concrete artifact instructions
Prefer the smallest production-ready artifact first:
- minimal runnable Python for `pubfig`, or
- minimal CLI/Python for `pubtab`
Then add publication parameters only when justified:
- labels, caption, width, export format, backend, preview, panel packaging, or composite layout.
Keep filenames and suffixes explicit.
Good defaults:
- figures: one `pubfig` call + one `save_figure(...)`
- multiple figure outputs: `batch_export(...)`
- tables: one `pubtab xlsx2tex ...` or `pubtab.preview ...`
- mixed requests: one figure route + one table route, clearly separated
### 5. Define the delivery contract
For every response, make these explicit when possible:
- the claim the artifact supports,
- which part is handled by `pubfig` and which by `pubtab`,
- the output filenames,
- the output formats,
- whether the artifact is draft / final / revision,
- what still needs user-provided data or manuscript context.
### 6. Run publication QA
After generation, check:
- title and legend density,
- axis labels and units,
- category ordering and baseline clarity,
- color accessibility and grayscale robustness,
- font / line-weight consistency,
- caption readiness,
- figure/table readability after downscaling,
- panel consistency for multi-panel figures,
- venue-fit issues such as width, crowding, or over-annotation.
The QA output must be concrete. Do not say “looks better” without naming why.
### 7. Revise
If the result is weak, revise with specific changes such as:
- switch chart family,
- remove chartjunk,
- reorder categories,
- move exact values into a table,
- split a crowded panel,
- add or simplify the caption,
- change export width,
- or convert the deliverable from figure-first to table-first.
## Missing dependency behavior
If `pubfig` or `pubtab` is not available:
- do **not** fail immediately,
- first attempt automatic installation into the active environment,
- prefer `python3 scripts/ensure_publication_tooling.py --require ...` when the bundled script exists,
- explicitly state which dependency is missing,
- state which install command or helper route is being used,
- re-check availability after installation,
- if installation succeeds, continue with the runnable workflow,
- if installation fails, degrade to a design/specification workflow,
- provide pseudocode or draft commands,
- preserve the recommended figure/table structure,
- still provide QA and revision guidance.
## Composite assembly rule
Treat composite or Figma assembly as **secondary**:
- use it when the user explicitly wants a multi-panel paper figure,
- or when panel-level export and layout polishing are genuinely needed.
Do not escalate simple figure tasks into composite/Figma workflows by default.
## Output style rules
- Prefer direct, implementation-usable outputs.
- Explain the **why** of chart/table choice briefly, then give the runnable route.
- When execution matters, include a short environment status block such as `pubfig: available/missing`, `pubtab: available/missing`.
- If a dependency is missing, state the exact helper command or install command, perform the installation, and report the post-install status.
- When a table is stronger than a figure, say so explicitly.
- When a figure is stronger than a table, say so explicitly.
- When both are needed, assign them different communication roles.
- Keep revision guidance actionable and falsifiable.
## Recommended response shape
A strong response using this skill usually has 6 parts:
1. **Artifact decision** — figure / table / paired deliverable, and why
2. **Tool route**`pubfig`, `pubtab`, or both
3. **Minimal implementation** — runnable code or CLI
4. **Export plan** — filenames, formats, width/backend/preview choices
5. **Publication QA** — what to verify before paper submission
6. **Revision plan** — what to change if the current artifact is weak
## Resources
Load these as needed:
- `references/workflow.md` — full end-to-end decision order and delivery contract
- `references/chart-selection.md` — task-to-chart mapping and anti-patterns
- `references/execution-and-verification.md` — environment probing, forced install behavior, and runnable verification
- `scripts/ensure_publication_tooling.py` — bundled probe + auto-install helper for `pubfig` / `pubtab`
- `references/pubfig-recipes.md` — shortest useful figure patterns and export routes
- `references/pubtab-recipes.md` — shortest useful table routes and backend guidance
- `references/source-guides/pubfig-architecture.md` — package layout and figure-generation boundaries from source
- `references/source-guides/pubfig-api-map.md` — stable public pubfig surface and chart-family map from `__init__.py`
- `references/source-guides/pubfig-export-flow.md` — figure export, publication sizing, and panel-export flow from source
- `references/source-guides/pubtab-architecture.md` — package layout and forward/reverse conversion architecture from source
- `references/source-guides/pubtab-cli-api-flow.md` — CLI-to-API control flow and batch/sheet behavior from source
- `references/source-guides/pubtab-backend-and-preview.md` — backend/theme split and real preview compile pipeline from source
- `references/publication-qa-checklist.md` — figure/table QA checklist
- `references/composite-assembly.md` — optional multi-panel and Figma branch
For prompt-shaped examples, see `examples/`.

View File

@@ -0,0 +1,25 @@
# Example 1 — Benchmark comparison figure
## User-style prompt
Help me make a publication-quality benchmark comparison figure for six methods across three datasets.
## Expected skill interpretation
- artifact: figure
- maturity: publication-ready generation
- structure: single panel
- goal: fast comparison across methods and datasets
## Preferred route
- primary tool: `pubfig`
- likely family: `grouped_scatter` or `bar_scatter`
- companion table: optional, only if exact values must be preserved nearby
## Minimum acceptable output shape
- explain why the chosen comparison form is better than a raw grouped bar if density is high
- provide a minimal `pubfig` implementation
- provide one explicit export command/path such as `benchmark.pdf`
- provide a short QA note about readability, legend density, and category ordering

View File

@@ -0,0 +1,25 @@
# Example 2 — Ablation figure
## User-style prompt
Turn these ablation results into a paper-ready figure that makes the contribution of each module easy to read.
## Expected skill interpretation
- artifact: figure
- maturity: publication-ready generation
- structure: single panel or compact paired panel
- goal: isolate incremental effect clearly
## Preferred route
- primary tool: `pubfig`
- likely family: `dumbbell` or `paired` for low-cardinality paired ablations, otherwise a compact grouped comparison chart or companion table
- do not default to a crowded decorative chart
## Minimum acceptable output shape
- recommend the ablation-focused visual form and why
- provide runnable `pubfig` code
- export to a paper-ready format
- include a QA note on baseline clarity and ordering

View File

@@ -0,0 +1,25 @@
# Example 3 — Calibration / evaluation figure
## User-style prompt
I need a publication-quality evaluation figure showing whether my predicted probabilities are calibrated.
## Expected skill interpretation
- artifact: figure
- maturity: publication-ready generation
- structure: single panel
- goal: diagnostic evaluation, not generic trend plotting
## Preferred route
- primary tool: `pubfig`
- likely family: `calibration`
- related alternatives: ROC / PR only if the scientific question changes
## Minimum acceptable output shape
- explain why calibration is the right diagnostic form
- provide minimal runnable code
- export to PDF or SVG
- include QA on labels, reference lines, and downscaled readability

View File

@@ -0,0 +1,25 @@
# Example 4 — Forest / diagnostic figure
## User-style prompt
Help me convert these effect estimates and confidence intervals into a paper-quality figure.
## Expected skill interpretation
- artifact: figure
- maturity: publication-ready generation
- structure: single panel
- goal: communicate effect size with uncertainty
## Preferred route
- primary tool: `pubfig`
- likely family: `forest_plot`
- table may accompany it in appendix if exact values are numerous
## Minimum acceptable output shape
- identify forest plot as the default route
- provide the required arrays/arguments shape
- export a paper-ready artifact
- include QA on reference line, label clarity, and ordering

View File

@@ -0,0 +1,26 @@
# Example 5 — Publication-ready LaTeX table from Excel
## User-style prompt
Convert this Excel benchmark sheet into a publication-ready LaTeX table and give me a preview path before I paste it into the paper.
## Expected skill interpretation
- artifact: table
- maturity: publication-ready generation
- structure: single table
- goal: exact benchmark values in LaTeX
## Preferred route
- primary tool: `pubtab`
- likely route: `xlsx2tex` + `preview`
- for a robust preview-first workflow, preview the table body first and keep final caption/label handling as a separate manuscript-facing step when needed
- `tabularray` only if the manuscript/backend requires it
## Minimum acceptable output shape
- provide the exact `pubtab` command or Python route
- include caption/label guidance when appropriate, but do not force them into the preview-first route
- include preview generation
- mention table width/span concerns if relevant

View File

@@ -0,0 +1,25 @@
# Example 6 — Mixed figure + table deliverable
## User-style prompt
For this results section, I want one summary figure and one companion table: the figure should show the overall pattern, and the table should preserve the exact metrics.
## Expected skill interpretation
- artifact: mixed deliverable
- maturity: publication-ready generation
- structure: one figure plus one table
- goal: split visual summary from exact evidence
## Preferred route
- figure: `pubfig`
- table: `pubtab`
- each artifact should have a distinct communication role
## Minimum acceptable output shape
- explicitly separate figure and table responsibilities
- provide one minimal `pubfig` route and one minimal `pubtab` route
- define export filenames for both
- include QA on redundancy and role separation

View File

@@ -0,0 +1,25 @@
# Example 7 — Revision from a weak chart request
## User-style prompt
I was thinking of using a radar chart for these benchmark results. Can you improve this into something publication-quality?
## Expected skill interpretation
- artifact: revision task
- maturity: review/revision
- structure: likely single figure or figure+table alternative
- goal: replace a weak chart choice with a stronger one
## Preferred route
- review the proposed radar choice critically
- recommend a stronger alternative such as grouped scatter, line, or a table depending on the claim
- only keep radar if the profile comparison is genuinely the right representation
## Minimum acceptable output shape
- explain why the original chart is weak or risky
- recommend a better artifact type
- provide the replacement implementation route
- include targeted QA / revision notes, not vague style comments

View File

@@ -0,0 +1,25 @@
# Example 8 — Review an existing figure or table draft
## User-style prompt
Here is my current results figure screenshot and the draft benchmark table. Please tell me what is weak, whether the figure should stay a figure or become a figure + table pair, and give me the recommended pubfig/pubtab revision path.
## Expected skill interpretation
- artifact: review / revision
- maturity: existing deliverable upgrade
- structure: figure-only or figure + companion table
- goal: keep the strongest communication role for each artifact instead of polishing a weak form blindly
## Preferred route
- inspect the current figure/table role split first
- recommend whether the figure should stay visual and the table should preserve exact values
- use `pubfig` for the figure revision and `pubtab` for the table revision when both are needed
## Minimum acceptable output shape
- identify the concrete publication weaknesses in the current artifact(s)
- say whether the final deliverable should be figure-only, table-only, or figure + table
- provide one runnable `pubfig` and/or `pubtab` revision route
- define explicit export filenames and a short QA checklist

View File

@@ -0,0 +1,47 @@
# Chart Selection
## Task-to-chart mapping
| Communication task | Preferred forms | Notes |
|---|---|---|
| Benchmark comparison | grouped scatter, bar, companion table | use table when exact values matter most |
| Ablation | grouped comparison, dumbbell, compact table | keep the dimension count small |
| Calibration / evaluation | calibration, ROC, PR, BlandAltman | choose what matches the evaluation claim |
| Distribution | box, violin, raincloud, histogram, density, ECDF, QQ | choose by whether shape or exact quantiles matter |
| Relationship | scatter, bubble, contour2d, hexbin | use hexbin/contour2d when overplotting is severe |
| Trend | line, area | line is usually the safer default |
| Diagnostic effect size | forest plot, volcano | match domain and inference style |
| Set/composition | UpSet, stacked ratio, donut, radial hierarchy | avoid decorative complexity unless it helps interpretation |
| Exact benchmark appendix | publication table | default to `pubtab` |
## Use X instead of Y
- Use **grouped scatter** or a **table** instead of a dense grouped bar when exact per-group values matter.
- Use **line** instead of bar for ordered progression over time or scale.
- Use **UpSet** instead of Venn-style thinking once the set count grows.
- Use **forest plot** instead of overloaded textual effect summaries.
- Use **table** instead of radar when precision and comparability matter more than shape.
- Use **hexbin** or **contour2d** instead of raw scatter when point overlap hides structure.
- Use **ECDF** when comparing cumulative distributions clearly is more important than showing a smoothed KDE.
## Anti-patterns
Avoid:
- pie/donut for exact quantitative comparison unless the composition story is primary and category count is small,
- radar for many categories or when axes are not semantically comparable,
- 3D effects,
- decorative color ramps without semantic purpose,
- overly dense legends that repeat axis information,
- mixed chart types that make the evidence harder to read,
- turning every result into a figure when a publication table would be cleaner.
## Selection heuristic
Ask in order:
1. What claim is the reader supposed to take away?
2. Does the reader need pattern perception or exact value lookup?
3. Are the groups ordered, categorical, repeated, hierarchical, or overlapping?
4. Is the result single-panel or likely part of a multi-panel figure?
5. Would a figure-only answer hide important exact values that should live in a table?

View File

@@ -0,0 +1,34 @@
# Composite Assembly
## Principle
Composite assembly is a **secondary branch**, not the default workflow.
Use it when:
- the user explicitly wants a multi-panel paper figure,
- panel-level maintenance matters,
- or the final paper figure needs finishing beyond a single exported plot.
## Default stance
- Single-panel figure → stay in `pubfig` normal export mode.
- Multi-panel figure with real assembly needs → use panel/composite export.
- Figma is optional and should not be introduced unless it solves a real assembly problem.
## pubfig routes
Relevant `pubfig` capabilities:
- `export_panel(...)`
- `export_panels(...)`
- `batch_export(...)`
- `save_figure(...)`
If the environment already uses a pubfig/Figma bridge workflow, keep `figure_id` stable across revisions.
## Practical rule
Escalate to composite assembly only after the panel content itself is strong.
Do not use Figma/composite assembly to hide weak chart choice, poor labels, or overloaded panels.

View File

@@ -0,0 +1,159 @@
# Execution and Verification
## Goal
Turn a high-level publication figure/table request into a route that is actually runnable in the current environment.
## Minimum environment probe
Prefer the lightest useful checks.
### Preferred bundled probe
```bash
python3 scripts/ensure_publication_tooling.py --require pubfig --json
python3 scripts/ensure_publication_tooling.py --require pubtab --json
```
The helper probes availability, force-installs missing dependencies into the active interpreter, and returns the post-install status.
### Equivalent manual checks
```bash
python -c "import pubfig; print(pubfig.__version__)"
python -c "import pubtab; print(pubtab.__version__)"
pubtab --help
```
Do not spend the whole turn on setup if the user primarily needs design guidance. Just identify whether the route is executable now or should degrade gracefully.
## Automatic installation policy
If a dependency is missing and the task requires real execution, install it automatically before continuing.
### Preferred bundled route
Use the bundled helper when it is present:
```bash
python3 scripts/ensure_publication_tooling.py --require pubfig
python3 scripts/ensure_publication_tooling.py --require pubtab
```
The helper chooses `uv pip install --python <active-python>` when the project is clearly `uv`-managed, and otherwise falls back to `python -m pip install ...`.
### Equivalent manual install commands
```bash
uv pip install --python "$VIRTUAL_ENV/bin/python" pubfig
uv pip install --python "$VIRTUAL_ENV/bin/python" pubtab
python -m pip install pubfig
python -m pip install pubtab
```
### Required follow-up
After installation:
1. re-run the availability probe,
2. report the updated environment status,
3. continue with the runnable figure/table workflow.
If installation fails, capture the exact error and then fall back to design/specification guidance.
## Route selection
### Use `pubfig` when
- the task is primarily a figure,
- the user already has Python data structures,
- the result is a plot family already covered by `pubfig`,
- export quality matters immediately.
### Use `pubtab` when
- the task is primarily a publication table,
- the input is an Excel workbook, a `.tex` table, or a file-driven workflow,
- the reader needs exact values,
- previewing the table before manuscript insertion matters.
### Use both when
- the figure carries the visual pattern,
- the table preserves exact benchmark values,
- the paper section benefits from one fast visual plus one exact-value artifact.
## First runnable verification
### `pubfig`
After generating a minimal figure route, the first useful verification is:
- can the code execute,
- does `save_figure(...)` or `batch_export(...)` produce the expected files,
- do output suffixes match the intended formats.
### `pubtab`
After generating a minimal table route, the first useful verification is:
- can `xlsx2tex` or `tex2xlsx` run,
- can `preview` render PNG or PDF,
- does the chosen backend (`tabular` or `tabularray`) match the manuscript need.
## Current practical notes
### `pubfig`
Useful export primitives include:
- `save_figure(...)`
- `batch_export(...)`
- `export_panel(...)`
- `export_panels(...)`
Use panel export only when multi-panel assembly is truly needed.
### `pubtab`
Useful file-oriented routes include:
- `pubtab xlsx2tex ...`
- `pubtab tex2xlsx ...`
- `pubtab preview ...`
Remember:
- `xlsx2tex` exports all sheets by default when `--sheet` is not set,
- `preview` can render PNG or PDF,
- `--latex-backend tabularray` should be chosen only when the manuscript/backend requires `tblr`,
- when preview reliability is the immediate priority, validate the table body first and add final `caption` / `label` in a separate manuscript-facing step if needed.
## Graceful degradation
If the tool is missing:
- first try the bundled auto-install helper,
- if that route is unavailable, use the manual install commands above,
- if installation still fails, provide:
- the artifact recommendation,
- the exact files the user should prepare,
- a draft CLI or Python route,
- the export targets,
- and the publication QA checklist.
## Default output wording
When the route is runnable now, say:
- what to run,
- what files should appear,
- what to inspect next.
When the route is not runnable now, say:
- what is missing,
- which helper command or install command was attempted,
- whether the install succeeded or failed,
- what the intended route will be after install,
- and what design decision can already be locked in today.

View File

@@ -0,0 +1,104 @@
# pubfig Recipes
`pubfig` is the default engine for scientific figures.
## Core route
Typical minimal workflow:
```python
import pubfig as pf
fig = pf.line(data, x=x, series_names=["A", "B"])
pf.save_figure(fig, "figure1.pdf")
```
## Common figure families
| Need | Preferred `pubfig` functions |
|---|---|
| benchmark comparison | `bar_scatter`, `grouped_scatter`, `bar`, `line` |
| ablation | `bar_scatter`, `dumbbell`, `paired`, `bar` |
| distribution | `box`, `violin`, `raincloud`, `histogram`, `density`, `ecdf`, `qq` |
| relationship | `scatter`, `bubble`, `contour2d`, `hexbin` |
| trend | `line`, `area` |
| diagnostic / evaluation | `calibration`, `forest_plot`, `bland_altman`, `volcano`, `roc`, `pr_curve` |
| composition / hierarchy | `donut`, `upset`, `radial_hierarchy`, `circular_grouped_bar`, `circular_stacked_bar`, `stacked_ratio_barh` |
| matrix / map | `heatmap`, `corr_matrix`, `clustermap` |
## Export defaults
For a normal first pass:
```python
pf.save_figure(fig, "figure1.pdf")
```
For multiple formats:
```python
pf.batch_export(
fig,
"figure1",
formats=("pdf", "svg", "png"),
spec="nature",
width="single",
dpi=300,
)
```
## When to add export parameters
Only add more export controls when the task demands them:
- `spec` / `width` for venue-style export
- explicit SVG for vector-first downstream editing
- PNG for quick review or raster deliverables
- panel export when the user truly needs composite assembly
- `batch_export(...)` when the same figure needs several publication-style outputs
## Panel export branch
Use these only when multi-panel assembly is genuinely needed:
- `export_panel(...)`
- `export_panels(...)`
Do not default to panel export for single figures.
## Minimal recipe patterns
### Benchmark comparison
```python
fig = pf.grouped_scatter(values, category_names=category_names, group_names=model_names)
pf.save_figure(fig, "benchmark.pdf")
```
### Ablation
```python
fig = pf.dumbbell(baseline, improved, category_names=labels)
pf.save_figure(fig, "ablation.pdf")
```
### Calibration
```python
fig = pf.calibration(prob_true, prob_pred)
pf.save_figure(fig, "calibration.pdf")
```
### Forest plot
```python
fig = pf.forest_plot(effect, lower, upper, labels=labels, reference=1.0)
pf.save_figure(fig, "forest.pdf")
```
### Heatmap
```python
fig = pf.heatmap(matrix)
pf.save_figure(fig, "heatmap.pdf")
```

View File

@@ -0,0 +1,47 @@
# Publication QA Checklist
## Figure QA
Check:
- Is the chart family appropriate for the scientific claim?
- Are axes labeled clearly, with units when needed?
- Is category ordering meaningful and stable?
- Are color choices readable in grayscale or for color-deficient readers?
- Are fonts, line weights, and marker sizes internally consistent?
- Is the legend necessary, and if so, is it compact?
- Does the figure stay readable after downscaling to likely paper width?
- If multi-panel, are labels, spacing, and styling consistent across panels?
- Does the caption need exact numbers that should instead live in a table?
## Table QA
Check:
- Is a table actually the right artifact, or should a companion figure exist?
- Are row/column labels short but unambiguous?
- Are important values easy to locate?
- Is the caption specific enough to stand alone?
- Is the table too dense for the main paper and better suited to appendix?
- If two-column format matters, was width/span considered explicitly?
- Was a preview rendered before treating the table as final?
## Mixed deliverable QA
If both a figure and table are present:
- Does each have a distinct role?
- Is the figure carrying pattern perception?
- Is the table preserving exact values?
- Is there duplication that should be reduced?
## Revision questions
If the artifact is weak, ask:
- Should the chart family change?
- Should exact values move into a table?
- Should the artifact split into two panels?
- Should labels or legends be simplified?
- Should export width/format change?
- Should the artifact move from figure-first to table-first, or the reverse?

View File

@@ -0,0 +1,133 @@
# pubtab Recipes
`pubtab` is the default engine for publication-ready tables.
## Core routes
### Excel to LaTeX
```bash
pubtab xlsx2tex results.xlsx -o results.tex
```
### LaTeX to Excel
```bash
pubtab tex2xlsx tables.tex -o tables.xlsx
```
### Preview
```bash
pubtab preview results.tex -o results.png --dpi 300
pubtab preview results.tex --format pdf -o results.pdf
```
## Python route
```python
import pubtab
pubtab.xlsx2tex("results.xlsx", output="results.tex", theme="three_line")
pubtab.preview("results.tex", output="results.png", dpi=300)
```
## Route selection rule
Prefer the **CLI** when:
- the user already speaks in files,
- the source is Excel or `.tex`,
- the main need is export and preview.
Prefer the **Python API** when:
- the task already lives inside a notebook or script,
- the table generation is part of a larger reproducible pipeline.
## Current practical notes
- `xlsx2tex` exports **all sheets by default** when `--sheet` is not set.
- `preview` can render **PNG or PDF**.
- `--latex-backend tabularray` is useful only when the manuscript/backend really requires `tblr`.
- `preview` can auto-detect `tblr`, but explicit backend override is still fine when needed.
- for a robust preview-first workflow, preview the table body first and add the final `caption` / `label` in the manuscript or in a final non-preview export step when needed.
## When to use `tabularray`
Use `--latex-backend tabularray` when:
- the user explicitly wants `tblr`,
- the manuscript already uses `tabularray`,
- or the backend must match an existing paper template.
Example:
```bash
pubtab xlsx2tex results.xlsx -o results_tblr.tex --theme three_line --latex-backend tabularray
```
## Common publication controls
Use these when they are justified:
- `--caption`
- `--label`
- `--span-columns`
- `--preview`
- `--latex-backend`
- `--sheet`
- `--with-resizebox`
- `--without-resizebox`
- `--resizebox-width`
## Default guidance
- start with the smallest `xlsx2tex` route,
- preview before treating the table as final,
- use a publication table when exact values matter more than quick pattern perception,
- keep figure and table roles distinct in mixed deliverables.
## Minimal recipe patterns
### Benchmark table from Excel
```bash
pubtab xlsx2tex benchmark.xlsx -o benchmark.tex --caption "Main benchmark results." --label "tab:benchmark"
```
### Two-column table
```bash
pubtab xlsx2tex benchmark.xlsx -o benchmark.tex --span-columns
```
### Preview before submission
```bash
pubtab xlsx2tex benchmark.xlsx -o benchmark_preview.tex
pubtab preview benchmark_preview.tex -o benchmark.png --dpi 300
```
Use this route when the immediate goal is a reliable visual check of the table body.
Keep `caption` / `label` as a separate manuscript-facing step if the preview is the main verification target.
### Final manuscript-facing export
```bash
pubtab xlsx2tex benchmark.xlsx -o benchmark.tex --caption "Main benchmark results." --label "tab:benchmark"
```
### All-sheets export
```bash
pubtab xlsx2tex benchmark.xlsx -o out/benchmark.tex
```
### Native file-pipeline batch roundtrip
```bash
pubtab tex2xlsx ./tables_tex -o ./out/xlsx
pubtab xlsx2tex ./out/xlsx -o ./out/tex
pubtab preview ./out/tex -o ./out/png --format png --dpi 300
```

View File

@@ -0,0 +1,199 @@
# pubfig API map (source-driven)
This guide maps the public `pubfig` API from `pubfig/src/pubfig/__init__.py` to the underlying modules.
## 1. Stable entrypoint
The public contract is defined by re-exports in `pubfig.__init__`.
For agents, this means:
- if a symbol is re-exported there, it is a good default public entrypoint;
- if a helper only exists in deep internal modules, treat it as implementation detail unless there is a strong reason not to.
## 2. Public API groups
### Themes
Public re-exports:
- `set_default_theme`
- `get_default_theme`
- `get_theme`
- `register_theme`
Use these when the task is really about reusable visual policy.
Do not hardcode theme assumptions if a registry call is more appropriate.
### Colors and palettes
Public re-exports include:
- `DEFAULT`, `NATURE`, `SCIENCE`, `LANCET`, `JAMA`
- `get_palette`
- `register_palette`
- `color_to_rgba`
- `darken_color`
- `show_palette`
Source fact:
- palette registration and palette inspection are exposed from the package root.
Operational implication:
- treat palette selection and palette registration as public API usage, not as deep internal customization.
### Export
Public re-exports:
- `save_figure`
- `batch_export`
- `PanelExportRecord`
- `export_panel`
- `export_panels`
- `package_figma_bundle`
- `validate_figma_bundle`
- `inspect_figma_bundle`
Skill implication:
- normal paper figures should usually stop at `save_figure` or `batch_export`
- panel workflows should use `export_panel(s)`
- bundle helpers are for bridge/Figma handoff, not the default answer
### Figure specs
Public re-exports:
- `FigureSpec`
- `get_figure_spec`
- `register_figure_spec`
- `list_figure_specs`
Use this layer whenever the user asks for venue-aware width, journal defaults, or a custom export profile.
### Plot families
The public plot surface is broad, but the source still clusters naturally.
#### Comparison / summary figures
Representative public calls:
- `bar`
- `bar_scatter`
- `stacked_bar`
- `stacked_ratio_barh`
- `donut`
- `dumbbell`
- `forest_plot`
- `grouped_scatter`
- `upset`
Use these for benchmark, ablation, summary, composition, and set-overlap tasks.
#### Distribution figures
Representative public calls:
- `ecdf`
- `qq`
- `box`
- `density`
- `hexbin`
- `histogram`
- `raincloud`
- `strip`
- `ridgeline`
- `violin`
Use these when the scientific claim is about spread, calibration of assumptions, or cohort structure.
#### Trend / profile figures
Representative public calls:
- `line`
- `area`
- `parallel_coordinates`
- `radar`
- `radial_hierarchy`
- `circular_stacked_bar`
- `circular_grouped_bar`
Not all of these are equally strong for publication use. The skill should still apply chart-selection discipline before calling them.
#### Relationship / embedding figures
Representative public calls:
- `scatter`
- `volcano`
- `bubble`
- `contour2d`
- `paired`
- `heatmap`
- `corr_matrix`
- `clustermap`
- `dimreduce`
- `pca_biplot`
Use these for association, error structure, feature layout, and representation views.
#### Evaluation figures
Representative public calls:
- `roc`
- `pr_curve`
- `calibration`
- `bland_altman`
This cluster matters because the source gives them dedicated implementation in `plots/evaluation.py`, which is a sign that evaluation charts are a first-class use case.
## 3. Return-value contract
The source in `export/io.py` makes a subtle but important contract explicit:
- export functions accept a Matplotlib `Figure`,
- or an `Axes`,
- or any object exposing a `.figure` attribute that resolves to a `Figure`.
Source fact:
- the export layer accepts standard Matplotlib figure objects or figure-bearing wrappers.
Operational implication:
- keep the `Figure` handle available and route export through the standard Matplotlib-facing export path.
For the skill, the safest phrasing is:
- create the figure,
- keep a handle to the `Figure`,
- then export explicitly.
## 4. What is not the main stable plotting interface
From the source tree, the CLI is not where normal chart creation happens.
It is mostly an operational layer for Figma bundle and bridge actions.
So if a user says “generate a paper-ready figure,” the skill should not default to a CLI answer.
## 5. Safe public usage pattern
The most source-faithful pattern is:
1. choose a public plot function from `pubfig`
2. generate a `Figure`
3. export via `save_figure(...)` or `batch_export(...)`
4. only use panel/bundle helpers when composition is actually required
## 6. Source-guided caution points
- Do not mix up plot-time design sizing with export-time publication sizing.
- Do not use `save_figure(...)` as a multi-format exporter; the source now pushes that role to `batch_export(...)`.
- Do not route ordinary figure-generation tasks through the Figma bridge CLI.
- Do not assume all public plot families are equally appropriate; the skill must still filter by scientific communication quality.

View File

@@ -0,0 +1,190 @@
# pubfig architecture (source-driven)
This guide reads `pubfig` from the source tree rather than from high-level overview material.
Source root:
- `pubfig/src/pubfig/__init__.py`
- `pubfig/src/pubfig/plots/`
- `pubfig/src/pubfig/export/`
- `pubfig/src/pubfig/specs.py`
- `pubfig/src/pubfig/themes/`
- `pubfig/src/pubfig/colors/`
- `pubfig/src/pubfig/cli.py`
## 1. Start at `pubfig.__init__`
The stable user-facing surface is re-exported from `__init__.py`.
That file tells you the package is organized into five main layers:
1. **plot constructors** from `plots/`
2. **export helpers** from `export/`
3. **publication sizing** from `specs.py`
4. **theme and palette registries** from `themes/` and `colors/`
5. **Figma/bridge helpers** and related CLI support
For skill design, this is the most important architectural fact:
- figure generation lives in `plots/`
- figure export lives in `export/`
- venue sizing lives in `specs.py`
- multi-panel/Figma handoff is a separate downstream layer
The default mental model is **plot first, export second, compose third**.
## 2. Package boundaries
### `plots/`
This is the core figure-construction layer.
Representative files:
- `plots/line.py`
- `plots/comparison.py`
- `plots/evaluation.py`
- `plots/_grouped_scatter.py`
From the source, plot functions usually do the same sequence:
1. normalize/coerce input data,
2. enter `theme_context(theme)`,
3. resolve design-time size via `resolve_design_dpi(...)`,
4. allocate figure/axes via `get_fig_ax(...)`,
5. style axes/legends through helpers in `_style.py`,
6. return a Matplotlib `Figure`.
Interpretation from source:
- `pubfig` behaves as a **Matplotlib-first figure factory layer**, not as a separate scene-graph runtime.
### `export/`
This is intentionally separated from plotting.
Important files:
- `export/io.py`
- `export/panels.py`
`export/io.py` handles normal figure export:
- coerce Figure/Axes into a real `Figure`
- enforce explicit suffixes
- apply publication width/height rules
- write vector or raster output
Current source implication:
- `batch_export(...)` now belongs to the same publication-aware export layer, rather than to a simple multi-format `savefig` wrapper.
`export/panels.py` handles panel-level export for composite or Figma-oriented workflows:
- one panel at a time or many panels together
- optional publication-aware sizing
- optional title stripping
- metadata index generation (`panel-index.json`)
### `specs.py`
This file is the publication-sizing contract.
`FigureSpec` defines:
- `font_family`
- `design_dpi`
- `single_column_mm`
- `double_column_mm`
- `default_raster_dpi`
- `background_color`
Built-in registry entries include:
- `nature`
- `science`
- `cell`
The source shows a strong split between:
- **design size** used when constructing interactive figures,
- **physical export size** used when saving publication figures.
That split is why the skill should not treat `width` in plot calls and `width` in export calls as the same semantic layer.
### `themes/` and `colors/`
These are registries, not plain constants.
From `__init__.py`, the public surface includes:
- `get_theme`, `register_theme`, `set_default_theme`
- `get_palette`, `register_palette`, `show_palette`
Operational implication:
- treat theme and palette selection as first-class API configuration rather than as hardcoded styling trivia.
### `cli.py`
The current CLI is not the main figure-generation interface.
From the source, `cli.py` is mainly about:
- Figma bridge serving
- bundle packaging/inspection/validation
- sync job submission and waiting
- local bridge auto-start logic
So for this skill:
- **Python API is the primary route for figure generation**
- `pubfig.cli` is a secondary operational layer for bridge/Figma workflows
## 3. Plotting architecture pattern
From `line.py`, `comparison.py`, and `evaluation.py`, the recurring internal pattern is:
- input normalization is local to the chart family,
- shared visual behavior is delegated to internal helpers,
- returned artifact is still a standard Matplotlib figure.
This is why the skill should map requests to a chart family first, instead of jumping directly to export or panel assembly.
Examples from source:
- `line.py` groups time/trend style plots
- `comparison.py` groups comparison-style statistical displays like `dumbbell` and `forest_plot`
- `evaluation.py` groups metric/evaluation plots like `roc`, `pr_curve`, and `calibration`
- `_grouped_scatter.py` contains the more specialized placement/jitter/annotation logic behind grouped scatter layouts
## 4. Export architecture pattern
From `export/io.py` and `export/panels.py`, `pubfig` uses three distinct output modes:
1. **single explicit artifact** via `save_figure(...)`
2. **publication-aware multi-format artifact set** via `batch_export(...)`
3. **panel bundle workflow** via `export_panel(...)` / `export_panels(...)`
Those are different contracts, and the skill should keep them separate in its recommendations.
## 5. Reading order for deep debugging
When a skill or agent needs source-level certainty, use this order:
1. `pubfig/src/pubfig/__init__.py`
2. relevant chart-family module in `plots/`
3. `pubfig/src/pubfig/specs.py`
4. `pubfig/src/pubfig/export/io.py`
5. `pubfig/src/pubfig/export/panels.py`
6. `pubfig/src/pubfig/cli.py` only if the task involves bridge/Figma sync
## 6. Implications for this skill
This source layout implies the skill should:
- default to **Python plot API + explicit export call**,
- treat publication sizing as an export concern,
- treat panel/Figma work as optional downstream composition,
- avoid presenting the CLI as the main path for ordinary figure generation,
- keep chart selection logically ahead of export tuning.

View File

@@ -0,0 +1,210 @@
# pubfig export flow (source-driven)
This guide explains how `pubfig` moves from a generated Matplotlib figure to paper-ready files.
Primary source files:
- `pubfig/src/pubfig/export/io.py`
- `pubfig/src/pubfig/export/panels.py`
- `pubfig/src/pubfig/specs.py`
## 1. Core export contract
`export/io.py` separates two concerns:
- **coercing a valid figure object**
- **writing explicit output files**
The helper `_coerce_mpl_figure(...)` accepts:
- a `Figure`
- an `Axes`
- an object with a `.figure` attribute pointing to a `Figure`
The export layer is standardized around Matplotlib figures, even if upstream plotting code returns a richer wrapper.
## 2. `save_figure(...)` is now single-target and suffix-explicit
A key source-level rule lives in `_resolve_save_figure_target(...)`:
- `save_figure(...)` now requires an explicit filename suffix,
- supported examples include `.pdf`, `.svg`, `.png`, `.jpg`, `.tif`, `.eps`, `.ps`,
- if there is no suffix, the function raises an error,
- if multiple outputs are wanted, the source tells you to use `batch_export(...)`.
Skill implication:
- always write `results/figure1.pdf` rather than `results/figure1`
- when you want several formats, recommend `batch_export(...)`, not legacy vector/raster format lists
## 3. Publication sizing path
`save_figure(...)` is publication-aware.
Internally it does the following:
1. load the chosen `FigureSpec` via `get_figure_spec(...)`
2. resolve width through `resolve_width_mm(...)`
3. resolve height through `resolve_height_mm(...)`
4. set the Matplotlib figure size in inches using mm-to-inch conversion
5. choose raster DPI from the spec unless overridden
6. save the explicit target file
7. restore original caller state afterward
Interpretation from source:
- export sizing is more than a file-write step; it can temporarily resize the figure to venue-oriented physical dimensions before output.
## 4. Width and height semantics
From `specs.py`:
- width can be `single`, `double`, or a numeric mm value
- the built-in registry contains `nature`, `science`, and `cell`
- height can be explicit `height_mm`
- otherwise height is derived from `aspect_ratio`
That yields a clean rule for the skill:
- if the user asks for publication width, use `save_figure(..., spec=..., width=...)`
- if the user only wants quick draft export, keep the recommendation minimal
## 5. `batch_export(...)`
`batch_export(...)` is the publication-aware multi-format lane.
Source behavior:
- it takes a `base_path`
- it accepts publication export controls such as `spec`, `width`, `height_mm`, `aspect_ratio`, and `dpi`
- appends each explicit suffix from `formats`
- relayouts the figure through `_export_with_publication_layout(...)` for each target format
- restores the original in-memory figure size/state after export
This is the right recommendation when the user needs, for example:
- `PDF` for manuscript submission
- `SVG` for downstream editing
- `PNG` for slides or issue threads
Operational implication:
- use `batch_export(...)` when the task needs multiple publication-style outputs from the same figure,
- do not describe it as a plain `savefig` loop.
## 6. What `_save_basic_figure(...)` still does
`_save_basic_figure(...)` is still relevant, but it is no longer the main multi-format path for `batch_export(...)`.
It remains the lower-level path used for:
- direct basic export helpers,
- size-preserving panel export in `export/panels.py`,
- and internal single-target save operations that do not need publication relayout.
From the source, it also handles:
- output directory creation
- vector-text rcParams (important for editable SVG/PDF text handling)
- post-layout legend alignment
- post-layout callbacks attached by plot code
- trim/tight bbox behavior
So export quality is partially centralized in the export layer, not only inside plot modules.
## 7. Panel export lane
`export/panels.py` defines the multi-panel handoff path.
Key components:
- `PanelExportRecord`
- `export_panel(...)`
- `export_panels(...)`
- `_write_panel_index(...)`
A `PanelExportRecord` stores:
- `panel_id`
- `path`
- `format`
- `exported_at`
- `figma_node_name`
- `pubfig_version`
- optional `title`
- optional `label`
This shows that panel export is not only file emission. It also preserves minimal sync metadata.
## 8. Title stripping is intentional
One subtle but important source behavior:
- `_temporarily_strip_titles(...)` removes figure/axes titles during panel export by default unless `include_title=True`
Operational implication:
- panel-first composite assembly usually wants clean panel artwork,
- whole-figure titles and layout labels are often handled later,
- prefer exporting clean panel art first and adding whole-figure titles or layout labels downstream when needed.
## 9. Publication-aware vs size-preserving panel export
`export_panel(...)` has two modes:
### Publication-aware mode
Triggered when any of these are supplied:
- `spec`
- `width`
- `height_mm`
Then it delegates to `save_figure(...)`.
### Size-preserving mode
If none of those are supplied, it falls back to `_save_basic_figure(...)` and preserves the figures current size.
Skill implication:
- for reproducible paper panels, specify publication export parameters
- for design review or quick composition, preserving current size may be acceptable
## 10. Multiple panel export
`export_panels(...)` does three main things:
1. normalize and validate panel ids,
2. resolve labels for each panel,
3. export each panel and optionally write `panel-index.json`.
Default recommendation:
- prefer this route when the user wants a structured panel directory rather than a single whole-figure asset.
## 11. Overwrite and safety behavior
From `_ensure_writable_target(...)`:
- an existing panel file raises unless `overwrite=True`
That is useful for skill guidance because it means refresh-in-place is an explicit decision.
## 12. Recommended source-faithful export patterns
### Single paper figure
- plot with `pubfig.<chart_family>(...)`
- save with `save_figure(fig, 'out/figure1.pdf', spec='nature', width='single')`
### Same figure in several formats
- plot once
- export with `batch_export(fig, 'out/figure1', formats=('pdf', 'svg', 'png'), spec='nature', width='single', dpi=300)`
### Multi-panel downstream assembly
- generate each panel as a separate `Figure`
- export with `export_panels(...)`
- use the index file for composite/Figma-aware downstream handling

View File

@@ -0,0 +1,216 @@
# pubtab architecture (source-driven)
This guide explains `pubtab` from the actual package layout under `pubtab/src/pubtab`.
Core files:
- `__init__.py`
- `cli.py`
- `models.py`
- `reader.py`
- `renderer.py`
- `config.py`
- `_preview.py`
- `tex_reader.py`
- `backends/`
- `themes/`
## 1. Start at `pubtab.__init__`
The public contract is defined in `__init__.py`.
Public exports are intentionally small:
- `xlsx2tex`
- `preview`
- `compile_pdf`
- `tex_to_excel`
- `SpacingConfig`
This is the key architectural signal: `pubtab` exposes a compact API, while the real complexity is pushed into reader/renderer/preview internals.
## 2. Core data model layer
`models.py` defines the structured table representation.
Important dataclasses:
- `CellStyle`
- `Cell`
- `TableData`
- `SpacingConfig`
- `ThemeConfig`
- `BackendConfig`
Source fact:
- the shared structured representation is `TableData`, not raw Excel cells or raw LaTeX text.
Forward and reverse conversions both pass through this structured table model.
## 3. Forward pipeline: Excel to LaTeX
The main forward path is:
1. `xlsx2tex(...)` in `__init__.py`
2. `read_excel(...)` in `reader.py`
3. `render(...)` in `renderer.py`
4. optional preview through `_preview.py`
This gives a clean source-driven decomposition:
- `reader.py` = file ingestion and structure recovery
- `renderer.py` = LaTeX generation
- `_preview.py` = compile and raster preview
## 4. Reverse pipeline: LaTeX to Excel
The reverse path is:
1. `tex_to_excel(...)` in `__init__.py`
2. `read_tex_multi(...)` from `tex_reader.py`
3. writer functions to `.xlsx`
So roundtrip support is not an afterthought. It is a real architecture branch.
## 5. `reader.py` is richer than a plain spreadsheet loader
From the source, `reader.py` does much more than “read cells”:
- supports `.xlsx` and `.xls`
- extracts rich text segments
- reconstructs merged cells and spans
- reads styling information
- trims only trailing globally empty columns
- reads pubtab metadata sheets
- restores group separators, multicolumn alignment hints, and math-script hints
Interpretation from source:
- `pubtab` is optimized for **publication table semantics**, rather than for plain tabular text dumping.
## 6. `renderer.py` is the central logic hub
`renderer.py` turns `TableData` into backend-specific LaTeX.
From the source, it handles:
- style/theme loading
- backend template loading
- spacing resolution
- column spec construction or projection
- tabular vs tabularray differences
- merged cells, row/column spans, header rules, vertical rules
- background colors and grouped separators
- final template rendering
This file is where most of the difficult publication logic lives.
For skill design, that means:
- backend choice is not a cosmetic toggle
- column spec and rule behavior are structural concerns
- preview/render bugs usually require reading `renderer.py`
## 7. Theme vs backend is a real split
The codebase separates:
- **themes** in `themes/`
- **LaTeX backends** in `backends/`
That is reflected in two dataclasses:
- `ThemeConfig`
- `BackendConfig`
And in two loaders:
- `load_theme(...)`
- `load_backend(...)`
This is a major architectural point for the skill:
- theme decides stylistic defaults,
- backend decides LaTeX environment/template behavior.
Do not explain them as if they were the same thing.
## 8. Config precedence is explicit
In `xlsx2tex(...)`, the source implements a clear precedence order:
1. hardcoded defaults
2. YAML config loaded by `config.py`
3. explicit function kwargs
4. in some roundtrip cases, values recovered from `TableData`
This is why user-facing guidance should say “CLI flags or function kwargs override YAML config.”
## 9. Multi-file and multi-sheet support are first-class
From `__init__.py`:
- directory input is supported for both forward and reverse paths
- sheet enumeration is supported when `sheet=None`
- multi-sheet export produces `*_sheetNN.tex`
The default skill guidance can therefore recommend batch/file-driven workflows, not only one-table-at-a-time usage.
## 10. Preview is a real compilation layer
`preview(...)` and `compile_pdf(...)` in `__init__.py` delegate into `_preview.py`.
That layer:
- finds or installs `pdflatex`
- builds a standalone document
- compiles the output
- retries missing packages through `tlmgr`
- converts PDF to PNG when requested
Preview is not a fake HTML-like snapshot. It is a real LaTeX compile pipeline.
## 11. `tex_reader.py` closes the roundtrip loop
`tex_reader.py` is substantial, not decorative.
From the source it supports parsing of:
- `tabular`
- `tblr`
- `longtblr`
- `talltblr`
It also handles:
- color parsing
- rule parsing
- multirow/multicolumn reconstruction
- metadata extraction
- grouped rows and placeholder cleanup
This makes `pubtab` suitable for source-aware roundtrip and migration tasks, rather than only one-way Excel export.
## 12. Reading order for source debugging
When you need source-level certainty, use this order:
1. `pubtab/src/pubtab/__init__.py`
2. `pubtab/src/pubtab/models.py`
3. `pubtab/src/pubtab/reader.py`
4. `pubtab/src/pubtab/renderer.py`
5. `pubtab/src/pubtab/_preview.py`
6. `pubtab/src/pubtab/tex_reader.py`
7. `pubtab/src/pubtab/backends/` and `themes/`
8. `pubtab/src/pubtab/cli.py` for flag-to-API mapping only
## 13. Implications for this skill
The source says the most faithful default workflow is:
- use `xlsx2tex(...)` or CLI `xlsx2tex` for forward generation,
- use `preview(...)` to verify actual compile output,
- use `tex_to_excel(...)` for roundtrip or migration tasks,
- explain theme/backend separately,
- escalate into renderer/source debugging only when table structure or LaTeX behavior is the real problem.

View File

@@ -0,0 +1,201 @@
# pubtab backend and preview internals (source-driven)
This guide focuses on the two most important deeper layers in `pubtab`:
- backend/theme separation
- real preview/compile execution
Primary source files:
- `pubtab/src/pubtab/themes/__init__.py`
- `pubtab/src/pubtab/backends/__init__.py`
- `pubtab/src/pubtab/renderer.py`
- `pubtab/src/pubtab/_preview.py`
## 1. Theme and backend are different contracts
The source separates them cleanly.
### Theme layer
In `themes/__init__.py`, a theme resolves to `ThemeConfig`.
It carries style defaults such as:
- `column_sep`
- `font_size`
- `caption_position`
- `SpacingConfig`
### Backend layer
In `backends/__init__.py`, a backend resolves to:
- `BackendConfig`
- a Jinja template string
`BackendConfig` carries things like:
- package requirements
- preamble hints
- backend identity
Operational implication:
- theme = stylistic defaults
- backend = LaTeX environment/template machinery
## 2. Legacy normalization exists, but it is not the conceptual model
The source still supports legacy composite theme names like `_tabularray` suffixed themes.
Normalization happens in places like:
- `_normalize_theme_backend_choice(...)`
- `resolve_theme(...)`
But that compatibility layer should not define the skills main explanation.
The current conceptual model is still **separate theme + backend**.
## 3. What `render(...)` actually does
`renderer.py` is the core place where theme/backend decisions become concrete LaTeX.
Inside `render(...)`, the source does roughly this:
1. normalize theme/backend choice
2. load theme config
3. load backend config and template
4. merge default/theme/user spacing
5. compute or project column specs
6. branch into backend-specific row/cell rendering
7. render through Jinja
Backend choice changes the internal rendering algorithm, not only the final environment name.
## 4. `tabular` vs `tabularray` from the source perspective
The source suggests this practical distinction:
### `tabular`
- more classic LaTeX path
- column spec and rules are handled in the traditional environment
- when source `column_spec` exists, renderer tries to preserve classic rule structure
### `tabularray`
- dedicated `tblr`-style rendering path
- special handling for promoted vertical lines and grouped header boundaries
- extra sanitization in preview compile path
Interpretation from source:
- `tabularray` is a distinct renderer path with its own structural handling, not merely a cosmetic wrapper around `tabular`.
## 5. Why backend choice sometimes matters a lot
From `renderer.py`, backend differences affect:
- how colspec is interpreted
- how vertical rules are preserved or promoted
- how merged cells are encoded
- how row coloring and header boundaries are emitted
So if a table is structurally complex, the skill should not present backend choice as arbitrary.
## 6. Preview is a real LaTeX toolchain
`_preview.py` proves preview is a full execution pipeline.
Major steps:
1. locate `pdflatex`
2. install TinyTeX if missing
3. build a standalone document around the table
4. compile with `pdflatex`
5. auto-install missing LaTeX packages when possible
6. return PDF or convert to PNG
Preview is therefore a genuine verification step.
## 7. `pdflatex` discovery and TinyTeX fallback
The source checks:
- system `PATH`
- pubtab-managed TinyTeX under `~/.pubtab/TinyTeX`
If neither exists, it installs TinyTeX automatically.
This is why the skill can confidently describe preview as relatively self-healing, while still warning that first-run setup may download TeX assets.
## 8. Missing package retry
A particularly important source behavior:
- compile logs are scanned for missing `.sty`
- missing style names are mapped to `tlmgr` package names when needed
- `tlmgr install <pkg>` is run automatically
- compilation is retried
This is strong evidence that the recommended workflow should include preview, because preview can repair part of the environment on the way.
## 9. Standalone preview wrapping
`_build_standalone(...)` does more than wrap text in a document.
It also:
- imports backend-required packages
- preserves setup commands outside the `resizebox` body
- wraps the body in a preview-friendly standalone/minipage layout
- converts `\caption{...}` into `\captionof{table}{...}` during float stripping
This explains why preview output can differ from naive manual compilation if the user simply pastes a table fragment into a document incorrectly.
## 10. `tabularray` preview sanitization
Before compilation, `_sanitize_tblr_for_compile(...)` removes some commands that break inside `tblr` preview contexts, including certain row-color and `\cmidrule` forms.
So when debugging preview-vs-final-document differences, this source behavior matters.
## 11. PDF to PNG conversion fallback stack
For PNG previews, the source tries:
1. `pdf2image`
2. fallback to PyMuPDF (`fitz`)
Preview generation remains resilient even after PDF compilation succeeds.
## 12. Practical skill guidance from the source
### Recommend `tabular` when
- the table is simple/classic,
- the user wants conservative LaTeX output,
- compatibility matters more than modern layout features.
### Recommend `tabularray` when
- grouped headers and more complex structural layouts matter,
- the user is already targeting a `tblr`-capable workflow,
- the roundtrip/source table has rule structure that benefits from the dedicated renderer path.
### Recommend preview almost always when
- the table is intended for publication,
- the user is changing backend/theme/colspec,
- the task involves debugging table layout,
- the task depends on compile-time package correctness.
## 13. Failure triage order
When the generated table is wrong, debug in this order:
1. check theme/backend choice,
2. inspect `render(...)` inputs (`TableData`, colspec, span settings),
3. run preview/compile,
4. inspect missing package or backend-specific compile issues,
5. only then move into manuscript-level integration debugging.

View File

@@ -0,0 +1,178 @@
# pubtab CLI and API flow (source-driven)
This guide follows the actual control flow from `pubtab/src/pubtab/cli.py` into the public API and then into the internal pipeline.
## 1. Architectural headline
`cli.py` is a **thin Click wrapper** over the public API in `pubtab.__init__`.
Operational implication:
- command-line behavior should usually match Python API behavior,
- when docs disagree, the source of truth is `pubtab.__init__`, not CLI help text alone.
## 2. CLI commands exposed in `cli.py`
The main commands are:
- `pubtab xlsx2tex`
- `pubtab themes`
- `pubtab tex2xlsx`
- `pubtab preview`
There is also a hidden backward-compatible alias:
- `convert` -> `xlsx2tex`
## 3. `xlsx2tex` command flow
CLI entrypoint:
- `xlsx2tex_cmd(...)` in `cli.py`
Control flow:
1. validate input/output shape
2. coerce `--sheet` into int when possible
3. build kwargs only for explicitly provided options
4. call `pubtab.xlsx2tex(input_file, output, **kwargs)`
5. print output summary based on sheet count and preview mode
This thin-wrapper design matters because the CLI does **not** reimplement conversion logic.
## 4. `xlsx2tex(...)` API flow
The public API in `__init__.py` adds the real orchestration:
### Input modes
- single Excel file
- directory of Excel files
- single sheet
- all sheets (`sheet=None`)
### Output path behavior
- single-sheet export can target a direct `.tex` path
- directory input must target a directory
- multi-sheet export uses `*_sheetNN.tex`
This behavior is implemented by `_build_sheet_output_paths(...)` and directory iteration helpers.
## 5. Config precedence in the real API
Inside `xlsx2tex(...)`, the source builds parameters in this order:
1. defaults
2. YAML config via `load_config(...)`
3. explicit kwargs passed from CLI or Python
4. roundtrip-restored values where relevant
Operational rule:
- YAML config sets baseline behavior,
- CLI flags / Python kwargs override it.
## 6. Sheet expansion behavior
When `sheet is None`, the source does not simply choose the first sheet.
It calls `list_excel_sheets(...)` and expands all sheet names into separate outputs.
That is why a single workbook can generate:
- `table_sheet01.tex`
- `table_sheet02.tex`
- ...
The skill should explicitly mention this when users want appendix exports or workbook-wide conversion.
## 7. Read -> render -> write flow
For each selected sheet, `xlsx2tex(...)` does:
1. `read_excel(...)`
2. optional header or group-separator reconstruction
3. `render(...)`
4. write `.tex`
5. optional preview generation to `.png`
Preview is downstream of actual `.tex` generation, not an alternate renderer.
## 8. `preview` command flow
CLI entrypoint:
- `preview_cmd(...)`
The CLI again mostly validates paths and forwards to `pubtab.preview(...)`.
The public `preview(...)` API supports:
- raw LaTeX content
- a single `.tex` file
- a directory of `.tex` files
- `png` or `pdf` output
A key source detail: when backend is omitted, `preview(...)` may infer it from the LaTeX content using `_resolve_preview_inputs(...)`.
## 9. Backend inference path
`_infer_latex_backend(...)` checks for environments like:
- `tblr`
- `longtblr`
- `talltblr`
If found, backend becomes `tabularray`; otherwise `tabular`.
Operational implication:
- a preview or compile call can often resolve the correct backend without requiring an explicit `--latex-backend` flag.
## 10. `compile_pdf(...)` API flow
Public `compile_pdf(...)` in `__init__.py` does:
1. detect whether input is raw LaTeX or a file path,
2. infer theme/backend if needed,
3. delegate to `_preview.compile_pdf(...)`.
The compile path is still part of the public API, even though the heavy lifting is in `_preview.py`.
## 11. `tex2xlsx` command flow
CLI entrypoint:
- `tex2xlsx(...)` in `cli.py`
It forwards to `pubtab.tex_to_excel(...)`.
The public API then handles:
- single `.tex` file -> one `.xlsx`
- multi-table `.tex` -> one workbook with multiple sheets
- directory of `.tex` files -> one `.xlsx` per file
This keeps the reverse path operationally symmetric with the forward path.
## 12. Why the CLI should stay thin in this skill
Because the real logic is centralized in `pubtab.__init__`, the skill should:
- use CLI examples for file-driven shell workflows,
- use Python API examples for notebooks or scripted pipelines,
- avoid duplicating pseudo-logic that already exists in the library.
## 13. Recommended source-faithful routing
### Use CLI when
- the user already has Excel or `.tex` files on disk,
- the task is batch conversion,
- the user wants a terminal-first workflow.
### Use Python API when
- the user is in a notebook or script,
- the table needs custom preprocessing before render,
- the agent is composing a larger Python pipeline.

View File

@@ -0,0 +1,82 @@
# Workflow
## Default decision order
1. Identify the scientific communication goal.
2. Probe the environment and available assets lightly.
3. Decide whether the evidence should be a figure, a table, or a paired figure+table deliverable.
4. Choose the strongest representation family.
5. Route to `pubfig`, `pubtab`, or both.
6. Produce the smallest runnable implementation.
7. Specify export outputs explicitly.
8. Run publication QA.
9. Propose revisions if the result is weak.
## Handoff checklist
For every task, try to make these explicit:
- claim the artifact is supposed to support
- data shape and grouping structure
- target audience or venue expectations
- figure vs table role
- exact output filenames and formats
- whether the artifact is final, draft, or revision
- whether the current environment can execute the proposed route immediately
## Delivery contract
A strong response should make clear:
- which artifact type was chosen,
- why it was chosen,
- which tool owns each artifact,
- what the first runnable command/code path is,
- what output files should be produced,
- what still needs user input or upstream data.
## Default output priorities
Prioritize in this order:
1. clarity of claim
2. correct artifact type
3. minimal runnable implementation
4. publication-ready export
5. QA and revision guidance
## Graceful degradation when tools are missing
If `pubfig` or `pubtab` is not installed:
- keep the workflow going,
- provide installation guidance,
- provide pseudocode or draft commands,
- specify the recommended artifact structure,
- preserve the QA and revision guidance.
## Figure / table split rules
Use a **figure** when the reader needs to quickly perceive:
- trend
- distribution shape
- relationship
- calibration or diagnostic behavior
- composition or hierarchy
- visual comparison across a moderate number of groups
Use a **table** when the reader needs:
- exact numbers
- many metrics side by side
- benchmark grids
- ablation matrices
- appendix-style detail
- reproducible value lookup
Use **both** when:
- the figure carries the visual claim,
- the table preserves exact values,
- or the paper section benefits from a fast visual summary plus precise numeric evidence.

View File

@@ -0,0 +1,172 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import importlib
import json
import shutil
import subprocess
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Sequence
@dataclass(frozen=True)
class PackageStatus:
package: str
available: bool
version: str | None = None
error: str | None = None
@dataclass(frozen=True)
class InstallPlan:
installer: str
command: tuple[str, ...]
DEFAULT_PACKAGES: tuple[str, ...] = ("pubfig", "pubtab")
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Probe and force-install pubfig/pubtab into the active Python environment."
)
parser.add_argument(
"--require",
dest="packages",
action="append",
choices=DEFAULT_PACKAGES,
help="Package that must be available. Defaults to pubfig + pubtab.",
)
parser.add_argument(
"--prefer",
choices=("auto", "uv", "pip"),
default="auto",
help="Installer selection policy. Default: auto.",
)
parser.add_argument(
"--cwd",
type=Path,
default=Path.cwd(),
help="Project directory used for uv-managed detection. Default: current directory.",
)
parser.add_argument(
"--json",
action="store_true",
help="Print machine-readable JSON summary.",
)
return parser.parse_args()
def probe_package(package: str) -> PackageStatus:
try:
module = importlib.import_module(package)
except Exception as exc: # noqa: BLE001
return PackageStatus(package=package, available=False, error=f"{type(exc).__name__}: {exc}")
version = getattr(module, "__version__", None)
return PackageStatus(package=package, available=True, version=str(version) if version else None)
def is_uv_managed(cwd: Path) -> bool:
for candidate in [cwd, *cwd.parents]:
if (candidate / "uv.lock").exists():
return True
pyproject = candidate / "pyproject.toml"
if pyproject.exists():
try:
text = pyproject.read_text(encoding="utf-8")
except OSError:
continue
if "[tool.uv" in text or "uv_build" in text:
return True
return False
def choose_installer(prefer: str, cwd: Path) -> str:
if prefer in {"uv", "pip"}:
return prefer
if shutil.which("uv") and is_uv_managed(cwd):
return "uv"
return "pip"
def build_install_plan(installer: str, package: str) -> InstallPlan:
if installer == "uv":
command = ("uv", "pip", "install", "--python", sys.executable, package)
else:
command = (sys.executable, "-m", "pip", "install", package)
return InstallPlan(installer=installer, command=command)
def run_command(command: Sequence[str]) -> subprocess.CompletedProcess[str]:
return subprocess.run(command, check=False, text=True, capture_output=True)
def emit_text(
before: list[PackageStatus],
after: list[PackageStatus],
attempts: list[dict[str, object]],
) -> None:
print("[publication-chart-skill] environment summary")
print(f"python: {sys.executable}")
print("before:")
for status in before:
suffix = f" ({status.version})" if status.version else ""
detail = f" - {status.error}" if status.error else ""
print(f" - {status.package}: {'available' if status.available else 'missing'}{suffix}{detail}")
if attempts:
print("install attempts:")
for attempt in attempts:
print(f" - {attempt['package']}: {attempt['command']} -> exit {attempt['returncode']}")
print("after:")
for status in after:
suffix = f" ({status.version})" if status.version else ""
detail = f" - {status.error}" if status.error else ""
print(f" - {status.package}: {'available' if status.available else 'missing'}{suffix}{detail}")
def main() -> int:
args = parse_args()
packages = tuple(dict.fromkeys(args.packages or DEFAULT_PACKAGES))
before = [probe_package(package) for package in packages]
missing = [status.package for status in before if not status.available]
installer = choose_installer(args.prefer, args.cwd.resolve())
attempts: list[dict[str, object]] = []
for package in missing:
plan = build_install_plan(installer=installer, package=package)
result = run_command(plan.command)
attempts.append(
{
"package": package,
"installer": plan.installer,
"command": " ".join(plan.command),
"returncode": result.returncode,
"stdout": result.stdout.strip(),
"stderr": result.stderr.strip(),
}
)
after = [probe_package(package) for package in packages]
payload = {
"python": sys.executable,
"installer": installer,
"before": [asdict(status) for status in before],
"attempts": attempts,
"after": [asdict(status) for status in after],
"ok": all(status.available for status in after),
}
if args.json:
print(json.dumps(payload, indent=2, ensure_ascii=False))
else:
emit_text(before=before, after=after, attempts=attempts)
return 0 if payload["ok"] else 1
if __name__ == "__main__":
raise SystemExit(main())