Published July 11, 2026 | Version v0.1.1

circadia-bio/hypnoR: v0.1.1

Authors/Creators

  • 1. King's College London

Description

✨ New features

  • Added new_hypnogram(), the constructor underlying all other hypnoR functions. Accepts either a bare tibble with epoch/stage columns (e.g. zeitR::export_hypnogram() output) or an mrpheus_hypnogram object (mrpheus::export_hypnogram() output), normalising both into a single hypnor_hypnogram representation. Staging resolution (AASM vs coarse) is auto-detected from the stage labels present.
  • Implemented compute_sleep_architecture(): TST, TIB, SE, SOL, WASO, REM/SWS latency, and stage percentages, all resolution-agnostic. Sleep onset is defined as the first non-"W" epoch for both AASM and coarse hypnograms. epoch_sec and staging resolution are read automatically from the hypnor_hypnogram object rather than passed as arguments.
  • Implemented compute_transitions(): stage-to-stage transition matrix (counts or row-normalised probabilities) plus fragmentation index and wake-transition count. New include_wake argument controls whether Wake is included as a state in the matrix; fragmentation metrics always use the full epoch sequence regardless of this setting.
  • Implemented compute_cycles(): NREM/REM cycle segmentation for full AASM hypnograms, with two selectable algorithms. method = "feinberg_floyd" (default) treats any maximal contiguous REM run of at least min_rem_epochs as a REM period, with no tolerance for interruption. method = "aasm" merges REM runs separated by a gap of at most rem_gap_min minutes (default 15) into a single REM period before applying the min_rem_epochs threshold. Errors on coarse hypnograms, which have no REM stage to segment on.
  • Added smooth_hypnogram(), a hypnogram-level cleanup step for raw unsmoothed per-epoch staging (e.g. mrpheus::stage_epochs(), which has no temporal continuity constraint and can produce isolated single-epoch stage flips). Two label-only rules, applicable independently or in sequence: "aasm_isolated" (default) reassigns a single epoch flanked identically on both sides; "min_run" merges any run shorter than min_run_epochs into whichever flanking run is longer, regardless of whether the flanks agree. The original labels are preserved in a new stage_raw column.
  • Added window_hypnogram(): restricts a hypnogram to a time (lights_off/ lights_on) or epoch (from_epoch/to_epoch) window, correctly preserving epoch_sec and resolution on the result rather than re-detecting them from the (possibly much smaller) subset. This is the single place windowing logic lives -- compute_cycles() and compute_transitions() have no lights_off/lights_on arguments of their own; window first, then pass the windowed hypnogram in.

πŸ“Š Visualisation

  • Implemented plot_hypnogram(), plot_architecture(), and plot_transition_matrix(). All three use a runtime ggplot2 check rather than a hard dependency (consistent with the rest of the ecosystem) and share the built-in Circadia Lab stage colour palette. plot_hypnogram() takes an optional cycles argument (the tibble from compute_cycles()) to overlay cycle-boundary lines; plot_architecture() facets on a night/id column when present, for comparing nights.
  • plot_hypnogram() gains an x_axis argument ("auto" (default), "time", or "hours"). When the hypnogram carries real timestamps (i.e. start_time was supplied to new_hypnogram() or mrpheus::export_hypnogram()), the x-axis now shows actual clock time by default instead of always using elapsed hours since the first epoch.
  • plot_hypnogram() gains a style argument: "step" (default, unchanged) or "capsule" -- rounded-pill bars per contiguous stage run, one lane per stage, loosely modelled on the Apple Watch sleep chart's visual language (Circadia Lab palette, full AASM lane ordering, light theme rather than Apple's dark coarse 4-stage scheme). ggplot2 has no native rounded-rect geom, so pills are hand-traced polygons (corner radius scales with each bar's own width, via the new corner_min argument).
  • Rotated the stage colour palette: N1 -> Wake -> REM -> N1. W is now cream (was N1's), REM is now amber (was wake's), N1 is now teal (was REM's); N2/N3/Sleep/Quiet sleep unchanged.

πŸ› Bug fixes

  • compute_cycles()'s start_epoch/end_epoch columns were reporting row position within hypnogram, not the actual values in hypnogram$epoch -- identical whenever epoch runs 1:n (true of every fixture in the test suite so far), but wrong for any hypnogram that doesn't start at epoch 1, e.g. after subsetting a longer recording down to a sleep-period window. Durations (nrem_min/rem_min/cycle_min) were unaffected, since those were already computed from row-position differences rather than the epoch column.
  • Behaviour change: compute_sleep_architecture()'s lights_off/ lights_on arguments now restrict every metric via window_hypnogram(), not just TIB/SE as before -- previously TST, SOL, WASO, and stage percentages were computed over the entire hypnogram regardless of the window, which was inconsistent. Requires hypnogram to carry real timestamps; errors if time is entirely NA.

πŸš€ CI

  • Fixed mrpheus/zeitR dependency resolution in CI: added Additional_repositories: https://circadia-bio.r-universe.dev and a repo-root .Rprofile setting options(repos = ...) directly. Additional_repositories alone doesn't automatically wire into pak's dependency resolution during CI -- it's mainly a documentation/NOTE- suppression field -- so the .Rprofile is what actually makes both packages resolvable.
  • Added a covr-based coverage step to the pkgdown.yaml workflow, writing a coverage badge (docs/badges/coverage.json) to gh-pages on pushes to main/master/release (matching zeitR's setup). covr added to Suggests; new dev/check_coverage.R for running coverage locally. README gains R CMD CHECK and Coverage badges.

πŸ“š Documentation

  • Rewrote vignette("getting-started") to reflect the actual current API (the previous version referenced read_hypnogram(), which doesn't exist yet), and to run against real recordings from both staging sources rather than hypothetical placeholder code: mrpheus's bundled SC4001E0 example for the AASM path, and zeitR's bundled input1.txt ActTrust recording (via its full rest-activity pipeline) for the coarse path -- demonstrating the staging-agnostic contract concretely: compute_sleep_architecture() returns NA for AASM-only fields on coarse hypnograms and populates the coarse-only ones instead, compute_transitions() works over a 3x3 matrix instead of 5x5, and compute_cycles() errors clearly on coarse staging (no REM stage to segment cycles on). Both mrpheus- and zeitR-dependent chunks are guarded with requireNamespace(); both packages added to Suggests. New dev/test_mrpheus_pipeline.R and dev/test_zeitR_pipeline.R.
  • Added two worked-example articles ("Worked examples" on the pkgdown site), cross-linked to each other: vignette("mrpheus-integration"), a warts-and-all walkthrough of diagnosing scattered raw REM calls, smoothing, windowing to the real sleep period, and comparing compute_cycles()'s two methods; and vignette("zeitR-integration"), the coarse-staging counterpart -- timestamp-gap inspection, why off-wrist time is folded into "W", picking the right night out of a multi-day recording, and checking (rather than assuming) whether smoothing matters as much for actigraphy-derived staging as it did for mrpheus's raw automatic staging.

Files

circadia-bio/hypnoR-v0.1.1.zip

Files (221.4 kB)

Name Size Download all
md5:0a60d24714d1d3ba96c26c5f9200f56b
221.4 kB Preview Download

Additional details

Related works