@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,107 @@
1
+ #!/usr/bin/env python3
2
+ """Validate MND BIDS structure and generate compliance report.
3
+
4
+ Checks directory structure, modality completeness, and participant group labeling.
5
+ """
6
+ import argparse
7
+ import csv
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Dict, List
11
+
12
+ # Expected modalities for MND
13
+ EXPECTED_MODALITIES = {
14
+ "func": ["task-rest_bold", "task-motor_bold"],
15
+ }
16
+
17
+
18
+ def validate_subject(subject_dir: Path) -> Dict[str, any]:
19
+ """Validate a single subject's BIDS structure."""
20
+ report = {
21
+ "subject": subject_dir.name,
22
+ "func_complete": False,
23
+ "rs_fMRI_present": False,
24
+ "task_fMRI_present": False,
25
+ "missing_files": [],
26
+ "warnings": [],
27
+ }
28
+
29
+ # Check func
30
+ func_dir = subject_dir / "func"
31
+ if func_dir.exists():
32
+ rest_bold = list(func_dir.glob("*_task-rest_bold.nii.gz"))
33
+ motor_bold = list(func_dir.glob("*_task-motor_bold.nii.gz"))
34
+
35
+ report["rs_fMRI_present"] = len(rest_bold) > 0
36
+ report["task_fMRI_present"] = len(motor_bold) > 0
37
+ report["func_complete"] = report["rs_fMRI_present"] and report["task_fMRI_present"]
38
+
39
+ if not rest_bold:
40
+ report["missing_files"].append("func/*_task-rest_bold.nii.gz")
41
+ if not motor_bold:
42
+ report["missing_files"].append("func/*_task-motor_bold.nii.gz")
43
+ else:
44
+ report["missing_files"].append("func/")
45
+
46
+ # Check anat (optional for MND)
47
+ anat_dir = subject_dir / "anat"
48
+ if not anat_dir.exists():
49
+ report["warnings"].append("No anat directory (optional for MND)")
50
+
51
+ return report
52
+
53
+
54
+ def main() -> int:
55
+ parser = argparse.ArgumentParser(
56
+ description="Validate MND BIDS structure."
57
+ )
58
+ parser.add_argument("--input", required=True, help="Path to MND BIDS directory")
59
+ parser.add_argument("--output", required=True, help="Output path for validation CSV")
60
+ args = parser.parse_args()
61
+
62
+ input_dir = Path(args.input).resolve()
63
+ if not input_dir.exists():
64
+ print(f"Input directory not found: {input_dir}", file=sys.stderr)
65
+ return 1
66
+
67
+ # Find subjects
68
+ subjects = sorted([d for d in input_dir.glob("sub-*") if d.is_dir()])
69
+ print(f"Found {len(subjects)} subjects in {input_dir}")
70
+
71
+ if not subjects:
72
+ print("[ERROR] No subjects found.", file=sys.stderr)
73
+ return 1
74
+
75
+ # Validate each subject
76
+ results = []
77
+ for sub_dir in subjects:
78
+ report = validate_subject(sub_dir)
79
+ results.append(report)
80
+
81
+ # Write output
82
+ output_path = Path(args.output).resolve()
83
+ output_path.parent.mkdir(parents=True, exist_ok=True)
84
+
85
+ fieldnames = ["subject", "func_complete", "rs_fMRI_present", "task_fMRI_present", "missing_files", "warnings"]
86
+ with open(output_path, "w", newline="", encoding="utf-8") as f:
87
+ writer = csv.DictWriter(f, fieldnames=fieldnames)
88
+ writer.writeheader()
89
+ for r in results:
90
+ r["missing_files"] = "; ".join(r["missing_files"])
91
+ r["warnings"] = "; ".join(r["warnings"])
92
+ writer.writerow(r)
93
+
94
+ # Summary
95
+ complete_subjects = sum(1 for r in results if r["func_complete"])
96
+ print(f"\nValidation Summary:")
97
+ print(f" Total subjects: {len(results)}")
98
+ print(f" Complete (rs-fMRI + task-fMRI): {complete_subjects}")
99
+ print(f" With rs-fMRI: {sum(1 for r in results if r['rs_fMRI_present'])}")
100
+ print(f" With task-fMRI: {sum(1 for r in results if r['task_fMRI_present'])}")
101
+ print(f" Output: {output_path}")
102
+
103
+ return 0
104
+
105
+
106
+ if __name__ == "__main__":
107
+ sys.exit(main())
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: mschallenge-skill
3
+ description: "Use this skill whenever the user wants an end-to-end workflow for the Longitudinal MS Lesion Segmentation Challenge dataset, including data validation, multimodal processing of T1w, T2w, FLAIR, and PD, lesion segmentation, and QC integration. Triggers include: 'MS Lesion Challenge', 'MS Lesion', 'ISBI MS', 'longitudinal MS', 'multiple sclerosis lesion', or any request to run the MS lesion segmentation pipeline."
4
+ license: MIT License (NeuroClaw custom skill - freely modifiable within the project)
5
+ layer: subagent
6
+ skill_type: dataset
7
+ dependencies:
8
+ - smri-skill
9
+ - nibabel-skill
10
+ - claw-shell
11
+ complementary_skills:
12
+ - brain-visualization
13
+ ---
14
+ # MS Challenge Skill (Dataset-Orchestration Layer)
15
+
16
+ ## Overview
17
+
18
+ `mschallenge-skill` is the NeuroClaw orchestration skill for the **Longitudinal MS Lesion Segmentation Challenge** dataset.
19
+
20
+ It strictly follows the NeuroClaw hierarchical design principles:
21
+ - This skill **only describes WHAT needs to be done** and **which tool skill to delegate to**.
22
+ - It contains **no implementation code or concrete commands**.
23
+ - All concrete execution is delegated to existing base/tool skills via `claw-shell`.
24
+ - Companion scripts in `scripts/` provide reference implementations for data validation, lesion analysis, and QC.
25
+
26
+ **Core workflow (never bypassed):**
27
+ 1. Identify input MS Challenge data and target modalities.
28
+ 2. Generate a **numbered execution plan** clearly stating WHAT needs to be done and which tool skill will handle each step.
29
+ 3. Present the full plan, estimated runtime, resource requirements, and risks to the user and wait for explicit confirmation ("YES" / "execute" / "proceed").
30
+ 4. On confirmation, delegate every step to the appropriate skill via `claw-shell`.
31
+ 5. After execution, save all outputs in a clean directory structure (`mschallenge_output/`).
32
+
33
+ **Research use only.**
34
+
35
+ ---
36
+
37
+ ## Quick Reference
38
+
39
+ | Task | What needs to be done | Delegate to | Expected output |
40
+ |---|---|---|---|
41
+ | Data validation | Validate MS Challenge directory structure | `scripts/validate_mschallenge.py` | Validation report |
42
+ | sMRI processing | Brain extraction, tissue segmentation | `smri-skill` | `smri_output/` derivatives |
43
+ | Lesion analysis | Lesion volume, count, location analysis | `scripts/analyze_lesions.py` | Lesion statistics CSV |
44
+ | Longitudinal analysis | Lesion change tracking across timepoints | `scripts/longitudinal_lesion.py` | Longitudinal change report |
45
+ | QC summary | Per-subject quality control | `scripts/mschallenge_qc_summary.py` | QC summary + exclusion list |
46
+
47
+ ---
48
+
49
+ ## Dataset Characteristics
50
+
51
+ - **Origin**: ISBI 2015 Longitudinal MS Lesion Segmentation Challenge
52
+ - **Training**: 5 subjects, each with 2 timepoints (longitudinal)
53
+ - **Testing**: 14 subjects (hidden ground truth), 4-6 timepoints each
54
+ - **Modalities**: T1w, T2w, FLAIR, PD (co-registered)
55
+ - **Ground truth**: Manual lesion segmentation masks (training only)
56
+ - **Resolution**: ~0.5 × 0.5 × 0.5 mm (isotropic)
57
+ - **Preprocessing**: Skull-stripped, co-registered to common space
58
+ - **Reference**: Carass et al. (2017), NeuroImage
59
+
60
+ ---
61
+
62
+ ## Supported Modalities
63
+
64
+ | Modality | Description | Use in MS |
65
+ |---|---|---|
66
+ | T1w | T1-weighted structural | Brain atrophy, gray matter lesions |
67
+ | T2w | T2-weighted | White matter lesion detection |
68
+ | FLAIR | Fluid-Attenuated Inversion Recovery | Periventricular lesion detection |
69
+ | PD | Proton Density | Complementary lesion contrast |
70
+
71
+ ---
72
+
73
+ ## Directory Structure (Native)
74
+
75
+ ```
76
+ training/
77
+ ├── subject01/
78
+ │ ├── time01/
79
+ │ │ ├── subject01_time01_T1.nii.gz
80
+ │ │ ├── subject01_time01_T2.nii.gz
81
+ │ │ ├── subject01_time01_FLAIR.nii.gz
82
+ │ │ ├── subject01_time01_PD.nii.gz
83
+ │ │ └── subject01_time01_lesion.nii.gz (ground truth)
84
+ │ └── time02/
85
+ │ └── ...
86
+ ```
87
+
88
+ ---
89
+
90
+ ## BIDS Preparation
91
+
92
+ ### Script: `scripts/validate_mschallenge.py`
93
+
94
+ Validates MS Challenge directory structure and generates a compliance report.
95
+
96
+ ```bash
97
+ python skills/mschallenge-skill/scripts/validate_mschallenge.py \
98
+ --input /path/to/MSChallenge/training \
99
+ --output /path/to/mschallenge_output/qc/validation.csv
100
+ ```
101
+
102
+ Features:
103
+ - Directory structure validation
104
+ - Modality completeness check (T1w, T2w, FLAIR, PD)
105
+ - Ground truth mask presence verification
106
+ - Longitudinal timepoint consistency
107
+ - Missing data identification
108
+
109
+ ---
110
+
111
+ ## Core Workflow (Never Bypassed)
112
+
113
+ 1. Identify user target: full MS Challenge processing, lesion analysis, or validation only.
114
+ 2. Generate a numbered plan with tools, outputs, runtime, storage, and risks.
115
+ 3. Wait for explicit confirmation (`YES` / `execute` / `proceed`).
116
+ 4. On confirmation, run data validation using `scripts/validate_mschallenge.py`.
117
+ 5. Delegate to `smri-skill` for structural MRI processing.
118
+ 6. If lesion analysis is requested, run `scripts/analyze_lesions.py`.
119
+ 7. If longitudinal analysis is requested, run `scripts/longitudinal_lesion.py`.
120
+ 8. If QC summary is requested, run `scripts/mschallenge_qc_summary.py`.
121
+ 9. Save outputs into `mschallenge_output/`.
122
+
123
+ ---
124
+
125
+ ## Modality Processing Delegation
126
+
127
+ | Modality | Delegated skill | Typical tasks | Main outputs |
128
+ |---|---|---|---|
129
+ | sMRI (T1w/T2w/FLAIR/PD) | `smri-skill` | brain extraction, tissue segmentation | `smri_output/` derivatives |
130
+ | Lesion masks | `nibabel-skill` | lesion volume, count, location | Lesion statistics |
131
+
132
+ ---
133
+
134
+ ## Standard Output Layout
135
+
136
+ ```
137
+ mschallenge_output/
138
+ ├── raw/ # Original MS Challenge files
139
+ ├── validation/ # Validation reports
140
+ ├── smri/ # Structural MRI derivatives
141
+ ├── lesions/ # Lesion analysis results
142
+ │ ├── lesion_stats.csv
143
+ │ └── longitudinal_change.csv
144
+ ├── qc/ # QC summaries and exclusion lists
145
+ └── logs/ # Processing logs
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Benchmark Adapter Guidance
151
+
152
+ For benchmark-style prompts, do not force the full orchestration when the task only asks for local MS Challenge data validation.
153
+
154
+ - If the task starts from MS Challenge data already present on disk and only asks for validation:
155
+ - Skip the download stage
156
+ - Default to the narrow path `local MS Challenge discovery -> validation -> report`
157
+ - In benchmark mode, do not require explicit confirmation before presenting the validation solution.
158
+
159
+ ---
160
+
161
+ ## Safety and Execution Policy
162
+ - No execution before explicit plan confirmation.
163
+ - All execution must be routed via `claw-shell`.
164
+ - Missing dependencies must be resolved by `dependency-planner` before running.
165
+
166
+ ---
167
+
168
+ ## Important Notes and Limitations
169
+ - MS Challenge is a longitudinal dataset; consider timepoint effects in analysis.
170
+ - Ground truth masks are only available for training subjects.
171
+ - All images are preprocessed (skull-stripped, co-registered).
172
+ - Lesion segmentation is the primary task; standard brain morphometry may be affected by lesions.
173
+ - The challenge is designed for benchmarking; results should be compared with published baselines.
174
+ - `mschallenge-skill` is orchestration-only; detailed preprocessing logic remains in modality skills.
175
+
176
+ ---
177
+
178
+ ## When to Call This Skill
179
+ - User asks for end-to-end MS Lesion Challenge workflow.
180
+ - User asks to validate MS Challenge data structure.
181
+ - User asks for lesion volume and count analysis.
182
+ - User asks for longitudinal lesion change tracking.
183
+ - User asks for MS lesion segmentation benchmarking.
184
+
185
+ ---
186
+
187
+ ## Complementary / Related Skills
188
+ - `smri-skill` → structural MRI preprocessing
189
+ - `nibabel-skill` → NIfTI I/O and mask manipulation
190
+ - `brain-visualization` → lesion overlay visualization
191
+ - `dependency-planner` → dependency resolution
192
+ - `conda-env-manager` → environment management
193
+ - `claw-shell` → command execution
194
+
195
+ ---
196
+
197
+ ## Reference
198
+ - Carass et al. (2017): Longitudinal multiple sclerosis lesion segmentation: Resource and challenge. NeuroImage.
199
+ - ISBI 2015 MS Lesion Challenge: https://smart-stats-tools.org/lesion-challenge
200
+
201
+ Created At: 2026-05-06 13:31 HKT
202
+ Last Updated At: 2026-05-06 13:31 HKT
203
+ Author: chengwang96
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env python3
2
+ """Analyze lesion masks from MS Lesion Challenge data.
3
+
4
+ Computes lesion volume, count, and location statistics from binary lesion masks.
5
+ """
6
+ import argparse
7
+ import csv
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Dict, List
11
+
12
+ try:
13
+ import numpy as np
14
+ except ImportError:
15
+ print("Error: numpy is required.", file=sys.stderr)
16
+ sys.exit(1)
17
+
18
+ try:
19
+ import nibabel as nib
20
+ except ImportError:
21
+ print("Error: nibabel is required.", file=sys.stderr)
22
+ sys.exit(1)
23
+
24
+
25
+ def count_lesions(lesion_data: np.ndarray) -> int:
26
+ """Count connected components (lesions) in binary mask."""
27
+ try:
28
+ from scipy.ndimage import label
29
+ labeled, num_features = label(lesion_data)
30
+ return num_features
31
+ except ImportError:
32
+ # Fallback: count unique non-zero regions
33
+ return int(np.sum(lesion_data > 0) > 0)
34
+
35
+
36
+ def compute_lesion_volume(lesion_data: np.ndarray, voxel_size: tuple) -> float:
37
+ """Compute total lesion volume in mm³."""
38
+ n_voxels = np.sum(lesion_data > 0)
39
+ voxel_volume = np.prod(voxel_size)
40
+ return float(n_voxels * voxel_volume)
41
+
42
+
43
+ def analyze_lesion_mask(mask_path: Path) -> Dict[str, float]:
44
+ """Analyze a single lesion mask."""
45
+ img = nib.load(str(mask_path))
46
+ data = img.get_fdata()
47
+ voxel_size = img.header.get_zooms()[:3]
48
+
49
+ n_lesions = count_lesions(data)
50
+ volume_mm3 = compute_lesion_volume(data, voxel_size)
51
+ volume_ml = volume_mm3 / 1000.0 # Convert mm³ to mL
52
+
53
+ return {
54
+ "n_lesions": n_lesions,
55
+ "volume_mm3": volume_mm3,
56
+ "volume_ml": volume_ml,
57
+ "n_voxels": int(np.sum(data > 0)),
58
+ "voxel_size": str(voxel_size),
59
+ }
60
+
61
+
62
+ def main() -> int:
63
+ parser = argparse.ArgumentParser(
64
+ description="Analyze lesion masks from MS Challenge data."
65
+ )
66
+ parser.add_argument("--input", required=True, help="Path to directory with lesion masks")
67
+ parser.add_argument("--output", required=True, help="Output path for lesion statistics CSV")
68
+ parser.add_argument("--pattern", default="*_lesion.nii.gz",
69
+ help="Glob pattern for lesion masks (default: *_lesion.nii.gz)")
70
+ args = parser.parse_args()
71
+
72
+ input_dir = Path(args.input).resolve()
73
+ if not input_dir.exists():
74
+ print(f"Input directory not found: {input_dir}", file=sys.stderr)
75
+ return 1
76
+
77
+ # Find lesion masks
78
+ mask_files = sorted(input_dir.rglob(args.pattern))
79
+ print(f"Found {len(mask_files)} lesion masks")
80
+
81
+ if not mask_files:
82
+ print("[WARN] No lesion masks found.", file=sys.stderr)
83
+ return 1
84
+
85
+ # Analyze each mask
86
+ results = []
87
+ for mask_path in mask_files:
88
+ try:
89
+ stats = analyze_lesion_mask(mask_path)
90
+ stats["file"] = str(mask_path.relative_to(input_dir))
91
+ results.append(stats)
92
+ except Exception as e:
93
+ print(f"[WARN] Error processing {mask_path}: {e}", file=sys.stderr)
94
+
95
+ # Write output
96
+ output_path = Path(args.output).resolve()
97
+ output_path.parent.mkdir(parents=True, exist_ok=True)
98
+
99
+ if results:
100
+ fieldnames = ["file", "n_lesions", "volume_mm3", "volume_ml", "n_voxels", "voxel_size"]
101
+ with open(output_path, "w", newline="", encoding="utf-8") as f:
102
+ writer = csv.DictWriter(f, fieldnames=fieldnames)
103
+ writer.writeheader()
104
+ writer.writerows(results)
105
+
106
+ # Summary
107
+ total_volume = sum(r["volume_ml"] for r in results)
108
+ total_lesions = sum(r["n_lesions"] for r in results)
109
+ print(f"\nLesion Analysis Summary:")
110
+ print(f" Masks analyzed: {len(results)}")
111
+ print(f" Total lesions: {total_lesions}")
112
+ print(f" Total volume: {total_volume:.2f} mL")
113
+ print(f" Output: {output_path}")
114
+
115
+ return 0
116
+
117
+
118
+ if __name__ == "__main__":
119
+ sys.exit(main())
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env python3
2
+ """Analyze longitudinal lesion changes across timepoints.
3
+
4
+ Tracks lesion volume, count, and new/enlarged/resolved lesions
5
+ across multiple timepoints for each subject.
6
+ """
7
+ import argparse
8
+ import csv
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Dict, List
12
+
13
+ try:
14
+ import numpy as np
15
+ except ImportError:
16
+ print("Error: numpy is required.", file=sys.stderr)
17
+ sys.exit(1)
18
+
19
+ try:
20
+ import nibabel as nib
21
+ except ImportError:
22
+ print("Error: nibabel is required.", file=sys.stderr)
23
+ sys.exit(1)
24
+
25
+
26
+ def load_lesion_mask(mask_path: Path) -> np.ndarray:
27
+ """Load lesion mask and return binary data."""
28
+ img = nib.load(str(mask_path))
29
+ return (img.get_fdata() > 0).astype(np.uint8)
30
+
31
+
32
+ def compute_lesion_changes(mask_t1: np.ndarray, mask_t2: np.ndarray) -> Dict[str, int]:
33
+ """Compute lesion changes between two timepoints."""
34
+ # New lesions: present in t2 but not in t1
35
+ new_lesions = np.sum((mask_t2 > 0) & (mask_t1 == 0))
36
+ # Resolved lesions: present in t1 but not in t2
37
+ resolved_lesions = np.sum((mask_t1 > 0) & (mask_t2 == 0))
38
+ # Stable lesions: present in both
39
+ stable_lesions = np.sum((mask_t1 > 0) & (mask_t2 > 0))
40
+ # Enlarged lesions: increased volume (approximate)
41
+ enlarged_lesions = 0 # Would need connected component analysis
42
+
43
+ return {
44
+ "new_voxels": int(new_lesions),
45
+ "resolved_voxels": int(resolved_lesions),
46
+ "stable_voxels": int(stable_lesions),
47
+ "enlarged_voxels": int(enlarged_lesions),
48
+ }
49
+
50
+
51
+ def analyze_subject(subject_dir: Path) -> Dict[str, any]:
52
+ """Analyze longitudinal lesion changes for a single subject."""
53
+ report = {
54
+ "subject": subject_dir.name,
55
+ "timepoints": [],
56
+ "volumes": [],
57
+ "changes": [],
58
+ }
59
+
60
+ # Find timepoints with lesion masks
61
+ timepoints = sorted([d for d in subject_dir.iterdir() if d.is_dir()])
62
+ masks = {}
63
+
64
+ for tp_dir in timepoints:
65
+ lesion_files = list(tp_dir.glob("*_lesion.nii.gz"))
66
+ if lesion_files:
67
+ masks[tp_dir.name] = lesion_files[0]
68
+ report["timepoints"].append(tp_dir.name)
69
+
70
+ if len(masks) < 2:
71
+ report["warning"] = "Need at least 2 timepoints for longitudinal analysis"
72
+ return report
73
+
74
+ # Compute volumes for each timepoint
75
+ for tp_name in report["timepoints"]:
76
+ mask_data = load_lesion_mask(masks[tp_name])
77
+ volume = int(np.sum(mask_data > 0))
78
+ report["volumes"].append(volume)
79
+
80
+ # Compute changes between consecutive timepoints
81
+ for i in range(len(report["timepoints"]) - 1):
82
+ tp1 = report["timepoints"][i]
83
+ tp2 = report["timepoints"][i + 1]
84
+ mask1 = load_lesion_mask(masks[tp1])
85
+ mask2 = load_lesion_mask(masks[tp2])
86
+ changes = compute_lesion_changes(mask1, mask2)
87
+ changes["from"] = tp1
88
+ changes["to"] = tp2
89
+ report["changes"].append(changes)
90
+
91
+ return report
92
+
93
+
94
+ def main() -> int:
95
+ parser = argparse.ArgumentParser(
96
+ description="Analyze longitudinal lesion changes."
97
+ )
98
+ parser.add_argument("--input", required=True, help="Path to MS Challenge directory")
99
+ parser.add_argument("--output", required=True, help="Output path for longitudinal analysis CSV")
100
+ args = parser.parse_args()
101
+
102
+ input_dir = Path(args.input).resolve()
103
+ if not input_dir.exists():
104
+ print(f"Input directory not found: {input_dir}", file=sys.stderr)
105
+ return 1
106
+
107
+ # Find subjects
108
+ subjects = sorted([d for d in input_dir.iterdir() if d.is_dir()])
109
+ print(f"Found {len(subjects)} subjects")
110
+
111
+ if not subjects:
112
+ print("[ERROR] No subjects found.", file=sys.stderr)
113
+ return 1
114
+
115
+ # Analyze each subject
116
+ results = []
117
+ for sub_dir in subjects:
118
+ report = analyze_subject(sub_dir)
119
+ results.append(report)
120
+
121
+ # Write output
122
+ output_path = Path(args.output).resolve()
123
+ output_path.parent.mkdir(parents=True, exist_ok=True)
124
+
125
+ with open(output_path, "w", newline="", encoding="utf-8") as f:
126
+ writer = csv.writer(f)
127
+ writer.writerow(["subject", "n_timepoints", "volumes", "changes"])
128
+ for r in results:
129
+ writer.writerow([
130
+ r["subject"],
131
+ len(r["timepoints"]),
132
+ str(r["volumes"]),
133
+ str(r["changes"]),
134
+ ])
135
+
136
+ # Summary
137
+ total_subjects = len(results)
138
+ subjects_with_changes = sum(1 for r in results if r.get("changes"))
139
+ print(f"\nLongitudinal Analysis Summary:")
140
+ print(f" Subjects: {total_subjects}")
141
+ print(f" With longitudinal data: {subjects_with_changes}")
142
+ print(f" Output: {output_path}")
143
+
144
+ return 0
145
+
146
+
147
+ if __name__ == "__main__":
148
+ sys.exit(main())