@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,138 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Extract and merge PPMI phenotype data.
|
|
3
|
+
|
|
4
|
+
Reads PPMI phenotype files (MDS-UPDRS, MoCA, DAT, demographics)
|
|
5
|
+
and produces a merged phenotype table aligned with imaging subject list.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import csv
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
COLUMN_MAP = {
|
|
14
|
+
"subject_id": ["subject", "Subject", "participant_id", "SubID", "PATNO"],
|
|
15
|
+
"age": ["age", "Age", "Age_at_visit"],
|
|
16
|
+
"sex": ["sex", "Sex", "Gender"],
|
|
17
|
+
"diagnosis": ["diagnosis", "Diagnosis", "Group", "COHORT"],
|
|
18
|
+
"diagnosis_detail": ["diagnosis_detail", "Diagnosis_Detail"],
|
|
19
|
+
# Motor
|
|
20
|
+
"mds_updrs_iii": ["MDS_UPDRS_III", "mds_updrs_iii", "NP3TOT"],
|
|
21
|
+
"mds_updrs_total": ["MDS_UPDRS_Total", "mds_updrs_total"],
|
|
22
|
+
"h_y": ["H_Y", "h_y", "HoehnYahr"],
|
|
23
|
+
# Cognitive
|
|
24
|
+
"moca": ["MoCA", "moca", "MCATOT"],
|
|
25
|
+
# Olfaction
|
|
26
|
+
"upsit": ["UPSIT", "upsit", "UPSIT_Total"],
|
|
27
|
+
# Sleep
|
|
28
|
+
"rbdsq": ["RBDSQ", "rbdsq"],
|
|
29
|
+
# DAT imaging
|
|
30
|
+
"dat_sbr": ["DAT_SBR", "dat_sbr", "CAUDATE_SBR", "PUTAMEN_SBR"],
|
|
31
|
+
# Biomarkers
|
|
32
|
+
"csf_abeta": ["CSF_ABeta", "csf_abeta"],
|
|
33
|
+
"csf_tau": ["CSF_tau", "csf_tau"],
|
|
34
|
+
"csf_ptau": ["CSF_ptau", "csf_ptau"],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def load_csv(path: Path) -> List[Dict[str, str]]:
|
|
39
|
+
delimiter = "\t" if path.suffix == ".tsv" else ","
|
|
40
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
41
|
+
reader = csv.DictReader(f, delimiter=delimiter)
|
|
42
|
+
return list(reader)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def find_column(row: Dict[str, str], candidates: List[str]) -> Optional[str]:
|
|
46
|
+
for col in candidates:
|
|
47
|
+
if col in row:
|
|
48
|
+
return col
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def extract_phenotype(
|
|
53
|
+
phenotype_files: List[Path],
|
|
54
|
+
imaging_ids: Optional[List[str]] = None,
|
|
55
|
+
columns: Optional[List[str]] = None,
|
|
56
|
+
) -> List[Dict[str, str]]:
|
|
57
|
+
all_data = []
|
|
58
|
+
for fpath in phenotype_files:
|
|
59
|
+
rows = load_csv(fpath)
|
|
60
|
+
all_data.extend(rows)
|
|
61
|
+
|
|
62
|
+
if not all_data:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
target_columns = columns if columns else list(COLUMN_MAP.keys())
|
|
66
|
+
merged = {}
|
|
67
|
+
|
|
68
|
+
for row in all_data:
|
|
69
|
+
subj_col = find_column(row, COLUMN_MAP["subject_id"])
|
|
70
|
+
if subj_col is None:
|
|
71
|
+
continue
|
|
72
|
+
subj_id = row[subj_col].strip()
|
|
73
|
+
if not subj_id:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if subj_id not in merged:
|
|
77
|
+
merged[subj_id] = {"subject_id": subj_id}
|
|
78
|
+
|
|
79
|
+
for target_col in target_columns:
|
|
80
|
+
if target_col == "subject_id":
|
|
81
|
+
continue
|
|
82
|
+
if target_col in merged[subj_id] and merged[subj_id][target_col]:
|
|
83
|
+
continue
|
|
84
|
+
candidates = COLUMN_MAP.get(target_col, [target_col])
|
|
85
|
+
src_col = find_column(row, candidates)
|
|
86
|
+
if src_col and row.get(src_col, "").strip():
|
|
87
|
+
merged[subj_id][target_col] = row[src_col].strip()
|
|
88
|
+
|
|
89
|
+
result = list(merged.values())
|
|
90
|
+
if imaging_ids:
|
|
91
|
+
imaging_set = set(imaging_ids)
|
|
92
|
+
result = [r for r in result if r["subject_id"] in imaging_set]
|
|
93
|
+
return result
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def main() -> int:
|
|
97
|
+
parser = argparse.ArgumentParser(description="Extract PPMI phenotype data.")
|
|
98
|
+
parser.add_argument("--phenotype-files", required=True, nargs="+")
|
|
99
|
+
parser.add_argument("--output", required=True)
|
|
100
|
+
parser.add_argument("--imaging-ids")
|
|
101
|
+
parser.add_argument("--columns")
|
|
102
|
+
args = parser.parse_args()
|
|
103
|
+
|
|
104
|
+
phenotype_files = [Path(f).resolve() for f in args.phenotype_files]
|
|
105
|
+
for f in phenotype_files:
|
|
106
|
+
if not f.exists():
|
|
107
|
+
print(f"File not found: {f}", file=sys.stderr)
|
|
108
|
+
return 1
|
|
109
|
+
|
|
110
|
+
imaging_ids = None
|
|
111
|
+
if args.imaging_ids:
|
|
112
|
+
id_file = Path(args.imaging_ids).resolve()
|
|
113
|
+
if id_file.exists():
|
|
114
|
+
imaging_ids = [l.strip() for l in id_file.read_text().splitlines() if l.strip()]
|
|
115
|
+
|
|
116
|
+
columns = None
|
|
117
|
+
if args.columns:
|
|
118
|
+
columns = [c.strip() for c in args.columns.split(",")]
|
|
119
|
+
|
|
120
|
+
merged = extract_phenotype(phenotype_files, imaging_ids, columns)
|
|
121
|
+
if not merged:
|
|
122
|
+
print("[ERROR] No phenotype data extracted.", file=sys.stderr)
|
|
123
|
+
return 1
|
|
124
|
+
|
|
125
|
+
output_path = Path(args.output).resolve()
|
|
126
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
127
|
+
fieldnames = list(merged[0].keys())
|
|
128
|
+
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
|
129
|
+
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
130
|
+
writer.writeheader()
|
|
131
|
+
writer.writerows(merged)
|
|
132
|
+
|
|
133
|
+
print(f"Phenotype: {len(merged)} subjects, {len(fieldnames)} columns -> {output_path}")
|
|
134
|
+
return 0
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
sys.exit(main())
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate per-subject QC summaries for PPMI processing.
|
|
3
|
+
|
|
4
|
+
PD-specific: tracks diagnostic group and applies appropriate QC criteria.
|
|
5
|
+
"""
|
|
6
|
+
import argparse
|
|
7
|
+
import csv
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, List
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_confounds(confounds_path: Path) -> Dict[str, float]:
|
|
14
|
+
metrics = {"fd_mean": float("nan"), "fd_max": float("nan")}
|
|
15
|
+
try:
|
|
16
|
+
import pandas as pd
|
|
17
|
+
df = pd.read_csv(confounds_path, sep="\t")
|
|
18
|
+
if "framewise_displacement" in df.columns:
|
|
19
|
+
fd = df["framewise_displacement"].dropna()
|
|
20
|
+
metrics["fd_mean"] = float(fd.mean())
|
|
21
|
+
metrics["fd_max"] = float(fd.max())
|
|
22
|
+
except Exception:
|
|
23
|
+
pass
|
|
24
|
+
return metrics
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def check_exclusion(metrics: Dict[str, float], fd_threshold: float = 0.3) -> List[str]:
|
|
28
|
+
reasons = []
|
|
29
|
+
if not (metrics["fd_mean"] != metrics["fd_mean"]):
|
|
30
|
+
if metrics["fd_mean"] > fd_threshold:
|
|
31
|
+
reasons.append(f"FD mean {metrics['fd_mean']:.3f} > {fd_threshold}")
|
|
32
|
+
return reasons
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main() -> int:
|
|
36
|
+
parser = argparse.ArgumentParser(description="Generate QC summaries for PPMI processing.")
|
|
37
|
+
parser.add_argument("--fmriprep-dir", help="Path to fMRIPrep output directory")
|
|
38
|
+
parser.add_argument("--output", required=True)
|
|
39
|
+
parser.add_argument("--exclude-output")
|
|
40
|
+
parser.add_argument("--fd-threshold", type=float, default=0.3)
|
|
41
|
+
parser.add_argument("--diagnosis-file", help="CSV with subject diagnosis info")
|
|
42
|
+
args = parser.parse_args()
|
|
43
|
+
|
|
44
|
+
output_path = Path(args.output).resolve()
|
|
45
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
|
|
47
|
+
diagnosis_map = {}
|
|
48
|
+
if args.diagnosis_file:
|
|
49
|
+
diag_path = Path(args.diagnosis_file).resolve()
|
|
50
|
+
if diag_path.exists():
|
|
51
|
+
with open(diag_path, "r", encoding="utf-8") as f:
|
|
52
|
+
reader = csv.DictReader(f)
|
|
53
|
+
for row in reader:
|
|
54
|
+
subj = row.get("subject_id") or row.get("PATNO", "")
|
|
55
|
+
diag = row.get("diagnosis") or row.get("Group") or row.get("COHORT", "")
|
|
56
|
+
if subj and diag:
|
|
57
|
+
diagnosis_map[subj] = diag
|
|
58
|
+
|
|
59
|
+
subjects = set()
|
|
60
|
+
if args.fmriprep_dir:
|
|
61
|
+
fmriprep_dir = Path(args.fmriprep_dir).resolve()
|
|
62
|
+
if fmriprep_dir.exists():
|
|
63
|
+
for d in fmriprep_dir.glob("sub-*"):
|
|
64
|
+
if d.is_dir():
|
|
65
|
+
subjects.add(d.name)
|
|
66
|
+
|
|
67
|
+
if not subjects:
|
|
68
|
+
print("[WARN] No subjects found.", file=sys.stderr)
|
|
69
|
+
return 1
|
|
70
|
+
|
|
71
|
+
results = []
|
|
72
|
+
excluded = []
|
|
73
|
+
for subj in sorted(subjects):
|
|
74
|
+
metrics = {"subject_id": subj}
|
|
75
|
+
if diagnosis_map:
|
|
76
|
+
metrics["diagnosis"] = diagnosis_map.get(subj, "unknown")
|
|
77
|
+
|
|
78
|
+
if args.fmriprep_dir:
|
|
79
|
+
confounds_files = list(Path(args.fmriprep_dir).glob(f"{subj}/func/*_desc-confounds_timeseries.tsv"))
|
|
80
|
+
if confounds_files:
|
|
81
|
+
metrics.update(load_confounds(confounds_files[0]))
|
|
82
|
+
|
|
83
|
+
exclusion_reasons = check_exclusion(metrics, args.fd_threshold)
|
|
84
|
+
metrics["excluded"] = len(exclusion_reasons) > 0
|
|
85
|
+
metrics["exclusion_reasons"] = "; ".join(exclusion_reasons)
|
|
86
|
+
|
|
87
|
+
results.append(metrics)
|
|
88
|
+
if exclusion_reasons:
|
|
89
|
+
excluded.append({"subject_id": subj, "reasons": "; ".join(exclusion_reasons)})
|
|
90
|
+
|
|
91
|
+
if results:
|
|
92
|
+
fieldnames = list(results[0].keys())
|
|
93
|
+
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
|
94
|
+
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
95
|
+
writer.writeheader()
|
|
96
|
+
writer.writerows(results)
|
|
97
|
+
print(f"QC: {len(results)} subjects, {len(excluded)} excluded -> {output_path}")
|
|
98
|
+
|
|
99
|
+
if args.exclude_output and excluded:
|
|
100
|
+
exclude_path = Path(args.exclude_output).resolve()
|
|
101
|
+
exclude_path.parent.mkdir(parents=True, exist_ok=True)
|
|
102
|
+
with open(exclude_path, "w", newline="", encoding="utf-8") as f:
|
|
103
|
+
writer = csv.DictWriter(f, fieldnames=["subject_id", "reasons"])
|
|
104
|
+
writer.writeheader()
|
|
105
|
+
writer.writerows(excluded)
|
|
106
|
+
|
|
107
|
+
return 0
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
sys.exit(main())
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate PPMI BIDS structure and generate compliance report.
|
|
3
|
+
|
|
4
|
+
Checks directory structure, diagnostic group completeness, and modality presence.
|
|
5
|
+
"""
|
|
6
|
+
import argparse
|
|
7
|
+
import csv
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, List
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate_subject(subject_dir: Path) -> Dict[str, any]:
|
|
14
|
+
report = {
|
|
15
|
+
"subject": subject_dir.name,
|
|
16
|
+
"anat_complete": False,
|
|
17
|
+
"rs_fMRI_present": False,
|
|
18
|
+
"task_fMRI_present": False,
|
|
19
|
+
"dwi_present": False,
|
|
20
|
+
"datscan_present": False,
|
|
21
|
+
"missing_files": [],
|
|
22
|
+
"warnings": [],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Check anat
|
|
26
|
+
anat_dir = subject_dir / "anat"
|
|
27
|
+
if anat_dir.exists():
|
|
28
|
+
t1w_files = list(anat_dir.glob("*_T1w.nii.gz"))
|
|
29
|
+
report["anat_complete"] = len(t1w_files) > 0
|
|
30
|
+
if not t1w_files:
|
|
31
|
+
report["missing_files"].append("anat/*_T1w.nii.gz")
|
|
32
|
+
else:
|
|
33
|
+
report["missing_files"].append("anat/")
|
|
34
|
+
|
|
35
|
+
# Check func
|
|
36
|
+
func_dir = subject_dir / "func"
|
|
37
|
+
if func_dir.exists():
|
|
38
|
+
rest_bold = list(func_dir.glob("*_task-rest_bold.nii.gz"))
|
|
39
|
+
task_bold = list(func_dir.glob("*_task-*_bold.nii.gz"))
|
|
40
|
+
task_bold = [f for f in task_bold if "task-rest" not in f.name]
|
|
41
|
+
report["rs_fMRI_present"] = len(rest_bold) > 0
|
|
42
|
+
report["task_fMRI_present"] = len(task_bold) > 0
|
|
43
|
+
else:
|
|
44
|
+
report["warnings"].append("No func directory")
|
|
45
|
+
|
|
46
|
+
# Check dwi
|
|
47
|
+
dwi_dir = subject_dir / "dwi"
|
|
48
|
+
if dwi_dir.exists():
|
|
49
|
+
dwi_files = list(dwi_dir.glob("*_dwi.nii.gz"))
|
|
50
|
+
report["dwi_present"] = len(dwi_files) > 0
|
|
51
|
+
else:
|
|
52
|
+
report["warnings"].append("No dwi directory")
|
|
53
|
+
|
|
54
|
+
# Check DaTscan (may be in pet/ or dat/)
|
|
55
|
+
for dat_dir_name in ["pet", "dat", "spect"]:
|
|
56
|
+
dat_dir = subject_dir / dat_dir_name
|
|
57
|
+
if dat_dir.exists():
|
|
58
|
+
report["datscan_present"] = True
|
|
59
|
+
break
|
|
60
|
+
|
|
61
|
+
return report
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main() -> int:
|
|
65
|
+
parser = argparse.ArgumentParser(description="Validate PPMI BIDS structure.")
|
|
66
|
+
parser.add_argument("--input", required=True)
|
|
67
|
+
parser.add_argument("--output", required=True)
|
|
68
|
+
args = parser.parse_args()
|
|
69
|
+
|
|
70
|
+
input_dir = Path(args.input).resolve()
|
|
71
|
+
if not input_dir.exists():
|
|
72
|
+
print(f"Input directory not found: {input_dir}", file=sys.stderr)
|
|
73
|
+
return 1
|
|
74
|
+
|
|
75
|
+
subjects = sorted([d for d in input_dir.glob("sub-*") if d.is_dir()])
|
|
76
|
+
print(f"Found {len(subjects)} subjects in {input_dir}")
|
|
77
|
+
|
|
78
|
+
if not subjects:
|
|
79
|
+
print("[ERROR] No subjects found.", file=sys.stderr)
|
|
80
|
+
return 1
|
|
81
|
+
|
|
82
|
+
results = []
|
|
83
|
+
for sub_dir in subjects:
|
|
84
|
+
report = validate_subject(sub_dir)
|
|
85
|
+
results.append(report)
|
|
86
|
+
|
|
87
|
+
output_path = Path(args.output).resolve()
|
|
88
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
|
|
90
|
+
fieldnames = [
|
|
91
|
+
"subject", "anat_complete", "rs_fMRI_present", "task_fMRI_present",
|
|
92
|
+
"dwi_present", "datscan_present", "missing_files", "warnings",
|
|
93
|
+
]
|
|
94
|
+
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
|
95
|
+
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
96
|
+
writer.writeheader()
|
|
97
|
+
for r in results:
|
|
98
|
+
r["missing_files"] = "; ".join(r["missing_files"])
|
|
99
|
+
r["warnings"] = "; ".join(r["warnings"])
|
|
100
|
+
writer.writerow(r)
|
|
101
|
+
|
|
102
|
+
complete = sum(1 for r in results if r["anat_complete"] and r["rs_fMRI_present"])
|
|
103
|
+
print(f"\nValidation Summary:")
|
|
104
|
+
print(f" Total subjects: {len(results)}")
|
|
105
|
+
print(f" Complete (anat + rs-fMRI): {complete}")
|
|
106
|
+
print(f" With T1w: {sum(1 for r in results if r['anat_complete'])}")
|
|
107
|
+
print(f" With rs-fMRI: {sum(1 for r in results if r['rs_fMRI_present'])}")
|
|
108
|
+
print(f" With task-fMRI: {sum(1 for r in results if r['task_fMRI_present'])}")
|
|
109
|
+
print(f" With dMRI: {sum(1 for r in results if r['dwi_present'])}")
|
|
110
|
+
print(f" With DaTscan: {sum(1 for r in results if r['datscan_present'])}")
|
|
111
|
+
print(f" Output: {output_path}")
|
|
112
|
+
|
|
113
|
+
return 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
sys.exit(main())
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qsiprep-tool
|
|
3
|
+
description: "Use this skill whenever the user wants to run QSIPrep (BIDS App) for diffusion MRI (DWI) preprocessing with best-practice workflows (topup/eddy, denoising/unringing options, susceptibility/motion correction, coregistration/normalization, QC reports) on BIDS datasets. This skill is the NeuroClaw interface-layer wrapper for QSIPrep: it checks installation (Docker/Singularity/conda), generates an execution plan with exact commands and resource estimates, waits for explicit confirmation, then routes all execution through claw-shell."
|
|
4
|
+
license: MIT License (NeuroClaw custom skill – freely modifiable within the project)
|
|
5
|
+
layer: base
|
|
6
|
+
skill_type: tool
|
|
7
|
+
dependencies:
|
|
8
|
+
- claw-shell
|
|
9
|
+
- bids-organizer
|
|
10
|
+
---
|
|
11
|
+
# QSIPrep Tool (Interface Layer)
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
QSIPrep is a BIDS-App pipeline for **diffusion MRI (DWI) preprocessing** that emphasizes:
|
|
15
|
+
- Robust distortion/motion/eddy-current correction
|
|
16
|
+
- Interoperable derivatives for downstream modeling (DTI/DKI/CSD, tractography, connectome, etc.)
|
|
17
|
+
- Strong QC reporting (HTML)
|
|
18
|
+
|
|
19
|
+
This skill is the **NeuroClaw interface-layer wrapper** for QSIPrep and strictly follows the NeuroClaw safety pattern:
|
|
20
|
+
|
|
21
|
+
1. Check whether QSIPrep is available (preferred: Docker/Singularity image; alternative: conda).
|
|
22
|
+
2. If missing → invoke `dependency-planner` to produce an installation plan.
|
|
23
|
+
3. Verify inputs (must be BIDS-compliant; detect DWI + fieldmaps/reverse-PE b0 if present).
|
|
24
|
+
4. Generate a clear numbered plan with **exact commands**, runtime/resource estimates, and risks.
|
|
25
|
+
5. Wait for explicit user confirmation (“YES” / “execute” / “proceed”).
|
|
26
|
+
6. On confirmation → delegate all commands to `claw-shell`.
|
|
27
|
+
7. Summarize outputs (derivatives paths + QC report location) and suggest next steps.
|
|
28
|
+
|
|
29
|
+
**Research use only.**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## What QSIPrep Typically Does (High-Level)
|
|
34
|
+
- Validates BIDS layout (or skips if requested)
|
|
35
|
+
- Creates brain mask(s)
|
|
36
|
+
- Denoising (optional), Gibbs unringing (optional)
|
|
37
|
+
- Susceptibility distortion correction (e.g., reverse phase-encoded b0 via topup-style approach)
|
|
38
|
+
- Eddy-current + motion correction (FSL eddy family behavior within containerized workflow)
|
|
39
|
+
- Gradient/bvec handling (rotation after motion correction)
|
|
40
|
+
- Coregistration to anatomical (and optionally standard space outputs)
|
|
41
|
+
- Produces derivatives + QC HTML reports
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Reference
|
|
46
|
+
|
|
47
|
+
| Task | Recommended Approach | Typical Output |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| Standard DWI preprocessing | QSIPrep BIDS-App `participant` | `derivatives/qsiprep/sub-*/dwi/*preproc_dwi.nii.gz` |
|
|
50
|
+
| Multi-subject run | `--participant-label sub-001 sub-002 ...` | per-subject derivatives |
|
|
51
|
+
| HPC / cluster | Singularity `.sif` execution | same derivatives |
|
|
52
|
+
| QC | Default QSIPrep reports | `derivatives/qsiprep/sub-*/figures/*.html` |
|
|
53
|
+
|
|
54
|
+
Typical runtime (very data-dependent): **~0.5–4+ hours per subject**.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Installation (Handled by `dependency-planner`)
|
|
59
|
+
Preferred: **Docker** (workstations) or **Singularity/Apptainer** (HPC).
|
|
60
|
+
|
|
61
|
+
Ask `dependency-planner` for one of:
|
|
62
|
+
- “Install Docker and pull latest QSIPrep image”
|
|
63
|
+
- “Install Apptainer/Singularity and pull QSIPrep .sif”
|
|
64
|
+
- “Install QSIPrep via conda (not recommended unless container is unavailable)”
|
|
65
|
+
|
|
66
|
+
Verification examples:
|
|
67
|
+
```bash
|
|
68
|
+
docker --version
|
|
69
|
+
docker image ls | grep -i qsiprep
|
|
70
|
+
# or
|
|
71
|
+
apptainer --version
|
|
72
|
+
apptainer exec qsiprep.sif qsiprep --version
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**FreeSurfer license**: QSIPrep often requires a FreeSurfer license file.
|
|
76
|
+
- Usually passed with: `--fs-license-file /path/to/license.txt`
|
|
77
|
+
- This skill will request it if not provided.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Common Command Templates (Executed via `claw-shell`)
|
|
82
|
+
|
|
83
|
+
### A) Docker (Recommended on workstations)
|
|
84
|
+
```bash
|
|
85
|
+
# Inputs:
|
|
86
|
+
BIDS_DIR=/data/bids
|
|
87
|
+
OUT_DIR=/data/derivatives
|
|
88
|
+
WORK_DIR=/data/work/qsiprep
|
|
89
|
+
FS_LICENSE=/data/license.txt
|
|
90
|
+
|
|
91
|
+
mkdir -p "$OUT_DIR" "$WORK_DIR"
|
|
92
|
+
|
|
93
|
+
docker run --rm -t \
|
|
94
|
+
-v "$BIDS_DIR":/data:ro \
|
|
95
|
+
-v "$OUT_DIR":/out \
|
|
96
|
+
-v "$WORK_DIR":/work \
|
|
97
|
+
-v "$FS_LICENSE":/opt/freesurfer/license.txt:ro \
|
|
98
|
+
pennbbl/qsiprep:latest \
|
|
99
|
+
/data /out participant \
|
|
100
|
+
--participant-label sub-001 \
|
|
101
|
+
--work-dir /work \
|
|
102
|
+
--fs-license-file /opt/freesurfer/license.txt \
|
|
103
|
+
--nthreads 16 --omp-nthreads 8 --mem-mb 64000
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### B) Singularity / Apptainer (Recommended on HPC)
|
|
107
|
+
```bash
|
|
108
|
+
BIDS_DIR=/data/bids
|
|
109
|
+
OUT_DIR=/data/derivatives
|
|
110
|
+
WORK_DIR=/data/work/qsiprep
|
|
111
|
+
FS_LICENSE=/data/license.txt
|
|
112
|
+
IMG=/images/qsiprep.sif
|
|
113
|
+
|
|
114
|
+
mkdir -p "$OUT_DIR" "$WORK_DIR"
|
|
115
|
+
|
|
116
|
+
apptainer run --cleanenv \
|
|
117
|
+
-B "$BIDS_DIR":/data:ro \
|
|
118
|
+
-B "$OUT_DIR":/out \
|
|
119
|
+
-B "$WORK_DIR":/work \
|
|
120
|
+
-B "$FS_LICENSE":/opt/freesurfer/license.txt:ro \
|
|
121
|
+
"$IMG" \
|
|
122
|
+
/data /out participant \
|
|
123
|
+
--participant-label sub-001 \
|
|
124
|
+
--work-dir /work \
|
|
125
|
+
--fs-license-file /opt/freesurfer/license.txt \
|
|
126
|
+
--nthreads 16 --omp-nthreads 8 --mem-mb 64000
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
> Notes:
|
|
130
|
+
> - Image name (`pennbbl/qsiprep:latest`) should be verified by `dependency-planner` against the latest official docs/releases.
|
|
131
|
+
> - Some flags vary by QSIPrep version; this skill will always generate commands after checking installed version.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## NeuroClaw recommended wrapper script (Reference): `qsiprep_wrapper.py`
|
|
136
|
+
|
|
137
|
+
> This wrapper only *builds and prints* a plan; actual execution must be routed through `claw-shell` by the calling skill.
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# qsiprep_wrapper.py (reference template)
|
|
141
|
+
import argparse
|
|
142
|
+
from pathlib import Path
|
|
143
|
+
from datetime import datetime
|
|
144
|
+
|
|
145
|
+
def build_qsiprep_cmd(engine, bids_dir, out_dir, work_dir, participant_labels, fs_license, img):
|
|
146
|
+
labels = " ".join(participant_labels) if participant_labels else ""
|
|
147
|
+
if engine == "docker":
|
|
148
|
+
cmd = f"""
|
|
149
|
+
mkdir -p "{out_dir}" "{work_dir}"
|
|
150
|
+
docker run --rm -t \
|
|
151
|
+
-v "{bids_dir}":/data:ro \
|
|
152
|
+
-v "{out_dir}":/out \
|
|
153
|
+
-v "{work_dir}":/work \
|
|
154
|
+
-v "{fs_license}":/opt/freesurfer/license.txt:ro \
|
|
155
|
+
{img} \
|
|
156
|
+
/data /out participant \
|
|
157
|
+
{"--participant-label " + labels if labels else ""} \
|
|
158
|
+
--work-dir /work \
|
|
159
|
+
--fs-license-file /opt/freesurfer/license.txt
|
|
160
|
+
""".strip()
|
|
161
|
+
else:
|
|
162
|
+
cmd = f"""
|
|
163
|
+
mkdir -p "{out_dir}" "{work_dir}"
|
|
164
|
+
apptainer run --cleanenv \
|
|
165
|
+
-B "{bids_dir}":/data:ro \
|
|
166
|
+
-B "{out_dir}":/out \
|
|
167
|
+
-B "{work_dir}":/work \
|
|
168
|
+
-B "{fs_license}":/opt/freesurfer/license.txt:ro \
|
|
169
|
+
"{img}" \
|
|
170
|
+
/data /out participant \
|
|
171
|
+
{"--participant-label " + labels if labels else ""} \
|
|
172
|
+
--work-dir /work \
|
|
173
|
+
--fs-license-file /opt/freesurfer/license.txt
|
|
174
|
+
""".strip()
|
|
175
|
+
return cmd
|
|
176
|
+
|
|
177
|
+
if __name__ == "__main__":
|
|
178
|
+
p = argparse.ArgumentParser()
|
|
179
|
+
p.add_argument("--engine", choices=["docker", "apptainer"], required=True)
|
|
180
|
+
p.add_argument("--bids-dir", required=True)
|
|
181
|
+
p.add_argument("--out-dir", required=True)
|
|
182
|
+
p.add_argument("--work-dir", required=True)
|
|
183
|
+
p.add_argument("--fs-license", required=True)
|
|
184
|
+
p.add_argument("--img", required=True, help="Docker image (e.g., pennbbl/qsiprep:latest) or .sif path")
|
|
185
|
+
p.add_argument("--participants", nargs="*", default=None)
|
|
186
|
+
args = p.parse_args()
|
|
187
|
+
|
|
188
|
+
cmd = build_qsiprep_cmd(
|
|
189
|
+
engine=args.engine,
|
|
190
|
+
bids_dir=Path(args.bids_dir).resolve(),
|
|
191
|
+
out_dir=Path(args.out_dir).resolve(),
|
|
192
|
+
work_dir=Path(args.work_dir).resolve(),
|
|
193
|
+
participant_labels=args.participants,
|
|
194
|
+
fs_license=Path(args.fs_license).resolve(),
|
|
195
|
+
img=args.img
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
tag = f"qsiprep_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
|
199
|
+
print("Execution plan (delegate to claw-shell):")
|
|
200
|
+
print(cmd)
|
|
201
|
+
print("\nLog tag suggestion:", tag)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Important Notes & Limitations
|
|
207
|
+
- **BIDS input is strongly recommended**. If you only have raw NIfTI/DICOM, use `bids-organizer` (and `dcm2nii`) first.
|
|
208
|
+
- QSIPrep benefits a lot from having **reverse phase-encoded b0 images (AP/PA)** or valid fieldmaps; otherwise distortion correction may be limited.
|
|
209
|
+
- Ensure adequate resources:
|
|
210
|
+
- RAM commonly **16–64 GB**
|
|
211
|
+
- Disk: work directory can be large (tens of GB)
|
|
212
|
+
- All execution must go through `claw-shell` due to long runtime and logging requirements.
|
|
213
|
+
- This skill does not replace downstream modeling (DTI/CSD/NODDI). After preprocessing, delegate to:
|
|
214
|
+
- `dipy-tool` for Python-based metrics/ROI features
|
|
215
|
+
- MRtrix/FSL-based workflows (future tool skills) for tractography/connectomes
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## When to Call This Skill
|
|
220
|
+
- User requests “run QSIPrep”, “preprocess DWI with QSIPrep”, “BIDS diffusion preprocessing”, “topup/eddy style pipeline with QC reports”.
|
|
221
|
+
- Before any quantitative diffusion features (FA/MD/tractometry/connectome) are extracted.
|
|
222
|
+
|
|
223
|
+
## Post-Execution Verification (Harness Integration)
|
|
224
|
+
|
|
225
|
+
After QSIPrep completes, this skill **automatically invokes harness-core's VerificationRunner** to validate diffusion preprocessing outputs:
|
|
226
|
+
|
|
227
|
+
**Integrated verification checks**:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from skills.harness_core import VerificationRunner, AuditLogger
|
|
231
|
+
import nibabel as nib
|
|
232
|
+
import numpy as np
|
|
233
|
+
from pathlib import Path
|
|
234
|
+
|
|
235
|
+
verifier = VerificationRunner(task_type="qsiprep_diffusion_preprocessing")
|
|
236
|
+
|
|
237
|
+
# 1. Preprocessed DWI files exist
|
|
238
|
+
verifier.add_check("preprocessed_dwi_exists",
|
|
239
|
+
checker=lambda: verify_preprocessed_dwi_files(output_dir),
|
|
240
|
+
severity="error"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# 2. Brain mask generated
|
|
244
|
+
verifier.add_check("brain_mask_generated",
|
|
245
|
+
checker=lambda: verify_brain_mask_exists(output_dir),
|
|
246
|
+
severity="error"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# 3. DWI data shape consistent and reasonable
|
|
250
|
+
verifier.add_check("dwi_shape_consistency",
|
|
251
|
+
checker=lambda: verify_dwi_shape(output_dir),
|
|
252
|
+
severity="error"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# 4. No NaN/Inf in preprocessed DWI
|
|
256
|
+
verifier.add_check("dwi_data_integrity",
|
|
257
|
+
checker=lambda: verify_dwi_no_nan_inf(output_dir),
|
|
258
|
+
severity="error"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# 5. Gradient table preserved and reasonable
|
|
262
|
+
verifier.add_check("gradient_table",
|
|
263
|
+
checker=lambda: verify_bval_bvec_files(output_dir),
|
|
264
|
+
severity="warning"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# 6. Motion/susceptibility distortion corrections applied
|
|
268
|
+
verifier.add_check("preprocessing_applied",
|
|
269
|
+
checker=lambda: verify_preprocessing_flags(output_dir),
|
|
270
|
+
severity="warning"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
# 7. Diffusion metrics (FA/MD) computable from output
|
|
274
|
+
verifier.add_check("diffusion_metric_bounds",
|
|
275
|
+
checker=lambda: verify_fa_md_bounds(output_dir),
|
|
276
|
+
severity="warning"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# 8. QC reports generated
|
|
280
|
+
verifier.add_check("qc_reports",
|
|
281
|
+
checker=lambda: verify_qc_html_reports(output_dir),
|
|
282
|
+
severity="warning"
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
report = verifier.run(output_dir)
|
|
286
|
+
|
|
287
|
+
# Log verification results
|
|
288
|
+
logger = AuditLogger(log_file=f"{output_dir}/qsiprep_verification.jsonl")
|
|
289
|
+
logger.log_validation(
|
|
290
|
+
task_name="qsiprep_diffusion_preprocessing",
|
|
291
|
+
checks_passed=len([r for r in report.results if r.passed]),
|
|
292
|
+
checks_failed=len([r for r in report.results if not r.passed]),
|
|
293
|
+
warnings=len([r for r in report.results if r.severity == "warning" and not r.passed]),
|
|
294
|
+
report_summary=report.to_dict()
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if report.failed:
|
|
298
|
+
raise ValueError(f"QSIPrep verification failed: {report.summary}")
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Output files generated**:
|
|
302
|
+
- `{output_dir}/qsiprep_verification.jsonl` — structured audit log
|
|
303
|
+
- `{output_dir}/.qsiprep_verification_timestamp` — completion marker
|
|
304
|
+
|
|
305
|
+
## Complementary / Related Skills
|
|
306
|
+
|
|
307
|
+
- `dependency-planner` → install Docker/Apptainer + QSIPrep image
|
|
308
|
+
- `docker-env-manager` → safe Docker operations (pull/run/prune) when needed
|
|
309
|
+
- `claw-shell` → mandatory safe execution layer
|
|
310
|
+
- `harness-core` → automated verification and audit logging
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Reference
|
|
315
|
+
- QSIPrep documentation and BIDS App usage (official docs; version-dependent)
|
|
316
|
+
- NeuroClaw interface-layer pattern aligned with `fmriprep-tool` and `hcppipeline-tool`
|
|
317
|
+
|
|
318
|
+
Created At: 2026-03-26 00:45 HKT
|
|
319
|
+
Last Updated At: 2026-04-05 02:01 HKT
|
|
320
|
+
Author: chengwang96
|