Skip to content




Moonlight is a Luna-based interactive viewer for EDF signal and annotation data, specifically designed for polysomnographic data. As well as visualization, Moonlight supports basic analyses and manipulation of sleep data, a range of summary statistics, and hypnogram-based analyses including automated staging using POPS. Below we give a brief tour of the current main components. Moonlight is actively under development - please let us know of any rough edges or missing functionality.


See these notes on how to access Moonlight. Briefly, you can:

  • use our AWS hosted instances at Advantages: no installation. Disadvantages: slower to upload EDFs to the cloud, limited number of instances available at any one time

  • pull our Dockerized version of luna and run from there. Advantages: runs on all platforms that can support Docker Desktop (see here). Disadvantages: requires Docker set up; some Docker versions can currently have slow I/O under default configurations on certain platforms

  • run directly from a local version of lunaR: Advantages: most flexible and fastest option. Disadvantages: requires installation of R and lunaR

Basic principles

Moonlight is designed to upload a single EDF (or EDF+) at a time, optionally along with one or more annotation files. You can then view basic properties of the data, including viewing raw signals. The window contains a number of panels, all of which show some aspect of the uploaded EDF:

  • Left panel : select files to upload and which channels/annotations to view

  • Headers : basic EDF headers

  • Structure : epoch level structure of the data, showing discontinuities (from masking or EDF+D)

  • Hypnogram : hypnogram-based summaries as well as automated staging (POPS) and stage evaluation (SOAP)

  • Annots : visualization and tabulation of annotations

  • Signals : raw signal viewer (including annotations)

  • Stats : basic signal summary statistics (e.g. means, skewness, etc)

  • Time/freq : several whole-night representations: multi-taper spectrograms, Hjorth-plots, and epoch-level time-series clustering

  • Manips : manipulations of the attached signals: resampling, rereferencing, filtering, copying, renaming, etc

  • Norms : prototype of a population-based norms model for EEG and other metrics

  • Luna : evaluation of arbitrary Luna commands

The easiest way to learn is to open an instance at and load the Example data (one of the NSRR tutorial individuals from the SHHS) and/or follow this tutorial which uses Moonlight to step through the the Luna and lunaR tutorial pages.

Left panel

Load data

To attach an EDF (and optionally annotation files) select Load data from the top of the left panel. Note that depending how Moonlight is configured (e.g. running locally versus on the web), the load button/dialog box may look slightly different (either left or right boxes):

img img

With either dialog box, you can upload:

  • a single EDF or EDF+ files (which must end in the extension .edf). If multiple EDFs are selected, only the first will be uploaded.

  • annotation files in Luna .annot format, Luna .eannot or NSRR-style XML formats (ending either .annot, .eannot or .xml). If multiple files are selected, all will be uploaded (and assumed to match the uploaded EDF).

  • All files need to be uploaded at the same time: this means that currently, all files must be in the same folder, in order that they can be concurrently selected.

Example data

Instead of uploading your own data, to try out Moonlight you can alternatively click Example data to attach the NSRR tutorial (learn-nsrr02) file along with the associated XML annotation file:



After uploading, the EDF channels will be available in the list box Channels. Multiple channels can be selected. Selected channels indicate those that will be shown in the Signals tab, and for cetain other panels (e.g. Stats). Note that some panels have their own channel selection method (e.g. the Manips panel, or the multi-taper spectrogram panel), and so they ignore this box. When signals are added to (or removed from) the dataset, this list will be updated.

The image below shows the Channels list box, along with other widgets described below.



As above, this list mirrors the Channels list, and determines which annotations are shown in the Annots and Signals panels. Multiple annotations can be selected.


This list selects a single channel (typically an EEG) to be used to generate the Spectrogram at the top of the main window. Note one wrinkle: this doesn't automatically update after masking/restructuring a dataset (deleting epochs). To update it, one currently must select a second channel, then go back to the first.

