A comprehensive Python package for analyzing and visualizing behavioral data from Ethopy experiments.
π Documentation
Ethopy Analysis provides a modern, modular approach to behavioral data analysis with the following key features:
- DataFrame-based: Most of plotting functions work with pandas DataFrames, making them independent of data source
- Modular Design: Composable functions for different analysis levels (animal, session, comparison)
- DataJoint-based: Works with DataJoint databases and provides DataFrame interfaces
- Extensible: Modular function-based architecture for easy extension
- Production Ready: Command-line interface, proper packaging, and configuration management
Requires Python 3.9+.
Use a virtual environment to keep the install isolated:
python -m venv venv
source venv/bin/activate # On Windows use: venv\Scripts\activateThen install:
# Clone the repository
git clone <repository-url>
cd ethopy_analysis
# Install in development mode
pip install -e .pyproject.toml declares supported version ranges. To install one exact combination that has been verified end-to-end against a live EthoPy database, use the checked-in constraints file:
pip install -e . -c constraints.txtUse this if you hit a dependency-related failure; it pins every transitive package to a known-good version.
pip install -e ".[notebooks]" # Jupyter kernel for examples/
pip install -e ".[dev]" # pytest, black, isort, flake8, mypy
pip install -e ".[docs]" # mkdocs + material theme| Package | Range | Purpose |
|---|---|---|
| datajoint | >=0.14.0,<2.0.0 | Database access |
| setuptools | <82 | Required by datajoint |
| pymysql | <1.2.0 | MySQL driver (via datajoint) |
| pandas | >=1.3.0 | DataFrame interchange |
| numpy | >=1.20.0 | Numerics |
| matplotlib | >=3.5.0 | Plotting |
| seaborn | >=0.11.0 | Statistical plots |
| click | >=8.0.0 | CLI |
ethopy-analysis/
βββ src/ethopy_analysis/
β βββ data/ # Data loading and processing
β β βββ loaders.py # DB loaders: sessions, trials, states,
β β β # licks, proximity, state windows,
β β β # ON-OFF pairs, per-trial raster data
β β βββ analysis.py # Derived metrics: performance,
β β β # port-exit-to-lick latency, summaries
β β βββ utils.py # Utilities: consecutive runs,
β β # column mapping, group helpers
β βββ plots/ # Plotting functions (DataFrame-based)
β β βββ animal.py # Animal-level plots across sessions
β β βββ session.py # Session-level plots: licks, proximity,
β β β # states, trial-events raster
β β βββ comparison.py # Multi-animal/condition comparisons
β β βββ utils.py # Plotting utilities
β βββ db/ # Database connectivity
β β βββ schemas.py # DataJoint schema management and caching
β βββ config/ # Configuration management
β β βββ settings.py # Config loading: ethopy_config.json,
β β β # dj_conf.json, EthoPy local_conf.json,
β β β # and environment variables
β β βββ styles.py # Plot style presets
β β βββ interactive.py # Interactive credential prompts
β βββ cli.py # Command-line interface
βββ examples/ # Example notebooks
β βββ load_example.ipynb # Data loading walkthrough
β βββ animal_analysis_example.ipynb # Animal-level analysis
β βββ session_analysis_example.ipynb # Session-level analysis incl.
β # proximity, state windows, raster plot
βββ docs/ # Documentation
βββ pyproject.toml # Package configuration
βββ README.md
If EthoPy is installed, ethopy-analysis automatically reads ~/.ethopy/local_conf.json β
no extra setup needed.
| Method | How |
|---|---|
| Config file | Create ethopy_config.json in the project root (see docs/configuration.md) |
| Environment variables | export DJ_HOST=β¦ DJ_USER=β¦ DJ_PASSWORD=β¦ |
| Interactive | Run any loader β credentials are prompted if nothing else is found |
See docs/configuration.md for the full priority order and format reference.
ethopy-analysis config-summary # which config file was picked up
ethopy-analysis test-db-connection # confirm credentials + schema access# Print a text summary of one session
ethopy-analysis session-summary --animal-id 201 --session 71
# Generate the standard animal-level plots
ethopy-analysis analyze-animal --animal-id 201 --min-trials 20 \
--save-plots --output-dir ./plots
# Full report for one animal
ethopy-analysis generate-report --animal-id 201 --output-dir ./reportsThe package is organised in three layers: loaders pull DataFrames out of the DataJoint schemas, analysis derives metrics from them, and plots render them.
from ethopy_analysis.data.loaders import get_sessions, get_trials, get_trial_licks
from ethopy_analysis.data.analysis import get_performance, session_summary
from ethopy_analysis.plots.animal import plot_session_performance
from ethopy_analysis.plots.session import LickPlot
animal_id = 201
# 1. Which sessions does this animal have (with at least 20 trials)?
sessions_df = get_sessions(animal_id, min_trials=20)
sessions = sessions_df["session"].tolist()
# 2. Animal-level view: performance across sessions, shaded by protocol
plot_session_performance(animal_id, sessions, get_performance)
# 3. Session-level view
session = sessions[len(sessions) // 2]
session_summary(animal_id, session)
LickPlot(animal_id, session)Loaders take a format argument: format="df" (default) returns a pandas DataFrame, format="dj" returns the underlying DataJoint expression so you can restrict or join it further before fetching.
# Compose a query server-side, then fetch once
trials_dj = get_trials(animal_id, session, format="dj")
late_trials = (trials_dj & "trial_idx > 100").fetch(format="frame").reset_index()Plot functions are plain functions over DataFrames β there is no base class to subclass and no registry to update. To add an analysis, write a function, put it in the module that matches its level, and import it.
1. Write the function. Take a DataFrame (or animal_id/session), return
(fig, ax):
# src/ethopy_analysis/plots/animal.py
import matplotlib.pyplot as plt
def plot_learning_rate(performance_df, animal_id=None, save_path=None):
"""Session-over-session change in performance."""
df = performance_df.sort_values("session").copy()
df["learning_rate"] = df["correct_rate"].diff()
fig, ax = plt.subplots(figsize=(12, 4))
ax.plot(df["session"], df["learning_rate"], marker="o")
ax.axhline(0, color="grey", linestyle="--", linewidth=1)
ax.set_xlabel("session")
ax.set_ylabel("Ξ correct rate")
ax.set_title(f"Animal {animal_id}")
if save_path:
from ethopy_analysis.plots.utils import save_plot
save_plot(fig, save_path)
return fig, ax2. Export it by adding the name to the imports and the __all__ list in src/ethopy_analysis/plots/__init__.py. Both must agree β a name in __all__ that is not imported makes from ethopy_analysis.plots import * raise AttributeError.
3. Use it β no registration step:
from ethopy_analysis.plots.animal import plot_learning_rate
fig, ax = plot_learning_rate(performance_df, animal_id=201)Because the plot layer only touches DataFrames, any data source works once the column names match:
df = pd.read_csv("my_experiment.csv").rename(columns={
"mouse_id": "animal_id",
"day": "session",
"success_percentage": "correct_rate",
})Conventional column names: animal_id, session, trial_idx, correct_rate,
outcome.
Loaders resolve the per-session condition table by name from experiment.Condition (e.g. stimulus_class == "Panda" β stimulus.Panda), then join any child tables that hold rows for that session.
A new EthoPy stimulus class works automatically as long as its condition table name matches the class name. Sessions using EthoPy's base Stimulus class have no dedicated table and fall back to stimulus.StimCondition.
Check out the examples/ directory for comprehensive notebooks:
load_example.ipynb: Data loading walkthroughanimal_analysis_example.ipynb: Comprehensive animal-level analysissession_analysis_example.ipynb: Detailed session-level analysis
Install the notebook extra first: pip install -e ".[notebooks]"
- Functions over classes where possible
- Clear, descriptive function names
- Pandas DataFrames for data exchange
- Matplotlib for plotting
