Observed since 20 Oct, 18:34 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
actirhythm-toolkit
Reproducible accelerometer analysis pipeline for circadian and behavioral rhythm studies
ActiRhythm Toolkit is a command-line workflow for analysing accelerometer activity data and characterising behavioural and circadian rhythms. It provides preprocessing, hidden Markov model state estimation, downstream rhythm analysis, and optional machine-learning and GLMM workflows.
This repository contains source code, notebooks and published figures only. No subject data is distributed: the maned wolf biologger recordings analysed in the accompanying thesis belong to the data owners and are not redistributable. Supply your own input files under data/ to run the workflow.
src/ importable package (actirhythm CLI and analysis modules)
scripts/ pipeline entry points, figure generators and reporting helpers
notebooks/ exploratory notebooks (outputs stripped)
tests/ unit tests
figures/ figures published in the thesis
docs/ pipeline description and methodological notes
data/ input data (git-ignored, placeholders only)
outputs/ run artefacts (git-ignored)
python -m pip install actirhythm-toolkit
Optional extras from PyPI:
python -m pip install "actirhythm-toolkit[ml]"
python -m pip install "actirhythm-toolkit[glmm]"
python -m pip install "actirhythm-toolkit[notebooks]"
PyPI project page:
https://pypi.org/project/actirhythm-toolkit/
python -m pip install "actirhythm-toolkit[ml]"
python -m pip install "actirhythm-toolkit[glmm]"
python -m pip install "actirhythm-toolkit[notebooks]"
The glmm extra also requires a local R installation and compatible R packages. Check your environment with:
actirhythm glmm-doctor
Run the complete workflow from a project directory containing your input data and optional config.yaml:
actirhythm
Inspect the planned inputs and outputs before running:
actirhythm --dry-run
Run a named analysis version:
actirhythm full --run-version v1
actirhythm full
actirhythm preprocess
actirhythm analytics
actirhythm glmm-doctor
Run actirhythm --help for all configuration, data-path, output-path, and resume options.
The workflow accepts accelerometer CSV data with a timestamp, subject identifier, activity measure, and optional axis or posture measurements. Use --data-revised-dir to specify an input directory and --raw-data-file to provide a fallback CSV file.
Set the analysis signal with --activity-signal (default ActMindata).
Some loggers export only the average of each accelerometer axis per epoch. The magnitude of a mean acceleration vector is dominated by gravity, so it describes body orientation, not movement intensity: it is longest when the animal holds a single posture and shortens as orientation varies within the epoch. Such a magnitude can therefore be negatively correlated with real activity and must not be used as an intensity index.
The toolkit still computes activity_xy and activity_xyz from the axes, but treats them
as posture descriptors. A genuine intensity metric (ODBA/VeDBA) requires within-epoch
variance, which averaged exports do not retain. Where a firmware activity count such as
ActMindata is available, prefer it.
Posture descriptors remain useful for validating decoded states: resting states should
show a higher and less variable posture magnitude than active ones. The preprocessing
stage writes this check to posture_state_validation.csv.
Records collected after a device is removed cannot be identified from the signal alone — a retrieved logger still registers varying posture and occasional activity while it is being transported, which is indistinguishable from genuine low-activity behaviour. Documented removal times are required.
Because removal times are study metadata that identify individual animals, none are
shipped with this repository. Place your own deployment_windows.csv in the project
directory and call qc.load_deployment_windows():
subject,end_timestamp,reason
A,2024-04-02 00:00,battery failure before explant
B,2023-07-07 10:15,documented device removal
Alternatively, pass a mapping directly to qc.apply_deployment_windows(). Without a
window file, post-removal records are treated as valid observations.
qc.assign_subject_codes() replaces subject names with codes (S01, S02, …) ordered by
first observation, and the preprocessing stage writes the mapping to
subject_code_mapping.csv. Treat that file as confidential — it is the re-identification
key. It is not required to reproduce any result.
--min-dwell sets the minimum bout length in bins for the post-decoding filter
(default 2; at 15-minute sampling that is 30 minutes).
This filter suppresses decoder flicker but also alters the decoded sequence, so transition
probabilities and dwell-time summaries describe the filtered series. Choose the threshold
against your own data rather than by convention: a value above the unfiltered median bout
length discards a large share of genuine bouts. Each run writes
dwell_time_sensitivity.csv comparing 15-, 30- and 60-minute thresholds so the choice can
be justified.
git clone https://github.com/nerminjukan/actirhythm-toolkit.git
cd actirhythm-toolkit
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
python -m pip install -e .
Development extras:
python -m pip install -e .[dev]
python -m pip install -e .[ml]
python -m pip install -e .[glmm]
python -m pip install -e .[notebooks]
Source code and issue tracking: https://github.com/nerminjukan/actirhythm-toolkit
GNU General Public License, version 3 or later. See LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
numpyEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | numpy>=1.21.0 | runtime |
pandasEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pandas>=1.3.0 | runtime |
scipyEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | scipy>=1.7.0 | runtime |
pyarrowEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pyarrow>=5.0.0 | runtime |
matplotlibEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | matplotlib>=3.4.0 | runtime |
seabornEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | seaborn>=0.11.0 | runtime |
statsmodelsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | statsmodels>=0.13.0 | runtime |
scikit-learnEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | scikit-learn>=1.0.0 | runtime |
hmmlearnEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | hmmlearn>=0.2.7 | runtime |
pyyamlEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pyyaml>=5.4.0 | runtime |
loguruEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | loguru>=0.5.3 | runtime |
xgboostEnvironment{
"extras": "",
"marker": "extra == \"ml\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | xgboost>=1.5.0; extra == "ml" | runtime |
pomegranateEnvironment{
"extras": "",
"marker": "extra == \"ml\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pomegranate>=0.14.8; extra == "ml" | runtime |
CosinorPyEnvironment{
"extras": "",
"marker": "extra == \"ml\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | CosinorPy>=1.1; extra == "ml" | runtime |
pymer4Environment{
"extras": "",
"marker": "extra == \"glmm\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pymer4>=0.7.0; extra == "glmm" | runtime |
polarsEnvironment{
"extras": "",
"marker": "extra == \"glmm\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | polars>=1.0.0; extra == "glmm" | runtime |
rpy2Environment{
"extras": "",
"marker": "extra == \"glmm\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | rpy2>=3.6.0; extra == "glmm" | runtime |
great-tablesEnvironment{
"extras": "",
"marker": "extra == \"glmm\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | great-tables>=0.23.0; extra == "glmm" | runtime |
jupyterEnvironment{
"extras": "",
"marker": "extra == \"notebooks\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | jupyter>=1.0.0; extra == "notebooks" | runtime |
ipykernelEnvironment{
"extras": "",
"marker": "extra == \"notebooks\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | ipykernel>=6.0.0; extra == "notebooks" | runtime |
nbformatEnvironment{
"extras": "",
"marker": "extra == \"notebooks\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | nbformat>=5.1.0; extra == "notebooks" | runtime |
tqdmEnvironment{
"extras": "",
"marker": "extra == \"notebooks\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | tqdm>=4.62.0; extra == "notebooks" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pytest>=6.2.0; extra == "dev" | runtime |
pytest-covEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | pytest-cov>=3.0.0; extra == "dev" | runtime |
python-dotenvEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | python-dotenv>=0.19.0; extra == "dev" | runtime |
bdist_wheel · 57.99 KB · Python py3
sdist · 54.94 KB · Python source
Shared repository data · GitHub
Observed since 20 Oct, 18:34 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:289e9d23bbf581da2ed27de9e745e3c98a5d772b0e00743536c2dd3a2625ea5b