@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,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adhd200-skill
|
|
3
|
+
description: "Use this skill whenever the user wants an end-to-end workflow for the ADHD-200 dataset, including download, BIDS organization, and processing of sMRI and rs-fMRI data. Triggers include: 'ADHD-200', 'ADHD200', 'process ADHD data', 'ADHD fMRI', or any request to run the ADHD-200 pipeline. This is the NeuroClaw dataset-orchestration layer for ADHD-200."
|
|
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
|
+
- fmri-skill
|
|
10
|
+
- bids-organizer
|
|
11
|
+
- claw-shell
|
|
12
|
+
---
|
|
13
|
+
# ADHD-200 Skill (Dataset-Orchestration Layer)
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
`adhd200-skill` is the NeuroClaw orchestration skill for the **ADHD-200** dataset.
|
|
17
|
+
|
|
18
|
+
It coordinates a fixed three-phase workflow:
|
|
19
|
+
1. Download ADHD-200 data from the FCP/INDI repository.
|
|
20
|
+
2. Prepare and validate BIDS-style data organization for downstream processing.
|
|
21
|
+
3. Delegate modality pipelines to `smri-skill` and `fmri-skill`.
|
|
22
|
+
|
|
23
|
+
It also provides **phenotype extraction** and **QC integration** paths:
|
|
24
|
+
- Extract and merge ADHD-200 phenotype tables (diagnosis, ADHD measures, demographics, medication).
|
|
25
|
+
- Generate per-subject QC summaries with exclusion lists.
|
|
26
|
+
|
|
27
|
+
This skill follows NeuroClaw hierarchy:
|
|
28
|
+
- Defines **WHAT to do**, not low-level implementation details.
|
|
29
|
+
- Does **not** execute direct shell commands itself.
|
|
30
|
+
- Delegates all execution via `claw-shell` to base/tool skills.
|
|
31
|
+
|
|
32
|
+
**Research use only.**
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Download Stage (Mandatory First Step)
|
|
37
|
+
|
|
38
|
+
### Source
|
|
39
|
+
ADHD-200 data is distributed through the **FCP/INDI** repository:
|
|
40
|
+
- Website: https://fcon_1000.projects.nitrc.org/indi/adhd200/
|
|
41
|
+
|
|
42
|
+
### Supported ADHD-200 Data Packages
|
|
43
|
+
- **Imaging data**: T1w, rs-fMRI (NIfTI format) from 8 imaging sites
|
|
44
|
+
- **Phenotype data**: CSV files with diagnosis, ADHD measures, demographics, medication history, QC measures
|
|
45
|
+
- **Sites**: Peking, Brown, NYU, KKI, NeuroImage, OHSU, Pitt, Washington University
|
|
46
|
+
|
|
47
|
+
### Delegation Rules for Download
|
|
48
|
+
- Environment/setup checks: `dependency-planner` + `conda-env-manager`
|
|
49
|
+
- Download tool installation and execution: `claw-shell`
|
|
50
|
+
- Optional raw-data organization to BIDS-style staging: `bids-organizer`
|
|
51
|
+
|
|
52
|
+
### Download Inputs to Confirm in Plan
|
|
53
|
+
- Target subset (full cohort, specific sites, or ADHD/control only)
|
|
54
|
+
- Subject list scope (full or custom IDs)
|
|
55
|
+
- Destination directory with sufficient disk space
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Narrow Path: ADHD-200 Raw NIfTI -> BIDS Staging
|
|
60
|
+
|
|
61
|
+
Use this path when the task only asks to reorganize raw ADHD-200 NIfTI files into a BIDS-style dataset and does not require preprocessing, ROI extraction, phenotype merging, or downstream analysis.
|
|
62
|
+
|
|
63
|
+
### When this narrow path should dominate
|
|
64
|
+
- The task objective is limited to ADHD-200 NIfTI staging, BIDS renaming, sidecar handling, and dataset-level metadata.
|
|
65
|
+
- Inputs are already local ADHD-200 NIfTI files or ADHD-200-style subject/site folders.
|
|
66
|
+
- The required deliverable is a direct staging script or command sequence, not a plan for fMRIPrep or downstream analysis.
|
|
67
|
+
|
|
68
|
+
### Narrow-path contract
|
|
69
|
+
- Do not widen the solution to fMRIPrep, ROI extraction, phenotype merging, or downstream analysis unless the task explicitly requires them.
|
|
70
|
+
- Treat this as a direct file-organization problem: scan ADHD-200 subject/site layout, normalize subject labels, map modalities to BIDS names, copy or symlink NIfTI plus matching sidecars, and write dataset-level metadata plus staging logs.
|
|
71
|
+
- If the task is benchmark-style, prefer a single direct end-to-end staging script over a confirmation-first orchestration plan.
|
|
72
|
+
|
|
73
|
+
### Expected narrow-path behavior
|
|
74
|
+
1. Detect ADHD-200-style subject IDs (numeric, e.g., `0010002`) and normalize to BIDS labels such as `sub-0010002`.
|
|
75
|
+
2. Detect site information and encode in `participants.tsv`.
|
|
76
|
+
3. Route modalities:
|
|
77
|
+
- T1w -> `anat/*_T1w`
|
|
78
|
+
- rs-fMRI/BOLD -> `func/*_task-rest_bold`
|
|
79
|
+
4. Preserve or rename matching JSON sidecars when available.
|
|
80
|
+
5. Emit dataset-level outputs such as `dataset_description.json`, `participants.tsv`, `README`, and a manifest or skipped-file report.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Core Workflow (Never Bypassed)
|
|
85
|
+
1. Identify user target: full ADHD-200 download, imaging subset, phenotype extraction, or BIDS staging only.
|
|
86
|
+
2. Generate a numbered plan with tools, outputs, runtime, storage, and risks.
|
|
87
|
+
3. Wait for explicit confirmation (`YES` / `execute` / `proceed`).
|
|
88
|
+
4. On confirmation, run download stage first (if needed).
|
|
89
|
+
5. After download success, run BIDS preparation using `scripts/reorganize_adhd200.py`.
|
|
90
|
+
6. Delegate to modality skills:
|
|
91
|
+
- `smri-skill` for structural MRI (T1w)
|
|
92
|
+
- `fmri-skill` for resting-state fMRI (rs-fMRI)
|
|
93
|
+
7. If phenotype extraction is requested, run `scripts/extract_adhd200_phenotype.py`.
|
|
94
|
+
8. If QC summary is requested, run `scripts/adhd200_qc_summary.py`.
|
|
95
|
+
9. Save outputs into an ADHD-200-centered structure under `adhd200_output/`.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Input Layout (Example)
|
|
100
|
+
|
|
101
|
+
Subject `0010002` from site Peking:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
adhd200_raw/
|
|
105
|
+
Peking/
|
|
106
|
+
0010002/
|
|
107
|
+
anat/
|
|
108
|
+
anat.nii.gz
|
|
109
|
+
func/
|
|
110
|
+
rest.nii.gz
|
|
111
|
+
phenotype/
|
|
112
|
+
ADHD200_..._phenotypic.csv
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## BIDS Preparation
|
|
118
|
+
|
|
119
|
+
### Script: `scripts/reorganize_adhd200.py`
|
|
120
|
+
|
|
121
|
+
Converts ADHD-200 raw directory structure to BIDS-compliant layout.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
python skills/adhd200-skill/scripts/reorganize_adhd200.py \
|
|
125
|
+
--input /path/to/adhd200_raw \
|
|
126
|
+
--output /path/to/adhd200_bids \
|
|
127
|
+
--phenotype /path/to/adhd200_raw/phenotype/ADHD200_phenotypic.csv
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Features:
|
|
131
|
+
- Subject ID normalization: numeric ADHD-200 IDs to BIDS `sub-NNNNNNN`
|
|
132
|
+
- Site extraction and encoding in `participants.tsv`
|
|
133
|
+
- Modality routing: T1w, rs-fMRI
|
|
134
|
+
- `dataset_description.json` and `participants.tsv` generation with phenotype metadata
|
|
135
|
+
- Dry-run mode: `--dry-run` to preview without copying
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Multimodal Processing Delegation
|
|
140
|
+
|
|
141
|
+
| Modality | Delegated skill | Typical tasks | Main outputs |
|
|
142
|
+
|---|---|---|---|
|
|
143
|
+
| sMRI (T1w) | `smri-skill` | brain extraction, tissue segmentation, cortical reconstruction | `smri_output/` |
|
|
144
|
+
| rs-fMRI | `fmri-skill` | preprocessing, denoising, ROI time series, connectivity | `fmri_output/` |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Phenotype Extraction
|
|
149
|
+
|
|
150
|
+
### Script: `scripts/extract_adhd200_phenotype.py`
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python skills/adhd200-skill/scripts/extract_adhd200_phenotype.py \
|
|
154
|
+
--phenotype-dir /path/to/adhd200_raw/phenotype \
|
|
155
|
+
--output /path/to/adhd200_output/phenotype/merged_phenotype.csv \
|
|
156
|
+
--columns subject,DX,AGE,SEX,ADHD_Index,Inatt,HyperImp \
|
|
157
|
+
--imaging-ids /path/to/adhd200_output/bids/participants.tsv
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## QC Integration
|
|
163
|
+
|
|
164
|
+
### Script: `scripts/adhd200_qc_summary.py`
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
python skills/adhd200-skill/scripts/adhd200_qc_summary.py \
|
|
168
|
+
--fmriprep-dir /path/to/adhd200_output/fmriprep \
|
|
169
|
+
--freesurfer-dir /path/to/adhd200_output/smri/freesurfer \
|
|
170
|
+
--output /path/to/adhd200_output/qc/qc_summary.csv \
|
|
171
|
+
--exclude-output /path/to/adhd200_output/qc/exclude_list.csv \
|
|
172
|
+
--fd-threshold 0.3
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Recommended Output Layout
|
|
178
|
+
All assets should be organized under `./adhd200_output/`:
|
|
179
|
+
- `adhd200_output/raw/` (downloaded original files)
|
|
180
|
+
- `adhd200_output/bids/` (staged BIDS data)
|
|
181
|
+
- `adhd200_output/smri/` (links or copies from `smri_output/`)
|
|
182
|
+
- `adhd200_output/fmri/` (links or copies from `fmri_output/`)
|
|
183
|
+
- `adhd200_output/phenotype/` (merged phenotype tables)
|
|
184
|
+
- `adhd200_output/qc/` (QC summaries and exclusion lists)
|
|
185
|
+
- `adhd200_output/logs/` (download + orchestration logs)
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Benchmark Adapter Guidance
|
|
190
|
+
|
|
191
|
+
For benchmark-style prompts, do not force the full `download -> staging -> multimodal processing` orchestration when the task is only asking for local ADHD-200 data staging or organization.
|
|
192
|
+
|
|
193
|
+
- If the task starts from raw ADHD-200 data already present on disk and only asks for BIDS-style staging / organization:
|
|
194
|
+
- skip the mandatory download stage
|
|
195
|
+
- default to the narrow path `local raw ADHD-200 discovery -> BIDS-style staging -> minimal metadata -> validation/report`
|
|
196
|
+
- In benchmark mode, do not require explicit confirmation before presenting the direct staging solution.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Safety and Execution Policy
|
|
201
|
+
- No execution before explicit plan confirmation.
|
|
202
|
+
- All execution must be routed via `claw-shell`.
|
|
203
|
+
- Missing dependencies must be resolved by `dependency-planner` before running.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Important Notes and Limitations
|
|
208
|
+
- ADHD-200 has heterogeneous acquisition parameters across 8 sites; site effects must be addressed in analysis.
|
|
209
|
+
- ADHD-200 subject IDs are numeric and vary in length across sites.
|
|
210
|
+
- Diagnosis labels vary by site (ADHD-combined, ADHD-inattentive, ADHD-hyperactive, typically developing).
|
|
211
|
+
- ADHD-200 data does not include task-fMRI; only resting-state fMRI is available.
|
|
212
|
+
- `adhd200-skill` is orchestration-only; detailed preprocessing logic remains in `smri-skill` and `fmri-skill`.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## When to Call This Skill
|
|
217
|
+
- User asks for end-to-end ADHD-200 workflow.
|
|
218
|
+
- User asks to download ADHD-200 data and then run sMRI/rs-fMRI processing.
|
|
219
|
+
- User needs BIDS staging for raw ADHD-200 NIfTI files.
|
|
220
|
+
- User asks to extract and merge ADHD-200 phenotype tables.
|
|
221
|
+
- User needs ADHD-200-specific QC summaries and exclusion lists.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Complementary / Related Skills
|
|
226
|
+
- `smri-skill`
|
|
227
|
+
- `fmri-skill`
|
|
228
|
+
- `bids-organizer`
|
|
229
|
+
- `fmriprep-tool`
|
|
230
|
+
- `freesurfer-tool`
|
|
231
|
+
- `brain_gnn`
|
|
232
|
+
- `dependency-planner`
|
|
233
|
+
- `conda-env-manager`
|
|
234
|
+
- `claw-shell`
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Reference
|
|
239
|
+
- ADHD-200: https://fcon_1000.projects.nitrc.org/indi/adhd200/
|
|
240
|
+
- BIDS spec: https://bids.neuroimaging.io/
|
|
241
|
+
|
|
242
|
+
Created At: 2026-05-06 01:50 HKT
|
|
243
|
+
Last Updated At: 2026-05-06 01:50 HKT
|
|
244
|
+
Author: chengwang96
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate per-subject QC summaries and exclusion lists for ADHD-200."""
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, List, Tuple
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import pandas as pd
|
|
10
|
+
except ImportError:
|
|
11
|
+
print("Error: pandas is required.", file=sys.stderr)
|
|
12
|
+
sys.exit(1)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def detect_delimiter(file_path: Path) -> str:
|
|
16
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
17
|
+
return "\t" if "\t" in f.readline() else ","
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def collect_fmriprep_qc(fmriprep_dir: Path) -> Dict[str, Dict[str, float]]:
|
|
21
|
+
qc = {}
|
|
22
|
+
for confounds_file in fmriprep_dir.rglob("**/*_desc-confounds_timeseries.tsv"):
|
|
23
|
+
subject_id = next((p for p in confounds_file.parts if p.startswith("sub-")), None)
|
|
24
|
+
if not subject_id:
|
|
25
|
+
continue
|
|
26
|
+
try:
|
|
27
|
+
df = pd.read_csv(confounds_file, sep=detect_delimiter(confounds_file), low_memory=False)
|
|
28
|
+
except Exception:
|
|
29
|
+
continue
|
|
30
|
+
fd_col = next((c for c in ["framewise_displacement", "fd", "FD"] if c in df.columns), None)
|
|
31
|
+
if fd_col:
|
|
32
|
+
fd = pd.to_numeric(df[fd_col], errors="coerce").dropna()
|
|
33
|
+
if len(fd) > 0:
|
|
34
|
+
metrics = {"mean_fd": float(fd.mean()), "max_fd": float(fd.max()), "n_volumes": len(df)}
|
|
35
|
+
if subject_id in qc:
|
|
36
|
+
qc[subject_id]["mean_fd"] = max(qc[subject_id].get("mean_fd", 0), metrics["mean_fd"])
|
|
37
|
+
qc[subject_id]["max_fd"] = max(qc[subject_id].get("max_fd", 0), metrics["max_fd"])
|
|
38
|
+
else:
|
|
39
|
+
qc[subject_id] = metrics
|
|
40
|
+
return qc
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def generate_qc_summary(fmriprep_qc: Dict, fd_threshold: float, max_fd_threshold: float) -> Tuple["pd.DataFrame", List[str]]:
|
|
44
|
+
rows = []
|
|
45
|
+
excluded = []
|
|
46
|
+
for sub_id in sorted(fmriprep_qc.keys()):
|
|
47
|
+
fp = fmriprep_qc[sub_id]
|
|
48
|
+
reasons = []
|
|
49
|
+
if fp.get("mean_fd", 0) > fd_threshold:
|
|
50
|
+
reasons.append(f"mean_fd={fp['mean_fd']:.3f}>{fd_threshold}")
|
|
51
|
+
if fp.get("max_fd", 0) > max_fd_threshold:
|
|
52
|
+
reasons.append(f"max_fd={fp['max_fd']:.3f}>{max_fd_threshold}")
|
|
53
|
+
row = {"subject_id": sub_id, "mean_fd": fp.get("mean_fd"), "max_fd": fp.get("max_fd"), "n_volumes": fp.get("n_volumes"), "exclude": bool(reasons), "exclude_reasons": "; ".join(reasons)}
|
|
54
|
+
if reasons:
|
|
55
|
+
excluded.append(sub_id)
|
|
56
|
+
rows.append(row)
|
|
57
|
+
return pd.DataFrame(rows), excluded
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main() -> int:
|
|
61
|
+
parser = argparse.ArgumentParser(description="Generate ADHD-200 QC summaries.")
|
|
62
|
+
parser.add_argument("--fmriprep-dir", help="Path to fMRIPrep output directory")
|
|
63
|
+
parser.add_argument("--output", required=True, help="Output path for QC summary CSV")
|
|
64
|
+
parser.add_argument("--exclude-output", help="Output path for exclusion list CSV")
|
|
65
|
+
parser.add_argument("--fd-threshold", type=float, default=0.3, help="Mean FD threshold (default: 0.3)")
|
|
66
|
+
parser.add_argument("--max-fd-threshold", type=float, default=5.0, help="Max FD threshold (default: 5.0)")
|
|
67
|
+
args = parser.parse_args()
|
|
68
|
+
|
|
69
|
+
fmriprep_qc = {}
|
|
70
|
+
if args.fmriprep_dir:
|
|
71
|
+
fp_dir = Path(args.fmriprep_dir).resolve()
|
|
72
|
+
if fp_dir.exists():
|
|
73
|
+
print(f"Collecting fMRIPrep QC from {fp_dir}...")
|
|
74
|
+
fmriprep_qc = collect_fmriprep_qc(fp_dir)
|
|
75
|
+
print(f" Found {len(fmriprep_qc)} subjects")
|
|
76
|
+
|
|
77
|
+
if not fmriprep_qc:
|
|
78
|
+
print("[ERROR] No QC data collected.", file=sys.stderr)
|
|
79
|
+
return 1
|
|
80
|
+
|
|
81
|
+
summary_df, excluded = generate_qc_summary(fmriprep_qc, args.fd_threshold, args.max_fd_threshold)
|
|
82
|
+
output_path = Path(args.output).resolve()
|
|
83
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
summary_df.to_csv(output_path, index=False)
|
|
85
|
+
print(f"\nQC Summary: {len(summary_df)} subjects -> {output_path}")
|
|
86
|
+
print(f" Excluded: {len(excluded)} / {len(summary_df)} ({100*len(excluded)/max(len(summary_df),1):.1f}%)")
|
|
87
|
+
|
|
88
|
+
if args.exclude_output:
|
|
89
|
+
exclude_path = Path(args.exclude_output).resolve()
|
|
90
|
+
exclude_path.parent.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
summary_df[summary_df["exclude"] == True][["subject_id", "exclude_reasons"]].to_csv(exclude_path, index=False)
|
|
92
|
+
print(f" Exclusion list: {exclude_path}")
|
|
93
|
+
|
|
94
|
+
return 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
sys.exit(main())
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Extract and merge ADHD-200 phenotype tables for downstream analysis."""
|
|
3
|
+
import argparse
|
|
4
|
+
import csv
|
|
5
|
+
import re
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, List, Optional, Set
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import pandas as pd
|
|
12
|
+
except ImportError:
|
|
13
|
+
print("Error: pandas is required. Install with: pip install pandas", file=sys.stderr)
|
|
14
|
+
sys.exit(1)
|
|
15
|
+
|
|
16
|
+
COLUMN_MAP = {
|
|
17
|
+
"subject": "subject_id",
|
|
18
|
+
"SUBJECT_ID": "subject_id",
|
|
19
|
+
"Subject": "subject_id",
|
|
20
|
+
"DX": "diagnosis",
|
|
21
|
+
"DX_GROUP": "diagnosis",
|
|
22
|
+
"AGE": "age",
|
|
23
|
+
"AGE_AT_SCAN": "age",
|
|
24
|
+
"SEX": "sex",
|
|
25
|
+
"ADHD_Index": "adhd_index",
|
|
26
|
+
"Inatt": "inattention",
|
|
27
|
+
"HyperImp": "hyperactivity",
|
|
28
|
+
"SITE_ID": "site",
|
|
29
|
+
"HANDEDNESS": "handedness",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def normalize_subject_id(raw_id) -> str:
|
|
34
|
+
clean = re.sub(r"[^a-zA-Z0-9]", "", str(raw_id).strip())
|
|
35
|
+
return f"sub-{clean}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def read_phenotype_file(file_path: Path) -> Optional["pd.DataFrame"]:
|
|
39
|
+
try:
|
|
40
|
+
return pd.read_csv(file_path, sep=None, engine="python", low_memory=False)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(f"[WARN] Failed to read {file_path}: {e}", file=sys.stderr)
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def main() -> int:
|
|
47
|
+
parser = argparse.ArgumentParser(description="Extract and merge ADHD-200 phenotype tables.")
|
|
48
|
+
parser.add_argument("--phenotype-dir", help="Directory containing ADHD-200 phenotype CSV files")
|
|
49
|
+
parser.add_argument("--phenotype-file", help="Direct path to ADHD-200 phenotype CSV file")
|
|
50
|
+
parser.add_argument("--output", required=True, help="Output path for merged phenotype CSV")
|
|
51
|
+
parser.add_argument("--columns", help="Comma-separated list of columns to select (default: all)")
|
|
52
|
+
parser.add_argument("--imaging-ids", help="Path to BIDS participants.tsv for imaging subject filtering")
|
|
53
|
+
parser.add_argument("--missing-threshold", type=float, default=0.5, help="Drop columns with > this fraction missing")
|
|
54
|
+
args = parser.parse_args()
|
|
55
|
+
|
|
56
|
+
phenotype_files = []
|
|
57
|
+
if args.phenotype_file:
|
|
58
|
+
p = Path(args.phenotype_file).resolve()
|
|
59
|
+
if p.exists():
|
|
60
|
+
phenotype_files.append(p)
|
|
61
|
+
elif args.phenotype_dir:
|
|
62
|
+
phenotype_dir = Path(args.phenotype_dir).resolve()
|
|
63
|
+
if phenotype_dir.exists():
|
|
64
|
+
phenotype_files = sorted(f for f in phenotype_dir.iterdir() if f.is_file() and f.suffix in (".csv", ".tsv"))
|
|
65
|
+
|
|
66
|
+
if not phenotype_files:
|
|
67
|
+
print("[ERROR] No phenotype files found.", file=sys.stderr)
|
|
68
|
+
return 1
|
|
69
|
+
|
|
70
|
+
print(f"Found {len(phenotype_files)} phenotype file(s)")
|
|
71
|
+
|
|
72
|
+
dataframes = []
|
|
73
|
+
for f in phenotype_files:
|
|
74
|
+
df = read_phenotype_file(f)
|
|
75
|
+
if df is not None and len(df) > 0:
|
|
76
|
+
rename = {k: v for k, v in COLUMN_MAP.items() if k in df.columns and v not in df.columns}
|
|
77
|
+
df = df.rename(columns=rename)
|
|
78
|
+
dataframes.append(df)
|
|
79
|
+
|
|
80
|
+
if not dataframes:
|
|
81
|
+
print("[ERROR] No data loaded.", file=sys.stderr)
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
merged = dataframes[0]
|
|
85
|
+
for df in dataframes[1:]:
|
|
86
|
+
if "subject_id" in merged.columns and "subject_id" in df.columns:
|
|
87
|
+
new_cols = [c for c in df.columns if c not in merged.columns or c == "subject_id"]
|
|
88
|
+
merged = pd.merge(merged, df[new_cols], on="subject_id", how="outer", suffixes=("", "_dup"))
|
|
89
|
+
dup_cols = [c for c in merged.columns if c.endswith("_dup")]
|
|
90
|
+
if dup_cols:
|
|
91
|
+
merged = merged.drop(columns=dup_cols)
|
|
92
|
+
else:
|
|
93
|
+
merged = pd.concat([merged, df], ignore_index=True)
|
|
94
|
+
|
|
95
|
+
if args.imaging_ids:
|
|
96
|
+
imaging_path = Path(args.imaging_ids).resolve()
|
|
97
|
+
if imaging_path.exists() and "subject_id" in merged.columns:
|
|
98
|
+
id_df = pd.read_csv(imaging_path, sep="\t")
|
|
99
|
+
for col in ["participant_id", "subject_id"]:
|
|
100
|
+
if col in id_df.columns:
|
|
101
|
+
imaging_ids = set(id_df[col].astype(str).str.strip())
|
|
102
|
+
normalized = {normalize_subject_id(sid) for sid in imaging_ids} | imaging_ids
|
|
103
|
+
merged["_norm"] = merged["subject_id"].apply(normalize_subject_id)
|
|
104
|
+
merged = merged[merged["_norm"].isin(normalized) | merged["subject_id"].astype(str).isin(normalized)]
|
|
105
|
+
merged = merged.drop(columns=["_norm"])
|
|
106
|
+
break
|
|
107
|
+
|
|
108
|
+
if args.columns:
|
|
109
|
+
requested = [c.strip() for c in args.columns.split(",")]
|
|
110
|
+
available = [c for c in requested if c in merged.columns]
|
|
111
|
+
if "subject_id" not in available and "subject_id" in merged.columns:
|
|
112
|
+
available = ["subject_id"] + available
|
|
113
|
+
if available:
|
|
114
|
+
merged = merged[available]
|
|
115
|
+
|
|
116
|
+
if args.missing_threshold < 1.0:
|
|
117
|
+
missing_frac = merged.isnull().mean()
|
|
118
|
+
cols_to_drop = [c for c in missing_frac[missing_frac > args.missing_threshold].index if c not in ("subject_id", "diagnosis")]
|
|
119
|
+
if cols_to_drop:
|
|
120
|
+
merged = merged.drop(columns=cols_to_drop)
|
|
121
|
+
|
|
122
|
+
output_path = Path(args.output).resolve()
|
|
123
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
124
|
+
merged.to_csv(output_path, index=False)
|
|
125
|
+
print(f"\nWrote {len(merged)} rows x {len(merged.columns)} columns to {output_path}")
|
|
126
|
+
|
|
127
|
+
if "diagnosis" in merged.columns:
|
|
128
|
+
print(f"\nDiagnosis distribution:\n{merged['diagnosis'].value_counts().to_string()}")
|
|
129
|
+
|
|
130
|
+
return 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
sys.exit(main())
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Reorganize ADHD-200 raw data into BIDS-compliant directory structure.
|
|
3
|
+
|
|
4
|
+
Handles FCP/INDI-style subject directories, site extraction, and modality
|
|
5
|
+
routing for T1w and rs-fMRI.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import csv
|
|
9
|
+
import json
|
|
10
|
+
import re
|
|
11
|
+
import shutil
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, List, Optional, Tuple
|
|
15
|
+
|
|
16
|
+
SIDECAR_EXTENSIONS = [".json", ".bval", ".bvec", ".tsv"]
|
|
17
|
+
|
|
18
|
+
ADHD200_SITES = [
|
|
19
|
+
"Peking", "Brown", "NYU", "KKI", "NeuroImage",
|
|
20
|
+
"OHSU", "Pitt", "WashU", "Washington",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def normalize_subject_id(raw_id: str) -> str:
|
|
25
|
+
clean = re.sub(r"[^a-zA-Z0-9]", "", str(raw_id).strip())
|
|
26
|
+
return f"sub-{clean}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def detect_site_from_path(file_path: Path, root_dir: Path) -> str:
|
|
30
|
+
rel = file_path.relative_to(root_dir)
|
|
31
|
+
for part in rel.parts:
|
|
32
|
+
for site in ADHD200_SITES:
|
|
33
|
+
if site.lower() in part.lower():
|
|
34
|
+
return site
|
|
35
|
+
return "unknown"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def detect_modality(directory: Path, filename: str) -> Optional[Tuple[str, str]]:
|
|
39
|
+
name_lower = (directory.name + " " + filename).lower()
|
|
40
|
+
if any(k in name_lower for k in ["t1w", "t1", "anat", "mprage"]):
|
|
41
|
+
if "bold" not in name_lower:
|
|
42
|
+
return ("T1w", "anat")
|
|
43
|
+
if any(k in name_lower for k in ["rest", "bold", "fmri", "func", "rsfmri"]):
|
|
44
|
+
return ("task-rest_bold", "func")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def find_nifti_files(directory: Path) -> List[Path]:
|
|
49
|
+
return [
|
|
50
|
+
f for f in directory.rglob("*")
|
|
51
|
+
if f.is_file() and (f.name.endswith(".nii") or f.name.endswith(".nii.gz"))
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def copy_with_sidecars(src_nifti: Path, dst_dir: Path, dst_stem: str) -> None:
|
|
56
|
+
dst_dir.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
ext = ".nii.gz" if src_nifti.name.endswith(".nii.gz") else ".nii"
|
|
58
|
+
dst_nifti = dst_dir / f"{dst_stem}{ext}"
|
|
59
|
+
if not dst_nifti.exists():
|
|
60
|
+
shutil.copy2(str(src_nifti), str(dst_nifti))
|
|
61
|
+
|
|
62
|
+
src_stem = src_nifti.name[:-7] if src_nifti.name.endswith(".nii.gz") else src_nifti.name[:-4]
|
|
63
|
+
for sidecar_ext in SIDECAR_EXTENSIONS:
|
|
64
|
+
src_sidecar = src_nifti.parent / f"{src_stem}{sidecar_ext}"
|
|
65
|
+
if src_sidecar.exists():
|
|
66
|
+
dst_sidecar = dst_dir / f"{dst_stem}{sidecar_ext}"
|
|
67
|
+
if not dst_sidecar.exists():
|
|
68
|
+
shutil.copy2(str(src_sidecar), str(dst_sidecar))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def write_dataset_description(bids_root: Path) -> None:
|
|
72
|
+
desc = {
|
|
73
|
+
"Name": "ADHD-200",
|
|
74
|
+
"BIDSVersion": "1.8.0",
|
|
75
|
+
"DatasetType": "raw",
|
|
76
|
+
"GeneratedBy": [{"Name": "NeuroClaw adhd200-skill", "Version": "1.0.0"}],
|
|
77
|
+
}
|
|
78
|
+
(bids_root / "dataset_description.json").write_text(
|
|
79
|
+
json.dumps(desc, indent=2), encoding="utf-8"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def write_participants_tsv(bids_root: Path, participants: List[Dict[str, str]], phenotype_file: Optional[Path] = None) -> None:
|
|
84
|
+
phenotype_map: Dict[str, Dict[str, str]] = {}
|
|
85
|
+
if phenotype_file and phenotype_file.exists():
|
|
86
|
+
try:
|
|
87
|
+
with open(phenotype_file, "r", encoding="utf-8") as f:
|
|
88
|
+
reader = csv.DictReader(f)
|
|
89
|
+
for row in reader:
|
|
90
|
+
sid = row.get("subject", row.get("SUBJECT_ID", row.get("Subject", "")))
|
|
91
|
+
if sid:
|
|
92
|
+
phenotype_map[normalize_subject_id(sid)] = row
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
tsv_path = bids_root / "participants.tsv"
|
|
97
|
+
headers = ["participant_id", "site"]
|
|
98
|
+
if phenotype_map:
|
|
99
|
+
sample = next(iter(phenotype_map.values()))
|
|
100
|
+
for col in sample:
|
|
101
|
+
if col not in headers and col not in ("subject", "SUBJECT_ID", "Subject"):
|
|
102
|
+
headers.append(col)
|
|
103
|
+
|
|
104
|
+
with open(tsv_path, "w", encoding="utf-8", newline="") as f:
|
|
105
|
+
writer = csv.writer(f, delimiter="\t")
|
|
106
|
+
writer.writerow(headers)
|
|
107
|
+
seen = set()
|
|
108
|
+
for p in participants:
|
|
109
|
+
pid = p["participant_id"]
|
|
110
|
+
if pid in seen:
|
|
111
|
+
continue
|
|
112
|
+
seen.add(pid)
|
|
113
|
+
row = [pid, p.get("site", "unknown")]
|
|
114
|
+
pheno = phenotype_map.get(pid, {})
|
|
115
|
+
for col in headers[2:]:
|
|
116
|
+
row.append(pheno.get(col, "n/a"))
|
|
117
|
+
writer.writerow(row)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def main() -> int:
|
|
121
|
+
parser = argparse.ArgumentParser(description="Reorganize ADHD-200 raw data into BIDS structure.")
|
|
122
|
+
parser.add_argument("--input", required=True, help="Path to ADHD-200 raw data directory")
|
|
123
|
+
parser.add_argument("--output", required=True, help="Path to output BIDS directory")
|
|
124
|
+
parser.add_argument("--phenotype", help="Path to ADHD-200 phenotype CSV file")
|
|
125
|
+
parser.add_argument("--dry-run", action="store_true", help="Preview without copying files")
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
input_dir = Path(args.input).resolve()
|
|
129
|
+
output_dir = Path(args.output).resolve()
|
|
130
|
+
|
|
131
|
+
if not input_dir.exists():
|
|
132
|
+
print(f"Input directory does not exist: {input_dir}", file=sys.stderr)
|
|
133
|
+
return 1
|
|
134
|
+
|
|
135
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
136
|
+
participants: List[Dict[str, str]] = []
|
|
137
|
+
converted = skipped = failed = 0
|
|
138
|
+
|
|
139
|
+
print(f"{'[DRY RUN] ' if args.dry_run else ''}Starting ADHD-200 reorganization...\n")
|
|
140
|
+
|
|
141
|
+
subject_dirs = sorted([p for p in input_dir.iterdir() if p.is_dir() and not p.name.startswith(".")])
|
|
142
|
+
|
|
143
|
+
for subject_dir in subject_dirs:
|
|
144
|
+
site = detect_site_from_path(subject_dir, input_dir)
|
|
145
|
+
nifti_files = find_nifti_files(subject_dir)
|
|
146
|
+
|
|
147
|
+
if not nifti_files:
|
|
148
|
+
# Treat as site directory
|
|
149
|
+
for sub_dir in sorted(subject_dir.iterdir()):
|
|
150
|
+
if not sub_dir.is_dir():
|
|
151
|
+
continue
|
|
152
|
+
sub_label = normalize_subject_id(sub_dir.name)
|
|
153
|
+
participants.append({"participant_id": sub_label, "site": site})
|
|
154
|
+
for nifti in find_nifti_files(sub_dir):
|
|
155
|
+
result = detect_modality(nifti.parent, nifti.name)
|
|
156
|
+
if result is None:
|
|
157
|
+
result = detect_modality(sub_dir, nifti.name)
|
|
158
|
+
if result is None:
|
|
159
|
+
failed += 1
|
|
160
|
+
continue
|
|
161
|
+
bids_suffix, bids_folder = result
|
|
162
|
+
bids_sub_dir = output_dir / sub_label / "ses-1" / bids_folder
|
|
163
|
+
dst_stem = f"{sub_label}_ses-1_{bids_suffix}"
|
|
164
|
+
if (bids_sub_dir / f"{dst_stem}.nii.gz").exists():
|
|
165
|
+
skipped += 1
|
|
166
|
+
continue
|
|
167
|
+
if args.dry_run:
|
|
168
|
+
print(f"[DRY] {sub_label}/ses-1/{bids_folder}/{dst_stem}")
|
|
169
|
+
else:
|
|
170
|
+
copy_with_sidecars(nifti, bids_sub_dir, dst_stem)
|
|
171
|
+
print(f"[OK] {sub_label} ({site}) / {bids_folder} / {dst_stem}")
|
|
172
|
+
converted += 1
|
|
173
|
+
else:
|
|
174
|
+
sub_label = normalize_subject_id(subject_dir.name)
|
|
175
|
+
participants.append({"participant_id": sub_label, "site": site})
|
|
176
|
+
for nifti in nifti_files:
|
|
177
|
+
result = detect_modality(nifti.parent, nifti.name)
|
|
178
|
+
if result is None:
|
|
179
|
+
result = detect_modality(subject_dir, nifti.name)
|
|
180
|
+
if result is None:
|
|
181
|
+
failed += 1
|
|
182
|
+
continue
|
|
183
|
+
bids_suffix, bids_folder = result
|
|
184
|
+
bids_sub_dir = output_dir / sub_label / "ses-1" / bids_folder
|
|
185
|
+
dst_stem = f"{sub_label}_ses-1_{bids_suffix}"
|
|
186
|
+
if (bids_sub_dir / f"{dst_stem}.nii.gz").exists():
|
|
187
|
+
skipped += 1
|
|
188
|
+
continue
|
|
189
|
+
if args.dry_run:
|
|
190
|
+
print(f"[DRY] {sub_label}/ses-1/{bids_folder}/{dst_stem}")
|
|
191
|
+
else:
|
|
192
|
+
copy_with_sidecars(nifti, bids_sub_dir, dst_stem)
|
|
193
|
+
print(f"[OK] {sub_label} ({site}) / {bids_folder} / {dst_stem}")
|
|
194
|
+
converted += 1
|
|
195
|
+
|
|
196
|
+
if not args.dry_run and converted > 0:
|
|
197
|
+
write_dataset_description(output_dir)
|
|
198
|
+
phenotype_path = Path(args.phenotype).resolve() if args.phenotype else None
|
|
199
|
+
write_participants_tsv(output_dir, participants, phenotype_path)
|
|
200
|
+
|
|
201
|
+
print(f"\nDone. Converted={converted}, Skipped={skipped}, Failed={failed}")
|
|
202
|
+
return 0 if failed == 0 else 2
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
sys.exit(main())
|