Code and data for the figures in:
Breda JR*, Charlton JA*, Willock JM, Kopec CD, Brody CD (2026).
FixGrower: An efficient and robust curriculum for shaping fixation behavior in rodents.
eLife — bioRxiv preprint
1. Create and activate the conda environment (Python 3.10)
conda env create -f environment.yml
conda activate fixation-grower2. Register the Jupyter kernel
python -m ipykernel install --user --name fixation-grower --display-name "fixation-grower"3. Data
Processed data files belong in data/ (not committed). Core fixation-curriculum files:
trials_df.parquet,days_df.parquet,poke_df.parquetfig04_fixgrower_continued_stage11.parquet— Figure 4 stage-11 continued assessmentfig05_cleaned_trials_df.parquet— Figure 5 DMS trial-level datafig05_fixgrow_days_to_target.parquet— Figure 5 per-animal days to fixation targetfig06_mouse_fixation_trials.parquet— Figure 6 / Supplement S4 mouse trial-level data
See the figures folder for the associated publication figures.
Open any notebook in notebooks/ with Jupyter, select the fixation-grower kernel, and run all cells top-to-bottom. Figures are saved to figures/.
jupyter notebook notebooks/fig01.ipynbBreda-Charlton-FixationGrower/
├── environment.yml # conda environment (Python 3.10)
├── pyproject.toml # installable package definition
├── data/ # parquet data files (not committed)
├── figures/ # figure outputs (not committed)
│ ├── figNN_FULL.png # main-figure composite (reference; added manually)
│ ├── suppSN_FULL.png # supplement composite (e.g. suppS3_FULL.png, suppS5_FULL.png)
│ └── figNN<letter>_….png # panel PNGs reproduced by notebooks
├── notebooks/
│ ├── fig01.ipynb # Figure 1: fixation growth example panels
│ ├── fig02.ipynb # Figure 2: FixGrower grows faster to fixation target
│ ├── fig03.ipynb # Figure 3: probe violation rates vs training time
│ ├── fig04.ipynb # Figure 4: extended post-probe performance
│ ├── fig05.ipynb # Figure 5: DMS task performance after FixGrower training
│ ├── fig06.ipynb # Figure 6: FixGrower generalization to mice
│ ├── fig07.ipynb # Figure 7: FixGrower vigor vs Legacy
│ ├── fig08.ipynb # Figure 8: within-session engagement
│ ├── fig09.ipynb # Figure 9: center-poke timing (fixation growth vs probe)
│ ├── suppS1.ipynb # Supplement Figure S1: metrics by curricula phase + stage progressions
│ ├── suppS2.ipynb # Supplement Figure S2: Legacy growth-ceiling simulations
│ ├── suppS3.ipynb # Supplement Figure S3: raw fixation, violation, and rig data
│ ├── suppS4.ipynb # Supplement Figure S4: extended mouse fixation data
│ └── suppS5.ipynb # Supplement Figure S5: warm-up exclusion and full growth poke timing
└── src/fixation_grower/
├── config.py # cohort definitions, colors, stage constants
├── paths.py # data/ and figures/ directory resolution
├── io.py # data loaders (load_trials_df, load_poke_df, …)
├── transforms.py # feature engineering (days relative to stage, …)
├── plotting.py # shared aesthetics and save_figure()
├── stats.py # Legacy vs FixGrower statistical comparisons
└── simulation.py # Legacy growth-ceiling simulation (Supplement S2)
Each notebook follows a standard structure to maximize readability:
- Figure overview (markdown) —
# Figure N, embedded, then## Code For …with goal, panel table, and list of panel outputs the notebook generates - Imports cell — package imports only, no logic
- Shared settings (optional) — constants reused across panels in the same notebook
- Panel sections — one
## Panel Xmarkdown header per panel, followed by its code - Cleared outputs — notebooks are committed without cell outputs
The figNN_FULL.png file is the full published figure for context; notebooks reproduce individual panels only.
Code placement rule: if logic is reused across figures or supplements it lives in src/fixation_grower/; if it is panel-specific constants and styling it stays inline in the notebook. No def statements in notebooks unless the function is fewer than 5 lines and used only once.
Terminology: curriculum arms are called Legacy and FixGrower throughout.
Data access: always use the package loaders (load_trials_df(), etc.) rather than bare pd.read_parquet() calls in notebooks.