Listed annotations

Whereas the top Annotations list indicates which annotations will be shown, this second box determines which annotation events are listed in the Instances box below.


If Listed Annotations are selected, any events will be listed in this box. Clicking on an entry when viewing the Signals panel will move the window to the epoch(s) containing that event. For events less than 10 seconds in duration, a single 30-second window is selected. For longer events, multiple epochs will be shown, centered around the selected event.



After masking epochs (e.g. via the Manips/Mask panel, or directly running MASK via the Luna panel), this button will effectively run a RESTRUCTURE command, to actually remove those masked epochs from the (in-memory) dataset.


Clicking Refresh returns the in-memory dataset to as it was when the files were first uploaded. i.e. any masks, new channels and other changes are dropped. It should be the same as reloading a file (but will be quicker).


Based on the channel selected in the Spectrogam list (left panel), Moonlight generates a spectrogram using Welch's method and Luna's PSD command. The x-axis is all currently included epochs; the y-axis is 0.5 to 25 Hz; the z-axis (color) is the log-scaled spectral power. Note that only signals with a sample rate of 50 Hz or more are included in the Spectrogram list.


Below the spectrogram, if sleep stage are available, Luna will output a hypnogram (red=REM, green=wake, yellow=Lights, gray=unknown, light-dark blue=N1, N2 and N3) in 30-second epochs. NREM cycles are estimated and shown as alternating orange/purple bars above the hypnogram.

You can select a range by clicking and dragging on the hypnogram to define the Lights Out range - all epochs before and after will be set to L internally - these changes will be respected by the POPS stager - i.e. only epochs within the Lights Out interval will be staged.

Finally, Below the hypnogram, a small bar plot shows which epochs are currently masked (gray) or not (orange). Running Re-epoch (or RESTRUCTURE) will remove gray epochs (and plot them as white, i.e. gaps) in this plot. If a dataset has been masked and re-epoched in this way, the spectrogram will only show included epochs:


In contrast, (unless different Lights Off/on markers are set) the hypnogram is only calculated once, when first uploading the data and based on all epochs.



The first panel in the main window gives a simple tabulation of the main EDF header values: overall (left) and per channel (right).


Note that the tables are scrollable (e.g. if the number of rows is too great to display) and can be copied to the Clipboard by clicking the Copy button.



This panel shows the epoch-level structure of a dataset.


This panel is only useful for EDF+D files (i.e. those with discontinuities, i.e. gaps. Internally, this runs Luna's SEGMENTS command and graphs the output. If epochs have subsequently been dropped (from either an EDF/EDF+C or EDF+D) then the lower figures show these selected epochs - i.e. what constitutes the current in-memory dataset, which may contain gaps, e.g. after selecting only N2 epochs.


The table below the plot shows actual times of segments/gaps in the data.


This panel shows three tables of the epochs in the dataset (30-seconds): 1) for the initial dataset, aligned to the EDF start, 2) for the initial dataset, aligned to sleep staging, 3) for the current in-memory dataset, aligned to staging annotations. See the tutorial for an example.



As well as generating the hypnogram in the top of the display, Moonlight derives numerous statistics based on the hypnogram, shown in various sub-panels as described below. All metrics are based on the staging uploaded at the study start (i.e. rather than SOAP/POPS staging).


Basic summaries from Luna's HYPNO command, including TST, WASO, sleep efficiency, etc.


Key times from HYPNO annotated in elapsed seconds, epochs and clock-time:

  • X0: recording start

  • X1: lights out (or start of recording)

  • X2: sleep onset

  • X3: sleep midpoint

  • X4: final wake

  • X5: lights on (or end of recording)

  • X6: end of recording


Stage duration (minutes, epochs and % of sleep) as well as the number of bouts and the median bout length (minutes). Stages are defined as N1, N2, N3, R and W. In addition, S is any sleep, WASO is wake afetr sleep onset, and ? denotes unknown epochs.



