@brainpilot/skills 0.0.6 → 0.0.8

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 (285) hide show
  1. package/package.json +2 -2
  2. package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
  3. package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
  4. package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
  5. package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
  6. package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
  7. package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
  8. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
  9. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
  10. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
  11. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
  12. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
  13. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
  14. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
  15. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
  16. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
  17. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
  18. package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
  19. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
  20. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
  21. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
  22. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
  23. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
  24. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
  25. package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
  26. package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
  27. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
  28. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
  29. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
  30. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
  31. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
  32. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
  33. package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
  34. package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
  35. package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
  36. package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
  37. package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
  38. package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
  39. package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
  40. package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
  41. package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
  42. package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
  43. package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
  44. package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
  45. package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
  46. package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
  47. package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
  48. package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
  49. package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
  50. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
  51. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
  52. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
  53. package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
  54. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
  55. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
  56. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
  57. package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
  58. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
  59. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
  60. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
  61. package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
  62. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
  63. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
  64. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
  65. package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
  66. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
  67. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
  68. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
  69. package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
  70. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
  71. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
  72. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
  73. package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
  74. package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
  75. package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
  76. package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
  77. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
  78. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
  79. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
  80. package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
  81. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
  82. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
  83. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
  84. package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
  85. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
  86. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
  87. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
  88. package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
  89. package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
  90. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
  91. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
  92. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
  93. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
  94. package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
  95. package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
  96. package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
  97. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
  98. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
  99. package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
  100. package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
  101. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
  102. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
  103. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
  104. package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
  105. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
  106. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
  107. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
  108. package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
  109. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
  110. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
  111. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
  112. package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
  113. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
  114. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
  115. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
  116. package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
  117. package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
  118. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
  119. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
  120. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
  121. package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
  122. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
  123. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
  124. package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
  125. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
  126. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
  127. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
  128. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
  129. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
  130. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
  131. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
  132. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
  133. package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
  134. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
  135. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
  136. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
  137. package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
  138. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
  139. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
  140. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
  141. package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
  142. package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
  143. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
  144. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
  145. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
  146. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
  147. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
  148. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
  149. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
  150. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
  151. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
  152. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
  153. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
  154. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
  155. package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
  156. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
  157. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
  158. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
  159. package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
  160. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
  161. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
  162. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
  163. package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
  164. package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
  165. package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
  166. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
  167. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
  168. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
  169. package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
  170. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
  171. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
  172. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
  173. package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
  174. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
  175. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
  176. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
  177. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
  178. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
  179. package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
  180. package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
  181. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
  182. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
  183. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
  184. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
  185. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
  186. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
  187. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
  188. package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
  189. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
  190. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
  191. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
  192. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
  193. package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
  194. package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
  195. package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
  196. package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
  197. package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
  198. package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
  199. package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
  200. package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
  201. package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
  202. package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
  203. package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
  204. package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
  205. package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
  206. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
  207. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
  208. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
  209. package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
  210. package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
  211. package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
  212. package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
  213. package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
  214. package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
  215. package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
  216. package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
  217. package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
  218. package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
  219. package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
  220. package/skills/14_Writing/paper-writing/SKILL.md +146 -0
  221. package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
  222. package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
  223. package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
  224. package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
  225. package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
  226. package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
  227. package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
  228. package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
  229. package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
  230. package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
  231. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
  232. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
  233. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
  234. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
  235. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
  236. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
  237. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
  238. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
  239. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
  240. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
  241. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
  242. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
  243. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
  244. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
  245. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
  246. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
  247. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
  248. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
  249. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
  250. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
  251. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
  252. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
  253. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
  254. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
  255. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
  256. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
  257. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
  258. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
  259. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
  260. package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
  261. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
  262. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
  263. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
  264. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
  265. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
  266. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
  267. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
  268. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
  269. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
  270. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
  271. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
  272. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
  273. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
  274. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
  275. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
  276. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
  277. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
  278. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
  279. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
  280. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
  281. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
  282. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
  283. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
  284. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
  285. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_data_readme.md +126 -0
