@brainpilot/skills 0.0.6 → 0.0.7

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,766 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import argparse
5
+ import hashlib
6
+ import json
7
+ import sys
8
+ import time
9
+ from pathlib import Path
10
+ from typing import Any, Dict, List, Optional, Tuple
11
+
12
+ import pandas as pd
13
+
14
+ MODALITY_ORDER = ["T1", "T2", "FLAIR", "PD", "DTI", "fMRI"]
15
+
16
+ MODALITY_DISPLAY = {
17
+ "T1": "T1W",
18
+ "T2": "T2W",
19
+ "FLAIR": "FLAIR",
20
+ "PD": "PD",
21
+ "DTI": "DTI",
22
+ "fMRI": "fMRI",
23
+ }
24
+
25
+ TASK2_OPTIONS = ["T1W", "T2W", "FLAIR", "PD", "DTI", "fMRI"]
26
+ TASK3_DIAGNOSIS_OPTIONS = ["CN", "MCI", "Dementia"]
27
+ YES_NO_OPTIONS = ["Yes", "No"]
28
+
29
+ RISK_LABEL_TEXT = {
30
+ "CN_to_impairment_risk": "Elevated risk of future cognitive impairment",
31
+ "stable_CN_short_term": "Stable CN in short-term follow-up",
32
+ "MCI_to_dementia_risk": "Risk of progression from MCI to dementia",
33
+ "stable_or_reverting_MCI": "Stable or reverting MCI",
34
+ "established_dementia": "Established dementia",
35
+ }
36
+
37
+ TASK5_RISK_OPTIONS = [
38
+ RISK_LABEL_TEXT["CN_to_impairment_risk"],
39
+ RISK_LABEL_TEXT["stable_CN_short_term"],
40
+ RISK_LABEL_TEXT["MCI_to_dementia_risk"],
41
+ RISK_LABEL_TEXT["stable_or_reverting_MCI"],
42
+ RISK_LABEL_TEXT["established_dementia"],
43
+ ]
44
+
45
+ TASK2_TEMPLATES = [
46
+ "What imaging modality is shown in this brain image?",
47
+ "Which MRI modality does the provided image correspond to?",
48
+ "Identify the imaging modality of this brain scan.",
49
+ ]
50
+
51
+ TASK3_DIAGNOSIS_TEMPLATES = [
52
+ "What is the cognitive diagnosis label for this visit?",
53
+ "Which diagnostic category best matches this visit?",
54
+ "What is the patient's cognitive status at this visit?",
55
+ ]
56
+
57
+ TASK3_IMPAIRMENT_TEMPLATES = [
58
+ "Does this visit indicate any cognitive impairment?",
59
+ "Is the patient cognitively impaired at this visit?",
60
+ "Is any cognitive impairment present at this visit?",
61
+ ]
62
+
63
+ TASK3_DEMENTIA_TEMPLATES = [
64
+ "Is this visit labeled as dementia?",
65
+ "Does this visit correspond to dementia?",
66
+ "Is the diagnosis for this visit dementia?",
67
+ ]
68
+
69
+ TASK5_RISK_TEMPLATES = [
70
+ "Based on the patient's longitudinal imaging history up to the current visit, what is the most appropriate prognosis label?",
71
+ "Considering the visit history up to the current date, which future risk label best applies?",
72
+ "Using the patient's longitudinal records up to this visit, which prognostic category is most appropriate?",
73
+ ]
74
+
75
+ TASK5_DECLINE_TEMPLATES = [
76
+ "Is there documented future cognitive decline after this visit?",
77
+ "Does the patient show later cognitive decline after the current visit?",
78
+ "Is future cognitive decline observed after this visit?",
79
+ ]
80
+
81
+ TASK5_DEMENTIA_TEMPLATES = [
82
+ "Does the patient later progress to dementia after this visit?",
83
+ "Is future conversion to dementia observed after the current visit?",
84
+ "Does this patient develop dementia at a later labeled visit?",
85
+ ]
86
+
87
+
88
+ def safe_int(value: object) -> Optional[int]:
89
+ if value is None or pd.isna(value):
90
+ return None
91
+ try:
92
+ return int(float(value))
93
+ except Exception:
94
+ return None
95
+
96
+
97
+ def none_if_na(value: object) -> Optional[object]:
98
+ if value is None or pd.isna(value):
99
+ return None
100
+ return value
101
+
102
+
103
+ def stable_pick(templates: List[str], key: str) -> str:
104
+ if not templates:
105
+ raise ValueError("Template list must not be empty.")
106
+ digest = hashlib.md5(key.encode("utf-8")).hexdigest()
107
+ index = int(digest, 16) % len(templates)
108
+ return templates[index]
109
+
110
+
111
+ def yes_no_answer(flag: object) -> Optional[str]:
112
+ value = safe_int(flag)
113
+ if value is None:
114
+ return None
115
+ return "Yes" if value == 1 else "No"
116
+
117
+
118
+ def ensure_dir(path: Path) -> None:
119
+ path.mkdir(parents=True, exist_ok=True)
120
+
121
+
122
+ def parse_modalities_arg(text: str) -> List[str]:
123
+ if not text:
124
+ return []
125
+ parts = [x.strip() for x in text.split(",")]
126
+ valid = []
127
+ for part in parts:
128
+ if not part:
129
+ continue
130
+ if part not in MODALITY_ORDER:
131
+ raise ValueError(f"Unknown modality in argument: {part}")
132
+ valid.append(part)
133
+ return valid
134
+
135
+
136
+ def load_csv_required(path: Path, name: str) -> pd.DataFrame:
137
+ if not path.exists():
138
+ raise FileNotFoundError(f"{name} not found: {path}")
139
+ df = pd.read_csv(path, low_memory=False)
140
+ required = ["subject_id", "visit_date"]
141
+ for col in required:
142
+ if col not in df.columns:
143
+ raise RuntimeError(f"{name} is missing required column: {col}")
144
+ df["subject_id"] = df["subject_id"].astype(str)
145
+ df["visit_date"] = df["visit_date"].astype(str)
146
+ return df
147
+
148
+
149
+ def build_task2_index(task2_df: pd.DataFrame) -> Dict[Tuple[str, str], pd.Series]:
150
+ index: Dict[Tuple[str, str], pd.Series] = {}
151
+ for _, row in task2_df.iterrows():
152
+ key = (str(row["subject_id"]), str(row["visit_date"]))
153
+ index[key] = row
154
+ return index
155
+
156
+
157
+ def is_existing_path(path_str: str) -> bool:
158
+ try:
159
+ return Path(path_str).exists()
160
+ except Exception:
161
+ return False
162
+
163
+
164
+ def collect_images_from_task2_row(
165
+ row: pd.Series,
166
+ allowed_modalities: List[str],
167
+ allow_missing_image_paths: bool = False,
168
+ current_visit_date: Optional[str] = None,
169
+ ) -> List[Dict[str, Any]]:
170
+ images: List[Dict[str, Any]] = []
171
+
172
+ for modality in MODALITY_ORDER:
173
+ if modality not in allowed_modalities:
174
+ continue
175
+
176
+ has_modality = safe_int(row.get(f"has_{modality}"))
177
+ path_value = none_if_na(row.get(f"{modality}_path"))
178
+
179
+ if has_modality != 1 or path_value is None:
180
+ continue
181
+
182
+ path_str = str(path_value)
183
+ if not allow_missing_image_paths and not is_existing_path(path_str):
184
+ continue
185
+
186
+ visit_date = str(row["visit_date"])
187
+ images.append(
188
+ {
189
+ "path": path_str,
190
+ "modality": modality,
191
+ "modality_display": MODALITY_DISPLAY[modality],
192
+ "visit_date": visit_date,
193
+ "is_current_visit": current_visit_date is None or visit_date == current_visit_date,
194
+ }
195
+ )
196
+
197
+ return images
198
+
199
+
200
+ def collect_history_visits(
201
+ task2_df: pd.DataFrame,
202
+ subject_id: str,
203
+ current_visit_date: str,
204
+ allowed_modalities: List[str],
205
+ max_history_visits: int,
206
+ allow_missing_image_paths: bool = False,
207
+ ) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
208
+ subset = task2_df[task2_df["subject_id"].astype(str) == str(subject_id)].copy()
209
+ subset = subset[subset["visit_date"].astype(str) <= str(current_visit_date)].copy()
210
+ subset = subset.sort_values("visit_date")
211
+
212
+ if max_history_visits > 0 and len(subset) > max_history_visits:
213
+ subset = subset.tail(max_history_visits)
214
+
215
+ history_visits: List[Dict[str, Any]] = []
216
+ flat_images: List[Dict[str, Any]] = []
217
+
218
+ for _, row in subset.iterrows():
219
+ visit_date = str(row["visit_date"])
220
+ visit_images = collect_images_from_task2_row(
221
+ row=row,
222
+ allowed_modalities=allowed_modalities,
223
+ allow_missing_image_paths=allow_missing_image_paths,
224
+ current_visit_date=current_visit_date,
225
+ )
226
+
227
+ if not visit_images:
228
+ continue
229
+
230
+ history_visits.append(
231
+ {
232
+ "visit_date": visit_date,
233
+ "visit_folder_path": str(none_if_na(row.get("visit_folder_path")) or ""),
234
+ "images": visit_images,
235
+ "image_paths": [img["path"] for img in visit_images],
236
+ "image_modalities": [img["modality"] for img in visit_images],
237
+ }
238
+ )
239
+ flat_images.extend(visit_images)
240
+
241
+ return history_visits, flat_images
242
+
243
+
244
+ def build_vqa_item(
245
+ pair_id: str,
246
+ task_id: str,
247
+ task_name: str,
248
+ subtask: str,
249
+ question_type: str,
250
+ question: str,
251
+ answer: str,
252
+ options: Optional[List[str]],
253
+ subject_id: str,
254
+ visit_date: str,
255
+ images: List[Dict[str, Any]],
256
+ metadata: Dict[str, Any],
257
+ history_visits: Optional[List[Dict[str, Any]]] = None,
258
+ ) -> Dict[str, Any]:
259
+ image_paths = [img["path"] for img in images]
260
+ image_modalities = [img["modality"] for img in images]
261
+
262
+ item = {
263
+ "id": pair_id,
264
+ "task_id": task_id,
265
+ "task_name": task_name,
266
+ "subtask": subtask,
267
+ "question_type": question_type,
268
+ "question": question,
269
+ "answer": answer,
270
+ "options": options if options is not None else [],
271
+ "subject_id": subject_id,
272
+ "visit_date": visit_date,
273
+ "images": images,
274
+ "image_paths": image_paths,
275
+ "image_modalities": image_modalities,
276
+ "history_visits": history_visits if history_visits is not None else [],
277
+ "metadata": metadata,
278
+ }
279
+ return item
280
+
281
+
282
+ def generate_task2_pairs(
283
+ task2_df: pd.DataFrame,
284
+ allow_missing_image_paths: bool,
285
+ ) -> List[Dict[str, Any]]:
286
+ pairs: List[Dict[str, Any]] = []
287
+ counter = 1
288
+
289
+ for _, row in task2_df.iterrows():
290
+ subject_id = str(row["subject_id"])
291
+ visit_date = str(row["visit_date"])
292
+
293
+ for modality in MODALITY_ORDER:
294
+ has_modality = safe_int(row.get(f"has_{modality}"))
295
+ path_value = none_if_na(row.get(f"{modality}_path"))
296
+
297
+ if has_modality != 1 or path_value is None:
298
+ continue
299
+
300
+ path_str = str(path_value)
301
+ if not allow_missing_image_paths and not is_existing_path(path_str):
302
+ continue
303
+
304
+ question = stable_pick(
305
+ TASK2_TEMPLATES,
306
+ f"task2|{subject_id}|{visit_date}|{modality}",
307
+ )
308
+ answer = MODALITY_DISPLAY[modality]
309
+
310
+ images = [
311
+ {
312
+ "path": path_str,
313
+ "modality": modality,
314
+ "modality_display": MODALITY_DISPLAY[modality],
315
+ "visit_date": visit_date,
316
+ "is_current_visit": True,
317
+ }
318
+ ]
319
+
320
+ metadata = {
321
+ "source_csv": "task2_imaging_modality_identification_labels.csv",
322
+ "subject_folder": str(none_if_na(row.get("subject_folder")) or ""),
323
+ "visit_folder_path": str(none_if_na(row.get("visit_folder_path")) or ""),
324
+ "answer_modality_code": modality,
325
+ "answer_modality_display": answer,
326
+ }
327
+
328
+ pairs.append(
329
+ build_vqa_item(
330
+ pair_id=f"task2_{counter:08d}",
331
+ task_id="task2",
332
+ task_name="Imaging Modality Identification",
333
+ subtask="single_image_modality_classification",
334
+ question_type="single-choice",
335
+ question=question,
336
+ answer=answer,
337
+ options=TASK2_OPTIONS,
338
+ subject_id=subject_id,
339
+ visit_date=visit_date,
340
+ images=images,
341
+ metadata=metadata,
342
+ )
343
+ )
344
+ counter += 1
345
+
346
+ return pairs
347
+
348
+
349
+ def generate_task3_pairs(
350
+ task3_df: pd.DataFrame,
351
+ task2_index: Dict[Tuple[str, str], pd.Series],
352
+ task3_modalities: List[str],
353
+ allow_missing_image_paths: bool,
354
+ ) -> List[Dict[str, Any]]:
355
+ pairs: List[Dict[str, Any]] = []
356
+ counter = 1
357
+
358
+ for _, row in task3_df.iterrows():
359
+ subject_id = str(row["subject_id"])
360
+ visit_date = str(row["visit_date"])
361
+ label_available = safe_int(row.get("task3_label_available"))
362
+
363
+ if label_available != 1:
364
+ continue
365
+
366
+ task2_row = task2_index.get((subject_id, visit_date))
367
+ if task2_row is None:
368
+ continue
369
+
370
+ images = collect_images_from_task2_row(
371
+ row=task2_row,
372
+ allowed_modalities=task3_modalities,
373
+ allow_missing_image_paths=allow_missing_image_paths,
374
+ current_visit_date=visit_date,
375
+ )
376
+ if not images:
377
+ continue
378
+
379
+ diagnosis = none_if_na(row.get("task3_diagnosis"))
380
+ if diagnosis is None:
381
+ continue
382
+ diagnosis = str(diagnosis)
383
+
384
+ common_metadata = {
385
+ "source_csv": "task3_disease_abnormality_diagnosis_labels.csv",
386
+ "subject_folder": str(none_if_na(row.get("subject_folder")) or ""),
387
+ "visit_folder_path": str(none_if_na(row.get("visit_folder_path")) or ""),
388
+ "task3_dx_source_date": str(none_if_na(row.get("task3_dx_source_date")) or ""),
389
+ "task3_dx_match_days": safe_int(row.get("task3_dx_match_days")),
390
+ "task3_dx_match_type": str(none_if_na(row.get("task3_dx_match_type")) or ""),
391
+ "task3_diagnosis_code": safe_int(row.get("task3_diagnosis_code")),
392
+ "task3_diagnosis": diagnosis,
393
+ }
394
+
395
+ # Multiclass diagnosis
396
+ question = stable_pick(
397
+ TASK3_DIAGNOSIS_TEMPLATES,
398
+ f"task3_diag|{subject_id}|{visit_date}",
399
+ )
400
+ pairs.append(
401
+ build_vqa_item(
402
+ pair_id=f"task3_{counter:08d}",
403
+ task_id="task3",
404
+ task_name="Disease / Abnormality Diagnosis",
405
+ subtask="multiclass_cognitive_diagnosis",
406
+ question_type="single-choice",
407
+ question=question,
408
+ answer=diagnosis,
409
+ options=TASK3_DIAGNOSIS_OPTIONS,
410
+ subject_id=subject_id,
411
+ visit_date=visit_date,
412
+ images=images,
413
+ metadata=common_metadata,
414
+ )
415
+ )
416
+ counter += 1
417
+
418
+ # Binary impairment
419
+ impairment_answer = yes_no_answer(row.get("task3_any_cognitive_impairment"))
420
+ if impairment_answer is not None:
421
+ question = stable_pick(
422
+ TASK3_IMPAIRMENT_TEMPLATES,
423
+ f"task3_impairment|{subject_id}|{visit_date}",
424
+ )
425
+ metadata = dict(common_metadata)
426
+ metadata["binary_target"] = "task3_any_cognitive_impairment"
427
+ pairs.append(
428
+ build_vqa_item(
429
+ pair_id=f"task3_{counter:08d}",
430
+ task_id="task3",
431
+ task_name="Disease / Abnormality Diagnosis",
432
+ subtask="binary_any_cognitive_impairment",
433
+ question_type="yes-no",
434
+ question=question,
435
+ answer=impairment_answer,
436
+ options=YES_NO_OPTIONS,
437
+ subject_id=subject_id,
438
+ visit_date=visit_date,
439
+ images=images,
440
+ metadata=metadata,
441
+ )
442
+ )
443
+ counter += 1
444
+
445
+ # Binary dementia
446
+ dementia_answer = yes_no_answer(row.get("task3_dementia"))
447
+ if dementia_answer is not None:
448
+ question = stable_pick(
449
+ TASK3_DEMENTIA_TEMPLATES,
450
+ f"task3_dementia|{subject_id}|{visit_date}",
451
+ )
452
+ metadata = dict(common_metadata)
453
+ metadata["binary_target"] = "task3_dementia"
454
+ pairs.append(
455
+ build_vqa_item(
456
+ pair_id=f"task3_{counter:08d}",
457
+ task_id="task3",
458
+ task_name="Disease / Abnormality Diagnosis",
459
+ subtask="binary_dementia",
460
+ question_type="yes-no",
461
+ question=question,
462
+ answer=dementia_answer,
463
+ options=YES_NO_OPTIONS,
464
+ subject_id=subject_id,
465
+ visit_date=visit_date,
466
+ images=images,
467
+ metadata=metadata,
468
+ )
469
+ )
470
+ counter += 1
471
+
472
+ return pairs
473
+
474
+
475
+ def generate_task5_pairs(
476
+ task5_df: pd.DataFrame,
477
+ task2_df: pd.DataFrame,
478
+ task5_modalities: List[str],
479
+ task5_max_history_visits: int,
480
+ allow_missing_image_paths: bool,
481
+ ) -> List[Dict[str, Any]]:
482
+ pairs: List[Dict[str, Any]] = []
483
+ counter = 1
484
+
485
+ for _, row in task5_df.iterrows():
486
+ subject_id = str(row["subject_id"])
487
+ visit_date = str(row["visit_date"])
488
+
489
+ has_future = safe_int(row.get("task5_has_future_labeled_visit"))
490
+ current_diag = none_if_na(row.get("task5_current_diagnosis"))
491
+ risk_label_raw = none_if_na(row.get("task5_risk_label"))
492
+
493
+ if has_future != 1:
494
+ continue
495
+ if current_diag is None:
496
+ continue
497
+
498
+ history_visits, images = collect_history_visits(
499
+ task2_df=task2_df,
500
+ subject_id=subject_id,
501
+ current_visit_date=visit_date,
502
+ allowed_modalities=task5_modalities,
503
+ max_history_visits=task5_max_history_visits,
504
+ allow_missing_image_paths=allow_missing_image_paths,
505
+ )
506
+ if not images:
507
+ continue
508
+
509
+ common_metadata = {
510
+ "source_csv": "task5_risk_forecasting_treatment_related_labels.csv",
511
+ "subject_folder": str(none_if_na(row.get("subject_folder")) or ""),
512
+ "visit_folder_path": str(none_if_na(row.get("visit_folder_path")) or ""),
513
+ "task5_current_diagnosis_code": safe_int(row.get("task5_current_diagnosis_code")),
514
+ "task5_current_diagnosis": str(current_diag),
515
+ "task5_subject_n_visits": safe_int(row.get("task5_subject_n_visits")),
516
+ "task5_subject_n_labeled_visits": safe_int(row.get("task5_subject_n_labeled_visits")),
517
+ "task5_has_longitudinal_followup": safe_int(row.get("task5_has_longitudinal_followup")),
518
+ "task5_baseline_diagnosis_code": safe_int(row.get("task5_baseline_diagnosis_code")),
519
+ "task5_baseline_diagnosis": str(none_if_na(row.get("task5_baseline_diagnosis")) or ""),
520
+ "task5_last_diagnosis_code": safe_int(row.get("task5_last_diagnosis_code")),
521
+ "task5_last_diagnosis": str(none_if_na(row.get("task5_last_diagnosis")) or ""),
522
+ "task5_next_labeled_visit_date": str(none_if_na(row.get("task5_next_labeled_visit_date")) or ""),
523
+ "task5_next_labeled_diagnosis_code": safe_int(row.get("task5_next_labeled_diagnosis_code")),
524
+ "task5_next_labeled_diagnosis": str(none_if_na(row.get("task5_next_labeled_diagnosis")) or ""),
525
+ "task5_days_to_next_labeled_visit": safe_int(row.get("task5_days_to_next_labeled_visit")),
526
+ "task5_history_visit_count_used": len(history_visits),
527
+ "task5_modalities_used": task5_modalities,
528
+ }
529
+
530
+ # Multiclass risk label
531
+ if risk_label_raw is not None:
532
+ risk_label_raw = str(risk_label_raw)
533
+ risk_answer = RISK_LABEL_TEXT.get(risk_label_raw)
534
+ if risk_answer is not None:
535
+ question = stable_pick(
536
+ TASK5_RISK_TEMPLATES,
537
+ f"task5_risk|{subject_id}|{visit_date}",
538
+ )
539
+ metadata = dict(common_metadata)
540
+ metadata["task5_risk_label_raw"] = risk_label_raw
541
+ metadata["task5_risk_label_text"] = risk_answer
542
+
543
+ pairs.append(
544
+ build_vqa_item(
545
+ pair_id=f"task5_{counter:08d}",
546
+ task_id="task5",
547
+ task_name="Risk Forecasting & Treatment-Related Labels",
548
+ subtask="multiclass_prognostic_risk",
549
+ question_type="single-choice",
550
+ question=question,
551
+ answer=risk_answer,
552
+ options=TASK5_RISK_OPTIONS,
553
+ subject_id=subject_id,
554
+ visit_date=visit_date,
555
+ images=images,
556
+ metadata=metadata,
557
+ history_visits=history_visits,
558
+ )
559
+ )
560
+ counter += 1
561
+
562
+ # Binary future decline
563
+ future_decline_answer = yes_no_answer(row.get("task5_future_decline"))
564
+ if future_decline_answer is not None:
565
+ question = stable_pick(
566
+ TASK5_DECLINE_TEMPLATES,
567
+ f"task5_decline|{subject_id}|{visit_date}",
568
+ )
569
+ metadata = dict(common_metadata)
570
+ metadata["binary_target"] = "task5_future_decline"
571
+
572
+ pairs.append(
573
+ build_vqa_item(
574
+ pair_id=f"task5_{counter:08d}",
575
+ task_id="task5",
576
+ task_name="Risk Forecasting & Treatment-Related Labels",
577
+ subtask="binary_future_decline",
578
+ question_type="yes-no",
579
+ question=question,
580
+ answer=future_decline_answer,
581
+ options=YES_NO_OPTIONS,
582
+ subject_id=subject_id,
583
+ visit_date=visit_date,
584
+ images=images,
585
+ metadata=metadata,
586
+ history_visits=history_visits,
587
+ )
588
+ )
589
+ counter += 1
590
+
591
+ # Binary future dementia
592
+ future_dementia_answer = yes_no_answer(row.get("task5_future_dementia"))
593
+ if future_dementia_answer is not None:
594
+ question = stable_pick(
595
+ TASK5_DEMENTIA_TEMPLATES,
596
+ f"task5_future_dementia|{subject_id}|{visit_date}",
597
+ )
598
+ metadata = dict(common_metadata)
599
+ metadata["binary_target"] = "task5_future_dementia"
600
+
601
+ pairs.append(
602
+ build_vqa_item(
603
+ pair_id=f"task5_{counter:08d}",
604
+ task_id="task5",
605
+ task_name="Risk Forecasting & Treatment-Related Labels",
606
+ subtask="binary_future_dementia",
607
+ question_type="yes-no",
608
+ question=question,
609
+ answer=future_dementia_answer,
610
+ options=YES_NO_OPTIONS,
611
+ subject_id=subject_id,
612
+ visit_date=visit_date,
613
+ images=images,
614
+ metadata=metadata,
615
+ history_visits=history_visits,
616
+ )
617
+ )
618
+ counter += 1
619
+
620
+ return pairs
621
+
622
+
623
+ def save_json(path: Path, data: Any) -> None:
624
+ with open(path, "w", encoding="utf-8") as f:
625
+ json.dump(data, f, ensure_ascii=False, indent=2)
626
+
627
+
628
+ def save_jsonl(path: Path, rows: List[Dict[str, Any]]) -> None:
629
+ with open(path, "w", encoding="utf-8") as f:
630
+ for row in rows:
631
+ f.write(json.dumps(row, ensure_ascii=False) + "\n")
632
+
633
+
634
+ def summarize_pairs(name: str, pairs: List[Dict[str, Any]]) -> None:
635
+ subtype_counts: Dict[str, int] = {}
636
+ for item in pairs:
637
+ subtype = str(item.get("subtask", "unknown"))
638
+ subtype_counts[subtype] = subtype_counts.get(subtype, 0) + 1
639
+
640
+ print(f"{name}: {len(pairs)}")
641
+ for subtype, count in sorted(subtype_counts.items()):
642
+ print(f" - {subtype}: {count}")
643
+
644
+
645
+ def main(argv: List[str]) -> int:
646
+ parser = argparse.ArgumentParser(description="Generate VQA pairs from ADNI task2/task3/task5 labels.")
647
+ parser.add_argument("--task-dir", default="task_outputs", help="Directory containing task CSV files")
648
+ parser.add_argument("--outdir", default="vqa_outputs", help="Directory to save generated VQA pairs")
649
+ parser.add_argument(
650
+ "--task3-modalities",
651
+ default="T1,FLAIR,T2,PD,DTI,fMRI",
652
+ help="Comma-separated modalities used for task3 current visit images",
653
+ )
654
+ parser.add_argument(
655
+ "--task5-modalities",
656
+ default="T1,FLAIR,T2,PD",
657
+ help="Comma-separated modalities used for task5 longitudinal history images",
658
+ )
659
+ parser.add_argument(
660
+ "--task5-max-history-visits",
661
+ type=int,
662
+ default=3,
663
+ help="Maximum number of history visits kept for task5, 0 means keep all",
664
+ )
665
+ parser.add_argument(
666
+ "--allow-missing-image-paths",
667
+ action="store_true",
668
+ help="Keep samples even if the image path does not exist on disk",
669
+ )
670
+ args = parser.parse_args(argv)
671
+
672
+ task_dir = Path(args.task_dir).resolve()
673
+ outdir = Path(args.outdir).resolve()
674
+ ensure_dir(outdir)
675
+
676
+ if not task_dir.exists() or not task_dir.is_dir():
677
+ print(f"Task directory does not exist: {task_dir}", file=sys.stderr)
678
+ return 1
679
+
680
+ task2_path = task_dir / "task2_imaging_modality_identification_labels.csv"
681
+ task3_path = task_dir / "task3_disease_abnormality_diagnosis_labels.csv"
682
+ task5_path = task_dir / "task5_risk_forecasting_treatment_related_labels.csv"
683
+
684
+ try:
685
+ task3_modalities = parse_modalities_arg(args.task3_modalities)
686
+ task5_modalities = parse_modalities_arg(args.task5_modalities)
687
+ except Exception as e:
688
+ print(f"Invalid modality argument: {e}", file=sys.stderr)
689
+ return 1
690
+
691
+ try:
692
+ task2_df = load_csv_required(task2_path, "task2 CSV")
693
+ task3_df = load_csv_required(task3_path, "task3 CSV")
694
+ task5_df = load_csv_required(task5_path, "task5 CSV")
695
+ except Exception as e:
696
+ print(f"Failed to load task CSVs: {e}", file=sys.stderr)
697
+ return 1
698
+
699
+ print("Generating VQA pairs...")
700
+ print(f"Task dir: {task_dir}")
701
+ print(f"Output dir: {outdir}")
702
+ print(f"Task3 modalities: {task3_modalities}")
703
+ print(f"Task5 modalities: {task5_modalities}")
704
+ print(f"Task5 max history visits: {args.task5_max_history_visits}")
705
+ print(f"Allow missing image paths: {args.allow_missing_image_paths}")
706
+
707
+ task2_index = build_task2_index(task2_df)
708
+
709
+ task2_pairs = generate_task2_pairs(
710
+ task2_df=task2_df,
711
+ allow_missing_image_paths=args.allow_missing_image_paths,
712
+ )
713
+ task3_pairs = generate_task3_pairs(
714
+ task3_df=task3_df,
715
+ task2_index=task2_index,
716
+ task3_modalities=task3_modalities,
717
+ allow_missing_image_paths=args.allow_missing_image_paths,
718
+ )
719
+ task5_pairs = generate_task5_pairs(
720
+ task5_df=task5_df,
721
+ task2_df=task2_df,
722
+ task5_modalities=task5_modalities,
723
+ task5_max_history_visits=args.task5_max_history_visits,
724
+ allow_missing_image_paths=args.allow_missing_image_paths,
725
+ )
726
+
727
+ all_pairs = task2_pairs + task3_pairs + task5_pairs
728
+
729
+ metadata = {
730
+ "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
731
+ "task_dir": str(task_dir),
732
+ "counts": {
733
+ "task2": len(task2_pairs),
734
+ "task3": len(task3_pairs),
735
+ "task5": len(task5_pairs),
736
+ "all": len(all_pairs),
737
+ },
738
+ "task3_modalities": task3_modalities,
739
+ "task5_modalities": task5_modalities,
740
+ "task5_max_history_visits": args.task5_max_history_visits,
741
+ "allow_missing_image_paths": args.allow_missing_image_paths,
742
+ }
743
+
744
+ save_json(outdir / "task2_vqa_pairs.json", task2_pairs)
745
+ save_json(outdir / "task3_vqa_pairs.json", task3_pairs)
746
+ save_json(outdir / "task5_vqa_pairs.json", task5_pairs)
747
+ save_json(outdir / "all_vqa_pairs.json", {"metadata": metadata, "data": all_pairs})
748
+ save_jsonl(outdir / "all_vqa_pairs.jsonl", all_pairs)
749
+
750
+ print("\nDone")
751
+ summarize_pairs("Task2 pairs", task2_pairs)
752
+ summarize_pairs("Task3 pairs", task3_pairs)
753
+ summarize_pairs("Task5 pairs", task5_pairs)
754
+ print(f"All pairs: {len(all_pairs)}")
755
+ print(f"\nSaved files:")
756
+ print(f" - {outdir / 'task2_vqa_pairs.json'}")
757
+ print(f" - {outdir / 'task3_vqa_pairs.json'}")
758
+ print(f" - {outdir / 'task5_vqa_pairs.json'}")
759
+ print(f" - {outdir / 'all_vqa_pairs.json'}")
760
+ print(f" - {outdir / 'all_vqa_pairs.jsonl'}")
761
+
762
+ return 0
763
+
764
+
765
+ if __name__ == "__main__":
766
+ raise SystemExit(main(sys.argv[1:]))