For NREM cycles inferred from the hypnogram, this sub-panel enumerates their start/stop times and extent of REM and NREM epochs.


This sub-panel shows an epoch-level tabulation of sleep stages alongside some other key metrics from HYPNO: e.g. a marker of persistent sleep and WASO, as well as counts of elasped (cumulative) sleep.

Stage annotations

If the annotations present in the dataset aren't recognized by Luna (i.e. are mapped to N1, N2, N3, ...) then the corresponding labels can be selected explicitly here. Click Assign to recalculate the hypnogram and metrics in this case. Often Luna will be able to guess, e.g. Stage N2 is remapped to the standard label N2 internally.


This sub-panel implements a simple single-channel instance of the SOAP model, described here. Select a channel (typically EEG, but it does not need to be - although it should have a minimal 50 Hz sample rate and be expected to vary with sleep stage) and then click Run SOAP. After a few seconds, a plot like the following will appear:


In all these plots, the x-axis corresponds to epochs - and will align with the top spectrogram, hypnogram and mask plots. The upper plot shows the posterior probabilities from SOAP (same color scheme as above). The middle plot shows the most likely SOAP stage for each epoch. The lower plot shows the original hypnogram in the same condensed form. The tables beneath gives the SOAP kappa values and estimates of stage duration, all as generated by the SOAP command. In the SOAP context, low kappa values (e.g. less than 0.5) indicate likely problems with the consistency of the signal and/or stage annotations provided.

If no stage annotations are uploaded, then the SOAP module will not be available.


Moonlight currently supports two precomputed POPS models for automated sleep staging. POPS can be run whether or not any original stage annotations are present.

  • M1 : single EEG model - expects a central EEG, contra-lateral mastoid referenced (although, in practice, the model is likely to be reasonably robust to other channels, e.g. frontal, or with linked-mastoid referencing used, etc)

  • M2 : similar to M1, except expecting two central EEGs (i.e. C3-M2 and C4-M1 typically). This uses POPS channel equivalance options to fit two single-EEG models and select the most confident predictions automatically (i.e. highest posterior for that epoch).

Both models expect signals to have been band-pass filtered 0.3 - 35 Hz -- you can check the Pre-filter button if the signals have not been filtered, and then Moonlight will perform the filtering on-the-fly. (After running, filtered and normalized versions of the signal(s) used will appear as new channels in the dataset, with _FLT and _NORM extensions.)

Checking SHAP will produce SHAP information content scores for different features used: this is an advanced feature that will not be of use for most users and will slow down POPS also.

After clicking Run POPS, it can take around 5 to 10 seconds typically (depending on recording duration and original sample rate) to generate the predictions, which will appear as below:


Above, the Summaries sub-panel shows a plot that is similar in structure to the SOAP plot described above (i.e. top two rows show POPS predictions, the bottom row shows any original staging). Beneath this, measures such as kappa and implied stage durations are shown, similar to SOAP.

The Epochs sub-panel lists the predicted stages along with the posterior probabilties and the original stages (if present). This can be copied to the Clipboard and saved.




This panel shows any annotations selected in the left panel Annotations list, in a whole-night plot (x-axis elapsed hours from EDF start), as below.


Benath the plot, the Summary sub-panel shows metrics for all annotations (not just those selected).



The Instances sub-panel shows the actual events for selected annotations only. This table can be sorted by different columns by clicking on the header; as with other Moonlight tables, it can be copied to the Clipboard.



For selected signals and annotations (from the left panel), this panel shows the raw data, e.g. here for several channels and annotations for a 30-second epoch (the default window size):


One can zoom out with the Out button (i.e. 1->3->5 epochs, etc) and back in with the In button. If the range is too large, raw signals will not be displayed.

