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. The display and the scheme are new in Potato 2.13. The page linked in each row has the configuration.
| Task | How Potato handles the task | Docs |
|---|---|---|
| Score sleep stages | Epoch mode shows one 30-second epoch at a time, and a stage key labels the epoch and moves to the next | Time series |
| Mark arousals or apneas | A second, free-mode scheme on the same plot, where annotators click to mark an event or drag to mark an interval | Time series |
| Mark EEG artifacts, seizures, and spikes | Free mode, with each interval on every channel or on one lane, set by channel_scope | Time series |
| Review ECG beats and rhythms | A WFDB record opens from the .hea header, and the beats and rhythms in the .atr file load as point events and intervals to correct | Time series |
| Label wearable recordings | CSV or Parquet files with one column per channel, such as accelerometer axes, labeled in free mode | Time series |
| Inter-scorer agreement | Per-epoch stages from every scorer in one export file, for Cohen's or Fleiss' kappa | Inter-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.
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. With the hypnogram hidden, 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_labelsrenames hypnogram entries such as "Sleep stage 2" to the scheme's labels. - WFDB. PhysioNet records open from the
.heafile and need thesignalsextra (pip install 'potato-annotation[signals]'). Join multi-segment records before loading. - CSV and Parquet. Each file has a time column plus one column per channel. That layout suits wearable exports. A BIDS
events.tsvnamed 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:
python -m potato.export -c config.yaml -f bids_events -o exports/bidsPotato'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. That table is the input to Cohen's kappa for two scorers or Fleiss' kappa for more.
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. EDFbrowser 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. Lunascope 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) for scoring a polysomnogram one 30-second epoch at a time with 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
- Time series, for every format, display option, and scheme option
- How many annotators do you need?, for choosing the number of scorers per recording
- Adjudication and disagreement, for settling the epochs scorers stage differently
- Air-gapped deployment, for running Potato on a network with no route out
- Healthcare and clinical and psychology, for neighboring fields on this site
References
- 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