psyclaw 0.28.0 → 0.28.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/agents/recommended/catalog.json +99 -0
- package/dist/apps/panel/index.html +5 -5
- package/dist/src/adapters/pi/extension.js +164 -18
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/adapters/pi/rpc.d.ts +2 -0
- package/dist/src/adapters/pi/rpc.js +9 -2
- package/dist/src/adapters/pi/rpc.js.map +1 -1
- package/dist/src/agents/recommended-personas.d.ts +42 -0
- package/dist/src/agents/recommended-personas.js +135 -0
- package/dist/src/agents/recommended-personas.js.map +1 -0
- package/dist/src/ars/mode-editor.d.ts +20 -0
- package/dist/src/ars/mode-editor.js +57 -0
- package/dist/src/ars/mode-editor.js.map +1 -0
- package/dist/src/ars/profile.d.ts +4 -1
- package/dist/src/ars/profile.js +23 -6
- package/dist/src/ars/profile.js.map +1 -1
- package/dist/src/cli.js +6 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/creation/contracts.d.ts +3 -0
- package/dist/src/creation/service.js +17 -5
- package/dist/src/creation/service.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/orchestration/bundled-personas.d.ts +16 -0
- package/dist/src/orchestration/bundled-personas.js +101 -0
- package/dist/src/orchestration/bundled-personas.js.map +1 -0
- package/dist/src/orchestration/effects.d.ts +8 -0
- package/dist/src/orchestration/effects.js +39 -0
- package/dist/src/orchestration/effects.js.map +1 -0
- package/dist/src/orchestration/personas.d.ts +2 -1
- package/dist/src/orchestration/personas.js +20 -7
- package/dist/src/orchestration/personas.js.map +1 -1
- package/dist/src/orchestration/pi-executor.d.ts +9 -5
- package/dist/src/orchestration/pi-executor.js +55 -22
- package/dist/src/orchestration/pi-executor.js.map +1 -1
- package/dist/src/orchestration/research-agents.d.ts +3 -7
- package/dist/src/orchestration/research-agents.js +5 -69
- package/dist/src/orchestration/research-agents.js.map +1 -1
- package/dist/src/panel/server.js +6 -0
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/style/cli-ui.d.ts +14 -0
- package/dist/src/style/cli-ui.js +45 -0
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/tui/skill-manager.js +1 -1
- package/dist/src/tui/skill-manager.js.map +1 -1
- package/dist/src/updates/update.js +9 -3
- package/dist/src/updates/update.js.map +1 -1
- package/package.json +11 -3
- package/vendor/academic-paper-skills/LICENSE +21 -0
- package/vendor/academic-paper-skills/NOTICE.md +7 -0
- package/vendor/academic-paper-skills/PSYCLAW_SOURCE.json +14 -0
- package/vendor/academic-paper-skills/academic-paper-composer/SKILL.md +840 -0
- package/vendor/academic-paper-skills/academic-paper-composer/references/section_guides.md +675 -0
- package/vendor/academic-paper-skills/academic-paper-composer/references/writing_standards.md +629 -0
- package/vendor/academic-paper-skills/academic-paper-composer/scripts/chapter_quality_check.py +470 -0
- package/vendor/academic-paper-skills/academic-paper-composer/scripts/final_evaluation.py +550 -0
- package/vendor/academic-paper-skills/academic-paper-strategist/SKILL.md +670 -0
- package/vendor/academic-paper-skills/academic-paper-strategist/references/quality_standards.md +336 -0
- package/vendor/academic-paper-skills/academic-paper-strategist/references/search_strategy.md +459 -0
- package/vendor/academic-paper-skills/academic-paper-strategist/scripts/evaluate_samples.py +300 -0
- package/vendor/academic-paper-skills/academic-paper-strategist/scripts/gap_analysis.py +399 -0
- package/vendor/ars/pi/wrapper.js +9 -0
- package/vendor/nature-skills/LICENSE +201 -0
- package/vendor/nature-skills/NOTICE.md +7 -0
- package/vendor/nature-skills/PSYCLAW_SOURCE.json +19 -0
- package/vendor/nature-skills/skills/nature-figure/README.md +107 -0
- package/vendor/nature-skills/skills/nature-figure/README_EN.md +107 -0
- package/vendor/nature-skills/skills/nature-figure/SKILL.md +154 -0
- package/vendor/nature-skills/skills/nature-figure/agents/openai.yaml +4 -0
- package/vendor/nature-skills/skills/nature-figure/evals/evals.json +325 -0
- package/vendor/nature-skills/skills/nature-figure/manifest.yaml +103 -0
- package/vendor/nature-skills/skills/nature-figure/references/ai-graphical-abstract-workflow.md +129 -0
- package/vendor/nature-skills/skills/nature-figure/references/api.md +576 -0
- package/vendor/nature-skills/skills/nature-figure/references/asset-adaptation.md +72 -0
- package/vendor/nature-skills/skills/nature-figure/references/backend-selection.md +118 -0
- package/vendor/nature-skills/skills/nature-figure/references/chart-types.md +348 -0
- package/vendor/nature-skills/skills/nature-figure/references/common-patterns.md +371 -0
- package/vendor/nature-skills/skills/nature-figure/references/demos.md +58 -0
- package/vendor/nature-skills/skills/nature-figure/references/design-theory.md +467 -0
- package/vendor/nature-skills/skills/nature-figure/references/figure-contract.md +122 -0
- package/vendor/nature-skills/skills/nature-figure/references/figure-legend-conventions.md +90 -0
- package/vendor/nature-skills/skills/nature-figure/references/multipanel-evidence-architecture.md +268 -0
- package/vendor/nature-skills/skills/nature-figure/references/nature-2026-observations.md +124 -0
- package/vendor/nature-skills/skills/nature-figure/references/nature-article-requirements.md +149 -0
- package/vendor/nature-skills/skills/nature-figure/references/openrouter-image-generation.md +141 -0
- package/vendor/nature-skills/skills/nature-figure/references/qa-contract.md +344 -0
- package/vendor/nature-skills/skills/nature-figure/references/r-template-index.md +66 -0
- package/vendor/nature-skills/skills/nature-figure/references/r-workflow.md +234 -0
- package/vendor/nature-skills/skills/nature-figure/references/template-catalog.md +33 -0
- package/vendor/nature-skills/skills/nature-figure/references/tutorials.md +260 -0
- package/vendor/nature-skills/skills/nature-figure/requirements.txt +1 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/audit_figure_collisions.py +742 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/audit_panel_alignment.py +933 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/audit_pdf_text.py +152 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/figure_safety.py +50 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/generate_openrouter_schematic.py +260 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/nature_figure_backend.py +93 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/panel_alignment.R +188 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/plot_templates.py +604 -0
- package/vendor/nature-skills/skills/nature-figure/scripts/validate_figure.py +835 -0
- package/vendor/nature-skills/skills/nature-figure/static/core/contract.md +55 -0
- package/vendor/nature-skills/skills/nature-figure/static/core/stance.md +41 -0
- package/vendor/nature-skills/skills/nature-figure/static/fragments/backend/python.md +56 -0
- package/vendor/nature-skills/skills/nature-figure/static/fragments/backend/r.md +63 -0
- package/vendor/nature-skills/skills/nature-figure/tests/test_figure_safety.py +209 -0
- package/vendor/nature-skills/skills/nature-polishing/README.md +58 -0
- package/vendor/nature-skills/skills/nature-polishing/README_EN.md +58 -0
- package/vendor/nature-skills/skills/nature-polishing/SKILL.md +111 -0
- package/vendor/nature-skills/skills/nature-polishing/agents/openai.yaml +4 -0
- package/vendor/nature-skills/skills/nature-polishing/manifest.yaml +101 -0
- package/vendor/nature-skills/skills/nature-polishing/references/latex-layout.md +211 -0
- package/vendor/nature-skills/skills/nature-polishing/references/nat-comms-2025-diction.md +73 -0
- package/vendor/nature-skills/skills/nature-polishing/references/phrasebank-playbook.md +175 -0
- package/vendor/nature-skills/skills/nature-polishing/references/published-article-patterns.md +126 -0
- package/vendor/nature-skills/skills/nature-polishing/references/section-moves.md +252 -0
- package/vendor/nature-skills/skills/nature-polishing/references/style-guardrails.md +94 -0
- package/vendor/nature-skills/skills/nature-polishing/references/writing-strategy.md +160 -0
- package/vendor/nature-skills/skills/nature-polishing/static/core/failure-modes.md +29 -0
- package/vendor/nature-skills/skills/nature-polishing/static/core/output-format.md +21 -0
- package/vendor/nature-skills/skills/nature-polishing/static/core/stance.md +26 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/journal/generic.md +17 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/journal/nat-comms.md +38 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/journal/nat-mach-intell.md +102 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/journal/nature.md +19 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/language/en.md +19 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/language/zh-to-en.md +19 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/paper_type/algorithmic.md +18 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/paper_type/hypothesis.md +17 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/paper_type/methods.md +35 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/paper_type/research.md +29 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/paper_type/review.md +17 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/abstract.md +26 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/conclusion.md +15 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/discussion.md +48 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/intro.md +33 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/methods.md +26 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/results.md +61 -0
- package/vendor/nature-skills/skills/nature-polishing/static/fragments/section/title.md +17 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/README.md +44 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/README_EN.md +44 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/SKILL.md +196 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/agents/openai.yaml +4 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/manifest.yaml +19 -0
- package/vendor/nature-skills/skills/nature-ref-verifier/references/common-patterns.md +96 -0
- package/vendor/nature-skills/skills/nature-shared/README.md +43 -0
- package/vendor/nature-skills/skills/nature-shared/README_EN.md +43 -0
- package/vendor/nature-skills/skills/nature-shared/SKILL.md +33 -0
- package/vendor/nature-skills/skills/nature-shared/agents/openai.yaml +6 -0
- package/vendor/nature-skills/skills/nature-shared/core/consistency-sweep.md +122 -0
- package/vendor/nature-skills/skills/nature-shared/core/discussion-argument-language.md +192 -0
- package/vendor/nature-skills/skills/nature-shared/core/ethics.md +88 -0
- package/vendor/nature-skills/skills/nature-shared/core/main-text-discipline.md +179 -0
- package/vendor/nature-skills/skills/nature-shared/core/nature-abstract.md +171 -0
- package/vendor/nature-skills/skills/nature-shared/core/nature-introduction.md +164 -0
- package/vendor/nature-skills/skills/nature-shared/core/nature-results-discussion.md +215 -0
- package/vendor/nature-skills/skills/nature-shared/core/paper-type-taxonomy.md +41 -0
- package/vendor/nature-skills/skills/nature-shared/core/reader-workflow.md +21 -0
- package/vendor/nature-skills/skills/nature-shared/core/research-compliance.md +192 -0
- package/vendor/nature-skills/skills/nature-shared/core/terminology-ledger.md +58 -0
- package/vendor/nature-skills/skills/nature-shared/journal-formats/nat-comms.md +139 -0
- package/vendor/nature-skills/skills/nature-shared/journal-formats/nature-machine-intelligence.md +431 -0
- package/vendor/nature-skills/skills/nature-shared/journal-formats/nature.md +313 -0
- package/vendor/nature-skills/skills/nature-shared/manifest.yaml +52 -0
- package/vendor/nature-skills/skills/nature-shared/scripts/check_consistency.py +273 -0
- package/vendor/nature-skills/skills/nature-shared/tests/test_check_consistency.py +63 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# QA Contract
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Current official references to verify](#current-official-references-to-verify)
|
|
6
|
+
- [Pre-submission checklist](#pre-submission-checklist)
|
|
7
|
+
- [Statistics legend minimum](#statistics-legend-minimum)
|
|
8
|
+
- [Image-integrity minimum](#image-integrity-minimum)
|
|
9
|
+
- [Automated source preflight](#automated-source-preflight)
|
|
10
|
+
- [Automatic multi-panel alignment gate](#automatic-multi-panel-alignment-gate)
|
|
11
|
+
- [Automatic rendered collision audit](#automatic-rendered-collision-audit)
|
|
12
|
+
- [Rendered panel-by-panel audit](#rendered-panel-by-panel-audit)
|
|
13
|
+
- [Typography and PDF glyph floor](#typography-and-pdf-glyph-floor)
|
|
14
|
+
- [Uncertainty consistency](#uncertainty-consistency)
|
|
15
|
+
- [Geometry and annotation placement](#geometry-and-annotation-placement)
|
|
16
|
+
- [Color separation and salience](#color-separation-and-salience)
|
|
17
|
+
- [Transformation and paired-effect checks](#transformation-and-paired-effect-checks)
|
|
18
|
+
- [Export checks](#export-checks)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Use this before final delivery, before a revision package, and whenever the figure
|
|
22
|
+
contains microscopy, blots, gels, clinical subgroup analysis, or statistical claims.
|
|
23
|
+
Journal rules change, so verify the latest target journal author guide for final
|
|
24
|
+
submission. The values below are conservative defaults for Nature-family style work.
|
|
25
|
+
For the flagship journal Nature, load `nature-article-requirements.md` and use
|
|
26
|
+
its stage-specific main-figure, Extended Data and legend contracts.
|
|
27
|
+
|
|
28
|
+
## Current official references to verify
|
|
29
|
+
|
|
30
|
+
- Nature research figure guide: `https://research-figure-guide.nature.com/`
|
|
31
|
+
- Nature building/exporting panels: `https://research-figure-guide.nature.com/figures/building-and-exporting-figure-panels/`
|
|
32
|
+
- Nature preparing figures/specifications: `https://research-figure-guide.nature.com/figures/preparing-figures-our-specifications/`
|
|
33
|
+
- Nature initial submission and statistics guidance: `https://www.nature.com/nature/for-authors/initial-submission`
|
|
34
|
+
- Nature formatting guide: `https://www.nature.com/nature/for-authors/formatting-guide`
|
|
35
|
+
- Journal of Cell Biology figure/video guidelines for microscopy-oriented image QA: `https://rupress.org/jcb/pages/fig-vid-guidelines`
|
|
36
|
+
- Elsevier/Cell-family image-manipulation baseline: `https://www.sciencedirect.com/journal/the-cell-surface/publish/guide-for-authors`
|
|
37
|
+
|
|
38
|
+
## Pre-submission checklist
|
|
39
|
+
|
|
40
|
+
| Check | Pass condition |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Core conclusion | One-sentence claim exists and every panel maps to it |
|
|
43
|
+
| Archetype | Figure has a declared archetype and panel hierarchy |
|
|
44
|
+
| Backend exclusivity | The selected backend produced all plotting, previews, exports, and visual QA renders |
|
|
45
|
+
| Final size | Single-column about 89 mm or double-column about 183 mm, height not above target journal limit |
|
|
46
|
+
| Text size | Body/tick/legend text is readable at final size, usually 5-7 pt for dense journal figures |
|
|
47
|
+
| Rendered glyph floor | Every PDF text run, including math superscripts/subscripts, is at least 5 pt |
|
|
48
|
+
| Panel labels | Lowercase, bold, near top-left, typically 8 pt at final size |
|
|
49
|
+
| Editable text | SVG/PDF text remains editable; no outlined text unless unavoidable for special symbols |
|
|
50
|
+
| Font | Arial/Helvetica/sans-serif fallback is used consistently |
|
|
51
|
+
| Color | No rainbow color maps; red/green is not the only encoding; grayscale print remains interpretable |
|
|
52
|
+
| Legend strategy | Shared or direct labels where possible; no repeated redundant legends |
|
|
53
|
+
| Display terminology | Legend labels use display-style initial capitalization and preserve canonical model names |
|
|
54
|
+
| Statistics | `n`, biological/technical repeat definition, center, spread, test, correction, and exact comparison are documented |
|
|
55
|
+
| Comparable uncertainty | Every comparable seed/fold/split aggregate panel shows the same variability definition or documents an exemption |
|
|
56
|
+
| Annotation clearance | Automatic PDF collision audit has no FAIL findings; every WARN is reviewed at final size and justified or fixed |
|
|
57
|
+
| Panel alignment | Every multi-panel figure has a fresh alignment JSON; comparable row/column edges, dimensions, labels and repeated gutters are within 1.5 pt or carry a reasoned exemption |
|
|
58
|
+
| Visual hierarchy | Hero evidence remains more salient than neutral baselines after rendering |
|
|
59
|
+
| Numerical transforms | Interpolation/normalization direction and monotonicity assumptions are asserted in code |
|
|
60
|
+
| Source data | Quantitative panels can be traced to a clean CSV/TSV/XLSX or script output |
|
|
61
|
+
| Raster resolution | Photos/microscopy are high-resolution enough for final size; line art uses vector where possible |
|
|
62
|
+
| Microscopy scale | Scale bar is present, calibrated, and not only a magnification factor |
|
|
63
|
+
| Image integrity | Crop, contrast, pseudo-color, stitching, reuse, and raw-file provenance are recorded |
|
|
64
|
+
| Export bundle | Script, source data, SVG, PDF, TIFF/PNG preview, and QA notes are delivered together when requested; previews are not mislabeled as accepted main-figure upload formats |
|
|
65
|
+
|
|
66
|
+
## Statistics legend minimum
|
|
67
|
+
|
|
68
|
+
For each quantitative panel, capture:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
n definition:
|
|
72
|
+
biological replicates:
|
|
73
|
+
technical replicates:
|
|
74
|
+
center statistic:
|
|
75
|
+
spread/interval:
|
|
76
|
+
test:
|
|
77
|
+
multiple-comparison correction:
|
|
78
|
+
p-value display:
|
|
79
|
+
source-data file:
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For machine-learning/model figures, also capture:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
train/validation/test split:
|
|
86
|
+
number of seeds or folds:
|
|
87
|
+
metric definition:
|
|
88
|
+
confidence interval or variability definition:
|
|
89
|
+
baseline definition:
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Image-integrity minimum
|
|
93
|
+
|
|
94
|
+
For each image panel, capture:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
raw file:
|
|
98
|
+
processed file:
|
|
99
|
+
crop:
|
|
100
|
+
brightness/contrast/gamma:
|
|
101
|
+
pseudo-color:
|
|
102
|
+
scale calibration:
|
|
103
|
+
stitching:
|
|
104
|
+
reuse in other figures:
|
|
105
|
+
quantification link:
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Global adjustments are generally safer than local selective edits. If an adjustment
|
|
109
|
+
changes the visibility of relevant background or bands, flag it instead of silently
|
|
110
|
+
normalizing it away.
|
|
111
|
+
|
|
112
|
+
## Automated source preflight
|
|
113
|
+
|
|
114
|
+
Run the dependency-free validator on the final plotting source before rendering the delivery bundle:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Python source
|
|
118
|
+
python skills/nature-figure/scripts/validate_figure.py path/to/figure.py
|
|
119
|
+
|
|
120
|
+
# R, R Markdown, or Quarto source
|
|
121
|
+
python skills/nature-figure/scripts/validate_figure.py path/to/figure.R
|
|
122
|
+
|
|
123
|
+
# Machine-readable report or stricter warning gate
|
|
124
|
+
python skills/nature-figure/scripts/validate_figure.py path/to/figure.py --json
|
|
125
|
+
python skills/nature-figure/scripts/validate_figure.py path/to/figure.py --strict
|
|
126
|
+
|
|
127
|
+
# Exported-PDF glyph-size audit
|
|
128
|
+
python skills/nature-figure/scripts/audit_pdf_text.py path/to/figure.pdf --min-pt 5
|
|
129
|
+
python skills/nature-figure/scripts/audit_pdf_text.py path/to/figure.pdf --min-pt 5 --json
|
|
130
|
+
|
|
131
|
+
# Backend-neutral audit of the render-time Python/R panel-layout manifest
|
|
132
|
+
python skills/nature-figure/scripts/audit_panel_alignment.py path/to/figure.alignment-layout.json \
|
|
133
|
+
--json-out path/to/figure.alignment.json \
|
|
134
|
+
--overlay-svg path/to/figure.alignment.svg \
|
|
135
|
+
--strict
|
|
136
|
+
|
|
137
|
+
# Mandatory rendered collision audit for Python and R figures
|
|
138
|
+
python skills/nature-figure/scripts/audit_figure_collisions.py path/to/figure.pdf \
|
|
139
|
+
--json-out path/to/figure.collision-audit.json \
|
|
140
|
+
--overlay-pdf path/to/figure.collision-audit.pdf
|
|
141
|
+
|
|
142
|
+
# Optional: make ambiguous WARN findings blocking
|
|
143
|
+
python skills/nature-figure/scripts/audit_figure_collisions.py path/to/figure.pdf --strict
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The source preflight checks syntax, font configuration and size floor, mathtext shrinkage risk, literal legend-label capitalization, unsafe color maps, editable-text settings, vector/raster exports, DPI, common journal widths, potential sampling or unreported missing-data exclusion, simulated-data leakage, log guards, interpolation monotonicity, stochastic uncertainty encoding, rotated-text anchoring, risky annotation workarounds, and obvious cross-backend plotting references. The panel-alignment gate reads final axes/grob rectangles measured by the selected backend and applies one physical-point contract to Python and R. The PDF text audit scans supported content streams for actual `Tf` font-size operators and catches reduced script glyphs that source-level `fontsize` checks miss. The rendered collision audit uses PyMuPDF geometry from the final PDF and therefore applies equally to Python- and R-generated figures.
|
|
147
|
+
|
|
148
|
+
Treat the result as a deterministic source audit, not as evidence that the analysis or rendered figure is correct. Resolve all `FAIL` findings before delivery. Review every `WARN`, then run the selected backend and inspect the actual SVG/PDF/TIFF/PNG outputs at final size. A warning may be acceptable only when the QA notes state the reason.
|
|
149
|
+
|
|
150
|
+
## Automatic multi-panel alignment gate
|
|
151
|
+
|
|
152
|
+
Run the gate for every figure with at least two comparable panels, after the
|
|
153
|
+
final layout engine has drawn fonts, legends, colorbars and constrained/tight
|
|
154
|
+
layout, and before exporting submission files. Rerun it after any change that
|
|
155
|
+
can affect panel geometry. A single-panel figure is `not applicable`; a
|
|
156
|
+
multi-panel figure with no declared or inferable comparison groups is `NOT
|
|
157
|
+
AUDITABLE`, not a pass.
|
|
158
|
+
|
|
159
|
+
The default tolerance is `1.5 pt` (about `0.53 mm`) at final physical size. The
|
|
160
|
+
auditor checks:
|
|
161
|
+
|
|
162
|
+
- panels in one row: common top and bottom edges plus equal plot-area height;
|
|
163
|
+
- three or four same-row panels with equal grid spans: equal final plot-area
|
|
164
|
+
widths within `1.5 pt`;
|
|
165
|
+
- panels in one column: common left and right edges plus equal plot-area width;
|
|
166
|
+
- unequal-span grid panels: shared outer start/stop edges, including automatic
|
|
167
|
+
`left two + right one` and `left one + right two` arrangements;
|
|
168
|
+
- three or more comparable panels: uniform repeated horizontal/vertical gutters;
|
|
169
|
+
- detectable bold lowercase top-left panel labels: common y anchors within rows
|
|
170
|
+
and common x anchors within columns;
|
|
171
|
+
- plot-area rectangles do not overlap.
|
|
172
|
+
|
|
173
|
+
For Matplotlib, copy `audit_panel_alignment.py` beside the plotting script or
|
|
174
|
+
add the skill scripts directory to `PYTHONPATH`, then call this after the last
|
|
175
|
+
layout change:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from audit_panel_alignment import require_matplotlib_panel_alignment
|
|
179
|
+
|
|
180
|
+
require_matplotlib_panel_alignment(
|
|
181
|
+
fig,
|
|
182
|
+
json_out="figure.alignment.json",
|
|
183
|
+
overlay_svg="figure.alignment.svg",
|
|
184
|
+
tolerance_pt=1.5,
|
|
185
|
+
gutter_tolerance_pt=1.5,
|
|
186
|
+
require_panel_labels=True,
|
|
187
|
+
strict=True,
|
|
188
|
+
)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Ordinary `subplots`/`GridSpec` row and column groups are inferred from
|
|
192
|
+
`SubplotSpec`. A panel spanning both grid rows is automatically compared with
|
|
193
|
+
the upper small panel at their shared top boundary and the lower small panel at
|
|
194
|
+
their shared bottom boundary; this works whether the spanning panel is in the
|
|
195
|
+
left or right column. The spanning panel is not incorrectly required to equal
|
|
196
|
+
either small panel's height. Position outside panel letters with a fixed point
|
|
197
|
+
offset from the axes corner rather than a shared axes-fraction offset, because
|
|
198
|
+
`y=1.02` produces different physical displacements for tall and short panels.
|
|
199
|
+
For a horizontal row of three or four panels, equal column spans imply equal
|
|
200
|
+
final widths. Intentional unequal `width_ratios` must use a narrow exemption
|
|
201
|
+
such as `{"panels": ["b"], "checks": ["panel-width"], "reason": "middle hero panel"}`;
|
|
202
|
+
do not exempt the entire row or increase the tolerance.
|
|
203
|
+
Pass explicit `row_groups` and `column_groups` when axes come from nested grids
|
|
204
|
+
or separately created containers. Exclude a
|
|
205
|
+
colorbar or inset with `exclude_axes=[...]`, or add an exemption containing the
|
|
206
|
+
affected panel, the exact checks and a non-empty scientific/layout reason.
|
|
207
|
+
|
|
208
|
+
For R/patchwork, source `panel_alignment.R` and call
|
|
209
|
+
`require_patchwork_panel_alignment()` with the same width/height used for final
|
|
210
|
+
export. Common patchwork groups and structured unequal-span designs are inferred
|
|
211
|
+
from gtable cells, including two stacked panels beside a two-row spanning panel
|
|
212
|
+
in either column. Same-row groups of three or four equal gtable spans must also
|
|
213
|
+
have equal final widths. Nested or manually positioned designs must provide explicit
|
|
214
|
+
`row_groups` / `column_groups`. The R helper requires `patchwork`, `grid` and
|
|
215
|
+
`jsonlite`; it measures in R and invokes the Python CLI only to audit the
|
|
216
|
+
resulting JSON, so it does not redraw or replace the R figure.
|
|
217
|
+
|
|
218
|
+
| Result | Required action |
|
|
219
|
+
|---|---|
|
|
220
|
+
| `NOT APPLICABLE`, exit `0` | Single rendered plot-area only; preserve the JSON and continue |
|
|
221
|
+
| `PASS`, exit `0` | Preserve the alignment JSON and continue to export/PDF QA |
|
|
222
|
+
| `FIX BEFORE DELIVERY`, exit `1` | Correct the selected-backend layout and rerun; do not export the delivery bundle |
|
|
223
|
+
| `REVIEW REQUIRED` | Resolve WARN or document it; `--strict` makes WARN blocking |
|
|
224
|
+
| `NOT AUDITABLE`, exit `2` | Supply valid measured geometry and comparison groups; do not claim alignment passed |
|
|
225
|
+
|
|
226
|
+
The QA-only alignment SVG shows measured panel rectangles, not scientific
|
|
227
|
+
content. It must not replace the selected backend's figure. Do not weaken the
|
|
228
|
+
global tolerance to hide one exception. Structured grid spanning is audited
|
|
229
|
+
automatically; a free-positioned hero panel, inset, legend-only axis or colorbar
|
|
230
|
+
should be omitted from unrelated groups or carry a specific exemption reason.
|
|
231
|
+
|
|
232
|
+
## Automatic rendered collision audit
|
|
233
|
+
|
|
234
|
+
Run `audit_figure_collisions.py` after **every generated figure and every
|
|
235
|
+
revision that can change layout**, including edits to text, fonts, legend,
|
|
236
|
+
annotations, axes, data, uncertainty, panel size or arrangement. Do not reuse a
|
|
237
|
+
report from an earlier render. Preserve the JSON report with the delivery QA;
|
|
238
|
+
the marked PDF is diagnostic only.
|
|
239
|
+
|
|
240
|
+
| Result | Meaning | Required action |
|
|
241
|
+
|---|---|---|
|
|
242
|
+
| `text-text` FAIL | Two rendered text boxes materially overlap | Separate, shorten, rotate or resize the labels and rerun |
|
|
243
|
+
| `text-stroke` FAIL | A line, curve, marker edge, error bar or other stroked path crosses the interior of text | Move the text or alter the layout; do not hide the path with an opaque white box |
|
|
244
|
+
| `text-page-clipping` FAIL | A rendered text trace extends beyond the final PDF page | Expand/reposition the layout and re-export |
|
|
245
|
+
| `text-fill-edge` WARN | Text only partly overlaps a bar, heatmap cell or other fill | Inspect at final size; fix unless the edge overlap is intentional and legible |
|
|
246
|
+
| `text-image-edge` WARN | Text only partly overlaps a raster image boundary | Inspect panel labels, scale bars and image annotations at final size |
|
|
247
|
+
| contained overlay count | Text is fully inside a fill or image | Informational because in-bar labels, heatmap values and image annotations can be intentional |
|
|
248
|
+
|
|
249
|
+
Exit code `1` and verdict `FIX BEFORE DELIVERY` block delivery. Exit code `2`
|
|
250
|
+
or `NOT AUDITABLE` means the PDF/dependency could not be checked and must not be
|
|
251
|
+
reported as a pass. `REVIEW REQUIRED` does not silently pass: inspect each WARN
|
|
252
|
+
and record the reason, or use `--strict` to make WARN blocking. PyMuPDF is
|
|
253
|
+
declared in `requirements.txt`; install it with:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
python -m pip install -r skills/nature-figure/requirements.txt
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The detector deliberately separates reliable geometry failures from ambiguous
|
|
260
|
+
fill/image overlays. It does not prove visual quality, semantic correctness,
|
|
261
|
+
adequate contrast or accessibility, so the final-size panel audit remains
|
|
262
|
+
mandatory.
|
|
263
|
+
|
|
264
|
+
## Rendered panel-by-panel audit
|
|
265
|
+
|
|
266
|
+
Do not approve a figure from a whole-page glance. Inspect each panel at final physical size, then inspect the assembled figure. Record one row per panel:
|
|
267
|
+
|
|
268
|
+
| Panel | Unique claim | Center/summary | Spread/interval | Replicate unit | Labels/legend | Alignment group/result | Collision check | Pass |
|
|
269
|
+
|---|---|---|---|---|---|---|---|---|
|
|
270
|
+
| a | What question only this panel answers | mean/median/raw | SD/SE/CI/none + reason | seeds/folds/subjects/etc. | exact display labels | row/column group, deviation or exemption | collision report findings + data/error extent + text bbox | yes/no |
|
|
271
|
+
|
|
272
|
+
Cover each panel mentally. If the figure's argument remains complete, merge or remove that panel. Compare repeated panels side by side for consistent terminology, uncertainty, axes, and color mapping. After adding error bars or uncertainty bands, remove arrows, brackets, or fills that encode the same gap and occupy the same geometry.
|
|
273
|
+
|
|
274
|
+
## Typography and PDF glyph floor
|
|
275
|
+
|
|
276
|
+
- The 5 pt floor applies to every rendered glyph, not only the parent `fontsize` in source code.
|
|
277
|
+
- Matplotlib mathtext commonly scales superscripts/subscripts to about 0.7 of the parent. A 7 pt `$R^2$` can therefore contain a 4.9 pt glyph. Prefer a Unicode glyph such as `R²` when it preserves the intended notation, or increase the parent size and confirm the PDF audit.
|
|
278
|
+
- Measure long labels against their allocated group width at final size. Compare rendered text bounding-box width in millimetres with the available slot; do not rely on the source font number alone.
|
|
279
|
+
- Keep canonical capitalization such as `XGBoost`, `DeepSeek`, `GPT-5.2`, and `RF`. Legend labels start with display-style capitalization, while prose follows normal sentence grammar. Do not use blind string title-casing.
|
|
280
|
+
|
|
281
|
+
## Uncertainty consistency
|
|
282
|
+
|
|
283
|
+
- If a line or bar is a mean/median across random seeds, folds, splits, subjects, or repeated experiments, encode the requested spread in every comparable panel.
|
|
284
|
+
- State the exact definition, for example `median ± one seed SD`, in the legend or panel notes. Do not infer or invent it.
|
|
285
|
+
- Presence of one `fill_between`, `errorbar`, `yerr`, or `geom_errorbar` call does not prove coverage. Use the panel audit table to verify every comparable panel.
|
|
286
|
+
- Recompute label clearance from the upper uncertainty extent after error bars are added.
|
|
287
|
+
|
|
288
|
+
## Geometry and annotation placement
|
|
289
|
+
|
|
290
|
+
- Measure spacing between the actual objects being compared. Use rendered/tight bounding boxes for panel-to-legend or legend-row gaps; scanning an entire raster row can mix unrelated objects at different horizontal positions.
|
|
291
|
+
- Use plot-area rectangles for axes alignment and tight bounding boxes for outer-content clearance; do not confuse unequal tick-label widths with a shifted data rectangle.
|
|
292
|
+
- Derive label positions from data and uncertainty bounds, for example `max(center + spread) + margin`, rather than a fixed `LABEL_Y`.
|
|
293
|
+
- For rotated Matplotlib text, use `rotation_mode="anchor"` and verify the final bounding box.
|
|
294
|
+
- If a curve crosses a label, reposition the label beyond the local data envelope. Avoid opaque white `bbox` masks that cut a conspicuous hole in a line.
|
|
295
|
+
- Equal pixel y-coordinates can still look uneven when bar heights create unequal whitespace. Diagnose the perceived gap before moving already aligned labels.
|
|
296
|
+
|
|
297
|
+
## Color separation and salience
|
|
298
|
+
|
|
299
|
+
- Pairwise ΔE and white-background contrast are necessary checks, not a complete design test.
|
|
300
|
+
- Verify hierarchy after rendering: neutral baselines should not appear stronger than the proposed method or primary evidence.
|
|
301
|
+
- Do not repurpose a sequential light-to-dark palette as unrelated categorical colors merely because the hues look attractive.
|
|
302
|
+
- Check grayscale and color-vision robustness, then inspect the actual figure because metrics do not encode which series should dominate attention.
|
|
303
|
+
|
|
304
|
+
## Transformation and paired-effect checks
|
|
305
|
+
|
|
306
|
+
- `numpy.interp` requires increasing `xp`. Use `scripts/figure_safety.py::interp_monotone`, or explicitly assert monotonicity and reverse/sort `xp` and `fp` together. Plausible-looking output is not evidence of correctness.
|
|
307
|
+
- Do not plan one figure per source table. Group panels by the distinct claims they support.
|
|
308
|
+
- When repeated units are matched, inspect paired differences. Broad between-dataset or between-subject heterogeneity can make four marginal distributions overlap even when the within-unit effect is strong; use a paired-difference view when the scientific claim is paired.
|
|
309
|
+
|
|
310
|
+
## Export checks
|
|
311
|
+
|
|
312
|
+
Run only the export block for the selected backend. If that backend is unavailable,
|
|
313
|
+
stop and report the missing runtime/package instead of producing a substitute export
|
|
314
|
+
with the other language.
|
|
315
|
+
|
|
316
|
+
### Python
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
import matplotlib as mpl
|
|
320
|
+
mpl.rcParams["svg.fonttype"] = "none"
|
|
321
|
+
mpl.rcParams["pdf.fonttype"] = 42
|
|
322
|
+
fig.savefig("figure.svg", bbox_inches="tight")
|
|
323
|
+
fig.savefig("figure.pdf", bbox_inches="tight")
|
|
324
|
+
fig.savefig("figure.tiff", dpi=600, bbox_inches="tight")
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### R
|
|
328
|
+
|
|
329
|
+
```r
|
|
330
|
+
svglite::svglite("figure.svg", width = width_mm / 25.4, height = height_mm / 25.4)
|
|
331
|
+
print(plot)
|
|
332
|
+
dev.off()
|
|
333
|
+
|
|
334
|
+
grDevices::cairo_pdf("figure.pdf", width = width_mm / 25.4, height = height_mm / 25.4, family = "Arial")
|
|
335
|
+
print(plot)
|
|
336
|
+
dev.off()
|
|
337
|
+
|
|
338
|
+
ragg::agg_tiff("figure.tiff", width = width_mm / 25.4, height = height_mm / 25.4, units = "in", res = 600)
|
|
339
|
+
print(plot)
|
|
340
|
+
dev.off()
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Open the SVG/PDF after export and verify that text can be selected, labels do not
|
|
344
|
+
overlap, and the figure still reads at final printed size.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Private R Template Adaptation
|
|
2
|
+
|
|
3
|
+
Use this reference when the user chooses R and provides or mentions an existing
|
|
4
|
+
R plotting template collection. Treat such material as private working context.
|
|
5
|
+
Do not reveal absolute paths, folder names, filenames, screenshots, provenance, or
|
|
6
|
+
any identifying labels from the source collection in user-facing output.
|
|
7
|
+
|
|
8
|
+
## Privacy rules
|
|
9
|
+
|
|
10
|
+
- Never include absolute local paths in generated code, reports, comments, or final replies.
|
|
11
|
+
- Never mention the original source file, folder, template number, course title, download
|
|
12
|
+
location, chat attachment, or private document name.
|
|
13
|
+
- When a template is useful, describe it generically by chart family: "a grouped bar
|
|
14
|
+
template", "a ComplexHeatmap workflow", "a survival plotting workflow".
|
|
15
|
+
- If a reusable idea is copied from a private template, rewrite the final code as a clean,
|
|
16
|
+
self-contained script with neutral function names and neutral comments.
|
|
17
|
+
- If the user asks where a style came from, say it was adapted from the provided working
|
|
18
|
+
materials without identifying the path or source file.
|
|
19
|
+
|
|
20
|
+
## Generic search strategy
|
|
21
|
+
|
|
22
|
+
Search private materials by chart family and package names, not by exposing paths:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
find <private-template-root> -type f \( -name '*.R' -o -name '*.Rmd' -o -name '*.r' \)
|
|
26
|
+
rg -n "ggplot|patchwork|ComplexHeatmap|ggrepel|svglite|cairo_pdf|survminer|circlize" <private-template-root>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Keep these commands in internal working notes only. Do not paste the user's private
|
|
30
|
+
root path into the final answer.
|
|
31
|
+
|
|
32
|
+
## Chart-family map
|
|
33
|
+
|
|
34
|
+
Use these generic families to decide what to inspect:
|
|
35
|
+
|
|
36
|
+
| Need | Search targets |
|
|
37
|
+
|---|---|
|
|
38
|
+
| Bars and grouped comparisons | `geom_col`, `geom_bar`, `position_dodge`, `stat_compare_means` |
|
|
39
|
+
| Error bars and point-interval plots | `geom_errorbar`, `geom_pointrange`, `mean_se`, `stat_summary` |
|
|
40
|
+
| Stacked or bidirectional bars | `position_stack`, `coord_flip`, signed values, paired positive/negative bars |
|
|
41
|
+
| Box, violin, paired, and raincloud-style distributions | `geom_boxplot`, `geom_violin`, `geom_jitter`, paired sample identifiers |
|
|
42
|
+
| Heatmaps and annotated heatmaps | `ComplexHeatmap`, `HeatmapAnnotation`, `pheatmap`, `geom_tile` |
|
|
43
|
+
| Correlation, scatter, bubble, and volcano plots | `geom_point`, `geom_smooth`, `ggrepel`, `logFC`, `pvalue`, bubble size scales |
|
|
44
|
+
| PCA, PCoA, NMDS, tSNE, UMAP | `prcomp`, `cmdscale`, `vegan`, `Rtsne`, `Seurat`, embedding coordinates |
|
|
45
|
+
| Survival, Cox, subgroup, ROC, forest | `survival`, `survminer`, `coxph`, `forestplot`, `timeROC`, hazard ratios |
|
|
46
|
+
| Enrichment and pathway summaries | `clusterProfiler`, `GSEA`, `enrichGO`, `enrichKEGG`, dot plots, ridge plots |
|
|
47
|
+
| Circular, genome, phylogeny, chromosome | `circlize`, `ggtree`, `karyoploteR`, genome interval tracks |
|
|
48
|
+
| Single-cell and omics workflows | `Seurat`, marker genes, differential expression, cell-type annotation |
|
|
49
|
+
| Maps, anatomy, and spatial summaries | `sf`, `maps`, `gganatogram`, spatial coordinates |
|
|
50
|
+
| Radar, lollipop, dumbbell, UpSet, Venn, Sankey | `ggradar`, `geom_segment`, `UpSetR`, `ggalluvial`, set operations |
|
|
51
|
+
|
|
52
|
+
## Adaptation checklist
|
|
53
|
+
|
|
54
|
+
When adapting a private template:
|
|
55
|
+
|
|
56
|
+
- Keep useful data wrangling, statistics, and geoms.
|
|
57
|
+
- Replace template-specific colors with the figure-level semantic palette.
|
|
58
|
+
- Normalize fonts to final-size 5-7 pt text and 8 pt bold lowercase panel labels.
|
|
59
|
+
- Convert single-output PNG/PDF scripts to SVG/PDF/TIFF export.
|
|
60
|
+
- Remove decorative elements that do not support the core conclusion.
|
|
61
|
+
- Ensure each statistical comparison has `n`, center, spread, test, and correction
|
|
62
|
+
information in the legend or source-data notes.
|
|
63
|
+
- For image panels, document raw file, crop, contrast, scale-bar calibration, and any
|
|
64
|
+
stitching or pseudo-coloring in private QA notes.
|
|
65
|
+
- Final code should be self-contained and should not require the original private
|
|
66
|
+
folder structure unless the user explicitly asks to keep that workflow.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# R Workflow
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [R-only execution rule](#r-only-execution-rule)
|
|
6
|
+
- [Required packages by task](#required-packages-by-task)
|
|
7
|
+
- [Contract scaffold](#contract-scaffold)
|
|
8
|
+
- [Panel labels in R](#panel-labels-in-r)
|
|
9
|
+
- [Patchwork layout patterns](#patchwork-layout-patterns)
|
|
10
|
+
- [Patchwork panel-alignment gate](#patchwork-panel-alignment-gate)
|
|
11
|
+
- [ComplexHeatmap export](#complexheatmap-export)
|
|
12
|
+
- [Template reuse rule](#template-reuse-rule)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Use this when the user chooses R, brings R data/scripts, or asks to reuse the local
|
|
16
|
+
R plotting templates. The R track should still follow the same figure contract:
|
|
17
|
+
claim first, evidence hierarchy second, plotting code third.
|
|
18
|
+
|
|
19
|
+
## R-only execution rule
|
|
20
|
+
|
|
21
|
+
When the user has selected R, do all figure drawing, previewing, exporting, and
|
|
22
|
+
visual QA in R. Do not call Python/matplotlib/seaborn/plotly to create a temporary
|
|
23
|
+
preview, fallback export, or layout approximation. If R, `Rscript`, or required R
|
|
24
|
+
packages are missing, pause rendering, continue independent script or data checks, and report the missing dependency. You
|
|
25
|
+
may still write the R script, provide `install.packages()` commands, or ask permission
|
|
26
|
+
to install dependencies, but do not cross-render the figure in another language.
|
|
27
|
+
|
|
28
|
+
Allowed non-R utilities are limited to non-visual tasks such as shell file inspection,
|
|
29
|
+
CSV line counts, checksums, archive extraction, or text search. They must not create
|
|
30
|
+
image/vector outputs or alter visual layout.
|
|
31
|
+
|
|
32
|
+
## Required packages by task
|
|
33
|
+
|
|
34
|
+
| Task | Preferred packages |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Bars, boxplots, violins, dot plots, lines, volcano plots | `ggplot2`, `ggrepel`, `dplyr`, `tidyr` |
|
|
37
|
+
| Multi-panel assembly and alignment QA | `patchwork`, `grid`, `jsonlite`; use `cowplot` only when inset alignment requires it |
|
|
38
|
+
| Rich omics heatmaps | `ComplexHeatmap`, `circlize`, `grid` |
|
|
39
|
+
| Survival and clinical subgroup plots | `survival`, `survminer`, `forestplot`, `ggplot2` |
|
|
40
|
+
| Circular/genome plots | `circlize`, `ggtree`, `gggenes`, domain-specific packages |
|
|
41
|
+
| Export | `svglite`, `grDevices::cairo_pdf`, `ragg` |
|
|
42
|
+
|
|
43
|
+
## Contract scaffold
|
|
44
|
+
|
|
45
|
+
```r
|
|
46
|
+
library(ggplot2)
|
|
47
|
+
library(patchwork)
|
|
48
|
+
source("skills/nature-figure/scripts/panel_alignment.R")
|
|
49
|
+
|
|
50
|
+
palette_contract <- c(
|
|
51
|
+
neutral_dark = "#272727",
|
|
52
|
+
neutral_mid = "#767676",
|
|
53
|
+
neutral_light = "#D8D8D8",
|
|
54
|
+
signal_blue = "#3182BD",
|
|
55
|
+
signal_teal = "#33B5A5",
|
|
56
|
+
accent_red = "#D24B40",
|
|
57
|
+
accent_orange = "#E28E2C"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
theme_nature_contract <- function(base_size = 6.5, base_family = "Arial") {
|
|
61
|
+
theme_classic(base_size = base_size, base_family = base_family) +
|
|
62
|
+
theme(
|
|
63
|
+
axis.line = element_line(linewidth = 0.35, colour = "black"),
|
|
64
|
+
axis.ticks = element_line(linewidth = 0.35, colour = "black"),
|
|
65
|
+
axis.title = element_text(size = base_size),
|
|
66
|
+
axis.text = element_text(size = base_size - 0.5),
|
|
67
|
+
legend.title = element_text(size = base_size - 0.3),
|
|
68
|
+
legend.text = element_text(size = base_size - 0.7),
|
|
69
|
+
strip.text = element_text(size = base_size - 0.3, face = "bold"),
|
|
70
|
+
plot.title = element_text(size = base_size + 0.5, face = "bold"),
|
|
71
|
+
panel.grid = element_blank()
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
theme_set(theme_nature_contract())
|
|
76
|
+
|
|
77
|
+
save_pub_r <- function(plot, filename, width_mm = 183, height_mm = 120, dpi = 600) {
|
|
78
|
+
w <- width_mm / 25.4
|
|
79
|
+
h <- height_mm / 25.4
|
|
80
|
+
|
|
81
|
+
if (inherits(plot, "patchwork")) {
|
|
82
|
+
require_patchwork_panel_alignment(
|
|
83
|
+
plot,
|
|
84
|
+
manifest_path = paste0(filename, ".alignment-layout.json"),
|
|
85
|
+
report_path = paste0(filename, ".alignment.json"),
|
|
86
|
+
overlay_svg = paste0(filename, ".alignment.svg"),
|
|
87
|
+
width_in = w,
|
|
88
|
+
height_in = h,
|
|
89
|
+
tolerance_pt = 1.5,
|
|
90
|
+
gutter_tolerance_pt = 1.5,
|
|
91
|
+
strict = TRUE
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
svglite::svglite(paste0(filename, ".svg"), width = w, height = h)
|
|
96
|
+
print(plot)
|
|
97
|
+
dev.off()
|
|
98
|
+
|
|
99
|
+
grDevices::cairo_pdf(paste0(filename, ".pdf"), width = w, height = h, family = "Arial")
|
|
100
|
+
print(plot)
|
|
101
|
+
dev.off()
|
|
102
|
+
|
|
103
|
+
ragg::agg_tiff(paste0(filename, ".tiff"), width = w, height = h, units = "in", res = dpi)
|
|
104
|
+
print(plot)
|
|
105
|
+
dev.off()
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Panel labels in R
|
|
110
|
+
|
|
111
|
+
Use patchwork tags for most multi-panel figures:
|
|
112
|
+
|
|
113
|
+
```r
|
|
114
|
+
fig <- (p_a | p_b) / (p_c | p_d) +
|
|
115
|
+
plot_annotation(tag_levels = "a") &
|
|
116
|
+
theme(plot.tag = element_text(size = 8, face = "bold"))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use manual labels only when dark image plates or inset geometry make patchwork tags
|
|
120
|
+
misalign.
|
|
121
|
+
|
|
122
|
+
## Patchwork layout patterns
|
|
123
|
+
|
|
124
|
+
### Quantitative grid
|
|
125
|
+
|
|
126
|
+
```r
|
|
127
|
+
fig <- (p_a | p_b | guide_area()) /
|
|
128
|
+
(p_c | p_d | p_e) +
|
|
129
|
+
plot_layout(guides = "collect", widths = c(1, 1, 0.45)) &
|
|
130
|
+
theme(legend.position = "right")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Schematic-led composite
|
|
134
|
+
|
|
135
|
+
```r
|
|
136
|
+
design <- "
|
|
137
|
+
AAAA
|
|
138
|
+
BBCD
|
|
139
|
+
"
|
|
140
|
+
fig <- p_schematic + p_b + p_c + p_d +
|
|
141
|
+
plot_layout(design = design, heights = c(1.8, 1))
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Image plate plus quant
|
|
145
|
+
|
|
146
|
+
Keep black backgrounds inside image panels only. Put scale bars on the image, then
|
|
147
|
+
place quantification next to or below the representative image.
|
|
148
|
+
|
|
149
|
+
```r
|
|
150
|
+
p_img <- ggplot(img_df, aes(x, y, fill = intensity)) +
|
|
151
|
+
geom_raster() +
|
|
152
|
+
scale_fill_gradient(low = "black", high = "white") +
|
|
153
|
+
coord_fixed(expand = FALSE) +
|
|
154
|
+
annotate("segment", x = 10, xend = 40, y = 10, yend = 10,
|
|
155
|
+
linewidth = 0.6, colour = "white") +
|
|
156
|
+
theme_void() +
|
|
157
|
+
theme(legend.position = "none", plot.background = element_rect(fill = "black", colour = NA))
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Patchwork panel-alignment gate
|
|
161
|
+
|
|
162
|
+
`panel_alignment.R` converts the final patchwork gtable cells to physical-point
|
|
163
|
+
rectangles on a temporary R graphics device with the same dimensions as the
|
|
164
|
+
real export. It then invokes the backend-neutral
|
|
165
|
+
`audit_panel_alignment.py` JSON auditor. Python does not render or modify the R
|
|
166
|
+
figure.
|
|
167
|
+
|
|
168
|
+
Simple patchwork grids infer row/column groups from gtable cells. Structured
|
|
169
|
+
unequal-span designs are also automatic: two stacked panels in the left column
|
|
170
|
+
beside one two-row panel in the right column, and the mirrored arrangement,
|
|
171
|
+
receive shared top/bottom boundary checks without an invalid equal-height
|
|
172
|
+
comparison. Horizontal groups of three or four equal gtable spans must also
|
|
173
|
+
have equal final widths; intentional unequal widths require a reasoned
|
|
174
|
+
`panel-width` exemption. For nested or manually composed figures, declare the intended
|
|
175
|
+
comparisons explicitly:
|
|
176
|
+
|
|
177
|
+
```r
|
|
178
|
+
require_patchwork_panel_alignment(
|
|
179
|
+
fig,
|
|
180
|
+
manifest_path = "figures/fig2.alignment-layout.json",
|
|
181
|
+
report_path = "figures/fig2.alignment.json",
|
|
182
|
+
overlay_svg = "figures/fig2.alignment.svg",
|
|
183
|
+
width_in = 183 / 25.4,
|
|
184
|
+
height_in = 120 / 25.4,
|
|
185
|
+
panel_ids = c("a", "b", "c", "d"),
|
|
186
|
+
row_groups = list(c("a", "b"), c("c", "d")),
|
|
187
|
+
column_groups = list(c("a", "c"), c("b", "d")),
|
|
188
|
+
exemptions = list(
|
|
189
|
+
list(
|
|
190
|
+
panels = c("a"),
|
|
191
|
+
checks = c("column", "panel-width"),
|
|
192
|
+
reason = "hero panel intentionally spans the evidence columns"
|
|
193
|
+
)
|
|
194
|
+
),
|
|
195
|
+
tolerance_pt = 1.5,
|
|
196
|
+
gutter_tolerance_pt = 1.5,
|
|
197
|
+
strict = TRUE
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Every exemption must name the panel, the exact check and the reason. Do not
|
|
202
|
+
increase the global tolerance to hide an inset, colorbar, legend-only cell or
|
|
203
|
+
hero panel. A non-zero audit status stops the R delivery script. Preserve both
|
|
204
|
+
the measured layout manifest and audit JSON; the alignment SVG is QA-only.
|
|
205
|
+
|
|
206
|
+
## ComplexHeatmap export
|
|
207
|
+
|
|
208
|
+
`ComplexHeatmap` objects are grid objects, not ggplot objects. Export them by opening
|
|
209
|
+
the graphics device, drawing, then closing it.
|
|
210
|
+
|
|
211
|
+
```r
|
|
212
|
+
library(ComplexHeatmap)
|
|
213
|
+
library(circlize)
|
|
214
|
+
|
|
215
|
+
pdf("heatmap.pdf", width = 7.2, height = 4.8, family = "Arial")
|
|
216
|
+
draw(ht, heatmap_legend_side = "right", annotation_legend_side = "right")
|
|
217
|
+
dev.off()
|
|
218
|
+
|
|
219
|
+
svglite::svglite("heatmap.svg", width = 7.2, height = 4.8)
|
|
220
|
+
draw(ht, heatmap_legend_side = "right", annotation_legend_side = "right")
|
|
221
|
+
dev.off()
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Template reuse rule
|
|
225
|
+
|
|
226
|
+
The local R materials are examples, not final style. When reusing them:
|
|
227
|
+
|
|
228
|
+
1. Inspect only the nearest template folder.
|
|
229
|
+
2. Keep useful data wrangling, statistics, and geoms.
|
|
230
|
+
3. Replace ad hoc colors, oversized fonts, dense legends, and PNG-only export.
|
|
231
|
+
4. Rebuild the final script around `theme_nature_contract()` and `save_pub_r()`.
|
|
232
|
+
5. Add source-data output if the figure is manuscript-facing.
|
|
233
|
+
|
|
234
|
+
Open `references/r-template-index.md` for the local template atlas.
|