actiRhythm turns activity counts or raw acceleration into the full set
of circadian rest-activity measures. It reads ActiGraph .agd counts
and raw .gt3x, .cwa, and .bin recordings, auto-calibrates the raw
signal, and derives the ENMO, MAD, and z-angle metrics that agree with
GGIR. From a single recording it computes what a chronobiology analysis
reports, from the nonparametric measures and cosinor through
periodograms and fractal structure to wavelet and empirical-mode
decomposition, sleep scoring, and a hidden Markov rest-activity model.
Methods that usually live in separate packages, or in no R package at
all, sit behind one consistent interface, and every analysis returns a
typed object that prints its own summary and draws its own plots.
Each method carries the reference that defined it, and where a trusted
implementation already exists, actiRhythm is checked against it: the raw
metrics against GGIR, the single-component cosinor against the cosinor
package, and the nonparametric measures against nparACT and ActCR.
Those cross-checks run live in the package’s validation
article.
You can usually see the answer before you compute it. Plot a recording as an actogram and a regular sleeper forms a single vertical band of activity at the same clock time each day, while a drifting rhythm scatters across the panel. The numbers that follow put a figure to what the picture shows, from Witting (1990) and van Someren (1999) through Cornelissen (2014) and the periodogram.
# install.packages("remotes")
remotes::install_github("rdazadda/actiRhythm")actiRhythm needs R 4.1 or newer and a C++17 compiler (Rtools on Windows, the Xcode command-line tools on macOS) for the small backend behind its nonparametric metrics.
One ActiGraph recording ships with the package, so this runs without any data of your own. The bundled file is a single de-identified 60-second-epoch recording, included only so the examples run.
library(actiRhythm)
# Read the bundled .agd and pull the count series
agd <- agd.counts(read.agd(example_agd(1), verbose = FALSE))
# Describe the rest-activity rhythm without assuming a waveform
rhythm <- circadian.rhythm(agd$axis1, agd$timestamp)
rhythm
#>
#> Circadian Rhythm Analysis
#>
#> Data Summary
#> Days analyzed: 8
#> Valid circadian days: 6
#> Epoch length: 60 seconds
#>
#> Non-Parametric Metrics (IS/IV: Witting et al. 1990; RA/L5/M10: van Someren et al. 1999)
#> L5 (least active 5h): 6.10 counts/min, onset 01:28
#> M10 (most active 10h): 602.93 counts/min, onset 12:02
#> L1 (least active 1h): 3.10 counts/min, onset 02:35
#> M1 (most active 1h): 1175.51 counts/min, onset 17:43
#> Relative Amplitude (RA): 0.9800 (range 0-1, higher=stronger rhythm)
#> Interdaily Stability (IS): 0.2279 (range 0-1, higher=more consistent)
#> Intradaily Variability (IV): 1.0008 (near 0 = sine, near 2 = noise)
#> Phi (autocorrelation): 0.4151 (higher=more predictable)
#>
#> Sleep-Based & Variability Metrics
#> Sleep Regularity Index: Not calculated (requires sleep_state input)
#> Onset timing variability: 2.23 hours
#> L5 timing variability: 0.77 hours (circular SD)
#> M10 timing variability: 3.70 hours (circular SD)
#>
#> References: Witting (1990), van Someren (1999)The actogram is usually the first thing worth plotting.
plot_actogram(agd$axis1, agd$timestamp)
Double-plotted actogram: each row is one day shown twice across 48 hours, so a stable rhythm forms a vertical band of activity at the same clock time each day, while scattered fill marks a fragmented or shifting rhythm.
For this recording a high relative amplitude near 0.98 sits with a low interdaily stability near 0.23: the days are strongly active, but the pattern does not land at the same clock time from one day to the next. Every number and figure here regenerates from the installed package and its bundled recording, and the calculations behind them are exercised by the package’s test suite.
Cosinor and the spectrum. cosinor.analysis() fits a 24-hour cosine
(Cornelissen 2014) and rhythmicity.test() checks whether the rhythm is
statistically real; cosinor.multicomponent() adds harmonics and
population.cosinor() compares groups. circadian.period() estimates
the free-running period from a Lomb-Scargle periodogram (Lomb 1976) and
chi.sq.periodogram() from the chi-square periodogram (Sokolove and
Bushell 1978); period.ci() puts a bootstrap interval on it, and
circadian.spectrogram() shows how the period drifts across the
recording. fractal.dfa() measures the long-range correlation in the
series (Peng et al. 1994), and mfdfa() and multiscale.entropy()
describe its finer nonlinear structure.
Rhythms that move rather than repeat. A set of nonstationary methods
reads the change directly. circadian.wavelet() returns the
time-frequency power surface with its cone of influence,
circadian.emd() with hilbert.huang() give a data-adaptive
decomposition and an instantaneous period, and circadian.ssa()
separates the series into trend, circadian, and residual components.
circadian.flm() fits a functional model of the daily profile,
rest.hmm() infers rest and active states with a hidden Markov model,
sleep.changepoints() locates each night’s onset and wake straight from
the counts (Chen and Sun 2024), and curve.registration() aligns the
days on their active-phase landmark for a scale-invariant phase marker.
Sleep, regularity, and fragmentation. sleep.cole.kripke() and
sleep.sadeh() score each epoch as sleep or wake (Cole et al. 1992;
Sadeh et al. 1994). rest.periods() (Roenneberg et al. 2015) returns
every consolidated rest bout, naps included, while rest.crespo()
(Crespo et al. 2012) detects the main daily rest periods.
sleep.regularity.index() (Phillips et al. 2017), social.jet.lag(),
and lids() (Winnebeck 2018) summarise sleep regularity, chronotype
misalignment, and the ultradian sleep cycle, and phase.concentration()
and state.transitions() test day-to-day phase clustering and
rest-activity fragmentation.
From files to counts to raw acceleration. Counts can come from more
than .agd files: read.actigraph.csv() reads ActiLife epoch CSVs, and
read.raw() turns raw .gt3x, .cwa, and .bin files into counts
with the agcounts implementation of the ActiGraph count algorithm
(Neishabouri 2022); gt3x.counts(), axivity.counts(), and
geneactiv.counts() do the same per brand, with cross-brand counts
treated as an approximation rather than native ActiGraph output.
raw.metrics() returns per-epoch ENMO, MAD, and the z-angle with van
Hees (2014) auto-calibration, and circadian.raw() runs every method
above on ENMO from one call. The z-angle drives a diary-free sleep
pipeline that counts cannot: rest.spt() finds the nightly sleep-period
window (HDCZA, van Hees et al. 2018), sib.vanhees() scores
sustained-inactivity bouts (van Hees et al. 2015), and
sleep.from.spt() reports onset, wake, WASO, and efficiency.
detect.nonwear.choi(), detect.nonwear.troiano(), and
detect.nonwear.raw() flag non-wear time (Choi et al. 2011; Troiano et
al. 2008; van Hees et al. 2013).
Plots and batch reports. Every analysis prints a readable summary
and draws a themed ggplot: the actogram and periodogram, the
spectrogram, the cosinor fit and confidence ellipse, the wavelet
scalogram, the singular-spectrum components, a circular phase rose, and
a rest-detector comparison strip, each one you can recolour with
theme_actiRhythm() and save with save.circadian.plot(). When a study
has many files, circadian.batch() runs the whole pipeline over a
folder and returns one row per recording, and circadian.workbook()
writes the full analysis to a multi-sheet Excel file.
The package website, https://rdazadda.github.io/actiRhythm/, collects
the full documentation. vignette("actiRhythm") is the get-started
walkthrough and vignette("output-codebook") is a data dictionary for
every metric the package reports. A set of articles goes deeper:
Choosing a
method
maps each question to the right function, Validation against reference
packages
cross-checks the metrics live against GGIR, nparACT, ActCR, and the
cosinor package, and the method-family articles (nonparametric,
cosinor, period, fractal, nonstationary, phase and regularity, sleep,
raw acceleration, batch) each work one family from the math to a worked
example. Every function’s help page also carries its method reference,
so ?circadian.rhythm, ?cosinor.analysis, and ?circadian.period are
good places to read more. Questions and bug reports go to the issue
tracker at https://github.com/rdazadda/actiRhythm/issues, and
contributions are welcome.
Run citation("actiRhythm") for the entry to use in published work.
When you publish results, report the version you ran, from
packageVersion("actiRhythm"), so the analysis stays reproducible
across releases.
MIT, see LICENSE.
actiRhythm is developed and maintained by the Center for Alaska Native Health Research at the University of Alaska Fairbanks.