@@ -0,0 +1,513 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """H5 radar plotting utilities (all-samples overlay OR group-mean comparison).
4
+
5
+ Reads kinematic parameter HDF5 files with (preferred) layout:
6
+ /KinematicParameter/ParameterName (params,)
7
+ /KinematicParameter/ParameterData (frames, params)
8
+
9
+ Modes:
10
+ - mode=per_sample: generate one radar per sample (single-sample, all parameters)
11
+ - mode=group_means: infer group from filename token and plot one polygon per group (group mean)
12
+ - mode=both: generate per_sample + group_means outputs
13
+ - mode=all_samples: (legacy) overlay all samples in one radar + per-sample radars
14
+
15
+ Outputs (default):
16
+ results/h5_radar/<mode>/
17
+
18
+ Run example:
19
+ python plot_h5_radar.py --project_dir "C:\\path\\to\\folder" --mode group_means
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import re
26
+ from pathlib import Path
27
+ from typing import Dict, List, Optional, Tuple
28
+
29
+ import numpy as np
30
+ import pandas as pd
31
+
32
+ import matplotlib
33
+ matplotlib.use("Agg")
34
+ import matplotlib.pyplot as plt
35
+
36
+ try:
37
+ import h5py
38
+ except Exception as e:
39
+ raise SystemExit(
40
+ "Missing dependency: h5py. In your conda env, run e.g.\n"
41
+ " conda install -c conda-forge h5py numpy pandas matplotlib\n"
42
+ f"Original import error: {e}"
43
+ )
44
+
45
+
46
+ def apply_publication_style():
47
+ """A clean, journal-like style (Cell/Nature-ish)."""
48
+ matplotlib.rcParams.update(
49
+ {
50
+ "figure.facecolor": "white",
51
+ "axes.facecolor": "white",
52
+ "savefig.facecolor": "white",
53
+ "font.size": 10,
54
+ "font.family": "sans-serif",
55
+ "font.sans-serif": ["Arial", "Helvetica", "DejaVu Sans"],
56
+ "pdf.fonttype": 42, # editable text
57
+ "ps.fonttype": 42,
58
+ "axes.linewidth": 1.0,
59
+ "grid.color": "#D0D0D0",
60
+ "grid.linestyle": "-",
61
+ "grid.linewidth": 0.8,
62
+ }
63
+ )
64
+
65
+
66
+ def nature_like_palette() -> List[str]:
67
+ return [
68
+ "#3C5488", # blue
69
+ "#E64B35", # red/orange
70
+ "#00A087", # green
71
+ "#4DBBD5", # cyan
72
+ "#F39B7F", # salmon
73
+ "#8491B4", # lavender
74
+ "#91D1C2", # mint
75
+ "#DC0000", # red
76
+ "#7E6148", # brown
77
+ "#B09C85", # tan
78
+ ]
79
+
80
+
81
+ def _decode_if_bytes(x):
82
+ if isinstance(x, (bytes, np.bytes_)):
83
+ return x.decode("utf-8", errors="ignore")
84
+ return str(x)
85
+
86
+
87
+ def guess_group_from_filename(name: str, regex: str = r"rec-\d+-([^-_]+)[-_]") -> str:
88
+ m = re.search(regex, name)
89
+ return m.group(1) if m else "unknown"
90
+
91
+
92
+ def find_dataset_by_candidates(h5: h5py.File, candidates: List[str]) -> Optional[h5py.Dataset]:
93
+ for p in candidates:
94
+ if p in h5:
95
+ obj = h5[p]
96
+ if isinstance(obj, h5py.Dataset):
97
+ return obj
98
+
99
+ found = []
100
+
101
+ def visitor(name, obj):
102
+ if isinstance(obj, h5py.Dataset):
103
+ base = name.split("/")[-1]
104
+ if base in {c.split("/")[-1] for c in candidates}:
105
+ found.append(obj)
106
+
107
+ h5.visititems(visitor)
108
+ return found[0] if found else None
109
+
110
+
111
+ def read_kinematic_features(h5_path: Path, stat: str = "mean") -> pd.Series:
112
+ with h5py.File(h5_path, "r") as h5:
113
+ ds_names = find_dataset_by_candidates(
114
+ h5,
115
+ [
116
+ "/KinematicParameter/ParameterName",
117
+ "KinematicParameter/ParameterName",
118
+ "/ParameterName",
119
+ ],
120
+ )
121
+ ds_data = find_dataset_by_candidates(
122
+ h5,
123
+ [
124
+ "/KinematicParameter/ParameterData",
125
+ "KinematicParameter/ParameterData",
126
+ "/ParameterData",
127
+ ],
128
+ )
129
+
130
+ if ds_names is None or ds_data is None:
131
+ keys = list(h5.keys())
132
+ raise KeyError(
133
+ f"Cannot find ParameterName/ParameterData in {h5_path.name}. "
134
+ f"Top-level keys: {keys}. Expected /KinematicParameter/..."
135
+ )
136
+
137
+ param_names = [_decode_if_bytes(x) for x in np.array(ds_names)]
138
+ data = np.array(ds_data)
139
+
140
+ if data.ndim != 2:
141
+ raise ValueError(
142
+ f"ParameterData must be 2D (frames x params). Got shape {data.shape} in {h5_path.name}."
143
+ )
144
+ if data.shape[1] != len(param_names):
145
+ if data.shape[0] == len(param_names):
146
+ data = data.T
147
+ else:
148
+ raise ValueError(
149
+ f"Mismatch: ParameterName len={len(param_names)} but ParameterData shape={data.shape} in {h5_path.name}."
150
+ )
151
+
152
+ if stat == "mean":
153
+ vec = np.nanmean(data, axis=0)
154
+ elif stat == "median":
155
+ vec = np.nanmedian(data, axis=0)
156
+ elif stat == "max":
157
+ vec = np.nanmax(data, axis=0)
158
+ else:
159
+ raise ValueError(f"Unknown stat: {stat}")
160
+
161
+ return pd.Series(vec, index=param_names, name=h5_path.stem)
162
+
163
+
164
+ def normalize_df(df: pd.DataFrame, method: str) -> pd.DataFrame:
165
+ if method == "none":
166
+ return df.copy()
167
+
168
+ out = df.astype(float).copy()
169
+
170
+ if method == "minmax":
171
+ mins = out.min(axis=0, skipna=True)
172
+ maxs = out.max(axis=0, skipna=True)
173
+ denom = (maxs - mins).replace(0, np.nan)
174
+ out = (out - mins) / denom
175
+ out = out.fillna(0.5)
176
+ return out
177
+
178
+ if method == "zscore":
179
+ mu = out.mean(axis=0, skipna=True)
180
+ sd = out.std(axis=0, skipna=True).replace(0, np.nan)
181
+ out = (out - mu) / sd
182
+ out = out.fillna(0.0)
183
+ return out
184
+
185
+ raise ValueError(f"Unknown normalize method: {method}")
186
+
187
+
188
+ def _set_ylim_if_unit(ax, arr: np.ndarray):
189
+ try:
190
+ vmin = float(np.nanmin(arr))
191
+ vmax = float(np.nanmax(arr))
192
+ if vmin >= -1e-9 and vmax <= 1 + 1e-9:
193
+ ax.set_ylim(0, 1)
194
+ except Exception:
195
+ pass
196
+
197
+
198
+ def radar_plot_all_samples(
199
+ df: pd.DataFrame,
200
+ out_png: Path,
201
+ out_pdf: Path,
202
+ title: str,
203
+ groups: Optional[Dict[str, str]] = None,
204
+ max_samples: int = 30,
205
+ palette: Optional[List[str]] = None,
206
+ ):
207
+ if df.empty:
208
+ return
209
+
210
+ params = list(df.columns)
211
+ n = len(params)
212
+ angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist() + [0.0]
213
+
214
+ fig = plt.figure(figsize=(max(8, n * 0.22), max(8, n * 0.22)))
215
+ ax = plt.subplot(111, polar=True)
216
+ ax.set_theta_offset(np.pi / 2)
217
+ ax.set_theta_direction(-1)
218
+ ax.set_xticks(angles[:-1])
219
+ ax.set_xticklabels(params, fontsize=8)
220
+ ax.tick_params(axis="y", labelsize=8)
221
+ _set_ylim_if_unit(ax, df.to_numpy(dtype=float))
222
+
223
+ plot_df = df.copy()
224
+ if len(plot_df) > max_samples:
225
+ keep = plot_df.var(axis=1).sort_values(ascending=False).head(max_samples).index
226
+ plot_df = plot_df.loc[keep]
227
+
228
+ if palette is None:
229
+ palette = nature_like_palette()
230
+
231
+ group_list = sorted({groups.get(s, "unknown") for s in plot_df.index}) if groups else ["all"]
232
+ group_color = {g: palette[i % len(palette)] for i, g in enumerate(group_list)}
233
+
234
+ for sample in plot_df.index:
235
+ values = plot_df.loc[sample].to_numpy(dtype=float).tolist()
236
+ values += values[:1]
237
+ g = groups.get(sample, "unknown") if groups else "all"
238
+ ax.plot(angles, values, linewidth=1.4, alpha=0.85, color=group_color[g])
239
+
240
+ if groups:
241
+ handles = [plt.Line2D([0], [0], color=group_color[g], lw=2) for g in group_list]
242
+ ax.legend(handles, group_list, loc="upper right", bbox_to_anchor=(1.18, 1.18), fontsize=9)
243
+
244
+ ax.set_title(title, y=1.08)
245
+ fig.tight_layout()
246
+
247
+ out_png.parent.mkdir(parents=True, exist_ok=True)
248
+ fig.savefig(out_png, dpi=200)
249
+ fig.savefig(out_pdf)
250
+ plt.close(fig)
251
+
252
+
253
+ def radar_plot_single(sample: str, row: pd.Series, out_png: Path, out_pdf: Path, title: str, color: str):
254
+ params = list(row.index)
255
+ n = len(params)
256
+ angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist() + [0.0]
257
+
258
+ values = row.to_numpy(dtype=float).tolist()
259
+ values += values[:1]
260
+
261
+ fig = plt.figure(figsize=(max(7, n * 0.18), max(7, n * 0.18)))
262
+ ax = plt.subplot(111, polar=True)
263
+ ax.set_theta_offset(np.pi / 2)
264
+ ax.set_theta_direction(-1)
265
+
266
+ ax.set_xticks(angles[:-1])
267
+ ax.set_xticklabels(params, fontsize=8)
268
+ ax.plot(angles, values, linewidth=2.0, color=color)
269
+ ax.fill(angles, values, alpha=0.12, color=color)
270
+
271
+ ax.set_title(title, y=1.08)
272
+ fig.tight_layout()
273
+
274
+ out_png.parent.mkdir(parents=True, exist_ok=True)
275
+ fig.savefig(out_png, dpi=200)
276
+ fig.savefig(out_pdf)
277
+ plt.close(fig)
278
+
279
+
280
+ def radar_plot_group_means(group_means: pd.DataFrame, out_png: Path, out_pdf: Path, title: str, palette=None):
281
+ if group_means.empty:
282
+ return
283
+
284
+ params = list(group_means.columns)
285
+ n = len(params)
286
+ angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist() + [0.0]
287
+
288
+ fig = plt.figure(figsize=(max(8, n * 0.22), max(8, n * 0.22)))
289
+ ax = plt.subplot(111, polar=True)
290
+ ax.set_theta_offset(np.pi / 2)
291
+ ax.set_theta_direction(-1)
292
+
293
+ ax.set_xticks(angles[:-1])
294
+ ax.set_xticklabels(params, fontsize=8)
295
+ ax.tick_params(axis="y", labelsize=8)
296
+ _set_ylim_if_unit(ax, group_means.to_numpy(dtype=float))
297
+
298
+ if palette is None:
299
+ palette = nature_like_palette()
300
+
301
+ for i, g in enumerate(group_means.index):
302
+ color = palette[i % len(palette)]
303
+ vals = group_means.loc[g].to_numpy(dtype=float).tolist()
304
+ vals += vals[:1]
305
+ ax.plot(angles, vals, linewidth=2.2, color=color, label=str(g))
306
+ ax.fill(angles, vals, alpha=0.10, color=color)
307
+
308
+ ax.legend(loc="upper right", bbox_to_anchor=(1.20, 1.18), fontsize=10)
309
+ ax.set_title(title, y=1.08)
310
+ fig.tight_layout()
311
+
312
+ out_png.parent.mkdir(parents=True, exist_ok=True)
313
+ fig.savefig(out_png, dpi=240)
314
+ fig.savefig(out_pdf)
315
+ plt.close(fig)
316
+
317
+
318
+ def main():
319
+ ap = argparse.ArgumentParser()
320
+ ap.add_argument("--project_dir", type=str, required=True)
321
+ ap.add_argument("--pattern", type=str, default="*.h5")
322
+ ap.add_argument(
323
+ "--mode",
324
+ type=str,
325
+ default="both",
326
+ choices=["per_sample", "group_means", "both", "all_samples"],
327
+ help="per_sample: one radar per sample; group_means: one radar per group mean; both: run both; all_samples: legacy combined overlay",
328
+ )
329
+ ap.add_argument("--out_dir", type=str, default="results/h5_radar")
330
+ ap.add_argument("--stat", type=str, default="mean", choices=["mean", "median", "max"])
331
+ ap.add_argument("--normalize", type=str, default="minmax", choices=["none", "minmax", "zscore"])
332
+ ap.add_argument("--max_samples_combined", type=int, default=30)
333
+ ap.add_argument("--n_params", type=int, default=0)
334
+ ap.add_argument("--param_select", type=str, default="variance", choices=["variance", "first"])
335
+ ap.add_argument("--style", type=str, default="nature", choices=["nature", "default"])
336
+ ap.add_argument("--group_regex", type=str, default=r"rec-\d+-([^-_]+)[-_]",
337
+ help="Regex with 1 capture group for group name")
338
+ args = ap.parse_args()
339
+
340
+ if args.style == "nature":
341
+ apply_publication_style()
342
+
343
+ project_dir = Path(args.project_dir)
344
+ if not project_dir.exists():
345
+ raise SystemExit(f"project_dir not found: {project_dir}")
346
+
347
+ h5_files = sorted(project_dir.glob(args.pattern))
348
+ if not h5_files:
349
+ raise SystemExit(f"No files matched: {project_dir / args.pattern}")
350
+
351
+ out_dir = Path(args.out_dir)
352
+ if not out_dir.is_absolute():
353
+ out_dir = project_dir / out_dir
354
+
355
+ # Decide output directory/ies
356
+ if args.mode == "both":
357
+ mode_dirs = {
358
+ "per_sample": out_dir / "per_sample",
359
+ "group_means": out_dir / "group_means",
360
+ }
361
+ for d in mode_dirs.values():
362
+ d.mkdir(parents=True, exist_ok=True)
363
+ else:
364
+ mode_dir = out_dir / args.mode
365
+ mode_dir.mkdir(parents=True, exist_ok=True)
366
+ mode_dirs = {args.mode: mode_dir}
367
+
368
+ series_list: List[pd.Series] = []
369
+ groups: Dict[str, str] = {}
370
+ skipped: List[Tuple[str, str]] = []
371
+
372
+ for p in h5_files:
373
+ try:
374
+ s = read_kinematic_features(p, stat=args.stat)
375
+ except Exception as e:
376
+ skipped.append((p.name, str(e)))
377
+ continue
378
+ series_list.append(s)
379
+ groups[s.name] = guess_group_from_filename(p.name, regex=args.group_regex)
380
+
381
+ if not series_list:
382
+ raise SystemExit("No valid .h5 files contained KinematicParameter/ParameterName + ParameterData.")
383
+
384
+ df = pd.DataFrame(series_list)
385
+ df.index.name = "sample"
386
+
387
+ # Save matrices into each active mode folder (so artifacts are self-contained)
388
+ df_norm = normalize_df(df, method=args.normalize)
389
+
390
+ for md in mode_dirs.values():
391
+ raw_csv = md / f"feature_matrix_{args.stat}.csv"
392
+ df.to_csv(raw_csv, encoding="utf-8-sig")
393
+
394
+ norm_csv = md / f"feature_matrix_{args.stat}__normalized_{args.normalize}.csv"
395
+ df_norm.to_csv(norm_csv, encoding="utf-8-sig")
396
+
397
+ df_plot = df_norm
398
+ if args.n_params and 0 < args.n_params < df_norm.shape[1]:
399
+ if args.param_select == "first":
400
+ cols = list(df_norm.columns[: args.n_params])
401
+ else:
402
+ cols = df_norm.var(axis=0).sort_values(ascending=False).head(args.n_params).index.tolist()
403
+ df_plot = df_norm.loc[:, cols]
404
+
405
+ palette = nature_like_palette() if args.style == "nature" else None
406
+
407
+ # Decide which sub-modes to run
408
+ if args.mode == "both":
409
+ run_modes = ["per_sample", "group_means"]
410
+ else:
411
+ run_modes = [args.mode]
412
+
413
+ outputs: List[str] = []
414
+
415
+ # --- per-sample radars (one radar per sample; all params) ---
416
+ if "per_sample" in run_modes:
417
+ md = mode_dirs["per_sample"]
418
+ by_sample_dir = md / "radar_by_sample"
419
+ by_sample_dir.mkdir(parents=True, exist_ok=True)
420
+
421
+ color0 = (palette[0] if palette else "#3C5488")
422
+ for sample in df_plot.index:
423
+ row = df_plot.loc[sample]
424
+ png = by_sample_dir / f"{sample}__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.png"
425
+ pdf = by_sample_dir / f"{sample}__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.pdf"
426
+ radar_plot_single(
427
+ sample,
428
+ row,
429
+ png,
430
+ pdf,
431
+ title=f"{sample} (group={groups.get(sample, 'unknown')})",
432
+ color=color0,
433
+ )
434
+ outputs.append(f"per_sample: {by_sample_dir}")
435
+
436
+ # --- group means radar (one polygon per group mean) ---
437
+ if "group_means" in run_modes:
438
+ md = mode_dirs["group_means"]
439
+ gser = pd.Series({s: groups.get(s, "unknown") for s in df_plot.index}, name="group")
440
+ tmp = df_plot.copy()
441
+ tmp.insert(0, "__group__", gser)
442
+ group_means = tmp.groupby("__group__").mean(numeric_only=True)
443
+ group_means.index.name = "group"
444
+
445
+ gm_csv = md / f"group_means__{args.stat}__{args.normalize}__p{group_means.shape[1]}.csv"
446
+ group_means.to_csv(gm_csv, encoding="utf-8-sig")
447
+
448
+ out_png = md / f"radar_group_means__{args.stat}__{args.normalize}__p{group_means.shape[1]}.png"
449
+ out_pdf = md / f"radar_group_means__{args.stat}__{args.normalize}__p{group_means.shape[1]}.pdf"
450
+ title = (
451
+ f"Radar (group means) | stat={args.stat} | norm={args.normalize} | "
452
+ f"groups={len(group_means)} | p={group_means.shape[1]}"
453
+ )
454
+ radar_plot_group_means(group_means, out_png, out_pdf, title=title, palette=palette)
455
+ outputs.append(f"group_means: {out_png}")
456
+
457
+ # --- legacy all-samples overlay ---
458
+ if "all_samples" in run_modes:
459
+ md = mode_dirs["all_samples"]
460
+ combined_png = md / f"radar_combined__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.png"
461
+ combined_pdf = md / f"radar_combined__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.pdf"
462
+ title = (
463
+ f"Radar (all samples overlay) | stat={args.stat} | norm={args.normalize} | "
464
+ f"n={len(df_plot)} | p={df_plot.shape[1]}"
465
+ )
466
+ radar_plot_all_samples(
467
+ df_plot,
468
+ combined_png,
469
+ combined_pdf,
470
+ title=title,
471
+ groups=groups,
472
+ max_samples=args.max_samples_combined,
473
+ palette=palette,
474
+ )
475
+
476
+ by_sample_dir = md / "radar_by_sample"
477
+ by_sample_dir.mkdir(parents=True, exist_ok=True)
478
+ color0 = (palette[0] if palette else "#3C5488")
479
+ for sample in df_plot.index:
480
+ row = df_plot.loc[sample]
481
+ png = by_sample_dir / f"{sample}__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.png"
482
+ pdf = by_sample_dir / f"{sample}__{args.stat}__{args.normalize}__p{df_plot.shape[1]}.pdf"
483
+ radar_plot_single(
484
+ sample,
485
+ row,
486
+ png,
487
+ pdf,
488
+ title=f"{sample} (group={groups.get(sample, 'unknown')})",
489
+ color=color0,
490
+ )
491
+ outputs.append(f"all_samples: {combined_png}")
492
+
493
+ # Save parameter order + skipped report into each produced folder
494
+ for m in set(run_modes):
495
+ md = mode_dirs[m]
496
+ (md / "parameter_order.txt").write_text("\n".join(df.columns), encoding="utf-8")
497
+ (md / f"parameter_order__p{df_plot.shape[1]}.txt").write_text(
498
+ "\n".join(df_plot.columns), encoding="utf-8"
499
+ )
500
+ if skipped:
501
+ rep = md / "skipped_files.txt"
502
+ rep.write_text("\n".join([f"{name}\t{err}" for name, err in skipped]), encoding="utf-8")
503
+
504
+ print("Done.")
505
+ print(f"Mode: {args.mode}")
506
+ for line in outputs:
507
+ print(line)
508
+ if skipped:
509
+ print(f"Skipped files: {len(skipped)} (see skipped_files.txt under each output folder)")
510
+
511
+
512
+ if __name__ == "__main__":
513
+ main()
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: ethoclaw-multiparameter-violin-stats-generate
3
+ description: "Read HDF5 (.h5/.hdf5) data, compare groups with appropriate statistical tests (2 groups: t-test/Mann–Whitney; 3+ groups: ANOVA/Kruskal–Wallis + post-hoc pairwise), and generate violin plots + summary table/JSON. Use when the user asks for multi-parameter violin plot generation/group difference testing/batch parameter statistical plotting."
4
+ ---
5
+
6
+ # H5 Multi-parameter Violin + Stats
7
+
8
+ Generate violin plots and run group-difference tests directly from `.h5/.hdf5` files.
9
+
10
+ ## Workflow
11
+
12
+ ### 1) Inspect the H5 structure (find dataset paths)
13
+ If you don’t know the internal paths, run:
14
+
15
+ ```bash
16
+ python scripts/h5_inspect.py your_data.h5
17
+ ```
18
+
19
+ Identify:
20
+ - a **numeric** 1D dataset path for values, e.g. `/metrics/score`
21
+ - a **label** 1D dataset path for group labels, e.g. `/meta/group`
22
+
23
+ ### 2) Run stats + generate violin plot
24
+
25
+ ```bash
26
+ python scripts/h5_violin_stats.py \
27
+ --h5 your_data.h5 \
28
+ --dataset /metrics/score \
29
+ --group /meta/group \
30
+ --method auto \
31
+ --config skills/ethoclaw-multiparameter-violin-stats-generate/config.toml \
32
+ --out outputs/violin.png \
33
+ --out-json outputs/result.json
34
+ ```
35
+
36
+ - `--method auto`: follows `config.toml` defaults
37
+ - 2 groups → `stats.default_2_groups`
38
+ - 3+ groups → `stats.default_3plus_groups`
39
+ - Choose nonparametric methods explicitly when needed:
40
+ - 2 groups: `--method mannwhitney`
41
+ - >=3 groups: `--method kruskal`
42
+
43
+ ### 3) Interpreting results
44
+ - For **2 groups**: the “overall” test is the direct group comparison.
45
+ - For **>=3 groups**: script runs overall ANOVA/Kruskal first; if `p <= alpha` (default 0.05), it runs **pairwise** comparisons and reports Holm-adjusted p-values (`p_holm`).
46
+
47
+ Stat rules reference: `references/stats-rule.md`.
48
+
49
+ ## Notes / Assumptions
50
+ - Current scripts assume `values` is a **1D numeric array** and `group` is a **1D label array** of the same length.
51
+ - If your H5 stores multiple metrics or nested structures, extend the loader in `scripts/h5_violin_stats.py::_read_h5_1d`.
52
+ - If dependencies are missing, install Python `pip` + packages (system-dependent). In WSL/Ubuntu, you typically need `python3-venv` and `python3-pip`.
@@ -0,0 +1,81 @@
1
+ # h5-multiparameter-violin-stats default configuration
2
+ # Edit this file to change default plotting style / statistics behavior.
3
+
4
+ [stats]
5
+ # Default tests used when CLI sets --method auto
6
+ # - For 2 groups: "ttest" or "mannwhitney"
7
+ # - For 3+ groups: "anova" or "kruskal"
8
+ default_2_groups = "ttest"
9
+ default_3plus_groups = "kruskal"
10
+
11
+ alpha = 0.05
12
+
13
+ # For 3+ groups, whether to run pairwise tests only when the overall test is significant.
14
+ pairwise_only_if_overall_sig = true
15
+
16
+ # Multiple-comparison correction for pairwise p-values.
17
+ # Supported: "holm" (default), "bonferroni"
18
+ pairwise_correction = "holm"
19
+
20
+ [plot]
21
+ # Seaborn theme
22
+ style = "whitegrid" # e.g. whitegrid, white, ticks
23
+ context = "notebook" # e.g. paper, notebook, talk, poster
24
+
25
+ # Color palette: seaborn palette name (Set2, tab10, etc.)
26
+ palette = "Set2"
27
+
28
+ # Violin appearance
29
+ fig_width = 10
30
+ fig_height = 5
31
+ cut = 0
32
+
33
+ # Raw points overlay
34
+ show_points = true
35
+ point_color = "black"
36
+ point_size = 3
37
+ point_alpha = 0.4
38
+ point_jitter = 0.2
39
+
40
+ # Summary overlay (what you called "box"):
41
+ # - "box" : seaborn inner="box"
42
+ # - "quartile" : seaborn inner="quartile" (median + quartiles)
43
+ # - "mean_sem" : overlay mean ± SEM (custom errorbar)
44
+ # - "median_iqr" : overlay median + IQR (custom errorbar)
45
+ # - "none" : no inner/summary
46
+ summary = "mean_sem"
47
+ summary_color = "black"
48
+ summary_capsize = 4
49
+ summary_linewidth = 1.5
50
+
51
+ # Output
52
+ [dump]
53
+ # Matplotlib savefig dpi
54
+ png_dpi = 200
55
+
56
+ # Also save a PDF copy alongside each PNG.
57
+ save_pdf = true
58
+
59
+ [annotate]
60
+ # Add significance brackets on each violin plot.
61
+ show = true
62
+
63
+ # Prefer adjusted p-values for multi-group pairwise (Holm/Bonferroni) when available.
64
+ use_p_adj = true
65
+
66
+ # Only show significant comparisons by default.
67
+ only_sig = true
68
+
69
+ # Whether to show non-significant (ns) comparisons.
70
+ show_ns = false
71
+
72
+ # Max number of pairwise brackets to draw per plot (avoid clutter).
73
+ max_pairs = 10
74
+
75
+ # Label format: "stars" | "p" | "stars+p"
76
+ label_format = "stars+p"
77
+
78
+ # Visual spacing relative to data range
79
+ step = 0.08
80
+ bracket_height = 0.02
81
+ fontsize = 9
@@ -0,0 +1,18 @@
1
+ # Inter-group Difference Testing Rules (Convention)
2
+
3
+ The statistical test selection for this skill follows these rules:
4
+
5
+ - **Two groups (2 groups)**:
6
+ - Parametric test: **t-test** (default: Welch t-test, more robust when variances are unequal)
7
+ - Non-parametric test: **Mann-Whitney U test**
8
+ - Directly compare differences between two groups
9
+
10
+ - **Three or more groups (>=3 groups)**:
11
+ - Parametric test: **One-way ANOVA**
12
+ - Non-parametric test: **Kruskal-Wallis test**
13
+ - First perform overall test to see if there are differences between groups; if overall is significant (p <= alpha), then perform **pairwise comparisons**
14
+
15
+ - **Pairwise comparisons**:
16
+ - If overall is parametric: default use **Welch t-test** for pairwise
17
+ - If overall is non-parametric: default use **Mann-Whitney U** for pairwise
18
+ - Multiple comparison correction: default **Holm-Bonferroni** (output p_holm)