psyclaw 0.28.1 → 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 +1 -1
- package/dist/src/adapters/pi/extension.js +43 -9
- package/dist/src/adapters/pi/extension.js.map +1 -1
- 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/package.json +10 -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,118 @@
|
|
|
1
|
+
# Backend Selection
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Quick decision table](#quick-decision-table)
|
|
6
|
+
- [Backend exclusivity rule](#backend-exclusivity-rule)
|
|
7
|
+
- [Default stacks](#default-stacks)
|
|
8
|
+
- [Mixed workflow rule](#mixed-workflow-rule)
|
|
9
|
+
- [Recommendation language](#recommendation-language)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Backend selection applies only to rendering or editing plotting code. Reuse a choice already established in the same task and its follow-ups; do not ask again merely because a new message omits the language. Read-only figure review and backend-independent data inspection may proceed without this choice. If the backend remains unresolved, retain the one-time Python/R question and pause only dependent plotting steps. Explicit approval requirements and backend exclusivity remain in force.
|
|
13
|
+
|
|
14
|
+
At the start of a plotting task, resolve the user's preferred backend in this order:
|
|
15
|
+
|
|
16
|
+
1. explicit Python/R choice in the current request;
|
|
17
|
+
2. clearly language-specific input file or workflow;
|
|
18
|
+
3. choice already established in this task, then saved preference from `scripts/nature_figure_backend.py get`;
|
|
19
|
+
4. if neither exists, ask **Python or R? I will remember this as your default.**
|
|
20
|
+
|
|
21
|
+
Pause dependent plotting steps after asking and wait for the user's answer; continue independent inspection. After the answer, save it with
|
|
22
|
+
`scripts/nature_figure_backend.py set python` or `scripts/nature_figure_backend.py set r`.
|
|
23
|
+
Do not infer Python just because the task involves simulation, NumPy-like data, or
|
|
24
|
+
custom layout, and do not infer R just because the task is biological or omics-adjacent.
|
|
25
|
+
|
|
26
|
+
Use the decision table only in either of these cases:
|
|
27
|
+
|
|
28
|
+
- the user explicitly asks you to recommend or choose the backend;
|
|
29
|
+
- the user provides an unambiguous language-specific workflow or file, such as an `.R`
|
|
30
|
+
script, RDS object, Python notebook, or existing Python plotting code.
|
|
31
|
+
|
|
32
|
+
## Quick decision table
|
|
33
|
+
|
|
34
|
+
| Recommend R when | Recommend Python when |
|
|
35
|
+
|---|---|
|
|
36
|
+
| The user brings R scripts, RData/RDS, Seurat objects, DESeq2/limma outputs, survival models, or ggplot templates | The data pipeline is already Python, NumPy/Pandas arrays, PyTorch/TensorFlow outputs, image arrays, or simulation output |
|
|
37
|
+
| The target plot is `ggplot2`, `patchwork`, `ComplexHeatmap`, `ggtree`, `circlize`, `survminer`, `maftools`, or Seurat/UMAP-heavy | The target plot needs low-level custom layout, Matplotlib patches, image plates, subplot mosaics, or custom drawing primitives |
|
|
38
|
+
| The user provides an R template collection or an existing R plotting workflow | The user wants a self-contained script with matplotlib/seaborn/statsmodels and no R dependency |
|
|
39
|
+
| Heatmap annotations are biologically rich and multi-layered | Image panels and quantitative panels need tight pixel/axis control |
|
|
40
|
+
|
|
41
|
+
If either backend can do the job, honor the user's saved preference. Do not switch
|
|
42
|
+
backends for aesthetics alone. If the user explicitly switches backend, save the new
|
|
43
|
+
preference.
|
|
44
|
+
|
|
45
|
+
## Backend exclusivity rule
|
|
46
|
+
|
|
47
|
+
Backend choice is not just a syntax preference; it defines the graphics engine for
|
|
48
|
+
the entire deliverable. Once Python or R has been selected, use that backend for
|
|
49
|
+
all of the following:
|
|
50
|
+
|
|
51
|
+
- plotting scripts;
|
|
52
|
+
- mock/simulated data examples that include plotting;
|
|
53
|
+
- preview PNG/TIFF files;
|
|
54
|
+
- SVG/PDF/TIFF exports;
|
|
55
|
+
- visual QA renders and final layout checks.
|
|
56
|
+
|
|
57
|
+
Do not generate a substitute preview or export with the non-selected backend. For
|
|
58
|
+
example, if the user selected R and `Rscript` is missing, do not use Python/matplotlib
|
|
59
|
+
to approximate the figure. If the user selected Python and `matplotlib` or another
|
|
60
|
+
required Python plotting package is missing, do not use R/ggplot2/ComplexHeatmap to
|
|
61
|
+
approximate the figure. Stop, report the selected-backend blocker, and provide the
|
|
62
|
+
selected-backend script plus install/run instructions or request permission to install
|
|
63
|
+
the selected-backend dependencies.
|
|
64
|
+
|
|
65
|
+
The non-selected language is allowed only for non-visual utility work, such as
|
|
66
|
+
listing files, checking CSV dimensions, decompressing an archive, or converting a
|
|
67
|
+
data file before the selected backend draws the figure. It must not import plotting
|
|
68
|
+
libraries, open graphics devices, save image/vector files, or decide visual layout.
|
|
69
|
+
|
|
70
|
+
## Default stacks
|
|
71
|
+
|
|
72
|
+
### R
|
|
73
|
+
|
|
74
|
+
- Core plotting: `ggplot2`
|
|
75
|
+
- Multi-panel assembly: `patchwork`
|
|
76
|
+
- Heatmaps: `ComplexHeatmap`, `circlize`
|
|
77
|
+
- Direct labels: `ggrepel`
|
|
78
|
+
- Survival/clinical: `survival`, `survminer`, `forestplot`, `ggplot2`
|
|
79
|
+
- Single-cell/omics: `Seurat`, `SingleCellExperiment`, `ComplexHeatmap`, `ggtree`
|
|
80
|
+
- Export: `svglite`, `grDevices::cairo_pdf`, `ragg`
|
|
81
|
+
|
|
82
|
+
### Python
|
|
83
|
+
|
|
84
|
+
- Core plotting: `matplotlib`
|
|
85
|
+
- Statistical plots: `seaborn`
|
|
86
|
+
- Layout: `subplot_mosaic`, `GridSpec`
|
|
87
|
+
- Tables/model output: `pandas`, `numpy`, `statsmodels`
|
|
88
|
+
- Images: `matplotlib.imshow`, `skimage`, `tifffile` when needed
|
|
89
|
+
- Export: `fig.savefig(... .svg/.pdf/.tiff)`, `svg.fonttype='none'`,
|
|
90
|
+
`pdf.fonttype=42`
|
|
91
|
+
|
|
92
|
+
## Mixed workflow rule
|
|
93
|
+
|
|
94
|
+
Use the selected plotting backend for final assembly and all visual output. A mixed
|
|
95
|
+
workflow is reasonable only when the non-selected language performs non-visual data
|
|
96
|
+
preparation and the selected backend assembles the figure. In that case:
|
|
97
|
+
|
|
98
|
+
1. Export clean source data as CSV/TSV with stable column names.
|
|
99
|
+
2. Assemble the final figure in the selected backend.
|
|
100
|
+
3. Keep the source-data file next to the plotting script.
|
|
101
|
+
4. Do not stitch, preview, QA-render, or export final image/vector outputs from the
|
|
102
|
+
non-selected backend unless the user explicitly changes the selected backend.
|
|
103
|
+
|
|
104
|
+
## Recommendation language
|
|
105
|
+
|
|
106
|
+
Use direct language:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
For this figure I recommend R because the main burden is ComplexHeatmap-style
|
|
110
|
+
omics annotation and patchwork assembly. I will still keep the export contract
|
|
111
|
+
SVG/PDF/TIFF with editable text.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
For this figure I recommend Python because the key panel is a custom image plate
|
|
116
|
+
with quantitative overlays and a subplot_mosaic layout. Matplotlib gives tighter
|
|
117
|
+
control over the raster and vector layers.
|
|
118
|
+
```
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# Chart Types — Nature Figure Making
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Radar / Polar Chart](#radar-polar-chart)
|
|
6
|
+
- [3D Sphere / Conceptual Illustration](#3d-sphere-conceptual-illustration)
|
|
7
|
+
- [Scatter Plot with Color-Coded Clusters](#scatter-plot-with-color-coded-clusters)
|
|
8
|
+
- [Probability + Manifold Concept Panel](#probability-manifold-concept-panel)
|
|
9
|
+
- [Ablation Line Panel with Reference Baselines](#ablation-line-panel-with-reference-baselines)
|
|
10
|
+
- [Fill-Between Area Chart (Stacked trend)](#fill-between-area-chart-stacked-trend)
|
|
11
|
+
- [Log-Scale Bar Chart](#log-scale-bar-chart)
|
|
12
|
+
- [GridSpec Multi-Panel Layout](#gridspec-multi-panel-layout)
|
|
13
|
+
- [Scientific Notation on Y-Axis](#scientific-notation-on-y-axis)
|
|
14
|
+
- [Custom Spine Positioning](#custom-spine-positioning)
|
|
15
|
+
- [Related files](#related-files)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Specialized chart patterns beyond basic bars and trends.
|
|
19
|
+
Each section includes the key code pattern extracted from production scripts.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Radar / Polar Chart
|
|
24
|
+
|
|
25
|
+
Used when comparing multiple methods across many benchmarks simultaneously.
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import numpy as np
|
|
29
|
+
import matplotlib.pyplot as plt
|
|
30
|
+
|
|
31
|
+
def plot_radar(methods, colors, subtask_names, value_matrix,
|
|
32
|
+
benchmark_radii, display_range=(45, 90)):
|
|
33
|
+
"""
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
methods : list[str] — one curve per method
|
|
37
|
+
colors : list[str]
|
|
38
|
+
subtask_names : list[str] — one spoke per subtask (may contain '\\n')
|
|
39
|
+
value_matrix : np.ndarray — shape (n_subtasks, n_methods)
|
|
40
|
+
benchmark_radii: dict — {benchmark_name: [tick1, tick2, ...]} for normalization
|
|
41
|
+
display_range : (r_min, r_max) — polar radial display window
|
|
42
|
+
"""
|
|
43
|
+
r_lo, r_hi = display_range
|
|
44
|
+
n_subtasks = len(subtask_names)
|
|
45
|
+
n_methods = len(methods)
|
|
46
|
+
|
|
47
|
+
fig = plt.figure(figsize=(12, 10))
|
|
48
|
+
ax = fig.add_subplot(111, projection='polar')
|
|
49
|
+
|
|
50
|
+
# Evenly spaced angles, clockwise from top
|
|
51
|
+
angles = np.linspace(2 * np.pi, 0, n_subtasks, endpoint=False)
|
|
52
|
+
angles_closed = np.append(angles, angles[0])
|
|
53
|
+
|
|
54
|
+
def _normalize(val, bench):
|
|
55
|
+
radii_list = benchmark_radii.get(bench, [0, 100])
|
|
56
|
+
span = max(radii_list) - min(radii_list)
|
|
57
|
+
if span <= 0:
|
|
58
|
+
return (r_lo + r_hi) / 2
|
|
59
|
+
frac = np.clip((val - min(radii_list)) / span, 0, 1)
|
|
60
|
+
return r_lo + (r_hi - r_lo) * frac
|
|
61
|
+
|
|
62
|
+
subtask_benchmarks = [s.split('\\n', 1)[-1] if '\\n' in s else s
|
|
63
|
+
for s in subtask_names]
|
|
64
|
+
|
|
65
|
+
# Draw data polygons
|
|
66
|
+
for m in range(n_methods):
|
|
67
|
+
norm_vals = np.array([_normalize(value_matrix[i, m], subtask_benchmarks[i])
|
|
68
|
+
for i in range(n_subtasks)])
|
|
69
|
+
closed = np.append(norm_vals, norm_vals[0])
|
|
70
|
+
ax.plot(angles_closed, closed, color=colors[m], lw=2, label=methods[m])
|
|
71
|
+
ax.fill(angles_closed, closed, color=colors[m], alpha=0.05)
|
|
72
|
+
ax.scatter(angles, norm_vals, color=colors[m], s=18, zorder=5)
|
|
73
|
+
|
|
74
|
+
# Style
|
|
75
|
+
ax.set_ylim(r_lo, r_hi)
|
|
76
|
+
ax.set_theta_zero_location('N')
|
|
77
|
+
for spine in ax.spines.values():
|
|
78
|
+
spine.set_visible(False)
|
|
79
|
+
ax.grid(False)
|
|
80
|
+
|
|
81
|
+
# Outer boundary ring
|
|
82
|
+
ax.plot(angles_closed, np.full_like(angles_closed, r_hi),
|
|
83
|
+
color='k', lw=0.8, zorder=4)
|
|
84
|
+
|
|
85
|
+
# Radial spokes
|
|
86
|
+
for a in angles:
|
|
87
|
+
ax.plot([a, a], [r_lo, r_hi], color='gray', lw=0.5, zorder=4)
|
|
88
|
+
|
|
89
|
+
# Benchmark-level contour polygons
|
|
90
|
+
max_levels = max(len(v) for v in benchmark_radii.values())
|
|
91
|
+
for k in range(max_levels):
|
|
92
|
+
disp = np.array([_normalize(benchmark_radii.get(b, [0,100])[
|
|
93
|
+
min(k, len(benchmark_radii.get(b,[0,100]))-1)], b)
|
|
94
|
+
for b in subtask_benchmarks])
|
|
95
|
+
ax.plot(angles_closed, np.append(disp, disp[0]),
|
|
96
|
+
color='k', lw=0.6, zorder=4)
|
|
97
|
+
|
|
98
|
+
ax.set_yticks([r_hi])
|
|
99
|
+
ax.set_yticklabels([])
|
|
100
|
+
ax.set_xticks(angles)
|
|
101
|
+
ax.set_xticklabels([])
|
|
102
|
+
|
|
103
|
+
# Spoke labels (outside outer ring)
|
|
104
|
+
for angle, label in zip(angles, subtask_names):
|
|
105
|
+
r_label = r_hi + 8 + 10 * abs(np.sin(angle))
|
|
106
|
+
ax.text(angle, r_label, label, fontsize=14,
|
|
107
|
+
ha='center', va='center',
|
|
108
|
+
transform=ax.transData, clip_on=False)
|
|
109
|
+
|
|
110
|
+
ax.legend(loc='upper right', bbox_to_anchor=(1.40, 0.05),
|
|
111
|
+
fontsize=15, frameon=False)
|
|
112
|
+
return fig, ax
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Key settings:**
|
|
116
|
+
- `ax.set_theta_zero_location('N')` — top-start convention
|
|
117
|
+
- Remove all default spines/grid; draw custom spokes + contour polygons manually
|
|
118
|
+
- Normalize each spoke independently using per-benchmark tick lists
|
|
119
|
+
- Legend placed **outside** the plot at `bbox_to_anchor=(1.40, 0.05)`
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 3D Sphere / Conceptual Illustration
|
|
124
|
+
|
|
125
|
+
Used for geometric conceptual diagrams (e.g., embedding space visualization).
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import numpy as np
|
|
129
|
+
import matplotlib.pyplot as plt
|
|
130
|
+
|
|
131
|
+
def draw_shaded_sphere(ax, light_dir=(-0.5, 0.5, 0.8),
|
|
132
|
+
resolution=512, alpha=1.0,
|
|
133
|
+
extent=(-1, 1, -1, 1)):
|
|
134
|
+
"""Draw a 2D shaded disk that mimics a 3D sphere using ray-casting."""
|
|
135
|
+
xs = np.linspace(extent[0], extent[1], resolution)
|
|
136
|
+
ys = np.linspace(extent[2], extent[3], resolution)
|
|
137
|
+
x, y = np.meshgrid(xs, ys)
|
|
138
|
+
r2 = x**2 + y**2
|
|
139
|
+
mask = r2 <= 1.0
|
|
140
|
+
|
|
141
|
+
z = np.zeros_like(x)
|
|
142
|
+
z[mask] = np.sqrt(1.0 - r2[mask])
|
|
143
|
+
|
|
144
|
+
# Surface normals
|
|
145
|
+
nx, ny, nz = x.copy(), y.copy(), z.copy()
|
|
146
|
+
nrm = np.sqrt(nx**2 + ny**2 + nz**2) + 1e-6
|
|
147
|
+
nx, ny, nz = nx/nrm, ny/nrm, nz/nrm
|
|
148
|
+
|
|
149
|
+
# Lambertian shading
|
|
150
|
+
ld = np.array(light_dir, dtype=float)
|
|
151
|
+
ld /= np.linalg.norm(ld)
|
|
152
|
+
intensity = np.maximum(0, nx*ld[0] + ny*ld[1] + nz*ld[2])
|
|
153
|
+
|
|
154
|
+
img = np.ones_like(x)
|
|
155
|
+
img[mask] = np.clip(0.2 + 0.9 * intensity[mask], 0, 1)
|
|
156
|
+
|
|
157
|
+
ax.imshow(img, cmap='gray',
|
|
158
|
+
extent=list(extent),
|
|
159
|
+
vmin=0, vmax=1, alpha=alpha)
|
|
160
|
+
ax.set_axis_off()
|
|
161
|
+
return ax
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def plot_3d_scatter_with_arrows(ax, points, grad_vectors,
|
|
165
|
+
point_color='#0c2458', arrow_color='#b64342'):
|
|
166
|
+
"""3D scatter plot with gradient arrow annotations."""
|
|
167
|
+
from mpl_toolkits.mplot3d import proj3d
|
|
168
|
+
from matplotlib.patches import FancyArrowPatch
|
|
169
|
+
|
|
170
|
+
class Arrow3D(FancyArrowPatch):
|
|
171
|
+
def __init__(self, xs, ys, zs, *args, **kwargs):
|
|
172
|
+
super().__init__((0,0), (0,0), *args, **kwargs)
|
|
173
|
+
self._verts3d = xs, ys, zs
|
|
174
|
+
def do_3d_projection(self, renderer=None):
|
|
175
|
+
xs, ys, zs = proj3d.proj_transform(*self._verts3d, self.axes.get_proj())
|
|
176
|
+
self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
|
|
177
|
+
return np.min(zs)
|
|
178
|
+
|
|
179
|
+
ax.scatter(points[:, 0], points[:, 1], points[:, 2],
|
|
180
|
+
s=80, color=point_color, alpha=0.5)
|
|
181
|
+
for p, g in zip(points, grad_vectors):
|
|
182
|
+
arrow = Arrow3D([p[0], p[0]+g[0]], [p[1], p[1]+g[1]], [p[2], p[2]+g[2]],
|
|
183
|
+
mutation_scale=16, lw=4, arrowstyle='->',
|
|
184
|
+
color=arrow_color, alpha=0.8)
|
|
185
|
+
ax.add_artist(arrow)
|
|
186
|
+
|
|
187
|
+
# Clean 3D axes
|
|
188
|
+
ax.grid(False)
|
|
189
|
+
ax.xaxis.pane.set_visible(False)
|
|
190
|
+
ax.yaxis.pane.set_visible(False)
|
|
191
|
+
ax.zaxis.pane.set_visible(False)
|
|
192
|
+
ax.set_xticks([])
|
|
193
|
+
ax.set_yticks([])
|
|
194
|
+
ax.set_zticks([])
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Scatter Plot with Color-Coded Clusters
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
def make_scatter(ax, x, y, labels_or_colors,
|
|
203
|
+
size=50, alpha=0.7, edgecolors='none'):
|
|
204
|
+
"""Single or multi-cluster scatter."""
|
|
205
|
+
import numpy as np
|
|
206
|
+
ax.scatter(x, y, c=labels_or_colors, s=size,
|
|
207
|
+
alpha=alpha, edgecolors=edgecolors)
|
|
208
|
+
ax.set_axis_off() # for conceptual diagrams; remove for data plots
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Probability + Manifold Concept Panel
|
|
214
|
+
|
|
215
|
+
Use when a manuscript needs a conceptual mechanism panel that links a probability
|
|
216
|
+
shift to a geometric or latent-space explanation. Build the pair from the
|
|
217
|
+
original pattern below: a 1D probability-density panel beside a contour/scatter
|
|
218
|
+
manifold panel.
|
|
219
|
+
|
|
220
|
+
**Pattern:**
|
|
221
|
+
- Left panel: draw 2-3 probability curves with transparent fills; use one vertical
|
|
222
|
+
reference line and a single double-headed arrow to define the conceptual gap.
|
|
223
|
+
- Right panel: sample points around smooth center curves, show low-alpha clouds,
|
|
224
|
+
contour density bands, and a small number of highlighted trajectory markers.
|
|
225
|
+
- Keep axes only where they carry meaning. The manifold panel can be axis-free if
|
|
226
|
+
labels and arrows carry the explanation.
|
|
227
|
+
- All math labels and manifold names must map to real manuscript concepts. Do not
|
|
228
|
+
reuse demo labels such as `VIG` or `DPO` unless they are the user's actual terms.
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
fig, (ax_prob, ax_manifold) = plt.subplots(1, 2, figsize=(24, 6))
|
|
232
|
+
plot_distribution(ax_prob) # probability curves + conceptual gap arrow
|
|
233
|
+
plot_manifold(ax_manifold) # density contours + trajectory markers
|
|
234
|
+
fig.tight_layout(pad=0.5)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Ablation Line Panel with Reference Baselines
|
|
240
|
+
|
|
241
|
+
Use when an ablation compares data fraction, hyperparameters, or coupled metrics
|
|
242
|
+
across a small set of methods. A robust original layout uses three horizontal
|
|
243
|
+
panels: data fraction, one hyperparameter sweep, and a dual-axis coupled metric
|
|
244
|
+
sweep.
|
|
245
|
+
|
|
246
|
+
**Pattern:**
|
|
247
|
+
- Use a dashed horizontal baseline for the simple/reference model.
|
|
248
|
+
- Use a dotted horizontal line for a meaningful operating point, e.g. "ours at
|
|
249
|
+
25% data", only when that comparison is called out in the text.
|
|
250
|
+
- Use `twinx()` sparingly. If two y-axes are needed, color each y label to match
|
|
251
|
+
the corresponding series and keep tick ranges narrow.
|
|
252
|
+
- Put legends inside low-density regions of each panel; avoid one giant legend
|
|
253
|
+
if panel-specific series differ.
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
fig, axes = plt.subplots(1, 3, figsize=(27, 6),
|
|
257
|
+
gridspec_kw={"width_ratios": [1.1, 1, 1]})
|
|
258
|
+
axes[0].plot(x, baseline, color="black", alpha=0.3, lw=4, ls="--")
|
|
259
|
+
axes[0].plot(x, reference, color=hero_color, lw=3, ls=":")
|
|
260
|
+
ax2 = axes[2].twinx()
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Fill-Between Area Chart (Stacked trend)
|
|
266
|
+
|
|
267
|
+
Used for cumulative publication counts, stacked contributions, etc.
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
# Filled area (stacked) with hatch for print safety
|
|
271
|
+
ax.fill_between(x, 0, y_bottom,
|
|
272
|
+
color='#ffa8a6', label='Category A')
|
|
273
|
+
ax.fill_between(x, 0, y_top,
|
|
274
|
+
color='#9BC8FA',
|
|
275
|
+
hatch='///', # hatch for grayscale print
|
|
276
|
+
edgecolor='black',
|
|
277
|
+
label='Category B')
|
|
278
|
+
# Erase border artifacts
|
|
279
|
+
ax.fill_between(x, 0, y_top,
|
|
280
|
+
facecolor='none',
|
|
281
|
+
edgecolor='white',
|
|
282
|
+
linewidth=2)
|
|
283
|
+
|
|
284
|
+
# Overlay the trend line for exact values
|
|
285
|
+
ax.plot(x, y_top, lw=3, color='#13457E')
|
|
286
|
+
ax.plot(x, y_bottom, lw=3, color='#850c0a')
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Log-Scale Bar Chart
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
ax.set_yscale('log')
|
|
295
|
+
ymin, ymax = ax.get_ylim()
|
|
296
|
+
ax.set_ylim(ymin, ymax * 20) # expand top for annotations
|
|
297
|
+
|
|
298
|
+
# Annotate values above bars
|
|
299
|
+
for i, val in enumerate(values):
|
|
300
|
+
ax.text(i, val * 1.1, f'{val:.3f}',
|
|
301
|
+
ha='center', va='bottom', fontsize=16)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## GridSpec Multi-Panel Layout
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
from matplotlib import gridspec
|
|
310
|
+
|
|
311
|
+
# 2-row, 4-column layout
|
|
312
|
+
fig = plt.figure(figsize=(36, 12))
|
|
313
|
+
gs = gridspec.GridSpec(2, 4)
|
|
314
|
+
|
|
315
|
+
ax_top_left = fig.add_subplot(gs[0, 0])
|
|
316
|
+
ax_top_right = fig.add_subplot(gs[0, 1:3]) # span columns 1-2
|
|
317
|
+
ax_legend = fig.add_subplot(gs[0, 3]) # legend panel
|
|
318
|
+
ax_bottom = fig.add_subplot(gs[1, :]) # full-width bottom
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Scientific Notation on Y-Axis
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
ax.ticklabel_format(axis='y', style='sci', scilimits=(0, 0))
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Custom Spine Positioning
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
# Move bottom spine to y=0 (for negative values)
|
|
335
|
+
ax.spines['bottom'].set_position(('data', 0))
|
|
336
|
+
ax.xaxis.set_ticks_position('bottom')
|
|
337
|
+
ax.spines['left'].set_bounds(0, y_max)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Related files
|
|
343
|
+
|
|
344
|
+
- [SKILL.md](../SKILL.md) — When to use this skill
|
|
345
|
+
- [api.md](api.md) — PALETTE and core helper signatures
|
|
346
|
+
- [common-patterns.md](common-patterns.md) — Bar, trend, and layout patterns
|
|
347
|
+
- [design-theory.md](design-theory.md) — Rationale and color theory
|
|
348
|
+
- [tutorials.md](tutorials.md) — Full end-to-end walkthroughs
|