A Python toolkit for standardizing the analysis of IntelliCage experiments.
The package provides reusable tools to load IntelliCage text exports, define experiment and subject metadata directly in Python, merge those metadata with visit and nose-poke records, compute behavioral metrics, and create publication-oriented summary plots. Raw export folders are treated as technical export blocks; biological analysis phases are defined by subject-specific time windows, ensuring standardized analysis across experiments.
The toolkit requires Python 3.12 or newer.
Create a clean environment and install the package in editable mode:
conda create -n ic_analysis python=3.12 -y
conda activate ic_analysis
pip install -e .For development and documentation work:
pip install -e ".[dev]"The import package is ic_analysis:
ic_analysis.loaderReads IntelliCage-styleVisits.txtandNosepokes.txtfiles from one or more export blocks, merges script-defined subject metadata, and adds experiment-relative timing and event annotations.ic_analysis.metricsComputes activity, bottle-preference, place-learning, reversal-learning, responder, onset, and group-comparison summary tables for internal workflow use and advanced custom analyses.ic_analysis.plottingCreates group-level and mouse-level figures from the computed metric tables, including raw or relative left/right bottle-consumption trajectories.ic_analysis.metadataDefines experiment phases and per-subject metadata in Python user scripts.ic_analysis.experimentProvides the generic object-oriented experiment workflow. Generic methods use names such asplot_ages,plot_mice_activity, andplot_bottle_preference; place-learning and reversal methods use theplot_plr_*prefix.
Example import:
from pathlib import Path
import ic_analysis as ic
dataset_root = Path("example_data/synthetic_group_ab_place_learning")
phases = {
1: {
"short_name": "Hab",
"long_name": "Habituation",
"scheduled_start_hour": 0.0},
2: {
"short_name": "NPA",
"long_name": "Nose-poke adaptation",
"scheduled_start_hour": 74.0},
3: {
"short_name": "PL",
"long_name": "Place learning",
"scheduled_start_hour": 122.0},
4: {
"short_name": "PR",
"long_name": "Place reversal",
"scheduled_start_hour": 194.0}}
experiment = {
"name": "Synthetic PL/PR example",
"root_data_path": dataset_root,
"results_data_path": dataset_root / "results",
"group_names": ["Group A", "Group B"],
"mouse_day": {
"start": "06:00",
"end": "18:00"}}
subjects = {
"910200000001000": {
"group": "Group A",
"sex": "male",
"true_id": "A01",
"date_of_birth": "2025-09-01",
"corner_assignments": {
3: 1,
4: 3},
"phases": {
1: {"time_window": ("2026-01-05 06:00:00", "2026-01-08 08:00:00")},
2: {"time_window": ("2026-01-08 08:00:00", "2026-01-10 08:00:00")},
3: {"time_window": ("2026-01-10 08:00:00", "2026-01-13 08:00:00")},
4: {"time_window": ("2026-01-13 08:00:00", "2026-01-16 08:00:00")}}}}
my_pl_exp = ic.experiment(EXPERIMENT=experiment, PHASES=phases, SUBJECTS=subjects)
my_pl_exp.load()
my_pl_exp.prepare_analysis(phase_max_hours={3: 72.0, 4: 72.0})
my_pl_exp.plot_ages(time_unit="months", show_N=True, figsize_cm=(5.8, 10.0))
my_pl_exp.plot_mice_activity(bin_hours=1, phases="all", dayphase="all", figsize_cm=(24.0, 10.0))
my_pl_exp.plot_phase_activity_summary(dayphase="all", figsize_cm=(7.0, 8.0))
my_pl_exp.plot_NP_adaptation(phases=2, bin_hours=1, dayphase="day")
my_pl_exp.plot_NP_counts(phases="all", bin_hours=1, dayphase="all")
my_pl_exp.plot_licking_counts(phases="all", bin_hours=1, dayphase="all")
my_pl_exp.plot_bottle_preference(
phases="all",
dayphase="day",
left_bottle="plain water",
right_bottle="saccharin",
calc="right_bottle/left_bottle",
bin_h=24,
x_unit="days",
indicate_dots=True,
figsize_cm=(24.0, 10.0))
my_pl_exp.plot_plr_learning_rate(
phase_number=3,
metric="rewarded_correct_corner_visit",
bin_hours=1,
dayphase="day",
figsize_cm=(12.8, 8.0))
my_pl_exp.plot_plr_learning_counts(
phase_number=3,
metric="rewarded_correct_corner_visit",
bin_hours=1,
dayphase="day",
figsize_cm=(12.8, 8.0))
my_pl_exp.plot_plr_experience_learning_curve(phase_number=3)
my_pl_exp.plot_plr_experience_learning_onset(phase_number=3, figsize_cm=(5.8, 10.0))Most behavioral analysis methods accept dayphase="day", "night", or
"all". The default is "day" so sparse inactive-phase visits do not bias
learning or preference estimates. The activity overview defaults to "all"
because it is meant to show the full day/night rhythm.
For larger cohorts, a YAML template can be generated from detected raw animal IDs and edited before loading:
ic.create_subjects_yaml_template(EXPERIMENT=experiment, PHASES=phases)
subjects = ic.load_subjects_yaml(dataset_root / "subjects.yaml")The repository includes a small synthetic place learning IntelliCage-style dataset at:
example_data/synthetic_group_ab_place_learning
It contains two groups with ten pseudo-mice each:
Group A: simulated stronger place learning, better reversal adaptation, and clear saccharin preference.Group B: simulated weaker place learning, stronger phase-4 perseveration at the previous correct corner, and a plain-water preference as an anhedonia-like phenotype.
It follows a four-phase IntelliCage place learning and place reversal protocol on an aligned 0-266 h analysis timeline:
- Phase 1, Free Hab: 0-74 h, free habituation and exploration of all corners. This may vary from 48-74 h depending on the experiment design.
- Phase 2, NPA: 74-122 h, nose-poke adaptation and licking behavior.
- Phase 3, PL: 122-194 h, place learning with an assigned rewarded correct corner.
- Phase 4, PR: 194-266 h, place reversal with a new rewarded corner and tracking of visits to the previous correct corner.
The run-group folders intentionally start at different real clock times: Group
A begins on 2026-01-05 at 06:00, while Group B begins 7.5 h later at 13:30.
This demonstrates why real phase time_window values are stored per subject.
Real and synthetic datasets use the same cage-run plus export-block layout. In
the public synthetic PL/PR dataset, the export blocks happen to be named
Phase1, Phase2, etc. because the generated export pieces match the protocol
phases. For real data, these folder names can be generic technical names such
as Export_Block_1 or dates:
data_root/
|-- CageRun_A/
| |-- Export_Block_1/
| | `-- IntelliCage/
| | |-- Visits.txt
| | `-- Nosepokes.txt
| `-- Export_Block_2/
| `-- IntelliCage/
| |-- Visits.txt
| `-- Nosepokes.txt
`-- CageRun_B/
|-- Export_Block_1/
| `-- IntelliCage/
| |-- Visits.txt
| `-- Nosepokes.txt
`-- Export_Block_2/
`-- IntelliCage/
|-- Visits.txt
`-- Nosepokes.txt
The loader concatenates all detected export blocks per cage run. The actual
analysis phases come from each subject's time_window entries, so one long
export, phase-matching exports, and interrupted mid-phase exports can be
analyzed with the same downstream code.
To regenerate the example data:
conda run -n ic_analysis python additional_scripts/generate_synthetic_group_ab_data.py --overwriteRun the public synthetic-data workflow with:
conda run -n ic_analysis python user_scripts/place_learning_example.pyThe script writes compact result tables and figures to:
example_data/synthetic_group_ab_place_learning/results
The workflow keeps several place-learning metrics in parallel:
correct_corner_visit_rate
Visits in the assigned correct corner divided by all visits.correct_np_visit_rate
Correct-corner visits with at least one nose-poke divided by all visits.rewarded_correct_corner_visit_rate
Correct-corner visits with nose-poke and licking divided by all visits.bottle_preference
Left/right nose-poke-side licking summarized as raw bottle consumption or as a bounded preference fraction, e.g.right_bottle / (left_bottle + right_bottle).
For a place reversal phase in a place learning experiment, the toolkit also separates:
- visits to the new correct corner
- visits to the previous correct corner
- visits to the neutral incorrect corners
The analysis distinguishes raw IntelliCage export blocks from biological analysis phases:
- export-block columns preserve the observed IntelliCage export structure
- analysis windows are assigned from subject-specific
time_windowvalues - mouse-day and awake/sleep windows can be configured for plotting and daily summaries
This makes runs with different start times, uninterrupted long exports, and interrupted recordings comparable on a common experiment timeline.
The toolkit is designed to be extensible to any IntelliCage experiment. The current release already supports the analysis of the following experiments:
- General activity and locomotor cage engagement
- Liquid-intake surveillance / drinking behavior
- Nosepoke adaptation
- Bottle preference / two-bottle choice
- Place learning
- Place learning and place reversal
- General readouts from any phase-wise structured experiment
We recommend to start with usage examples on the documentation website (will come soon). The folder user_scripts/ contains interactive scripts that are described in the documentation and can be run cell by cell in VS Code's interactive window or in a notebook-like environment. They are designed to be run with provided example datasets (download from Zenodo or from this repository, here stored in example_data/) or with your own IntelliCage data.
If you use the IntelliCage Analysis Toolkit in scientific work, please cite it as follows:
Musacchio, F. (2026). IntelliCage Analysis Toolkit: A Python toolkit for standardizing the analysis of IntelliCage experiments.. Zenodo. https://doi.org/10.5281/zenodo.22181525