You can click on the condensed hypnogram above the plot to move to that postiion (a small black dot under indicates the current location). You can also move the window forward and backward in time with the Next and Prev buttons. As noted above, you can also navigate around the recording by clicking on Listed annotations in the left panel. (To also see those annotations in the plot, they must also be selected in the upper Annotations list in the left panel.)

Filter toggles on/off a bandpass filter to all displayed signals (in the view only, this does not impact the underlying signal data).

You can also select a region (holding down left mouse button) of the main window to zoom in - e.g. to look at only a few seconds of recording, as below:




The Stats window takes the channels as selected in the left Channels tab, and for the current set of unmasked epochs calculates basic statistics (e.g. mean, min, max, etc).


Channel-level statistics are based on the median of epoch-level statistics, and are shown under the Stats/Channels sub-panel.



Epoch-level statistics are also available under the Stats/Epochs sub-panel.




This tab contains a number of more advanced summaries and metrics.


The Spectrogram sub-panel applies the MTM multi-taper spectrogram command. This is quite instence for a long/high-sample rate signal, i.e. it may take 5-10 seconds to complete. It is based not on the channel(s) in the left Channels box, but rather has its own Channel tab. You must hit Run MTM to generate the top level spectrogram.


Note that the min/max frequency controls, as well as the winsorization (i.e. of the heatmap) can be altered after running the MTM - these modify the plot on-the-fly which can be useful for visualization. Here are the same data but with these parameters changed:


If you click anywhere within the top (whole-night) spectrogram, then (after a few seconds) two lower spectrograms will appear. The middle is a window of 1 minute, using a segment size of 6 seconds (with 0.25s increments) and tw parameter of 3. In contrast, the top spectrogram has a segment size of 30, no overlap, and tw of 15.

Clicking on the middle window re-centers the lower spectrogram, which is a 10-second window, using a segment size of 2.5s (increment 0.05 seconds) and tw of 5. The raw signal is also shown beneath for this interval:

The plot below shows the four windows: img


The Hjorth panel shows a series of so-called "Hjorth plots" for the signals selected by the left Channels tab.

Briefly, each line is one epoch, the x-axis is time across the night. The height of each bar is proportional to the first Hjorth parameter (activity / RMS). The color/heat of the top half of each line is proportional to the second Hjorth parameter, which basically tracks modal frequency. Thus blue means slower activity, reds mean faster activity. The lower half of each line is proportional to the third Hjorth parameter (complexity). Thus blues indicate signals that do not change markedly (in terms of their typical frequency of oscillation), whereas reds indicates more changeable/complex signals. A bottom panel will show the raw signal (30s epoch) for which channel/epoch the mouse is currently hovering over:


The plot below gives a three example epochs of raw signal (A, B and C) corresponding to various parts of the night for a single EEG.

  • A : both sides dark blue, meaning slower oscillations and consistent signals

  • B : a faster and more variable signal (i.e. reflecting interference)

  • C : a highly corrupt, clipped large-amplitude signal


These types of plots can provide convenient summaries to show broad patterns of structure/gross artifacts in signls - in particular for signals where the typical time/frequency spectrograms may not be as convenient or readily interpretable (as they are for the EEG).


The EXE panel provides an implementation of the EXE representative command.

Select a single channel using the box in this panel (i.e. not the left Channels tab). The m, t and Splits parameters control aspects of the clustering heuristic. After clicking Run ExE, you will see a) a heatmap of the epoch-by-epoch distance matrix on the left, b) five (by default) exemplar epochs, along with an indication of the other epochs that are similar to it.

If you hover with the mouse over the heatmap, the corresponding raw signals will be shown at the top (left/right = row/column). Overall, this can provide a quick way to see the overall structure of a signal, and to zoom in on aberrant epochs, etc.




This panel provies a series of sub-panels to perform basic manipulations of signals.

documentation for each sub-panel to be added



Bandpass filter






Map channels

Map annots



documentation to be added



documentation to be added


documentation to be added

img img img


documentation to be added



Back to top