@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,96 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate per-subject QC summaries for BOLD5000."""
|
|
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
|
+
qc[subject_id]["n_volumes"] = qc[subject_id].get("n_volumes", 0) + metrics["n_volumes"]
|
|
39
|
+
else:
|
|
40
|
+
qc[subject_id] = metrics
|
|
41
|
+
return qc
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def main() -> int:
|
|
45
|
+
parser = argparse.ArgumentParser(description="Generate BOLD5000 QC summaries.")
|
|
46
|
+
parser.add_argument("--fmriprep-dir", help="Path to fMRIPrep output directory")
|
|
47
|
+
parser.add_argument("--output", required=True, help="Output path for QC summary CSV")
|
|
48
|
+
parser.add_argument("--exclude-output", help="Output path for exclusion list CSV")
|
|
49
|
+
parser.add_argument("--fd-threshold", type=float, default=0.3, help="Mean FD threshold (default: 0.3)")
|
|
50
|
+
parser.add_argument("--max-fd-threshold", type=float, default=5.0, help="Max FD threshold (default: 5.0)")
|
|
51
|
+
args = parser.parse_args()
|
|
52
|
+
|
|
53
|
+
fmriprep_qc = {}
|
|
54
|
+
if args.fmriprep_dir:
|
|
55
|
+
fp_dir = Path(args.fmriprep_dir).resolve()
|
|
56
|
+
if fp_dir.exists():
|
|
57
|
+
print(f"Collecting fMRIPrep QC from {fp_dir}...")
|
|
58
|
+
fmriprep_qc = collect_fmriprep_qc(fp_dir)
|
|
59
|
+
print(f" Found {len(fmriprep_qc)} subjects")
|
|
60
|
+
|
|
61
|
+
if not fmriprep_qc:
|
|
62
|
+
print("[ERROR] No QC data collected.", file=sys.stderr)
|
|
63
|
+
return 1
|
|
64
|
+
|
|
65
|
+
rows = []
|
|
66
|
+
excluded = []
|
|
67
|
+
for sub_id in sorted(fmriprep_qc.keys()):
|
|
68
|
+
fp = fmriprep_qc[sub_id]
|
|
69
|
+
reasons = []
|
|
70
|
+
if fp.get("mean_fd", 0) > args.fd_threshold:
|
|
71
|
+
reasons.append(f"mean_fd={fp['mean_fd']:.3f}>{args.fd_threshold}")
|
|
72
|
+
if fp.get("max_fd", 0) > args.max_fd_threshold:
|
|
73
|
+
reasons.append(f"max_fd={fp['max_fd']:.3f}>{args.max_fd_threshold}")
|
|
74
|
+
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)}
|
|
75
|
+
if reasons:
|
|
76
|
+
excluded.append(sub_id)
|
|
77
|
+
rows.append(row)
|
|
78
|
+
|
|
79
|
+
summary_df = pd.DataFrame(rows)
|
|
80
|
+
output_path = Path(args.output).resolve()
|
|
81
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
summary_df.to_csv(output_path, index=False)
|
|
83
|
+
print(f"\nQC Summary: {len(summary_df)} subjects -> {output_path}")
|
|
84
|
+
print(f" Excluded: {len(excluded)} / {len(summary_df)} ({100*len(excluded)/max(len(summary_df),1):.1f}%)")
|
|
85
|
+
|
|
86
|
+
if args.exclude_output:
|
|
87
|
+
exclude_path = Path(args.exclude_output).resolve()
|
|
88
|
+
exclude_path.parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
summary_df[summary_df["exclude"] == True][["subject_id", "exclude_reasons"]].to_csv(exclude_path, index=False)
|
|
90
|
+
print(f" Exclusion list: {exclude_path}")
|
|
91
|
+
|
|
92
|
+
return 0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
sys.exit(main())
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Extract and organize BOLD5000 stimulus metadata for downstream analysis."""
|
|
3
|
+
import argparse
|
|
4
|
+
import csv
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, List
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def extract_stimulus_metadata(stimulus_dir: Path, events_dir: Path = None) -> List[Dict[str, str]]:
|
|
12
|
+
"""Extract stimulus metadata from BOLD5000 stimulus files."""
|
|
13
|
+
metadata = []
|
|
14
|
+
|
|
15
|
+
# Look for stimulus images
|
|
16
|
+
image_extensions = {".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff"}
|
|
17
|
+
image_files = sorted(
|
|
18
|
+
f for f in stimulus_dir.rglob("*")
|
|
19
|
+
if f.is_file() and f.suffix.lower() in image_extensions
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
for img in image_files:
|
|
23
|
+
entry = {
|
|
24
|
+
"stimulus_file": img.name,
|
|
25
|
+
"stimulus_path": str(img.relative_to(stimulus_dir)),
|
|
26
|
+
"category": _extract_category(img),
|
|
27
|
+
}
|
|
28
|
+
metadata.append(entry)
|
|
29
|
+
|
|
30
|
+
# Look for event files if events_dir provided
|
|
31
|
+
if events_dir and events_dir.exists():
|
|
32
|
+
event_files = sorted(events_dir.rglob("*events.tsv"))
|
|
33
|
+
for ef in event_files:
|
|
34
|
+
try:
|
|
35
|
+
with open(ef, "r", encoding="utf-8") as f:
|
|
36
|
+
reader = csv.DictReader(f, delimiter="\t")
|
|
37
|
+
for row in reader:
|
|
38
|
+
if "stim_file" in row or "stimulus_file" in row:
|
|
39
|
+
stim = row.get("stim_file", row.get("stimulus_file", ""))
|
|
40
|
+
for entry in metadata:
|
|
41
|
+
if entry["stimulus_file"] == stim:
|
|
42
|
+
entry["onset"] = row.get("onset", "")
|
|
43
|
+
entry["duration"] = row.get("duration", "")
|
|
44
|
+
entry["trial_type"] = row.get("trial_type", "")
|
|
45
|
+
break
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
return metadata
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _extract_category(image_path: Path) -> str:
|
|
53
|
+
"""Try to extract category from image filename or parent directory."""
|
|
54
|
+
# BOLD5000 uses COCO categories in filenames
|
|
55
|
+
name = image_path.stem.lower()
|
|
56
|
+
parent = image_path.parent.name.lower()
|
|
57
|
+
|
|
58
|
+
# Common COCO/scene categories
|
|
59
|
+
categories = [
|
|
60
|
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
|
61
|
+
"truck", "boat", "traffic", "fire", "stop", "parking", "bench", "bird",
|
|
62
|
+
"cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra",
|
|
63
|
+
"giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
|
|
64
|
+
"skis", "snowboard", "sports", "kite", "baseball", "skateboard", "surfboard",
|
|
65
|
+
"tennis", "bottle", "wine", "cup", "fork", "knife", "spoon", "bowl",
|
|
66
|
+
"banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot",
|
|
67
|
+
"pizza", "donut", "cake", "chair", "couch", "potted", "bed", "dining",
|
|
68
|
+
"toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell",
|
|
69
|
+
"microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock",
|
|
70
|
+
"vase", "scissors", "teddy", "hair", "toothbrush", "indoor", "outdoor",
|
|
71
|
+
"scene", "building", "mountain", "forest", "ocean", "beach", "desert",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
for cat in categories:
|
|
75
|
+
if cat in name or cat in parent:
|
|
76
|
+
return cat
|
|
77
|
+
|
|
78
|
+
return "unknown"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def main() -> int:
|
|
82
|
+
parser = argparse.ArgumentParser(description="Extract BOLD5000 stimulus metadata.")
|
|
83
|
+
parser.add_argument("--stimulus-dir", required=True, help="Path to BOLD5000 stimuli directory")
|
|
84
|
+
parser.add_argument("--events-dir", help="Path to BOLD5000 events directory")
|
|
85
|
+
parser.add_argument("--output", required=True, help="Output path for stimulus metadata CSV")
|
|
86
|
+
args = parser.parse_args()
|
|
87
|
+
|
|
88
|
+
stimulus_dir = Path(args.stimulus_dir).resolve()
|
|
89
|
+
events_dir = Path(args.events_dir).resolve() if args.events_dir else None
|
|
90
|
+
|
|
91
|
+
if not stimulus_dir.exists():
|
|
92
|
+
print(f"Stimulus directory not found: {stimulus_dir}", file=sys.stderr)
|
|
93
|
+
return 1
|
|
94
|
+
|
|
95
|
+
print(f"Extracting stimulus metadata from {stimulus_dir}...")
|
|
96
|
+
metadata = extract_stimulus_metadata(stimulus_dir, events_dir)
|
|
97
|
+
|
|
98
|
+
if not metadata:
|
|
99
|
+
print("[WARN] No stimulus files found.")
|
|
100
|
+
return 1
|
|
101
|
+
|
|
102
|
+
output_path = Path(args.output).resolve()
|
|
103
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
|
|
105
|
+
with open(output_path, "w", encoding="utf-8", newline="") as f:
|
|
106
|
+
writer = csv.DictWriter(f, fieldnames=metadata[0].keys(), delimiter="\t")
|
|
107
|
+
writer.writeheader()
|
|
108
|
+
writer.writerows(metadata)
|
|
109
|
+
|
|
110
|
+
print(f"Wrote {len(metadata)} stimulus entries to {output_path}")
|
|
111
|
+
|
|
112
|
+
# Print category summary
|
|
113
|
+
categories = {}
|
|
114
|
+
for entry in metadata:
|
|
115
|
+
cat = entry.get("category", "unknown")
|
|
116
|
+
categories[cat] = categories.get(cat, 0) + 1
|
|
117
|
+
print(f"\nCategory distribution ({len(categories)} categories):")
|
|
118
|
+
for cat, count in sorted(categories.items(), key=lambda x: -x[1])[:15]:
|
|
119
|
+
print(f" {cat}: {count}")
|
|
120
|
+
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
sys.exit(main())
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Verify and reorganize BOLD5000 data into BIDS-compliant layout.
|
|
3
|
+
|
|
4
|
+
BOLD5000 from OpenNeuro is already in BIDS format; this script validates
|
|
5
|
+
and optionally copies/reorganizes the structure.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import json
|
|
9
|
+
import shutil
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def validate_bids_structure(root: Path) -> list:
|
|
15
|
+
"""Validate BIDS structure and return list of issues."""
|
|
16
|
+
issues = []
|
|
17
|
+
desc = root / "dataset_description.json"
|
|
18
|
+
if not desc.exists():
|
|
19
|
+
issues.append("Missing dataset_description.json")
|
|
20
|
+
else:
|
|
21
|
+
try:
|
|
22
|
+
data = json.loads(desc.read_text(encoding="utf-8"))
|
|
23
|
+
if "BIDSVersion" not in data:
|
|
24
|
+
issues.append("dataset_description.json missing BIDSVersion")
|
|
25
|
+
except Exception:
|
|
26
|
+
issues.append("dataset_description.json is not valid JSON")
|
|
27
|
+
|
|
28
|
+
participants = root / "participants.tsv"
|
|
29
|
+
if not participants.exists():
|
|
30
|
+
issues.append("Missing participants.tsv")
|
|
31
|
+
|
|
32
|
+
subject_dirs = sorted(root.glob("sub-*"))
|
|
33
|
+
if not subject_dirs:
|
|
34
|
+
issues.append("No subject directories found (sub-*)")
|
|
35
|
+
else:
|
|
36
|
+
for sub_dir in subject_dirs:
|
|
37
|
+
if not sub_dir.is_dir():
|
|
38
|
+
continue
|
|
39
|
+
anat = sub_dir / "anat"
|
|
40
|
+
func = sub_dir / "func"
|
|
41
|
+
if not anat.exists() and not func.exists():
|
|
42
|
+
# Check for session directories
|
|
43
|
+
ses_dirs = list(sub_dir.glob("ses-*"))
|
|
44
|
+
if not ses_dirs:
|
|
45
|
+
issues.append(f"{sub_dir.name}: no anat/, func/, or ses-* directories")
|
|
46
|
+
else:
|
|
47
|
+
for ses in ses_dirs:
|
|
48
|
+
if not (ses / "anat").exists() and not (ses / "func").exists():
|
|
49
|
+
issues.append(f"{sub_dir.name}/{ses.name}: no anat/ or func/ directories")
|
|
50
|
+
|
|
51
|
+
return issues
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main() -> int:
|
|
55
|
+
parser = argparse.ArgumentParser(description="Verify and reorganize BOLD5000 BIDS data.")
|
|
56
|
+
parser.add_argument("--input", required=True, help="Path to BOLD5000 data directory")
|
|
57
|
+
parser.add_argument("--output", help="Path to output BIDS directory (if copy needed)")
|
|
58
|
+
parser.add_argument("--validate-only", action="store_true", help="Only validate, do not copy")
|
|
59
|
+
parser.add_argument("--dry-run", action="store_true", help="Preview without copying")
|
|
60
|
+
args = parser.parse_args()
|
|
61
|
+
|
|
62
|
+
input_dir = Path(args.input).resolve()
|
|
63
|
+
if not input_dir.exists():
|
|
64
|
+
print(f"Input directory does not exist: {input_dir}", file=sys.stderr)
|
|
65
|
+
return 1
|
|
66
|
+
|
|
67
|
+
print(f"Validating BIDS structure at {input_dir}...")
|
|
68
|
+
issues = validate_bids_structure(input_dir)
|
|
69
|
+
|
|
70
|
+
if issues:
|
|
71
|
+
print(f"\nFound {len(issues)} issue(s):")
|
|
72
|
+
for issue in issues:
|
|
73
|
+
print(f" - {issue}")
|
|
74
|
+
else:
|
|
75
|
+
print("BIDS structure is valid.")
|
|
76
|
+
|
|
77
|
+
if args.validate_only:
|
|
78
|
+
return 1 if issues else 0
|
|
79
|
+
|
|
80
|
+
output_dir = Path(args.output).resolve() if args.output else None
|
|
81
|
+
if output_dir:
|
|
82
|
+
print(f"\n{'[DRY RUN] ' if args.dry_run else ''}Copying to {output_dir}...")
|
|
83
|
+
if not args.dry_run:
|
|
84
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
85
|
+
# Copy BIDS structure
|
|
86
|
+
for item in input_dir.iterdir():
|
|
87
|
+
dst = output_dir / item.name
|
|
88
|
+
if item.is_dir():
|
|
89
|
+
if not dst.exists():
|
|
90
|
+
shutil.copytree(str(item), str(dst))
|
|
91
|
+
else:
|
|
92
|
+
if not dst.exists():
|
|
93
|
+
shutil.copy2(str(item), str(dst))
|
|
94
|
+
print("Copy complete.")
|
|
95
|
+
else:
|
|
96
|
+
print("[DRY RUN] Would copy all BIDS files to output directory.")
|
|
97
|
+
|
|
98
|
+
return 0
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
sys.exit(main())
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: camcan-skill
|
|
3
|
+
description: "Use this skill whenever the user wants an end-to-end workflow for the Cam-CAN (Cambridge Centre for Ageing and Neuroscience) dataset, including BIDS validation, multimodal processing of sMRI, rs-fMRI, task-fMRI, and MEG, phenotype extraction, and QC integration. Triggers include: 'Cam-CAN', 'CamCAN', 'process Cam-CAN data', 'Cam-CAN MEG', 'Cam-CAN fMRI', or any request to run the Cam-CAN multimodal pipeline."
|
|
4
|
+
license: MIT License (NeuroClaw custom skill - freely modifiable within the project)
|
|
5
|
+
layer: subagent
|
|
6
|
+
skill_type: dataset
|
|
7
|
+
dependencies:
|
|
8
|
+
- smri-skill
|
|
9
|
+
- fmri-skill
|
|
10
|
+
- meg-skill
|
|
11
|
+
- bids-organizer
|
|
12
|
+
- claw-shell
|
|
13
|
+
complementary_skills:
|
|
14
|
+
- mne-eeg-tool
|
|
15
|
+
---
|
|
16
|
+
# Cam-CAN Skill (Dataset-Orchestration Layer)
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
`camcan-skill` is the NeuroClaw orchestration skill for the **Cam-CAN (Cambridge Centre for Ageing and Neuroscience)** dataset.
|
|
21
|
+
|
|
22
|
+
It strictly follows the NeuroClaw hierarchical design principles:
|
|
23
|
+
- This skill **only describes WHAT needs to be done** and **which tool skill to delegate to**.
|
|
24
|
+
- It contains **no implementation code or concrete commands**.
|
|
25
|
+
- All concrete execution is delegated to existing base/tool skills via `claw-shell`.
|
|
26
|
+
- Companion scripts in `scripts/` provide reference implementations for BIDS validation, phenotype extraction, and QC.
|
|
27
|
+
|
|
28
|
+
**Core workflow (never bypassed):**
|
|
29
|
+
1. Identify input Cam-CAN data and target modalities.
|
|
30
|
+
2. Generate a **numbered execution plan** clearly stating WHAT needs to be done and which tool skill will handle each step.
|
|
31
|
+
3. Present the full plan, estimated runtime, resource requirements, and risks to the user and wait for explicit confirmation ("YES" / "execute" / "proceed").
|
|
32
|
+
4. On confirmation, delegate every step to the appropriate skill via `claw-shell`.
|
|
33
|
+
5. After execution, save all outputs in a clean directory structure (`camcan_output/`).
|
|
34
|
+
|
|
35
|
+
**Research use only.**
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Quick Reference
|
|
40
|
+
|
|
41
|
+
| Task | What needs to be done | Delegate to | Expected output |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| BIDS validation | Validate Cam-CAN BIDS structure | `scripts/validate_camcan.py` | Validation report |
|
|
44
|
+
| sMRI processing | Brain extraction, tissue segmentation, cortical reconstruction | `smri-skill` | `smri_output/` derivatives |
|
|
45
|
+
| rs-fMRI processing | Preprocessing, denoising, connectivity | `fmri-skill` | `fmri_output/` derivatives |
|
|
46
|
+
| task-fMRI processing | Movie-watching task GLM, activation analysis | `fmri-skill` | `fmri_output/` task results |
|
|
47
|
+
| MEG processing | Source localization, time-frequency analysis | `meg-skill` | `meg_output/` TFR and source |
|
|
48
|
+
| Phenotype extraction | Cognitive, sensory, health measures | `scripts/extract_camcan_phenotype.py` | Merged phenotype CSV |
|
|
49
|
+
| QC summary | Per-subject quality control | `scripts/camcan_qc_summary.py` | QC summary + exclusion list |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Dataset Characteristics
|
|
54
|
+
|
|
55
|
+
- **Cohort**: ~700 participants spanning the adult lifespan (18-88 years)
|
|
56
|
+
- **Design**: Cross-sectional population-based sample
|
|
57
|
+
- **Site**: MRC Cognition and Brain Sciences Unit, Cambridge, UK
|
|
58
|
+
- **Scanner**: Siemens 3T TIM TRIO
|
|
59
|
+
- **MEG system**: CTF 275-channel system
|
|
60
|
+
- **Access**: OpenNeuro ds003097 (CC0 license)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Supported Modalities
|
|
65
|
+
|
|
66
|
+
| Modality | Description | Tasks/Conditions |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| T1w | High-resolution structural MRI | Single acquisition |
|
|
69
|
+
| T2*w | Functional MRI (multi-echo EPI) | Resting-state (eyes open), Movie-watching |
|
|
70
|
+
| MEG | Magnetoencephalography | Resting-state (eyes open), Auditory (passive listening), Visual (passive viewing) |
|
|
71
|
+
| dMRI | Diffusion-weighted imaging | DTI tractography |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Cam-CAN Task Paradigms
|
|
76
|
+
|
|
77
|
+
### fMRI Tasks
|
|
78
|
+
| Task | Description | Duration |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| REST | Resting-state (eyes open) | ~8 min |
|
|
81
|
+
| MOVIE | Movie-watching (feature film excerpts) | ~15 min |
|
|
82
|
+
|
|
83
|
+
### MEG Tasks
|
|
84
|
+
| Task | Description | Duration |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| REST | Resting-state (eyes open, eyes closed) | ~8 min |
|
|
87
|
+
| AUDITORY | Passive listening to tones and speech | ~5 min |
|
|
88
|
+
| VISUAL | Passive viewing of visual stimuli | ~5 min |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## BIDS Preparation
|
|
93
|
+
|
|
94
|
+
### Script: `scripts/validate_camcan.py`
|
|
95
|
+
|
|
96
|
+
Validates Cam-CAN BIDS structure and generates a compliance report.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python skills/camcan-skill/scripts/validate_camcan.py \
|
|
100
|
+
--input /path/to/CamCAN/bids \
|
|
101
|
+
--output /path/to/camcan_output/qc/bids_validation.csv
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Features:
|
|
105
|
+
- BIDS directory structure validation
|
|
106
|
+
- Modality completeness check (T1w, T2*w, MEG, dMRI)
|
|
107
|
+
- Sidecar JSON presence and content validation
|
|
108
|
+
- Participant ID consistency across modalities
|
|
109
|
+
- Missing data identification and reporting
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Core Workflow (Never Bypassed)
|
|
114
|
+
|
|
115
|
+
1. Identify user target: full Cam-CAN processing, imaging subset, phenotype extraction, or BIDS validation only.
|
|
116
|
+
2. Generate a numbered plan with tools, outputs, runtime, storage, and risks.
|
|
117
|
+
3. Wait for explicit confirmation (`YES` / `execute` / `proceed`).
|
|
118
|
+
4. On confirmation, run BIDS validation using `scripts/validate_camcan.py`.
|
|
119
|
+
5. Delegate to `smri-skill` for structural MRI processing.
|
|
120
|
+
6. Delegate to `fmri-skill` for functional MRI processing (resting-state and movie-watching).
|
|
121
|
+
7. Delegate to `meg-skill` for MEG processing (source localization, time-frequency analysis).
|
|
122
|
+
8. If phenotype extraction is requested, run `scripts/extract_camcan_phenotype.py`.
|
|
123
|
+
9. If QC summary is requested, run `scripts/camcan_qc_summary.py`.
|
|
124
|
+
10. Save outputs into `camcan_output/`.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Modality Processing Delegation
|
|
129
|
+
|
|
130
|
+
| Modality | Delegated skill | Typical tasks | Main outputs |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| sMRI (T1w) | `smri-skill` | brain extraction, tissue segmentation, cortical reconstruction | `smri_output/` derivatives |
|
|
133
|
+
| fMRI (T2*w) | `fmri-skill` | preprocessing, denoising, connectivity, task GLM | `fmri_output/` derivatives |
|
|
134
|
+
| MEG | `meg-skill` | source localization, time-frequency, connectivity | `meg_output/` TFR and source |
|
|
135
|
+
| dMRI | `dwi-skill` | diffusion preprocessing, tensor metrics | `dwi_output/` metrics |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Standard Output Layout
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
camcan_output/
|
|
143
|
+
├── bids/ # BIDS-staged data (or validation report)
|
|
144
|
+
├── smri/ # Structural MRI derivatives
|
|
145
|
+
├── fmri/ # Functional MRI derivatives (rest + movie)
|
|
146
|
+
├── meg/ # MEG derivatives (TFR, source, connectivity)
|
|
147
|
+
├── dwi/ # Diffusion MRI derivatives
|
|
148
|
+
├── phenotype/ # Merged phenotype tables
|
|
149
|
+
├── qc/ # QC summaries and exclusion lists
|
|
150
|
+
└── logs/ # Processing logs
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Benchmark Adapter Guidance
|
|
156
|
+
|
|
157
|
+
For benchmark-style prompts, do not force the full orchestration when the task only asks for local Cam-CAN data validation or staging.
|
|
158
|
+
|
|
159
|
+
- If the task starts from Cam-CAN data already present on disk and only asks for BIDS validation:
|
|
160
|
+
- Skip the download stage
|
|
161
|
+
- Default to the narrow path `local Cam-CAN discovery -> BIDS validation -> report`
|
|
162
|
+
- In benchmark mode, do not require explicit confirmation before presenting the validation solution.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Safety and Execution Policy
|
|
167
|
+
- No execution before explicit plan confirmation.
|
|
168
|
+
- All execution must be routed via `claw-shell`.
|
|
169
|
+
- Missing dependencies must be resolved by `dependency-planner` before running.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Important Notes and Limitations
|
|
174
|
+
- Cam-CAN is a population-based sample spanning the full adult lifespan (18-88 years).
|
|
175
|
+
- MEG data uses CTF 275-channel system; MEG processing requires system-specific handling.
|
|
176
|
+
- Movie-watching fMRI is a unique task paradigm; standard GLM may not apply.
|
|
177
|
+
- Age range is a key variable; consider age-stratified analyses.
|
|
178
|
+
- Data is available on OpenNeuro ds003097 in BIDS format.
|
|
179
|
+
- `camcan-skill` is orchestration-only; detailed preprocessing logic remains in modality skills.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## When to Call This Skill
|
|
184
|
+
- User asks for end-to-end Cam-CAN workflow.
|
|
185
|
+
- User asks to process Cam-CAN MRI and/or MEG data.
|
|
186
|
+
- User needs BIDS validation for Cam-CAN data.
|
|
187
|
+
- User asks to extract Cam-CAN phenotype data (cognitive, sensory, health).
|
|
188
|
+
- User asks for age-related brain imaging analysis using Cam-CAN.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Complementary / Related Skills
|
|
193
|
+
- `smri-skill` → structural MRI preprocessing
|
|
194
|
+
- `fmri-skill` → functional MRI preprocessing and analysis
|
|
195
|
+
- `meg-skill` → MEG processing (source localization, time-frequency)
|
|
196
|
+
- `mne-eeg-tool` → MNE-Python EEG/MEG processing
|
|
197
|
+
- `bids-organizer` → BIDS validation and organization
|
|
198
|
+
- `brain-visualization` → visualization of derivatives
|
|
199
|
+
- `dependency-planner` → dependency resolution
|
|
200
|
+
- `conda-env-manager` → environment management
|
|
201
|
+
- `claw-shell` → command execution
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Reference
|
|
206
|
+
- Cam-CAN: https://camcan.mrc-cbu.cam.ac.uk/
|
|
207
|
+
- OpenNeuro ds003097: https://openneuro.org/datasets/ds003097
|
|
208
|
+
- Shafto et al. (2014): The Cam-CAN study protocol. BMC Neurology.
|
|
209
|
+
- Taylor et al. (2017): The Cam-CAN data repository. NeuroImage.
|
|
210
|
+
|
|
211
|
+
Created At: 2026-05-06 13:31 HKT
|
|
212
|
+
Last Updated At: 2026-05-06 13:31 HKT
|
|
213
|
+
Author: chengwang96
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate per-subject QC summaries for Cam-CAN processing.
|
|
3
|
+
|
|
4
|
+
Combines fMRIPrep confounds, FreeSurfer metrics, and MEG QC
|
|
5
|
+
to produce a unified QC summary with exclusion recommendations.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import csv
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, List
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load_confounds(confounds_path: Path) -> Dict[str, float]:
|
|
15
|
+
"""Extract QC metrics from fMRIPrep confounds TSV."""
|
|
16
|
+
metrics = {"fd_mean": float("nan"), "fd_max": float("nan")}
|
|
17
|
+
try:
|
|
18
|
+
import pandas as pd
|
|
19
|
+
df = pd.read_csv(confounds_path, sep="\t")
|
|
20
|
+
if "framewise_displacement" in df.columns:
|
|
21
|
+
fd = df["framewise_displacement"].dropna()
|
|
22
|
+
metrics["fd_mean"] = float(fd.mean())
|
|
23
|
+
metrics["fd_max"] = float(fd.max())
|
|
24
|
+
except Exception:
|
|
25
|
+
pass
|
|
26
|
+
return metrics
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_freesurfer_qc(fs_dir: Path, subject_id: str) -> Dict[str, float]:
|
|
30
|
+
"""Extract FreeSurfer QC metrics."""
|
|
31
|
+
metrics = {"fs_eTIV": float("nan")}
|
|
32
|
+
stats_file = fs_dir / subject_id / "stats" / "aseg.stats"
|
|
33
|
+
if stats_file.exists():
|
|
34
|
+
try:
|
|
35
|
+
for line in stats_file.read_text().splitlines():
|
|
36
|
+
if "EstimatedTotalIntraCranialVol" in line:
|
|
37
|
+
parts = line.split(",")
|
|
38
|
+
if len(parts) > 4:
|
|
39
|
+
metrics["fs_eTIV"] = float(parts[4].strip())
|
|
40
|
+
except Exception:
|
|
41
|
+
pass
|
|
42
|
+
return metrics
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def check_exclusion(metrics: Dict[str, float], fd_threshold: float = 0.3) -> List[str]:
|
|
46
|
+
"""Check exclusion criteria."""
|
|
47
|
+
reasons = []
|
|
48
|
+
if not (metrics["fd_mean"] != metrics["fd_mean"]):
|
|
49
|
+
if metrics["fd_mean"] > fd_threshold:
|
|
50
|
+
reasons.append(f"FD mean {metrics['fd_mean']:.3f} > {fd_threshold}")
|
|
51
|
+
return reasons
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main() -> int:
|
|
55
|
+
parser = argparse.ArgumentParser(
|
|
56
|
+
description="Generate QC summaries for Cam-CAN processing."
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument("--fmriprep-dir", help="Path to fMRIPrep output directory")
|
|
59
|
+
parser.add_argument("--freesurfer-dir", help="Path to FreeSurfer output directory")
|
|
60
|
+
parser.add_argument("--output", required=True, help="Output path for QC summary CSV")
|
|
61
|
+
parser.add_argument("--exclude-output", help="Output path for exclusion list CSV")
|
|
62
|
+
parser.add_argument("--fd-threshold", type=float, default=0.3,
|
|
63
|
+
help="FD threshold (default: 0.3 mm)")
|
|
64
|
+
args = parser.parse_args()
|
|
65
|
+
|
|
66
|
+
output_path = Path(args.output).resolve()
|
|
67
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
|
|
69
|
+
# Discover subjects
|
|
70
|
+
subjects = set()
|
|
71
|
+
if args.fmriprep_dir:
|
|
72
|
+
fmriprep_dir = Path(args.fmriprep_dir).resolve()
|
|
73
|
+
if fmriprep_dir.exists():
|
|
74
|
+
for d in fmriprep_dir.glob("sub-*"):
|
|
75
|
+
if d.is_dir():
|
|
76
|
+
subjects.add(d.name)
|
|
77
|
+
|
|
78
|
+
if args.freesurfer_dir:
|
|
79
|
+
fs_dir = Path(args.freesurfer_dir).resolve()
|
|
80
|
+
if fs_dir.exists():
|
|
81
|
+
for d in fs_dir.iterdir():
|
|
82
|
+
if d.is_dir() and not d.name.startswith("."):
|
|
83
|
+
subjects.add(f"sub-{d.name}" if not d.name.startswith("sub-") else d.name)
|
|
84
|
+
|
|
85
|
+
if not subjects:
|
|
86
|
+
print("[WARN] No subjects found.", file=sys.stderr)
|
|
87
|
+
return 1
|
|
88
|
+
|
|
89
|
+
results = []
|
|
90
|
+
excluded = []
|
|
91
|
+
for subj in sorted(subjects):
|
|
92
|
+
metrics = {"subject_id": subj}
|
|
93
|
+
|
|
94
|
+
if args.fmriprep_dir:
|
|
95
|
+
confounds_files = list(Path(args.fmriprep_dir).glob(f"{subj}/func/*_desc-confounds_timeseries.tsv"))
|
|
96
|
+
if confounds_files:
|
|
97
|
+
metrics.update(load_confounds(confounds_files[0]))
|
|
98
|
+
|
|
99
|
+
if args.freesurfer_dir:
|
|
100
|
+
fs_id = subj.replace("sub-", "")
|
|
101
|
+
metrics.update(load_freesurfer_qc(Path(args.freesurfer_dir), fs_id))
|
|
102
|
+
|
|
103
|
+
exclusion_reasons = check_exclusion(metrics, args.fd_threshold)
|
|
104
|
+
metrics["excluded"] = len(exclusion_reasons) > 0
|
|
105
|
+
metrics["exclusion_reasons"] = "; ".join(exclusion_reasons)
|
|
106
|
+
|
|
107
|
+
results.append(metrics)
|
|
108
|
+
if exclusion_reasons:
|
|
109
|
+
excluded.append({"subject_id": subj, "reasons": "; ".join(exclusion_reasons)})
|
|
110
|
+
|
|
111
|
+
if results:
|
|
112
|
+
fieldnames = list(results[0].keys())
|
|
113
|
+
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
|
114
|
+
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
|
115
|
+
writer.writeheader()
|
|
116
|
+
writer.writerows(results)
|
|
117
|
+
print(f"QC: {len(results)} subjects, {len(excluded)} excluded -> {output_path}")
|
|
118
|
+
|
|
119
|
+
if args.exclude_output and excluded:
|
|
120
|
+
exclude_path = Path(args.exclude_output).resolve()
|
|
121
|
+
exclude_path.parent.mkdir(parents=True, exist_ok=True)
|
|
122
|
+
with open(exclude_path, "w", newline="", encoding="utf-8") as f:
|
|
123
|
+
writer = csv.DictWriter(f, fieldnames=["subject_id", "reasons"])
|
|
124
|
+
writer.writeheader()
|
|
125
|
+
writer.writerows(excluded)
|
|
126
|
+
|
|
127
|
+
return 0
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
sys.exit(main())
|