evalrx 0.1.2__py3-none-any.whl

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.
Files changed (339) hide show
  1. evalrx/__init__.py +139 -0
  2. evalrx/agent_assets/__init__.py +2 -0
  3. evalrx/agent_assets/skills/README.md +28 -0
  4. evalrx/agent_assets/skills/eval-chart-style/SKILL.md +172 -0
  5. evalrx/agent_assets/skills/evalrx-report-ui/SKILL.md +116 -0
  6. evalrx/agent_assets/skills/nature-figure/LICENSE +201 -0
  7. evalrx/agent_assets/skills/nature-figure/README.md +412 -0
  8. evalrx/agent_assets/skills/nature-figure/SKILL.md +60 -0
  9. evalrx/agent_assets/skills/nature-figure/manifest.yaml +59 -0
  10. evalrx/agent_assets/skills/nature-figure/references/api.md +436 -0
  11. evalrx/agent_assets/skills/nature-figure/references/backend-selection.md +100 -0
  12. evalrx/agent_assets/skills/nature-figure/references/chart-types.md +281 -0
  13. evalrx/agent_assets/skills/nature-figure/references/common-patterns.md +350 -0
  14. evalrx/agent_assets/skills/nature-figure/references/demos.md +65 -0
  15. evalrx/agent_assets/skills/nature-figure/references/design-theory.md +439 -0
  16. evalrx/agent_assets/skills/nature-figure/references/figure-contract.md +93 -0
  17. evalrx/agent_assets/skills/nature-figure/references/figure-legend-conventions.md +71 -0
  18. evalrx/agent_assets/skills/nature-figure/references/nature-2026-observations.md +112 -0
  19. evalrx/agent_assets/skills/nature-figure/references/qa-contract.md +119 -0
  20. evalrx/agent_assets/skills/nature-figure/references/r-template-index.md +66 -0
  21. evalrx/agent_assets/skills/nature-figure/references/r-workflow.md +161 -0
  22. evalrx/agent_assets/skills/nature-figure/references/tutorials.md +251 -0
  23. evalrx/agent_assets/skills/nature-figure/static/core/contract.md +29 -0
  24. evalrx/agent_assets/skills/nature-figure/static/core/stance.md +37 -0
  25. evalrx/agent_assets/skills/nature-figure/static/fragments/backend/python.md +37 -0
  26. evalrx/agent_assets/skills/nature-figure/static/fragments/backend/r.md +44 -0
  27. evalrx/agent_assets/skills/outcome-driver-analysis/SKILL.md +213 -0
  28. evalrx/agent_assets/skills/outcome-driver-analysis/assets/analysis_report_template.md +53 -0
  29. evalrx/agent_assets/skills/outcome-driver-analysis/references/model_selection.md +72 -0
  30. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/explanatory_var_eda.R +130 -0
  31. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/explanatory_var_eda.py +150 -0
  32. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/fit_outcome_model.R +181 -0
  33. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/fit_outcome_model.py +186 -0
  34. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/univariate_eda.R +149 -0
  35. evalrx/agent_assets/skills/outcome-driver-analysis/scripts/univariate_eda.py +177 -0
  36. evalrx/agent_assets/skills.py +27 -0
  37. evalrx/agent_runtime/__init__.py +78 -0
  38. evalrx/agent_runtime/_docker_runner.py +89 -0
  39. evalrx/agent_runtime/cli_runtime.py +103 -0
  40. evalrx/agent_runtime/cli_transcript.py +138 -0
  41. evalrx/agent_runtime/cli_types.py +68 -0
  42. evalrx/agent_runtime/codegen/__init__.py +5 -0
  43. evalrx/agent_runtime/codegen/runner.py +94 -0
  44. evalrx/agent_runtime/experiment_harness.py +117 -0
  45. evalrx/agent_runtime/factory.py +102 -0
  46. evalrx/agent_runtime/json_shape.py +44 -0
  47. evalrx/agent_runtime/judges/__init__.py +28 -0
  48. evalrx/agent_runtime/judges/agy.py +179 -0
  49. evalrx/agent_runtime/judges/autodetect.py +135 -0
  50. evalrx/agent_runtime/judges/claude.py +159 -0
  51. evalrx/agent_runtime/judges/codex.py +120 -0
  52. evalrx/agent_runtime/providers/__init__.py +21 -0
  53. evalrx/agent_runtime/providers/antigravity.py +31 -0
  54. evalrx/agent_runtime/providers/base.py +145 -0
  55. evalrx/agent_runtime/providers/claude_code.py +49 -0
  56. evalrx/agent_runtime/providers/codex.py +37 -0
  57. evalrx/agent_runtime/providers/gemini_cli.py +26 -0
  58. evalrx/agent_runtime/providers/kimi_cli.py +27 -0
  59. evalrx/agent_runtime/providers/opencode.py +27 -0
  60. evalrx/agent_runtime/providers/registry.py +58 -0
  61. evalrx/agent_runtime/sandbox.py +517 -0
  62. evalrx/agent_runtime/skill_audit.py +143 -0
  63. evalrx/agent_runtime/skills/__init__.py +19 -0
  64. evalrx/agent_runtime/skills/installer.py +68 -0
  65. evalrx/agent_runtime/skills/prompt_policy.py +86 -0
  66. evalrx/agent_runtime/skills/resolver.py +19 -0
  67. evalrx/analysis/__init__.py +132 -0
  68. evalrx/analysis/adjudicate.py +154 -0
  69. evalrx/analysis/analysis_module.py +361 -0
  70. evalrx/analysis/api.py +171 -0
  71. evalrx/analysis/case_studio.py +651 -0
  72. evalrx/analysis/cli.py +114 -0
  73. evalrx/analysis/dashboard.py +350 -0
  74. evalrx/analysis/eval_case_matrix.py +118 -0
  75. evalrx/analysis/eval_viz_theme.py +833 -0
  76. evalrx/analysis/explore_run.py +333 -0
  77. evalrx/analysis/explorer.py +1276 -0
  78. evalrx/analysis/failure_modes.py +607 -0
  79. evalrx/analysis/fused_pipeline.py +489 -0
  80. evalrx/analysis/holdout.py +300 -0
  81. evalrx/analysis/hypothesis_agent.py +230 -0
  82. evalrx/analysis/narration.py +177 -0
  83. evalrx/analysis/operationalize.py +442 -0
  84. evalrx/analysis/plain_language.py +42 -0
  85. evalrx/analysis/planner.py +283 -0
  86. evalrx/analysis/probe_search.py +203 -0
  87. evalrx/analysis/profile.py +268 -0
  88. evalrx/analysis/prompts/__init__.py +0 -0
  89. evalrx/analysis/prompts/explorer.py +417 -0
  90. evalrx/analysis/prompts/failure_modes.py +33 -0
  91. evalrx/analysis/prompts/holdout.py +27 -0
  92. evalrx/analysis/prompts/hypothesis_agent.py +78 -0
  93. evalrx/analysis/prompts/run_codebase.py +47 -0
  94. evalrx/analysis/prompts/stats_agent.py +72 -0
  95. evalrx/analysis/prompts/stats_tool_generator.py +43 -0
  96. evalrx/analysis/result_marker.py +47 -0
  97. evalrx/analysis/run_codebase.py +242 -0
  98. evalrx/analysis/run_view.py +205 -0
  99. evalrx/analysis/stage_views.py +93 -0
  100. evalrx/analysis/stats_agent.py +944 -0
  101. evalrx/analysis/stats_tool_agent.py +261 -0
  102. evalrx/analysis/stats_tool_generator.py +415 -0
  103. evalrx/analysis/stats_tools.py +1153 -0
  104. evalrx/analysis/trajectory_records.py +193 -0
  105. evalrx/analysis/workbench.py +431 -0
  106. evalrx/analyzers/__init__.py +42 -0
  107. evalrx/analyzers/agent/__init__.py +25 -0
  108. evalrx/analyzers/agent/counterfactual.py +84 -0
  109. evalrx/analyzers/agent/first_error_judge.py +96 -0
  110. evalrx/analyzers/agent/ignored_obs.py +81 -0
  111. evalrx/analyzers/agent/loop_detect.py +79 -0
  112. evalrx/analyzers/agent/reliability.py +165 -0
  113. evalrx/analyzers/agent/tool_shap.py +225 -0
  114. evalrx/analyzers/agent/trajectory_rubric.py +168 -0
  115. evalrx/analyzers/attention/__init__.py +19 -0
  116. evalrx/analyzers/attention/relative_attn.py +610 -0
  117. evalrx/analyzers/attention/rollout.py +73 -0
  118. evalrx/analyzers/attention/sink.py +56 -0
  119. evalrx/analyzers/attention/summary.py +190 -0
  120. evalrx/analyzers/attribution/__init__.py +6 -0
  121. evalrx/analyzers/attribution/generic_attn.py +31 -0
  122. evalrx/analyzers/attribution/gradcam.py +30 -0
  123. evalrx/analyzers/base.py +12 -0
  124. evalrx/analyzers/geometry/__init__.py +6 -0
  125. evalrx/analyzers/geometry/cka.py +70 -0
  126. evalrx/analyzers/geometry/linear_probe.py +157 -0
  127. evalrx/analyzers/hallucination/__init__.py +9 -0
  128. evalrx/analyzers/hallucination/chair.py +78 -0
  129. evalrx/analyzers/hallucination/opera.py +29 -0
  130. evalrx/analyzers/hallucination/pope.py +119 -0
  131. evalrx/analyzers/hallucination/selfcheck.py +155 -0
  132. evalrx/analyzers/hallucination/vcd.py +29 -0
  133. evalrx/analyzers/lens/__init__.py +7 -0
  134. evalrx/analyzers/lens/layer_contrast.py +133 -0
  135. evalrx/analyzers/lens/logit_lens.py +138 -0
  136. evalrx/analyzers/lens/tuned_lens.py +30 -0
  137. evalrx/analyzers/patching/__init__.py +5 -0
  138. evalrx/analyzers/patching/causal_trace.py +30 -0
  139. evalrx/analyzers/perturbation/__init__.py +23 -0
  140. evalrx/analyzers/perturbation/_shapley.py +54 -0
  141. evalrx/analyzers/perturbation/context_shap.py +174 -0
  142. evalrx/analyzers/perturbation/cot_faithfulness.py +239 -0
  143. evalrx/analyzers/perturbation/format_sensitivity.py +237 -0
  144. evalrx/analyzers/perturbation/mm_shap.py +146 -0
  145. evalrx/analyzers/perturbation/modality_ablation.py +196 -0
  146. evalrx/analyzers/perturbation/perturbation_battery.py +274 -0
  147. evalrx/analyzers/perturbation/prompt_contrast.py +265 -0
  148. evalrx/analyzers/perturbation/rise.py +94 -0
  149. evalrx/analyzers/perturbation/vl_shap.py +102 -0
  150. evalrx/analyzers/reasoning/__init__.py +33 -0
  151. evalrx/analyzers/reasoning/_text.py +328 -0
  152. evalrx/analyzers/reasoning/answer_extraction_audit.py +327 -0
  153. evalrx/analyzers/reasoning/arith_audit.py +226 -0
  154. evalrx/analyzers/reasoning/contamination.py +214 -0
  155. evalrx/analyzers/reasoning/knowledge_split.py +253 -0
  156. evalrx/analyzers/reasoning/self_repair.py +246 -0
  157. evalrx/analyzers/reasoning/step_rollout_value.py +216 -0
  158. evalrx/analyzers/reasoning/termination_audit.py +258 -0
  159. evalrx/analyzers/uncertainty/__init__.py +18 -0
  160. evalrx/analyzers/uncertainty/calibration.py +174 -0
  161. evalrx/analyzers/uncertainty/coverage_gap.py +199 -0
  162. evalrx/analyzers/uncertainty/entropy.py +90 -0
  163. evalrx/analyzers/uncertainty/logprob_entropy.py +69 -0
  164. evalrx/analyzers/uncertainty/self_consistency.py +204 -0
  165. evalrx/analyzers/uncertainty/verbalized_conf.py +64 -0
  166. evalrx/cli.py +411 -0
  167. evalrx/config.py +77 -0
  168. evalrx/contract/__init__.py +179 -0
  169. evalrx/contract/common.py +452 -0
  170. evalrx/contract/emit.py +948 -0
  171. evalrx/contract/export.py +237 -0
  172. evalrx/contract/m1.py +325 -0
  173. evalrx/contract/m2.py +317 -0
  174. evalrx/contract/m3.py +165 -0
  175. evalrx/contract/m4.py +130 -0
  176. evalrx/contract/m5.py +292 -0
  177. evalrx/contract/methodology.py +76 -0
  178. evalrx/contract/pre_m1.py +58 -0
  179. evalrx/contract/typescript.py +140 -0
  180. evalrx/core/__init__.py +85 -0
  181. evalrx/core/analyzer.py +174 -0
  182. evalrx/core/capability.py +54 -0
  183. evalrx/core/case.py +443 -0
  184. evalrx/core/experiment.py +106 -0
  185. evalrx/core/model.py +198 -0
  186. evalrx/core/pipeline.py +42 -0
  187. evalrx/core/registry.py +142 -0
  188. evalrx/core/result.py +64 -0
  189. evalrx/core/spec.py +173 -0
  190. evalrx/core/tokentype.py +165 -0
  191. evalrx/core/tool.py +92 -0
  192. evalrx/datasets/__init__.py +41 -0
  193. evalrx/datasets/base.py +68 -0
  194. evalrx/datasets/gui_os.py +52 -0
  195. evalrx/datasets/llm_qa.py +57 -0
  196. evalrx/datasets/pure_qa.py +12 -0
  197. evalrx/datasets/vlm_qa.py +695 -0
  198. evalrx/datasets/web_search_qa.py +52 -0
  199. evalrx/eval_agent/__init__.py +341 -0
  200. evalrx/eval_agent/_tools.py +81 -0
  201. evalrx/eval_agent/ab_runner.py +50 -0
  202. evalrx/eval_agent/agentic/__init__.py +43 -0
  203. evalrx/eval_agent/agentic/actions.py +216 -0
  204. evalrx/eval_agent/agentic/board.py +107 -0
  205. evalrx/eval_agent/agentic/loop.py +190 -0
  206. evalrx/eval_agent/agentic/tools.py +538 -0
  207. evalrx/eval_agent/checkpoint.py +57 -0
  208. evalrx/eval_agent/cli_agent.py +59 -0
  209. evalrx/eval_agent/cli_skills.py +5 -0
  210. evalrx/eval_agent/evolution.py +396 -0
  211. evalrx/eval_agent/git_manager.py +215 -0
  212. evalrx/eval_agent/hypothesis.py +172 -0
  213. evalrx/eval_agent/label_quarantine.py +209 -0
  214. evalrx/eval_agent/legacy.py +530 -0
  215. evalrx/eval_agent/log_schema.py +497 -0
  216. evalrx/eval_agent/loop.py +2159 -0
  217. evalrx/eval_agent/loop_reports.py +116 -0
  218. evalrx/eval_agent/model_instrumentation.py +282 -0
  219. evalrx/eval_agent/narration.py +193 -0
  220. evalrx/eval_agent/nl_runner.py +460 -0
  221. evalrx/eval_agent/orchestrator.py +61 -0
  222. evalrx/eval_agent/preregister.py +93 -0
  223. evalrx/eval_agent/prompts/__init__.py +1 -0
  224. evalrx/eval_agent/prompts/agentic.py +46 -0
  225. evalrx/eval_agent/prompts/case_discovery.py +25 -0
  226. evalrx/eval_agent/prompts/diagnosis.py +125 -0
  227. evalrx/eval_agent/prompts/experiment_writer.py +265 -0
  228. evalrx/eval_agent/prompts/explore_step.py +37 -0
  229. evalrx/eval_agent/prompts/fix_agent.py +257 -0
  230. evalrx/eval_agent/prompts/hypothesis_tester.py +15 -0
  231. evalrx/eval_agent/prompts/nl_runner.py +38 -0
  232. evalrx/eval_agent/prompts/probe_agent.py +25 -0
  233. evalrx/eval_agent/prompts/probe_candidate_generator.py +14 -0
  234. evalrx/eval_agent/prompts/probe_generator.py +35 -0
  235. evalrx/eval_agent/prompts/whitebox_probe_generator.py +38 -0
  236. evalrx/eval_agent/report.py +58 -0
  237. evalrx/eval_agent/run_context.py +354 -0
  238. evalrx/eval_agent/run_log.schema.json +1215 -0
  239. evalrx/eval_agent/run_logger_v2.py +1764 -0
  240. evalrx/eval_agent/run_metadata.py +208 -0
  241. evalrx/eval_agent/stages/__init__.py +56 -0
  242. evalrx/eval_agent/stages/case_discovery.py +293 -0
  243. evalrx/eval_agent/stages/diagnosis.py +1017 -0
  244. evalrx/eval_agent/stages/experiment_writer.py +1634 -0
  245. evalrx/eval_agent/stages/fix_agent.py +3916 -0
  246. evalrx/eval_agent/stages/fix_internals.py +499 -0
  247. evalrx/eval_agent/stages/fix_pipeline.py +725 -0
  248. evalrx/eval_agent/stages/fix_tiers.py +187 -0
  249. evalrx/eval_agent/stages/fix_tools.py +1034 -0
  250. evalrx/eval_agent/stages/hypothesis_tester.py +1014 -0
  251. evalrx/eval_agent/stages/probe.py +439 -0
  252. evalrx/eval_agent/stages/probe_agent.py +1079 -0
  253. evalrx/eval_agent/stages/probe_candidate_generator.py +128 -0
  254. evalrx/eval_agent/stages/probe_generator.py +326 -0
  255. evalrx/eval_agent/stages/probe_search_agent.py +106 -0
  256. evalrx/eval_agent/stages/protocol.py +112 -0
  257. evalrx/eval_agent/stages/repair_catalog.py +273 -0
  258. evalrx/eval_agent/stages/surgery.py +524 -0
  259. evalrx/eval_agent/stages/whitebox_probe_generator.py +351 -0
  260. evalrx/eval_agent/store.py +231 -0
  261. evalrx/logging_utils.py +112 -0
  262. evalrx/models/__init__.py +161 -0
  263. evalrx/models/_discover.py +101 -0
  264. evalrx/models/agent.py +380 -0
  265. evalrx/models/backends/__init__.py +58 -0
  266. evalrx/models/backends/api.py +169 -0
  267. evalrx/models/backends/base.py +57 -0
  268. evalrx/models/backends/gemini_compat.py +579 -0
  269. evalrx/models/backends/hf_local.py +2074 -0
  270. evalrx/models/backends/openai_compat.py +301 -0
  271. evalrx/models/backends/vllm_offline.py +116 -0
  272. evalrx/models/base.py +24 -0
  273. evalrx/models/blackbox/__init__.py +4 -0
  274. evalrx/models/blackbox/agent.py +31 -0
  275. evalrx/models/blackbox/base.py +29 -0
  276. evalrx/models/blackbox/gemini.py +279 -0
  277. evalrx/models/blackbox/llm_api.py +17 -0
  278. evalrx/models/blackbox/vlm_api.py +17 -0
  279. evalrx/models/compose.py +66 -0
  280. evalrx/models/inference.py +88 -0
  281. evalrx/models/paper_methods/__init__.py +8 -0
  282. evalrx/models/paper_methods/aad.py +53 -0
  283. evalrx/models/paper_methods/ifcd.py +204 -0
  284. evalrx/models/paper_methods/pai.py +164 -0
  285. evalrx/models/paper_methods/tcd.py +202 -0
  286. evalrx/models/paper_methods/vcd.py +45 -0
  287. evalrx/models/paper_methods/vicrop.py +137 -0
  288. evalrx/models/toolcodec.py +143 -0
  289. evalrx/models/tools/__init__.py +20 -0
  290. evalrx/models/tools/perception.py +300 -0
  291. evalrx/models/tools/visual.py +174 -0
  292. evalrx/models/whitebox/__init__.py +26 -0
  293. evalrx/models/whitebox/agent.py +31 -0
  294. evalrx/models/whitebox/base.py +24 -0
  295. evalrx/models/whitebox/qwen.py +61 -0
  296. evalrx/models/whitebox/qwen2_5_omni.py +29 -0
  297. evalrx/models/whitebox/qwen2_audio.py +25 -0
  298. evalrx/models/whitebox/qwen_omni.py +53 -0
  299. evalrx/models/whitebox/qwen_vl.py +62 -0
  300. evalrx/observability/__init__.py +21 -0
  301. evalrx/observability/envelope.py +122 -0
  302. evalrx/observability/outbox.py +111 -0
  303. evalrx/observability/tracer.py +882 -0
  304. evalrx/reporting/__init__.py +28 -0
  305. evalrx/reporting/case_study.py +947 -0
  306. evalrx/reporting/compiler.py +587 -0
  307. evalrx/reporting/dynamic.py +1882 -0
  308. evalrx/reporting/html_report.py +2225 -0
  309. evalrx/reporting/langfuse_exporter.py +38 -0
  310. evalrx/reporting/langfuse_source.py +155 -0
  311. evalrx/reporting/model.py +151 -0
  312. evalrx/reporting/run_events.py +184 -0
  313. evalrx/reporting/server.py +557 -0
  314. evalrx/reporting/stages.py +58 -0
  315. evalrx/reporting/static_export.py +142 -0
  316. evalrx/reporting/web_dist/index.html +146 -0
  317. evalrx/specs.py +727 -0
  318. evalrx/stats/__init__.py +47 -0
  319. evalrx/stats/api.py +192 -0
  320. evalrx/stats/bootstrap.py +86 -0
  321. evalrx/stats/ebh.py +27 -0
  322. evalrx/stats/evalue.py +98 -0
  323. evalrx/stats/friedman.py +138 -0
  324. evalrx/stats/mcnemar.py +40 -0
  325. evalrx/stats/multiplicity.py +159 -0
  326. evalrx/stats/subset_sampling.py +55 -0
  327. evalrx/term_links.py +43 -0
  328. evalrx/viz/__init__.py +7 -0
  329. evalrx/viz/labels.py +77 -0
  330. evalrx/viz/prompts.py +39 -0
  331. evalrx/viz/renderer.py +590 -0
  332. evalrx/viz/schema.py +36 -0
  333. evalrx/viz/style.py +134 -0
  334. evalrx-0.1.2.dist-info/METADATA +532 -0
  335. evalrx-0.1.2.dist-info/RECORD +339 -0
  336. evalrx-0.1.2.dist-info/WHEEL +5 -0
  337. evalrx-0.1.2.dist-info/entry_points.txt +3 -0
  338. evalrx-0.1.2.dist-info/licenses/LICENSE +121 -0
  339. evalrx-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,281 @@
