| name | haipipe-display-table |
| description | Render a publication-quality LaTeX table from an aggregated data file (CSV/JSON) for a paper display unit. Use when user says "做表", "生成表格", "regression table", "coefficient table", "descriptive table", "comparison table", or needs a typeset booktabs table from results. The data renderer for tables, parallel to haipipe-display-figure (plots). Reads aggregated outputs only; never recomputes from raw data. |
| argument-hint | [table-spec-or-data-path] |
| allowed-tools | Bash(*), Read, Write, Edit, Grep, Glob, Agent, mcp__codex__codex, mcp__codex__codex-reply |
| metadata | {"version":"0.2.1","last_updated":"2026-07-27","summary":"Render publication-quality LaTeX tables from a provenance-bound Display Intake into a display unit."} |
Paper Display Table: Publication-Quality LaTeX Tables from Aggregated Data
Render the LaTeX table(s) for a paper based on: $ARGUMENTS
This is the data-table renderer of the display family.
Its sibling
haipipe-display-figure renders data plots; this skill renders data
tables.
Both read an aggregated data file and emit a reproducible asset; neither
recomputes from raw evidence (that is a haipipe-task-for-display task).
Output: write into a display unit
The table goes into a displays/displayNN-<slug>/ unit per the shared contract:
../../ref/display-unit-output-contract.md.
THIS renderer's row: asset -> assets/table-body.tex (the tabular/threeparttable
block), with caller-owned float.tex the wrapper that \inputs it (caption + label + placement); rebuild recipe
-> recipe/gen_*.py, reading only the approved aggregate in intake/inputs/.
For a new unit, read intake/manifest.yaml before doing anything else.
It must name the task holder, run, canonical artifact, and snapshot that this table may use.
Do not search task folders or select rows from an arbitrary CSV.
Legacy units that contain only source/ remain legacy and are not silently migrated.
Scope: What This Skill Can and Cannot Do
| Category | Can render? | Examples |
|---|
| Coefficient / regression tables | ✅ Yes | OLS/IV/DiD coefficients with SE rows + significance stars, one column per model |
| Descriptive / summary tables | ✅ Yes | Means, SD, N by group; balance tables; sample composition |
| Comparison / feature tables | ✅ Yes | Method × property matrices, prior-work comparison, capability grids |
| Ablation tables | ✅ Yes | Variant × metric grids with best-row bolding |
| Multi-panel tables | ✅ Yes | Panel A / Panel B stacked under one float with shared header |
| Plots (line/bar/scatter/heatmap) | ❌ No | Use haipipe-display-figure |
| Computing the numbers | ❌ No | The aggregated CSV/JSON must already exist (from a task/probe) |
Boundary with the figure renderer: if the asset is a chart, use
haipipe-display-figure.
If it is a typeset table, use this skill.
Tables
were previously a side-feature of the figure renderer; they now live here so the
table-specific concerns (column alignment, decimal places, significance stars, SE
rows, panels, table notes) can be done properly.
Constants
- STYLE =
booktabs — Table rule style.
Always three-line (top/mid/bottom rule), never vertical rules.
- NUMBER_ALIGN =
siunitx — Align numeric columns on the decimal point via S[table-format=...]; fall back to r if siunitx is unavailable.
- STARS =
* p<0.05, ** p<0.01, *** p<0.001 — Default significance thresholds.
State the exact mapping in the table note.
- SE_STYLE =
paren-below — Standard errors in parentheses on the line below each coefficient.
- DECIMALS = 3 — Default decimal places for coefficients; 0-2 for counts/N.
- NOTES =
threeparttable — Table notes go in a threeparttable tablenotes block, not in \caption{}.
- FORMAT =
tex — Output is assets/table-body.tex; the caller-owned float.tex wraps it.
- REVIEWER_MODEL =
gpt-5.5 — Model used via Codex MCP for table quality review.
Inputs
- Display contract — the unit's
README.md (claim, caption intent, section) under displays/displayNN-<slug>/
- Display Intake —
intake/manifest.yaml plus an aggregated CSV/JSON snapshot of already-computed results.
Never raw PHI data.
- Optional table spec — column order, which models, star thresholds, decimals, transpose (variables-as-rows vs models-as-columns), rows to bold
If no display contract or verified intake exists, stop and ask the caller to create one.
Workflow
Step 1: Read the Display Contract and Locate Data
Read displays/displayNN-<slug>/README.md for the claim this table must defend,
the target section, and the caption intent.
Read intake/manifest.yaml, then its declared snapshot path.
Confirm the snapshot holds aggregated results, not row-level PHI, and that its hash matches.
Step 2: Infer the Table Type
| Data shape | Table type | Layout |
|---|
| coef + SE + p, by model | Regression/coefficient table | variables as rows, models as columns |
| stat × group | Descriptive table | stats as rows, groups as columns |
| method × property | Comparison table | methods as rows, properties as columns |
| variant × metric | Ablation table | variants as rows, metrics as columns; bold best |
| two grouped blocks | Multi-panel | Panel A / Panel B stacked, shared column header |
Step 3: Choose the Template
Decide: booktabs always; add threeparttable if there are notes; add siunitx
S columns if numeric alignment matters; \resizebox or tabularx only if the
table would exceed column/text width.
Step 4: Write One Generation Script per Table
For each table, write a standalone Python script that reads the data file and
emits the .tex. Numbers come from the file, never hardcoded.
from pathlib import Path
import pandas as pd
df = pd.read_csv('intake/inputs/reg_main.csv')
def stars(p):
return '***' if p < 0.001 else '**' if p < 0.01 else '*' if p < 0.05 else ''
def cell(coef, se, p):
return f"{coef:.3f}{stars(p)}", f"({se:.3f})"
lines = [
r"\begin{threeparttable}",
r"\begin{tabular}{l S[table-format=-1.3] S[table-format=-1.3]}",
r"\toprule",
r" & {(1) Baseline} & {(2) +Controls} \\",
r"\midrule",
]
for _, r in df.iterrows():
c1, s1 = cell(r.m1_coef, r.m1_se, r.m1_p)
c2, s2 = cell(r.m2_coef, r.m2_se, r.m2_p)
lines.append(f"{r.term} & {c1} & {c2} \\\\")
lines.append(f" & {s1} & {s2} \\\\")
lines += [
r"\midrule",
r"Observations & {%d} & {%d} \\" % (df.attrs.get(, ), df.attrs.get(, )),
,
,
,
,
,
,
]
out = Path()
out.parent.mkdir(parents=, exist_ok=)
out.write_text(.join(lines) + , encoding=)
()
Step 5: Run the Script, Emit the Include, and Verify
python gen_table*.py
Confirm assets/table-body.tex exists and the numbers match the declared Intake
snapshot by spot-check. The Paper caller supplies and approves float.tex (caption,
label, placement); it \inputs the body asset. Do not create latex_include.tex or
write a self-contained wrapper: a table renderer never invents or changes paper-facing
caption semantics.
Step 6: Table Quality Review with REVIEWER_MODEL
Send the rendered table + caption to GPT-5.5 (via Codex MCP) for review:
mcp__codex__codex:
model: gpt-5.5
config: {"model_reasoning_effort": "xhigh"}
prompt: |
Review this LaTeX table for a [VENUE] submission.
1. Is the caption self-contained and the header unambiguous?
2. Are significance stars defined in a note, and consistent with the p-values?
3. Is numeric alignment correct (decimal-aligned)?
4. Does the table exceed column/text width?
5. Any missing rows (Observations, R^2, controls indicator)?
[paste assets/table-body.tex + caller-approved caption]
Step 7: Quality Checklist
Output
The display unit layout (asset -> assets/table-body.tex wrapped by float.tex,
approved values -> intake/inputs/, rebuild recipe -> recipe/gen_table*.py) is the shared contract:
../../ref/display-unit-output-contract.md.
Relation to the Display Stage and Tasks
display-input task (server, PHI) --aggregate + provenance--> Intake --> this skill --> table body
computes the numbers freezes approved values (Paper wraps it)
The heavy computation (regression, descriptives) is a haipipe-task-for-display
task that runs against secure data and exports a movable aggregated CSV.
This
skill turns that CSV into the publication table.
Same split as
haipipe-display-figure: the task owns the data, the renderer owns the
typesetting.
Specialist Return Contract
status: ok | blocked | failed
summary: which table(s) rendered, from which data file, into which display unit
artifacts: [assets/table-body.tex, recipe/gen script, preview paths]
next: suggested next command (often /haipipe-paper-display build or insert)