Skip to content
Sleep and physiology

Potato for sleep and physiological signals

Score polysomnograms in 30-second epochs, mark EEG artifacts and seizures, or review ECG beats, then export each scorer's labels as BIDS events files.

Potato shows polysomnography, EEG, ECG, and wearable recordings in the browser, where annotators score sleep stages in 30-second epochs or mark artifacts, seizures, beats, and activity bouts as intervals and events on the signal. Potato is free and open source, runs on your own server, and keeps each scorer's labels apart for export as BIDS events files.

Sleep staging assigns each 30-second epoch of a polysomnogram one of the five stages W, N1, N2, N3, and R (REM) defined by the American Academy of Sleep Medicine (AASM). In the AASM's inter-scorer reliability program, more than 2,500 scorers staged the same 1,800 epochs, and average agreement on sleep stage was 82.6% (Rosenberg and Van Hout, 2013). Agreement with the majority score was lowest for N1, at 63.0%, followed by N3 at 67.4%. A study that reports N1 or N3 time therefore gains from several scorers per recording and an agreement figure between the scorers. Potato runs that kind of study by sending each recording to the number of scorers you set and storing every scorer's stages under that scorer's name.

Sleep and physiology tasks in Potato

Each row uses the time_series display and the interval_label scheme, both new in Potato 2.13, and the linked page has the configuration.

TaskHow Potato handles the taskDocs
Score sleep stagesEpoch mode shows one 30-second epoch at a time, and a stage key labels the epoch and moves to the nextTime series
Mark arousals or apneasA second, free-mode scheme on the same plot, where annotators click to mark an event or drag to mark an intervalTime series
Mark EEG artifacts, seizures, and spikesFree mode, with each interval on every channel or on one lane, set by channel_scopeTime series
Review ECG beats and rhythmsA WFDB record opens from the .hea header, and the beats and rhythms in the .atr file load as point events and intervals to correctTime series
Label wearable recordingsCSV or Parquet files with one column per channel, such as accelerometer axes, labeled in free modeTime series
Inter-scorer agreementPer-epoch stages from every scorer in one export file, for Cohen's or Fleiss' kappaInter-annotator agreement

A sleep staging study with three scorers

The config below has three scorers stage every recording in 30-second epochs on an EEG, an EOG, and a chin EMG lane. The time series page has every option and the item format.

yaml
annotation_task_name: "Sleep staging"
task_dir: .
media_directory: media
output_annotation_dir: annotation_output
data_files: [data/psg.json]       # each item names its EDF file in "signal"
item_properties: {id_key: id, text_key: note}
user_config:
  allow_all_users: true
 
num_annotators_per_item: 3
 
instance_display:
  fields:
    - key: signal
      type: time_series
      label: "PSG"
      display_options:
        window: 30
        channels:
          - {name: "EEG Fpz-Cz", range: [-120, 120]}
          - {name: "EOG", range: [-150, 150]}
          - "EMG chin"
 
annotation_schemes:
  - annotation_type: interval_label
    name: stage
    description: "Sleep stage of each 30-second epoch"
    signal_field: signal
    mode: epoch
    epoch_length: 30
    pre_annotations: false
    require_all_epochs: true
    label_requirement: {required: true}
    labels:
      - {name: W, key_value: "1"}
      - {name: N1, key_value: "2"}
      - {name: N2, key_value: "3"}
      - {name: N3, key_value: "4"}
      - {name: REM, key_value: "5"}

num_annotators_per_item: 3 sends each recording to three scorers. A hypnogram already stored in an EDF+ file would show as a dashed starting point, and pre_annotations: false hides that hypnogram so the three scorings stay independent. With require_all_epochs and label_requirement together, Next stays blocked until every epoch has a stage.

Getting recordings in and labels out

The file extension of each recording picks the reader:

  • EDF and BDF. EDF, EDF+, BDF, and BDF+ files open with no extra library. EDF+ annotations load as pre-annotations, and preannotation_labels renames hypnogram entries such as "Sleep stage 2" to the scheme's labels.
  • WFDB. PhysioNet records open from the .hea file and need the signals extra (pip install 'potato-annotation[signals]'). Join multi-segment records before loading.
  • CSV and Parquet. A time column plus one column per channel, which suits wearable exports. A BIDS events.tsv named in an item field loads as pre-annotations.

Signal files are read on the Potato server from the media directory, and the display refuses URLs. The bids_events export writes one events.tsv per scorer and recording, with the onset and duration columns that the BIDS specification requires:

bash
python -m potato.export -c config.yaml -f bids_events -o exports/bids

Potato's agreement metrics do not cover interval_label schemes. The interval_label export writes intervals.csv, and in epoch mode the file has one row per epoch per scorer. Joining the rows on instance_id and start gives one row per epoch with every scorer's stage, the table that Cohen's kappa for two scorers or Fleiss' kappa for more needs.

Working alongside EDFbrowser, Lunascope, and MNE-Python

EDFbrowser is a free viewer, annotator, and toolbox for EDF, EDF+, and BDF files, with an annotation editor and a hypnogram, and suits one scorer working through files on a desktop. Lunascope is a desktop application for sleep signal visualization, annotation, and analysis, with automated staging and import from the National Sleep Research Resource, and fits large cohorts where a model stages first. MNE-Python lets EEG researchers drag annotations onto raw.plot() and suits labeling done inside a scripted analysis. For ECG, PhysioNet's LightWAVE views and edits WFDB annotations in the browser. Potato fits when several scorers label the same recordings, because Potato assigns each recording to a set number of scorers and exports each scorer's labels separately.

Setting up the study with a coding agent

potato-skill 1.2.0 knows interval_label and time_series by name and guides Claude Code, Codex, or Cursor through the study-design side, such as what to ask scorers, how many scorers see each recording, training and attention checks, and export. The skill does not yet document the signal file formats, the display options, or the signals extra. Point the agent at the time series page and the page's Markdown copy, https://www.potatoannotator.com/docs/annotation-types/time-series.md, for the formats and options.

Frequently asked questions

Is there free software for scoring sleep stages in 30-second epochs?

Potato is free, open-source software (GPL-3.0-or-later) that scores a polysomnogram one 30-second epoch at a time in the epoch mode of the interval_label scheme. A stage key labels the current epoch and moves to the next, and [ and ] move without labeling. The strip under the plot colors every scored epoch by stage.

Can I mark a seizure or artifact on some EEG channels only?

Yes. With channel_scope: channel, an interval applies to the lane where the drag started, and with channel_scope: either a toggle above the plot chooses between one lane and every channel. An electrode artifact can sit on one lane while a generalized seizure spans every channel. The stored interval names the channel, or null for all channels, and the channel column of the export names the same lane.

Can scorers start from an existing hypnogram and correct the stages?

Yes. Stage annotations in an EDF+ file load as a dashed starting hypnogram, and preannotation_labels maps names such as "Sleep stage 2" to the scheme's labels. Scorers keep, edit, or discard the starting stages, and a stage left unchanged is exported with source set to file.

How do I save manual EEG annotations to a file?

Potato stores each annotator's labels on the Potato server, and python -m potato.export writes the labels to intervals.csv or to one BIDS events.tsv per annotator and recording. Each row of intervals.csv names the annotator, the item, the label, the start and end times, and the channel.

Further reading

References

  1. Rosenberg and Van Hout (2013). The American Academy of Sleep Medicine Inter-scorer Reliability Program: Sleep Stage Scoring. Journal of Clinical Sleep Medicine 9(1). https://doi.org/10.5664/jcsm.2350

Start here

Other fields

All use cases