1
+ # Chart Types — Nature Figure Making
2
+
3
+ Specialized chart patterns beyond basic bars and trends.
4
+ Each section includes the key code pattern extracted from production scripts.
5
+
6
+ ---
7
+
8
+ ## Radar / Polar Chart
9
+
10
+ Used when comparing multiple methods across many benchmarks simultaneously.
11
+
12
+ ```python
13
+ import numpy as np
14
+ import matplotlib.pyplot as plt
15
+
16
+ def plot_radar(methods, colors, subtask_names, value_matrix,
17
+ benchmark_radii, display_range=(45, 90)):
18
+ """
19
+ Parameters
20
+ ----------
21
+ methods : list[str] — one curve per method
22
+ colors : list[str]
23
+ subtask_names : list[str] — one spoke per subtask (may contain '\\n')
24
+ value_matrix : np.ndarray — shape (n_subtasks, n_methods)
25
+ benchmark_radii: dict — {benchmark_name: [tick1, tick2, ...]} for normalization
26
+ display_range : (r_min, r_max) — polar radial display window
27
+ """
28
+ r_lo, r_hi = display_range
29
+ n_subtasks = len(subtask_names)
30
+ n_methods = len(methods)
31
+
32
+ fig = plt.figure(figsize=(12, 10))
33
+ ax = fig.add_subplot(111, projection='polar')
34
+
35
+ # Evenly spaced angles, clockwise from top
36
+ angles = np.linspace(2 * np.pi, 0, n_subtasks, endpoint=False)
37
+ angles_closed = np.append(angles, angles[0])
38
+
39
+ def _normalize(val, bench):
40
+ radii_list = benchmark_radii.get(bench, [0, 100])
41
+ span = max(radii_list) - min(radii_list)
42
+ if span <= 0:
43
+ return (r_lo + r_hi) / 2
44
+ frac = np.clip((val - min(radii_list)) / span, 0, 1)
45
+ return r_lo + (r_hi - r_lo) * frac
46
+
47
+ subtask_benchmarks = [s.split('\\n', 1)[-1] if '\\n' in s else s
48
+ for s in subtask_names]
49
+
50
+ # Draw data polygons
51
+ for m in range(n_methods):
52
+ norm_vals = np.array([_normalize(value_matrix[i, m], subtask_benchmarks[i])
53
+ for i in range(n_subtasks)])
54
+ closed = np.append(norm_vals, norm_vals[0])
55
+ ax.plot(angles_closed, closed, color=colors[m], lw=2, label=methods[m])
56
+ ax.fill(angles_closed, closed, color=colors[m], alpha=0.05)
57
+ ax.scatter(angles, norm_vals, color=colors[m], s=18, zorder=5)
58
+
59
+ # Style
60
+ ax.set_ylim(r_lo, r_hi)
61
+ ax.set_theta_zero_location('N')
62
+ for spine in ax.spines.values():
63
+ spine.set_visible(False)
64
+ ax.grid(False)
65
+
66
+ # Outer boundary ring
67
+ ax.plot(angles_closed, np.full_like(angles_closed, r_hi),
68
+ color='k', lw=0.8, zorder=4)
69
+
70
+ # Radial spokes
71
+ for a in angles:
72
+ ax.plot([a, a], [r_lo, r_hi], color='gray', lw=0.5, zorder=4)
73
+
74
+ # Benchmark-level contour polygons
75
+ max_levels = max(len(v) for v in benchmark_radii.values())
76
+ for k in range(max_levels):
77
+ disp = np.array([_normalize(benchmark_radii.get(b, [0,100])[
78
+ min(k, len(benchmark_radii.get(b,[0,100]))-1)], b)
79
+ for b in subtask_benchmarks])
80
+ ax.plot(angles_closed, np.append(disp, disp[0]),
81
+ color='k', lw=0.6, zorder=4)
82
+
83
+ ax.set_yticks([r_hi])
84
+ ax.set_yticklabels([])
85
+ ax.set_xticks(angles)
86
+ ax.set_xticklabels([])
87
+
88
+ # Spoke labels (outside outer ring)
89
+ for angle, label in zip(angles, subtask_names):
90
+ r_label = r_hi + 8 + 10 * abs(np.sin(angle))
91
+ ax.text(angle, r_label, label, fontsize=14,
92
+ ha='center', va='center',
93
+ transform=ax.transData, clip_on=False)
94
+
95
+ ax.legend(loc='upper right', bbox_to_anchor=(1.40, 0.05),
96
+ fontsize=15, frameon=False)
97
+ return fig, ax
98
+ ```
99
+
100
+ **Key settings:**
101
+ - `ax.set_theta_zero_location('N')` — top-start convention
102
+ - Remove all default spines/grid; draw custom spokes + contour polygons manually
103
+ - Normalize each spoke independently using per-benchmark tick lists
104
+ - Legend placed **outside** the plot at `bbox_to_anchor=(1.40, 0.05)`
105
+
106
+ ---
107
+
108
+ ## 3D Sphere / Conceptual Illustration
109
+
110
+ Used for geometric conceptual diagrams (e.g., embedding space visualization).
111
+
112
+ ```python
113
+ import numpy as np
114
+ import matplotlib.pyplot as plt
115
+
116
+ def draw_shaded_sphere(ax, light_dir=(-0.5, 0.5, 0.8),
117
+ resolution=512, alpha=1.0,
118
+ extent=(-1, 1, -1, 1)):
119
+ """Draw a 2D shaded disk that mimics a 3D sphere using ray-casting."""
120
+ xs = np.linspace(extent[0], extent[1], resolution)
121
+ ys = np.linspace(extent[2], extent[3], resolution)
122
+ x, y = np.meshgrid(xs, ys)
123
+ r2 = x**2 + y**2
124
+ mask = r2 <= 1.0
125
+
126
+ z = np.zeros_like(x)
127
+ z[mask] = np.sqrt(1.0 - r2[mask])
128
+
129
+ # Surface normals
130
+ nx, ny, nz = x.copy(), y.copy(), z.copy()
131
+ nrm = np.sqrt(nx**2 + ny**2 + nz**2) + 1e-6
132
+ nx, ny, nz = nx/nrm, ny/nrm, nz/nrm
133
+
134
+ # Lambertian shading
135
+ ld = np.array(light_dir, dtype=float)
136
+ ld /= np.linalg.norm(ld)
137
+ intensity = np.maximum(0, nx*ld[0] + ny*ld[1] + nz*ld[2])
138
+
139
+ img = np.ones_like(x)
140
+ img[mask] = np.clip(0.2 + 0.9 * intensity[mask], 0, 1)
141
+
142
+ ax.imshow(img, cmap='gray',
143
+ extent=list(extent),
144
+ vmin=0, vmax=1, alpha=alpha)
145
+ ax.set_axis_off()
146
+ return ax
147
+
148
+
149
+ def plot_3d_scatter_with_arrows(ax, points, grad_vectors,
150
+ point_color='#0c2458', arrow_color='#b64342'):
151
+ """3D scatter plot with gradient arrow annotations."""
152
+ from mpl_toolkits.mplot3d import proj3d
153
+ from matplotlib.patches import FancyArrowPatch
154
+
155
+ class Arrow3D(FancyArrowPatch):
156
+ def __init__(self, xs, ys, zs, *args, **kwargs):
157
+ super().__init__((0,0), (0,0), *args, **kwargs)
158
+ self._verts3d = xs, ys, zs
159
+ def do_3d_projection(self, renderer=None):
160
+ xs, ys, zs = proj3d.proj_transform(*self._verts3d, self.axes.get_proj())
161
+ self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
162
+ return np.min(zs)
163
+
164
+ ax.scatter(points[:, 0], points[:, 1], points[:, 2],
165
+ s=80, color=point_color, alpha=0.5)
166
+ for p, g in zip(points, grad_vectors):
167
+ arrow = Arrow3D([p[0], p[0]+g[0]], [p[1], p[1]+g[1]], [p[2], p[2]+g[2]],
168
+ mutation_scale=16, lw=4, arrowstyle='->',
169
+ color=arrow_color, alpha=0.8)
170
+ ax.add_artist(arrow)
171
+
172
+ # Clean 3D axes
173
+ ax.grid(False)
174
+ ax.xaxis.pane.set_visible(False)
175
+ ax.yaxis.pane.set_visible(False)
176
+ ax.zaxis.pane.set_visible(False)
177
+ ax.set_xticks([])
178
+ ax.set_yticks([])
179
+ ax.set_zticks([])
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Scatter Plot with Color-Coded Clusters
185
+
186
+ ```python
187
+ def make_scatter(ax, x, y, labels_or_colors,
188
+ size=50, alpha=0.7, edgecolors='none'):
189
+ """Single or multi-cluster scatter."""
190
+ import numpy as np
191
+ ax.scatter(x, y, c=labels_or_colors, s=size,
192
+ alpha=alpha, edgecolors=edgecolors)
193
+ ax.set_axis_off() # for conceptual diagrams; remove for data plots
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Fill-Between Area Chart (Stacked trend)
199
+
200
+ Used for cumulative publication counts, stacked contributions, etc.
201
+
202
+ ```python
203
+ # Filled area (stacked) with hatch for print safety
204
+ ax.fill_between(x, 0, y_bottom,
205
+ color='#ffa8a6', label='Category A')
206
+ ax.fill_between(x, 0, y_top,
207
+ color='#9BC8FA',
208
+ hatch='///', # hatch for grayscale print
209
+ edgecolor='black',
210
+ label='Category B')
211
+ # Erase border artifacts
212
+ ax.fill_between(x, 0, y_top,
213
+ facecolor='none',
214
+ edgecolor='white',
215
+ linewidth=2)
216
+
217
+ # Overlay the trend line for exact values
218
+ ax.plot(x, y_top, lw=3, color='#13457E')
219
+ ax.plot(x, y_bottom, lw=3, color='#850c0a')
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Log-Scale Bar Chart
225
+
226
+ ```python
227
+ ax.set_yscale('log')
228
+ ymin, ymax = ax.get_ylim()
229
+ ax.set_ylim(ymin, ymax * 20) # expand top for annotations
230
+
231
+ # Annotate values above bars
232
+ for i, val in enumerate(values):
233
+ ax.text(i, val * 1.1, f'{val:.3f}',
234
+ ha='center', va='bottom', fontsize=16)
235
+ ```
236
+
237
+ ---
238
+
239
+ ## GridSpec Multi-Panel Layout
240
+
241
+ ```python
242
+ from matplotlib import gridspec
243
+
244
+ # 2-row, 4-column layout
245
+ fig = plt.figure(figsize=(36, 12))
246
+ gs = gridspec.GridSpec(2, 4)
247
+
248
+ ax_top_left = fig.add_subplot(gs[0, 0])
249
+ ax_top_right = fig.add_subplot(gs[0, 1:3]) # span columns 1-2
250
+ ax_legend = fig.add_subplot(gs[0, 3]) # legend panel
251
+ ax_bottom = fig.add_subplot(gs[1, :]) # full-width bottom
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Scientific Notation on Y-Axis
257
+
258
+ ```python
259
+ ax.ticklabel_format(axis='y', style='sci', scilimits=(0, 0))
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Custom Spine Positioning
265
+
266
+ ```python
267
+ # Move bottom spine to y=0 (for negative values)
268
+ ax.spines['bottom'].set_position(('data', 0))
269
+ ax.xaxis.set_ticks_position('bottom')
270
+ ax.spines['left'].set_bounds(0, y_max)
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Related files
276
+
277
+ - [SKILL.md](../SKILL.md) — When to use this skill
278
+ - [api.md](api.md) — PALETTE and core helper signatures
279
+ - [common-patterns.md](common-patterns.md) — Bar, trend, and layout patterns
280
+ - [design-theory.md](design-theory.md) — Rationale and color theory
281
+ - [tutorials.md](tutorials.md) — Full end-to-end walkthroughs
@@ -0,0 +1,350 @@
1
+ # Common Patterns — Nature Figure Making
2
+
3
+ Reusable layout and encoding patterns used across publication-grade scripts.
4
+
5
+ ---
6
+
7
+ ## Pattern 1: Ultra-wide multi-metric bar panel
8
+
9
+ For 3–4 metrics compared across many methods, use a wide canvas so bars and labels don't crowd.
10
+
11
+ ```python
12
+ fig = plt.figure(figsize=(45, 12)) # or (28, 6) for fewer metrics
13
+ gs = gridspec.GridSpec(1, n_metrics)
14
+
15
+ for i, metric in enumerate(metrics):
16
+ ax = fig.add_subplot(gs[i])
17
+ ax.bar(x, values[metric], color=colors, ...)
18
+ ax.set_ylabel(metric, fontsize=54, labelpad=12)
19
+ ax.set_xticks([])
20
+
21
+ # Last panel: legend only
22
+ ax_leg = fig.add_subplot(gs[-1])
23
+ ax_leg.legend(handles, labels, fontsize=38, loc='center', frameon=False)
24
+ ax_leg.set_axis_off()
25
+
26
+ fig.tight_layout(pad=2)
27
+ ```
28
+
29
+ **Rule**: Width often 3–4× height. Allows left-to-right narrative scanning.
30
+
31
+ ---
32
+
33
+ ## Pattern 2: Dedicated legend panel
34
+
35
+ When the legend is large, give it its own axis so data panels stay clean.
36
+
37
+ ```python
38
+ fig, axes = plt.subplots(1, n_data + 1, figsize=(...))
39
+
40
+ for i, ax in enumerate(axes[:-1]):
41
+ bars = ax.bar(...)
42
+ if i == 0:
43
+ handles, labels = ax.get_legend_handles_labels()
44
+
45
+ # Legend-only panel
46
+ axes[-1].legend(handles, labels, fontsize=28, loc='center', frameon=False)
47
+ axes[-1].set_axis_off()
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Pattern 3: Categorical bars without x-tick labels
53
+
54
+ When methods are named in the legend, hide x-ticks entirely.
55
+
56
+ ```python
57
+ ax.set_xticks([]) # removes ticks and labels
58
+ # Alternatively:
59
+ ax.set_xticklabels([]) # keeps tick marks, removes labels
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Pattern 4: Dynamic y-axis tightening
65
+
66
+ Never use 0–100 when all values are in 80–95.
67
+
68
+ ```python
69
+ margin = (values.max() - values.min()) * 0.1 # 10% padding
70
+ ax.set_ylim([values.min() - margin, values.max() + margin])
71
+
72
+ # Manual ticks at clean round numbers
73
+ ax.set_yticks([0.75, 0.80, 0.85, 0.90])
74
+ ax.tick_params(axis='y', labelsize=36, length=10, width=2)
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Pattern 5: Alpha-graduated ablation bars (same color, varying opacity)
80
+
81
+ ```python
82
+ import numpy as np
83
+
84
+ blue_rgb = (0.215686, 0.458824, 0.729412) # #3775BA as float tuple
85
+ n_ablations = len(ablation_configs)
86
+ alphas = np.linspace(0.2, 1.0, n_ablations)
87
+ colors = [(blue_rgb[0], blue_rgb[1], blue_rgb[2], a) for a in alphas]
88
+ # Full method → alpha=1.0, most ablated → alpha=0.2
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Pattern 6: Hatch encoding for print-safe grayscale
94
+
95
+ Add hatching so bars remain distinct when printed in black-and-white.
96
+
97
+ ```python
98
+ hatches = ['/', '\\\\', '.', 'x', 'o', '+']
99
+ for bar_container, hatch in zip(grouped_bars, hatches):
100
+ for patch in bar_container:
101
+ patch.set_hatch(hatch)
102
+ patch.set_edgecolor('black')
103
+ patch.set_linewidth(1.5)
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Pattern 7: Semantic or family color mapping
109
+
110
+ Always map colors consistently across all panels in a figure:
111
+
112
+ ```python
113
+ method_colors = {
114
+ 'ResNet1d18': '#484878', # baseline_dark
115
+ 'ResNet1d34': '#7884B4', # baseline_mid
116
+ 'ECGFounder': '#B4C0E4', # baseline_soft
117
+ 'CSFM-Tiny': '#E4E4F0', # ours_tiny
118
+ 'CSFM-Base': '#E4CCD8', # ours_base
119
+ 'CSFM-Large': '#F0C0CC', # ours_large
120
+ }
121
+ colors = [method_colors[m] for m in methods]
122
+ ```
123
+
124
+ Prefer coherent hue families over alternating saturated blue/green/red just because categories differ.
125
+ Green and red should usually be reserved for **directional annotations**, not primary series identity:
126
+
127
+ ```python
128
+ ax.scatter(x_gain, y_gain, marker='^', color='#2E9E44', s=90, zorder=6) # improvement
129
+ ax.scatter(x_drop, y_drop, marker='v', color='#E53935', s=90, zorder=6) # degradation
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Pattern 8: In-bar text with luminance-aware color
135
+
136
+ ```python
137
+ def annotate_bars(ax, bars, colors, fmt='{:.2f}', fontsize=32, offset=-0.10):
138
+ for bar, color in zip(bars, colors):
139
+ c = color.lstrip('#')
140
+ r, g, b = int(c[0:2],16)/255, int(c[2:4],16)/255, int(c[4:6],16)/255
141
+ lum = 0.299*r + 0.587*g + 0.114*b
142
+ textcolor = 'white' if lum < 0.5 else 'black'
143
+ value = bar.get_height()
144
+ ax.text(bar.get_x() + bar.get_width()/2,
145
+ value + offset,
146
+ fmt.format(value),
147
+ ha='center', va='bottom',
148
+ fontsize=fontsize, color=textcolor)
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Pattern 9: Fill-between trend with hatch (print-safe)
154
+
155
+ ```python
156
+ ax.fill_between(x, 0, cumsum_series,
157
+ color=fill_color,
158
+ hatch='\\\\\\', # triple backslash for dense hatch
159
+ edgecolor='black',
160
+ label=label_name)
161
+ # Visually erase the border artifacts:
162
+ ax.fill_between(x, 0, cumsum_series,
163
+ facecolor='none',
164
+ edgecolor='white',
165
+ linewidth=2)
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Pattern 10: Annotate events on trend lines
171
+
172
+ ```python
173
+ def mark_events(ax, x_labels, y_cumsum, events_dict, dy_fraction=0.1):
174
+ """Add labeled arrows at event dates on a trend line."""
175
+ x_index = {label: i for i, label in enumerate(x_labels)}
176
+ y_lo, y_hi = ax.get_ylim()
177
+ dy = dy_fraction * (y_hi - y_lo)
178
+ for date, label in events_dict.items():
179
+ if date not in x_index:
180
+ continue
181
+ i = x_index[date]
182
+ stars = label.count('*')
183
+ clean_label = label.replace('*', '')
184
+ y_data = y_cumsum[i]
185
+ ax.annotate(
186
+ clean_label,
187
+ xy=(i, y_data),
188
+ xytext=(i, y_data + (1 + 0.8 * stars) * dy),
189
+ ha='center', va='bottom', fontsize=11,
190
+ arrowprops=dict(arrowstyle='-|>', lw=1.3, color='black',
191
+ shrinkA=0, shrinkB=0, mutation_scale=15)
192
+ )
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Pattern 11: Grouped bars across multiple datasets (grouped-within-grouped)
198
+
199
+ ```python
200
+ num_methods = len(methods)
201
+ xtick_positions = []
202
+
203
+ for dataset_idx, dataset_name in enumerate(datasets):
204
+ x_start = dataset_idx * (num_methods + 1) # gap of 1 between groups
205
+ ax.bar(
206
+ np.arange(num_methods) + x_start,
207
+ values[dataset_name],
208
+ color=method_colors,
209
+ label=methods if dataset_idx == 0 else ['_nolegend_'] * num_methods,
210
+ )
211
+ xtick_positions.append(np.mean(np.arange(num_methods)) + x_start)
212
+
213
+ ax.set_xticks(xtick_positions)
214
+ ax.set_xticklabels(datasets)
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Pattern 12: Schematic hero panel with supporting quant row
220
+
221
+ Use when one mechanism or fabrication story needs to lead, with 2–4 smaller evidence plots below.
222
+
223
+ ```python
224
+ fig = plt.figure(figsize=(7.2, 6.2))
225
+ gs = fig.add_gridspec(
226
+ 2, 4,
227
+ height_ratios=[2.2, 1.0],
228
+ hspace=0.18, wspace=0.28,
229
+ )
230
+
231
+ ax_top = fig.add_subplot(gs[0, :]) # hero schematic
232
+ ax_b = fig.add_subplot(gs[1, 0])
233
+ ax_c = fig.add_subplot(gs[1, 1:3])
234
+ ax_d = fig.add_subplot(gs[1, 3])
235
+
236
+ # top panel should carry the main palette and the main visual narrative
237
+ ```
238
+
239
+ Rules:
240
+
241
+ - Allocate `45–60%` of total height to the hero schematic.
242
+ - Reuse softened versions of the same colors in the lower plots.
243
+ - Keep support plots quieter than the hero panel.
244
+
245
+ ---
246
+
247
+ ## Pattern 13: Dark image plate with repeated views
248
+
249
+ Use for microscopy, volume rendering, or fluorescence-heavy panels.
250
+
251
+ ```python
252
+ fig = plt.figure(figsize=(7.2, 6.5))
253
+ gs = fig.add_gridspec(3, 5, hspace=0.08, wspace=0.04)
254
+
255
+ for r in range(3):
256
+ for c in range(5):
257
+ ax = fig.add_subplot(gs[r, c])
258
+ ax.set_facecolor('black')
259
+ ax.set_xticks([])
260
+ ax.set_yticks([])
261
+ for spine in ax.spines.values():
262
+ spine.set_visible(False)
263
+ ```
264
+
265
+ Rules:
266
+
267
+ - Use black only within the image plate cells.
268
+ - Put channel labels, scale bars and small crop guides directly on the plate.
269
+ - Keep crop geometry and scale-bar placement consistent across the grid.
270
+
271
+ ---
272
+
273
+ ## Pattern 14: Clinical triptych
274
+
275
+ Use for outcome-over-time figures that combine trajectories, effect sizes, and summary proportions.
276
+
277
+ ```python
278
+ fig = plt.figure(figsize=(7.2, 6.8))
279
+ gs = fig.add_gridspec(
280
+ 3, 3,
281
+ height_ratios=[1.0, 1.35, 0.8],
282
+ hspace=0.28, wspace=0.32,
283
+ )
284
+
285
+ axes_top = [fig.add_subplot(gs[0, i]) for i in range(3)]
286
+ axes_mid = [fig.add_subplot(gs[1, i]) for i in range(3)]
287
+ axes_bot = [fig.add_subplot(gs[2, i]) for i in range(3)]
288
+
289
+ # Put one shared legend strip above axes_top rather than repeating legends.
290
+ ```
291
+
292
+ Rules:
293
+
294
+ - Keep the three columns semantically parallel.
295
+ - Use a dashed vertical reference line in the forest-plot row.
296
+ - Group shading in the forest-plot row should be pale and subordinate.
297
+
298
+ ---
299
+
300
+ ## Pattern 15: Asymmetric hero panel
301
+
302
+ Use when one panel is conceptually central and should dominate.
303
+
304
+ ```python
305
+ fig = plt.figure(figsize=(7.2, 5.8))
306
+ gs = fig.add_gridspec(3, 4, hspace=0.25, wspace=0.28)
307
+
308
+ ax_a = fig.add_subplot(gs[0, :2])
309
+ ax_b = fig.add_subplot(gs[0, 2])
310
+ ax_c = fig.add_subplot(gs[1, :2])
311
+ ax_d = fig.add_subplot(gs[1, 2])
312
+ ax_e = fig.add_subplot(gs[:, 3]) # hero panel spans all rows
313
+ ax_f = fig.add_subplot(gs[2, :2])
314
+ ```
315
+
316
+ Rule: do not normalize every subplot to the same size if the science does not have equal importance.
317
+
318
+ ---
319
+
320
+ ## Pattern 16: Direct labels inside filled regions
321
+
322
+ Use when the same categorical structure repeats and a legend would become too large.
323
+
324
+ ```python
325
+ for x_text, y_text, text, color in label_specs:
326
+ ax.text(
327
+ x_text, y_text, text,
328
+ color=color,
329
+ ha='center', va='center',
330
+ fontsize=9, fontweight='bold',
331
+ )
332
+ ```
333
+
334
+ Rules:
335
+
336
+ - Keep labels inside stable, visually large regions.
337
+ - Use a small white or black stroke if the fill varies strongly underneath.
338
+ - Prefer direct labels over a mega-legend for repeated stacked-area or phase diagrams.
339
+
340
+ ---
341
+
342
+ ## Related files
343
+
344
+ - [SKILL.md](../SKILL.md) — When to use this skill
345
+ - [api.md](api.md) — Helper function signatures and PALETTE
346
+ - [design-theory.md](design-theory.md) — Rationale behind every pattern above
347
+ - [nature-2026-observations.md](nature-2026-observations.md) — Real Nature page archetypes behind these patterns
348
+ - [tutorials.md](tutorials.md) — End-to-end walkthroughs
349
+ - [chart-types.md](chart-types.md) — Radar, 3D, scatter patterns
350
+ - [demos.md](demos.md) — Bundled figures4papers scripts and previews
@@ -0,0 +1,65 @@
1
+ # figures4papers Demo Index
2
+
3
+ Use this file when a user asks for a `figures4papers` look, cites the older
4
+ `scientific-figure-making` skill, or needs a concrete Python/matplotlib example
5
+ instead of only abstract style rules.
6
+
7
+ The bundled examples live under `../assets/figures4papers/`. They are reference
8
+ materials for the Python track only. Keep the normal `nature-figure` contract first:
9
+ define the scientific claim, pick Python or R, and only then adapt a demo pattern.
10
+
11
+ ## How to use the demos
12
+
13
+ 1. Select the closest chart family from the table below.
14
+ 2. Read the listed `plot_*.py` files for layout, palette, axis, legend, and export
15
+ patterns.
16
+ 3. Reuse the pattern, not the demo data or manuscript-specific labels.
17
+ 4. Preserve editable SVG/PDF/TIFF export rules from `api.md`.
18
+ 5. Do not reveal local repository paths or internal asset filenames in user-facing
19
+ prose unless the user asks for an audit trail.
20
+
21
+ ## Bundled project map
22
+
23
+ | Project | Open when | Local examples |
24
+ |---------|-----------|----------------|
25
+ | `figure_ImmunoStruct` | Method comparison bars, ablation bars, large readable annotations | `../assets/figures4papers/figure_ImmunoStruct/plot_bars.py`, `raw_data.py`, `figures/*.png` |
26
+ | `figure_CellSpliceNet` | Compact comparison and ablation bars | `../assets/figures4papers/figure_CellSpliceNet/plot_comparison.py`, `plot_ablation.py` |
27
+ | `figure_brainteaser` | Composition breakdown bars, category/subcategory comparisons, rewriting/self-correction panels | `../assets/figures4papers/figure_brainteaser/plot_*.py` |
28
+ | `figure_VIGIL` | Radar/polar comparison and post-training trend lines | `../assets/figures4papers/figure_VIGIL/plot_comparison_radar.py`, `plot_posttraining.py` |
29
+ | `figure_ophthal_review` | Time trends and composition heatmaps for review/survey style figures | `../assets/figures4papers/figure_ophthal_review/plot_trend.py`, `plot_composition.py` |
30
+ | `figure_RNAGenScape` | Heatmaps, optimization/speed comparisons, manifold illustrations, sweep plots | `../assets/figures4papers/figure_RNAGenScape/plot_*.py` |
31
+ | `figure_Dispersion` | Conceptual 3D-style sphere diagrams and observation/idea panels | `../assets/figures4papers/figure_Dispersion/plot_illustration.py`, `plot_idea.py` |
32
+ | `figure_Cflows` | Diffusion/trajectory illustrations, gene-regulatory comparisons, ablation comparisons | `../assets/figures4papers/figure_Cflows/*.py` |
33
+ | `figure_FPGM` | Frequency-prior or distribution-style method motivation figure | `../assets/figures4papers/figure_FPGM/plot_freq_prior.py` |
34
+ | `assets` | Partially manual schematic/result panels for visual inspiration only | `../assets/figures4papers/assets/*.png` |
35
+
36
+ ## Pattern routing
37
+
38
+ - Grouped bars: start with `figure_ImmunoStruct`, `figure_CellSpliceNet`, or
39
+ `figure_brainteaser`; then apply the tighter Nature export and font rules in
40
+ `api.md`.
41
+ - Radar/polar: start with `figure_VIGIL`; cross-check `chart-types.md` before
42
+ implementing normalization, radial labels, and legend placement.
43
+ - Trend/line: start with `figure_VIGIL` or `figure_ophthal_review`; use shared
44
+ legends and direct event labels where they reduce eye travel.
45
+ - Heatmap/matrix: start with `figure_RNAGenScape` or `figure_ophthal_review`; keep
46
+ colorbars and labels readable at final journal dimensions.
47
+ - Conceptual 3D/spheres: start with `figure_Dispersion` or `figure_Cflows`; use this
48
+ only when it supports the manuscript claim, not as decorative filler.
49
+
50
+ ## Relationship to the older skill
51
+
52
+ The original `scientific-figure-making` skill focused on publication-ready
53
+ matplotlib figures and the figures4papers house style. In this repository, that
54
+ guidance is folded into `nature-figure`:
55
+
56
+ - `api.md` contains the palette, helper signatures, and export conventions.
57
+ - `common-patterns.md` expands the reusable layout patterns.
58
+ - `design-theory.md` captures the typography, color, and composition rationale.
59
+ - `tutorials.md` gives end-to-end scaffold examples.
60
+ - This file preserves the real demo script map and bundled example assets.
61
+
62
+ ## External source
63
+
64
+ Original upstream repository:
65
+ <https://github.com/ChenLiu-1996/figures4papers>