@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.
- package/package.json +2 -2
- package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
- package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
- package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
- package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
- package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
- package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
- package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
- package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
- package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
- package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
- package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
- package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
- package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
- package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
- package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
- package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
- package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
- package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
- package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
- package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
- package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
- package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
- package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
- package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
- package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
- package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
- package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
- package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
- package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
- package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
- package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
- package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
- package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
- package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
- package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
- package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
- package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
- package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
- package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
- package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
- package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
- package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
- package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
- package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
- package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
- package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
- package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
- package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
- package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
- package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
- package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
- package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
- package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
- package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
- package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
- package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
- package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
- package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
- package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
- package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
- package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
- package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
- package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
- package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
- package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
- package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
- package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
- package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
- package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
- package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
- package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
- package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
- package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
- package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
- package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
- package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
- package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
- package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
- package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
- package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
- package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
- package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
- package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
- package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
- package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
- package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
- package/skills/14_Writing/paper-writing/SKILL.md +146 -0
- package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
- package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
- package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
- package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
- package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
- package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
- package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
- package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
- package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
- package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
- package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
- 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())
|