Python analysis pipeline for the Delayed Conditional Discrimination (DCD) comparative cognition study across eight animal species. Computes learning metrics (trials-to-criterion), correlates them with brain size, and provides statistical inference through exact permutation tests and bootstrap confidence intervals. This analysis was based on work originally carried out by Cwyn Solvi using R.
Associated manuscript: Cwyn Solvi, Eleni Vasilaki, Anna Wilkinson, Valentina Truppa, Guinevere Schipper, P.C. Scarbro, Rosa Rugani, Lucia Regolin, Thomas W. Pike, Fei Peng, Faelan Mourmourakis, Sanne Lamers, Shannon M. A. Kundey, Robin D. Johnsson, Keely S. Hermanson, Kristy Gould, Andrew B. Barron, Cross-species comparison of a rule-based task reveals faster learning in smaller brains.
# 1. Validate data consistency
python Brains_data_validation.py
# 2. Fit EMA time constant (optional - already fitted as α=0.35)
python Brains_time_constant.py
# 3. Impute missing test values based on training performance (optional - already pached at 0.576 for the cappuchins)
python Brains_predict_test_from_training
# 4. Run main analysis
python Brains_main_analysis.py
Results appear in outputs/<config-name>/.
Brains/
├── README.md
├── Brains_DCD_Analysis_Pipeline_Report.md # Technical documentation
│
├── # ===== LIBRARY MODULES =====
├── libraries/
│ ├── Brains_config.py # All parameters and constants
│ ├── Brains_lib.py # Data loading, TTC computation, plotting
│ ├── Brains_stats.py # Statistics: correlation, regression, permutation, bootstrap
│ └── Brains_log.py # Output logging utilities
│
├── # ===== ANALYSIS SCRIPTS =====
├── Brains_main_analysis.py # Main analysis: composite scores, correlations, figures
├── Brains_data_validation.py # Data consistency checks
├── Brains_time_constant.py # EMA α fitting
├── Brains_predict_test_from_training.py # Impute missing test scores
│
├── data/
│ ├── DCD_SpeciesLearningCurves_noShps.csv # Aggregated learning curves
│ ├── IndividualBinnedData_DCD.csv # Subject-level binned data
│ └── DCD_SpeciesTests_noShps.csv # Test phase performance
│
└── outputs/ # Generated by analysis scripts
│ └── <config-name>/ # One folder per configuration
│ ├── analysis.log # Full console output
│ ├── config.txt # Configuration snapshot
│ ├── bootstrap-summary.txt
│ ├── figures/
│ │ ├── fig3_main_results.pdf
│ │ └── fig_ttc_vs_brain.pdf
│ └── figure-data/ # CSVs for figure reproduction
│ ├── fig3A_learning_curves.csv
│ ├── fig3B_test_performance.csv
│ ├── fig3C_rank_trajectories.csv
│ ├── fig3D_mean_rank_CI.csv
│ ├── fig3E_brain_neurons_vs_composite.csv
│ ├── fig3F_brain_volume_vs_composite.csv
│ └── fig_ttc_vs_brain.csv
Each run creates a folder in outputs/ named by configuration:
outputs/EMA-0.35-forward-all-species-TTC-nonlearners-109-test-0.576/
Contents:
| File | Description |
|---|---|
analysis.log |
Complete console output (all statistics, tables) |
config.txt |
Snapshot of all configuration parameters |
bootstrap-summary.txt |
Summary of bootstrap results |
outputs/<config-name>/figures/fig3_main_results.pdf |
Main 6-panel figure |
outputs/<config-name>/figures/fig_ttc_vs_brain.pdf |
TTC vs brain (neurons and volume) figure |
figure-data/*.csv |
Data behind each figure panel (for reproduction) |
Where to find results:
- TTC values:
analysis.log, search for "TTC (" - Correlation results:
analysis.log, search for "BRAIN SIZE vs" - Regression coefficients:
analysis.log, search for "Regression:" - Bootstrap CIs:
analysis.logandbootstrap-summary.txt - Leave-one-out:
analysis.log, search for "Leave-one-out:" - Figure:
outputs/<config-name>/figures/fig3_main_results.pdf
libraries/Brains_config.py (project metadata: paths, schemas, species/brain metadata)
libraries/Brains_stats.py (statistical primitives: correlation/regression/permutation/bootstrap)
libraries/Brains_lib.py (project pipeline utilities: loading, preprocessing, TTC, plotting, RNG helpers)
libraries/Brains_log.py (run logging utilities)
|
v
Analysis scripts (Brains_main_analysis.py + supporting scripts)
Project constants and dataset metadata:
- Data paths and CSV schemas (
RAW_LEARNING_DTYPES,TEST_DTYPES) - Species mappings (
SPECIES_NAME_MAP,get_plural_name()) - Brain metrics (
neuron_counts,brain_volumes_mm3) - Shared plotting metadata (
SPECIES_COLORS)
Statistical functions (reusable statistical backend):
pearson_r(),spearman_rho(),linregress()leave_one_out_regression()— LOO cross-validation*_permutation_test()— exact enumeration for N≤8*_bootstrap_ci()— percentile CIs with rejection samplingweighted_linregress(),weighted_pearson_r()— WLS
Data and computation utilities:
load_structured_csv()— CSV loading with type validationcompute_ttc_from_curve()— TTC computation (EMA or run-rule)compute_ttc_across_species()— species-level TTC from reconstructed curvesbeautify_ax(),set_brains_matplotlib_style()— plotting
setup_logging()/close_logging()— tee stdout toanalysis.logwrite_bootstrap_summary()— save bootstrap results
Main analysis pipeline. Run this for the primary results.
Computes:
- TTC per species (EMA-based)
- Composite scores (speed + test performance)
- Brain size correlations (Pearson, Spearman)
- Exact permutation tests (all 8! = 40,320 permutations)
- Bootstrap confidence intervals
- Optional: N-weighted regression
Generates:
- 6-panel figure (learning curves, test performance, ranks, correlations)
- CSV data for figure reproduction
- Full statistical report
Key configuration options:
# TTC computation
TTC_MODE = "ema" # "ema" or "run"
EXP_ALPHA = 0.35 # EMA smoothing
EMA_DIRECTION = "forward" # "forward" or "backward"
EMA_FORWARD_CONFIRM_FIRST_BIN = 1 # require first crossing bin confirmation
NUM_CONSECUTIVE_BINS = 3 # used in run-mode TTC
CRITERION_MODE = "all" # run-mode criterion mode
BINS_THRESHOLD = 0.5 # learning criterion
TOLERANCE = 1e-3
MAX_CRITERION_BIN = None
# Non-learner handling
EXCLUDE_NON_LEARNERS_FROM_ANALYSIS = False
MAX_BINS = 108
NON_LEARNERS_LOWER_BOUND = MAX_BINS + 1
NON_LEARNERS_TTC = MAX_BINS + 1
# Composite/test patching
SHIFT_NON_LEARNERS = 0.1
PATCH_MISSING_TEST_SUBJECTS = True
PATCH_TEST_VALUE = 0.576
# Bootstrap/permutation
B_BOOTSTRAP = 20000
B_CI = 20000
B_BOOT_TTC_SLOPE = 20000
N_PERM_TTC = 20000
PERM_EXACT_N_MAX = 8
# Weighted TTC-vs-brain analysis
TTC_WEIGHT_MODE = "none" # "none", "N", or "precision"
# Reproducibility
GLOBAL_SEED = 0
USE_FIXED_SEED = FalseThis pipeline expects a fixed input schema. For a new dataset, the recommended approach is to keep the same column format and only re-point file paths/metadata.
-
Keep the same CSV schemas:
- Main analysis input:
IndividualBinnedData_DCD.csvcolumnsSubjectID, Species, Bin, Correct Num, Total Trials, Prop % - Main analysis input:
DCD_SpeciesTests_noShps.csvcolumnsSpecies, SpeciesID, Perf - Validation input:
DCD_SpeciesLearningCurves_noShps.csv
- Main analysis input:
-
Change file locations/names in
libraries/Brains_config.py:raw_learning_pathtest_pathlearning_path(for validation script)
-
Update dataset metadata in
libraries/Brains_config.py:- Species mappings (
SPECIES_NAME_MAP,get_plural_name()) - Brain metrics (
neuron_counts,brain_volumes_mm3) - Colors (
SPECIES_COLORS)
- Species mappings (
Only if your dataset cannot be represented in this schema should you modify loader or pipeline code.
- Python 3.8+
- NumPy
- SciPy
- Matplotlib
pip install numpy scipy matplotlibDevelopment assisted by generative AI tools (Claude Opus 4.5, ChatGPT 5.2, Codex GPT-5), which reduced development time and helped refine the analysis pipeline, code architecture and documentation.