A Python package for hypnogram analysis. hypnofunk provides a streamlined, open-source toolkit to extract structural and continuous data from sleep stages, evaluate Markov-chain stage transitions, and analyze polysomnography (PSG) macro-architecture.
- Use edf reader instead of heavy mne to read edf annotations
- Better handling of transitions.py function to report sleep compactness correctly even when say N1 stage is not present
- Better documentation for onset (for example R onset is calculated from onset of a sleep stage and not from the start of the hypnogram)
- Improve annotation reading and autofixes when there are non sleep annotations like movements, ?s, other labels like leg movement or apnea
hypnofunk is a high-performance toolkit for sleep researchers. It calculates 40+ macrostructure parameters, performs first-order Markov-chain transition analysis, and detects sleep cyclesβall from simple hypnogram sequences.
# Core package
pip install hypnofunk
# Full installation β includes Lempel-Ziv complexity, plotting, and EDF support
pip install hypnofunk[full]hypnofunk accepts standard AASM sleep stage labels (W, N1, N2, N3, R) as:
- Python lists, NumPy arrays, or Pandas Series.
The included polyman_analysis.py provides a turnkey solution for:
- EDF / EDF+: Reads Polyman-style annotations directly.
- CSV: Processes exported spreadsheets with epoch-by-epoch scoring.
hypnofunk uses industry-standard defaults, all of which are configurable via function arguments:
| Parameter | Default | Logic |
|---|---|---|
epoch_duration |
30s |
The standard temporal resolution for clinical sleep scoring. |
max_wake_epochs |
10 |
Keeps 5 mins of wake after final sleep before trimming terminal wake. |
min_nrem_epochs |
30 |
Defines a NREM cycle as β₯15 mins of continuous NREM starting with N2. |
min_rem_epochs |
10 |
Subsequent REM cycles must be β₯5 mins (1st REM cycle can be any length). |
- TIB (Time In Bed):
Total number of epochs Γ epoch_length- What it conveys: The absolute total recording duration from "lights out" to "lights on."
- SPT (Sleep Period Time):
(Epoch of final sleep awakening - Epoch of initial sleep onset) Γ epoch_length- What it conveys: The boundary-to-boundary time elapsed from the very first moment of sleep to the final awakening.
- TST (Total Sleep Time):
Sum of all sleep epochs (N1 + N2 + N3 + REM) Γ epoch_length- What it conveys: The true total time spent asleep during the entire recording.
- WT (Wake Time):
Sum of all Wake epochs Γ epoch_length- What it conveys: The total cumulative time spent awake while in bed.
- SOL (Sleep Onset Latency):
(Index of first sleep epoch - Index of lights out) Γ epoch_length- What it conveys: The time it takes to initially transition from wakefulness into any stage of sleep.
- LPS (Latency to Persistent Sleep):
(Index of first epoch of 10 consecutive minutes of sleep - Index of lights out) Γ epoch_length- What it conveys: The time required to achieve a stable, sustained, and uninterrupted block of sleep.
- REML (REM Latency):
(Index of first REM epoch - Index of first sleep epoch) Γ epoch_length- What it conveys: The duration from initial sleep onset until the brain enters its first cycle of Rapid Eye Movement sleep.
- WASO (Wake After Sleep Onset):
Sum of Wake epochs strictly bounded between the first and last sleep epochs Γ epoch_length- What it conveys: The total amount of awake time that fragments and disrupts the main sleep period.
- SE (Sleep Efficiency):
(TST / TIB) Γ 100- What it conveys: The overall percentage of Time in Bed successfully spent asleep, acting as a primary marker of sleep quality.
- SME (Sleep Maintenance Efficiency):
(TST / SPT) Γ 100- What it conveys: The efficiency of sleep continuity, isolating the ability to stay asleep by ignoring initial sleep latency.
- W (Wake Duration):
Count of Wake epochs Γ epoch_length- What it conveys: Total volume of wakefulness.
- N1 (Stage 1 Duration):
Count of N1 epochs Γ epoch_length- What it conveys: Total volume of transitional, light sleep.
- N2 (Stage 2 Duration):
Count of N2 epochs Γ epoch_length- What it conveys: Total volume of intermediate, stable sleep (typically the majority of the night).
- N3 (Stage 3 / SWS Duration):
Count of N3 epochs Γ epoch_length- What it conveys: Total volume of deep, physically restorative slow-wave sleep.
- REM (REM Duration):
Count of REM epochs Γ epoch_length- What it conveys: Total volume of dream-state, cognitively restorative sleep.
- %N1, %N2, %N3, %REM (Percentage of TST):
(Stage Duration / TST) Γ 100- What it conveys: The internal architecture and proportion of the total sleep spent in each specific stage.
- %W_SPT, %N1_SPT, %N2_SPT, %N3_SPT, %REM_SPT (Percentage of SPT):
(Stage Duration / SPT) Γ 100- What it conveys: The composition of the sleep period, factoring in the WASO (Wake After Sleep Onset) as part of the denominator.
- Num_Awak (Number of Awakenings):
Count of transitions where previous stage β [N1, N2, N3, REM] and current stage = W- What it conveys: The absolute number of times the subject woke up after initially falling asleep.
- Awak_Index (Awakening Index):
Num_Awak / (TST in hours)- What it conveys: The frequency of awakenings normalized per hour of sleep.
- Num_Shifts (Number of Stage Shifts):
Count of transitions where Stage(t) β Stage(t-1)- What it conveys: A gross measure of general sleep instability and macro-architectural fragmentation.
- Shift_Index:
Num_Shifts / (TST in hours)- What it conveys: The frequency of moving between any two sleep stages normalized per hour of sleep.
- Transition Matrix (First-Order Markov Probabilities):
Count of transitions (Stage X β Stage Y) / Total outbound transitions from Stage X- What it conveys: The mathematical probability (from 0 to 1) of moving directly from one specific physiological state to another.
- Transition Counts:
Absolute frequency of (Stage X β Stage Y)- What it conveys: The raw count of specific state changes, useful for mapping specific pathological patterns (e.g., REM β Wake).
- Bout_Count (per stage):
Number of continuous, uninterrupted blocks of a specific stage- What it conveys: How intensely fragmented a specific stage is (higher count for same duration = more fragmented).
- Mean_Bout_Duration (per stage):
Total Stage Duration / Bout_Count for that stage- What it conveys: The average length of time the subject can sustain a specific sleep stage before shifting.
- Max_Bout_Duration (per stage):
Max(duration of all individual continuous bouts for that stage)- What it conveys: The longest single continuous stretch of a given sleep stage achieved during the recording.
Our detection algorithms follow standard clinical research criteria to ensure consistency across datasets:
A sequence is identified as a NREM cycle if:
- It starts with N2 sleep.
- It contains at least 15 minutes (30 epochs) of continuous NREM (N1, N2, or N3).
- This prevents short "transitional" light sleep from being miscounted as a full cycle.
REM detection handles the unique nature of early-night sleep:
- First REM Cycle: Accepted at any length (standard research practice).
- Subsequent REM Cycles: Must be at least 5 minutes (10 epochs) long.
- This ensures that REM "fragments" commonly found in fragmented sleep don't artificially inflate cycle counts.
hypnofunk provides a robust framework for quantifying sleep stability and fragmentation using first-order Markov chains:
- Full Transition Matrix: A 5Γ5 matrix of probabilities for transitions between every sleep stage (W, N1, N2, N3, R).
- Stage Persistence: The probability of remaining in a specific stage (diagonal nodes of the Markov chain).
- Awakening Probabilities: The specific likelihood of transitioning to Wake from each individual sleep stage.
- Sleep Compactness: A global consolidation index calculated as the mean persistence across all sleep stages.
- Fragility Metrics: Proportion of all transitions that result in awakening.
from hypnofunk import hypnoman, analyze_transitions
# 10 epochs Wake, 50 N2, 30 N3, 20 REM, 5 Wake
hypnogram = ["W"]*10 + ["N2"]*50 + ["N3"]*30 + ["R"]*20 + ["W"]*5
# Get 40+ parameters in one line (Macrostructure)
params = hypnoman(hypnogram, epoch_duration=30)
print(f"TST: {params['TST'].values[0]:.1f} min | SE: {params['Sleep_efficiency'].values[0]:.1f}%")
# Analyze stage transitions & Markov chain dynamics
trans = analyze_transitions(hypnogram)
print(f"Sleep Compactness: {trans['Sleep_Compactness'].values[0]:.3f}")
print(f"Prob. N2 Persistence: {trans['Persistence_N2'].values[0]:.3f}")Returns a single-row pd.DataFrame containing:
- Time metrics: TRT, TST, SPT, WASO, SOL.
- Efficiency: Sleep Efficiency (SE), Sleep Maintenance Efficiency (SME).
- Stage statistics: Duration, percentage, and onset latency for all stages.
- Streak analysis: Longest, mean, and median "runs" (streaks) for every stage.
- Information Theory: Lempel-Ziv complexity (LZc) β a non-linear measure of sleep stage variety (requires
antropy).
Performs the Markov-chain analysis described above, returning:
- Total transitions (fragmentation count).
- Probability of awakening.
- Sleep compactness index.
- Per-stage persistence and awakening probabilities.
- Complete transition matrix (25 probability values).
read_edf_hypnogram(): Standardized loader for Polyman EDF and EDF+ files.
hypnoman(): The main entry point for macrostructure metrics.find_nremstretches()&find_rem_stretches(): Cycle detection engines.trim_terminal_wake(): Utility to clean extended wake at the end of recordings.
analyze_transitions(): Main entry point for fragmentation and Markov metrics.compute_transition_matrix(): Raw transition probability calculations.compute_sleep_compactness(): Statistical consolidated sleep index.
plot_hypnogram_with_cycles(): Clean hypnograms with cycle-overlay bars.plot_transition_matrix(): Heatmap visualization of stage dynamics (Markov matrix).
@software{hypnofunk2026,
author = {Venugopal, Rahul},
title = {hypnofunk: A Python package for sleep analysis},
year = {2026},
url = {https://github.com/rahulvenugopal/hypnofunk}
}MIT β see LICENSE for details. Developed by Rahul Venugopal.
