Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow user-defined specification of vigilance states #87

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c48eb12
Fix min/max chan amps for all-positive(/neg) data
TomBugnon Jul 21, 2020
c6e0b79
Load and check states_config_file (incomplete)
TomBugnon Jan 29, 2021
8c31e70
Update Hypnogram object to use new state cfg
TomBugnon Jan 29, 2021
75803d4
Update ui_panels and ui_settings for flex states config
TomBugnon Feb 4, 2021
ecedebb
Use user-defined shortcuts for scoring
TomBugnon Feb 4, 2021
bd3456b
Update scor to and from table for flex state
TomBugnon Feb 4, 2021
35ab9af
Update hypnoprocessing and info table
TomBugnon Feb 5, 2021
9163a2f
Connect hypno color modification
TomBugnon Feb 5, 2021
64c33ae
Update `write_hypno` for flexible state cfg
TomBugnon Feb 9, 2021
029023b
Update read_hypno methods for flexible state cfg
TomBugnon Feb 10, 2021
8c181a5
Allow disabling of info popups in rw_hypno
TomBugnon Feb 10, 2021
79390d3
Update test_rw_hypno
TomBugnon Feb 10, 2021
e561099
Check user state config and use yaml rather than json
TomBugnon Feb 10, 2021
3700819
Add example with user states config
TomBugnon Feb 10, 2021
8df7fb9
Display states' shortcut on GUI
TomBugnon Feb 10, 2021
1e74b72
Change default state colors
TomBugnon Feb 10, 2021
f4e5c23
Add test_read_states_cfg.py
TomBugnon Feb 11, 2021
1afdcf7
Update doc for flexible vigilance states
TomBugnon Feb 11, 2021
bddc0fc
Update write_fig_hypno
TomBugnon Feb 12, 2021
2c8172a
Make sure hypno default value is recognized
TomBugnon Feb 12, 2021
5a7b2d1
Fix sleepstats in case N1 stage is absent
TomBugnon Feb 12, 2021
3ebd21b
Add image with custom states in doc
TomBugnon Feb 12, 2021
8bb433e
Update Sleep() docstring
TomBugnon Feb 12, 2021
8c8376d
Add pyyaml dependencies in .travis and .appveyor
TomBugnon Feb 12, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ install:
# Install dependencies :
- if [ "${TEST}" == "standard" ] || [ "${TEST}" == "examples" ]; then
pip install codecov pytest pytest-cov pytest-sugar pytest-travis-fold pytest-faulthandler openpyxl xlrd;
pip install mne nibabel pandas tensorpac imageio lxml;
pip install mne nibabel pandas tensorpac imageio lxml pyyaml;
conda install -c conda-forge scikit-image;
pip install git+https://github.com/hbldh/lspopt.git#egg=lspopt;
fi;
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ install:
# Install latest vispy version :
- pip install git+https://github.com/vispy/vispy.git
# Install dependencies :
- "pip install mne nibabel setuptools PyOpenGL PyOpenGL_accelerate pytest pandas openpyxl tensorpac xlrd scikit-image imageio lxml"
- "pip install mne nibabel setuptools PyOpenGL PyOpenGL_accelerate pytest pandas openpyxl tensorpac xlrd scikit-image imageio lxml pyyaml"
- "pip install git+https://github.com/hbldh/lspopt.git#egg=lspopt"
- "dir"
# ------------------- VISBRAIN -------------------
Expand Down
Binary file added docs/_static/sleep/flex_vigilance_states.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 95 additions & 19 deletions docs/sleep.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Main features
<div class="alert alert-dismissible alert-primary">
<b>Hypnogram</b>
<ul>
<li>Flexible definition of vigilance states</li>
<li>Load, edit and save</li>
<li>Real-time computation of sleep statistics</li>
<li>Export high-quality hypnogram figure</li>
Expand Down Expand Up @@ -143,7 +144,7 @@ The contextual menu allows to perform several functions such as the loading and
* *Lock scoring to display* : When this option is selected (default), the scoring window is equal to the display window. When this option is off, the epoch used for scoring can be independent from the displayed epoch. See :ref:`hypnogram_scoring`..

**Settings panel** :
The setting panels is where most of the (advanced) functions of the software are! Among other things, you can control which channel to display, adjust the amplitudes, customize the spectrogram and hypnogram, compute the duration of each sleep stage, add annotations to the recording, and perform a bunch of semi-automatic detection (spindles, K-complexes...). See the section :ref:`sleep_settings_panel` for a description of each tab.
The setting panels is where most of the (advanced) functions of the software are! Among other things, you can control which channel to display, adjust the amplitudes, customize the spectrogram and hypnogram, compute the duration of each vigilance state, add annotations to the recording, and perform a bunch of semi-automatic detection (spindles, K-complexes...). See the section :ref:`sleep_settings_panel` for a description of each tab.

.. _sleep_settings_panel:

Expand Down Expand Up @@ -238,15 +239,15 @@ The Infos panel displays the recording infos (e.g. name and downsampling frequen
* Wake After Sleep Onset (WASO) : duration of wake periods within SPT
* Sleep Efficiency (SE) : TST / TDT * 100 (%)
* Total Sleep Time (TST) : SPT - WASO
* W, N1, N2, N3 and REM : sleep stages duration
* Latencies : latencies of sleep stages from the beginning of the record
* Vigilance state duration: "Wake", "N1", "N2", "N3" and "REM" by default
* Latencies of vigilance states from the beginning of the record: "LatWake", "LatN1", "LatN2", "LatN3" and "LatREM" by default

.. _scoringtab:

Scoring
+++++++

This tab contains the scoring table, i.e. where each stage start and finish. For further informations about how to score your hypnogram see :ref:`hypnogram_scoring`.
This tab contains the scoring table, i.e. where each state start and finish. For further informations about how to score your hypnogram see :ref:`hypnogram_scoring`.

.. _detectiontab:

Expand Down Expand Up @@ -279,12 +280,6 @@ mouse wheel Move the current window
double left click Add annotation under mouse cursor
\- Decrease amplitude
\+ Increase amplitude
a Score the current epoch as Artefact
w Score the current epoch as Wake
1 Score the current epoch as N1
2 Score the current epoch as N2
3 Score the current epoch as N3
r Score the current epoch as REM
b Previous window
n Next window
s Display / hide spectrogram
Expand All @@ -305,6 +300,21 @@ CTRL + t Display shortcuts window
CTRL + q Close the window
=================== =======================================================

Some shortcuts are used for scoring the current epoch and may be modified by
the user (see `Hypnogram` section). By default, the vigilance states and their
corresponding shortcuts are the following:

=================== =======================================================
Keys Description
=================== =======================================================
a Score the current epoch as Artefact
w Score the current epoch as Wake
1 Score the current epoch as N1
2 Score the current epoch as N2
3 Score the current epoch as N3
r Score the current epoch as REM
=================== =======================================================

.. ##########################################################################
.. ##########################################################################
.. TUTORIAL
Expand Down Expand Up @@ -357,7 +367,66 @@ If you have a file format that is currently not supported, :class:`Sleep` also p
Sleep(data='mydata.edf', hypno='myhypno.csv', downsample=128).show()

Hypnogram
^^^^^^^^^
~~~~~~~~~


User-defined vigilance states configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

By default, Sleep uses the guidelines of Iber et al. 2007 for vigilance states
nomenclature. Each vigilance state has an associated shortcuts for scoring, and
numerical value on point-per-second hypnograms (see below), as follows::

========== ====== ======================================================
State Value Shortcut
========== ====== ======================================================
Wake 0 'w'
Art \-1 'a'
N1 1 '1'
N2 2 '2'
N3 3 '3'
REM 4 '4'

However, Sleep also offers the possibility to specify custom configuration for
vigilance states:

* 1. Create a `yaml <http://https://learnxinyminutes.com/docs/yaml/>`_ file
formatted as follows:

.. code-block:: yaml
state_1: # Label of vigilance state
value: 1 # Associated value on 'point-per-second'-style hypnogram. Mandatory key
shortcut: 1 # Must require a single key-press. Mandatory key
display_order: 1 # Position on GUI. Mandatory key
color: 'red' # matplotlib color, hexadecimal color or tuple of RGB. default is "black"
state_2: # Must be unique
value: 2 # Must be unique
shortcut: 2 # Must be unique
display_order: 2.0 # Must be unique
# color: 'black' # 'black' if key is missing
state_3:
value: 42
shortcut: w
display_order: 1.00005 # It's not the value but the rank across states that matters.
color: '#56bf8b'

Note that the keys listed in the `Shortcuts` section are reserved and can't be used as shortcuts for scoring.

* 2. Specify the path to you vigilance states configuration file when creating a `Sleep` instance with the `states_config_file` kwarg as follows:

.. code-block:: python
from visbrain.gui import Sleep

Sleep(states_config_file='path/to/my/states_cfg_file.yml').show()

.. figure:: _static/sleep/flex_vigilance_states.png
:align: center

If the `states_config_file` kwarg is not specified, Sleep will use the default
configuration.

Supported hypnogram formats
^^^^^^^^^^^^^^

One of the main objective of Sleep is to **facilitate the sharing of data** across laboratories. This involves being able to accomodate for a variety of hypnogram format (unfortunately, there is no current gold standard on how to save hypnogram data). Here's the list of supported extensions for hypnogram files :

Expand All @@ -367,15 +436,20 @@ One of the main objective of Sleep is to **facilitate the sharing of data** acro
* **.edf** (EDF+)
* **.hyp** (`ELAN <http://elan.lyon.inserm.fr>`_)


.. warning::
Note that during loading of edf-style (.edf or .txt) and Elan-style (.hyp) hypnograms, NREM-S3 and NREM-S4 sleep states will be merged into the N3 vigilance state. That also means that if you load and then save your hypnogram in Sleep, you will loose differentiation between S3 and S4 so be sure not to overwrite your original file!

.. warning::
Please note that Sleep uses the guidelines of *Iber et al. 2007* for sleep stage nomenclature (Wake, N1, N2, N3, REM and Artefact). If your hypnogram includes both NREM-S3 and NREM-S4 sleep stages you can add “N4” categories with the corresponding values in the description file. However, keep in mind that S3 and S4 will be merged into N3 during the import to the Sleep module. That also means that if you load and then save your hypnogram in Sleep, you will loose differentiation between S3 and S4 so be sure not to overwrite your original file!
Note also that `edf` and `ELAN` style hypnogram can only be saved or loaded
with the default configuration for vigilance states.


Save hypnogram
^^^^^^^^^^^^^^

.. important::
Since release v0.4, the default hypnogram export format uses stage duration rather than point-per-second encoding. This format avoids potential errors caused by downsampling and confusion in the values assigned to each sleep stage (which can drastically differ between two labs, e.g. N2 sleep can be encoded with the value 2 in one lab, and -2 in another lab). However, for retro-compatibility, we still allow user to save and load hypnogram in point-per-second format. Please see the image below to see the difference between stage-duration and point-per-second encoding.
Since release v0.4, the default hypnogram export format uses stage duration rather than point-per-second encoding. This format avoids potential errors caused by downsampling and confusion in the values assigned to each vigilance state (which can drastically differ between two labs, e.g. N2 sleep can be encoded with the value 2 in one lab, and -2 in another lab). However, for retro-compatibility, we still allow user to save and load hypnogram in point-per-second format. Please see the image below to see the difference between stage-duration and point-per-second encoding.

.. figure:: _static/sleep/hypno_encoding.png
:align: center
Expand All @@ -399,7 +473,7 @@ Stage Duration

The subject was awake from 0 to 500 seconds, then fell in N1 sleep between 500 to 750 seconds, then in N2 sleep between 750 to 2000 seconds, then in N3 sleep and so on. The subject was awakened in REM sleep, and the recording was stopped shortly after. The total duration of the recording (in seconds) corresponds to the last value of the hypnogram, in that case 30100 seconds.

The main advantages of using such an encoding format for the hypnogram is that it avoids any confusion related to the values used for each sleep stage, and drastically reduces the hypnogram file length without loosing any information. Please note that the software contains command-line functions to convert between point-per-second and stage-duration encoding.
The main advantages of using such an encoding format for the hypnogram is that it avoids any confusion related to the values used for each vigilance state, and drastically reduces the hypnogram file length without loosing any information. Please note that the software contains command-line functions to convert between point-per-second and stage-duration encoding.

.. tip::
If you want to add any relevant informations / comments to the hypnogram, you can do so by adding lines preceded by an asterisk directly within the text file. Sleep will not read any line in the hypnogram that starts with an asterisk mark. For example, you can add the name of the scorer::
Expand All @@ -413,11 +487,13 @@ The main advantages of using such an encoding format for the hypnogram is that i
Elan .hyp format
++++++++++++++++

Alternatively, if you prefer point-per-second encoding, you can save your data in .hyp format, which can be read with any text editor. Sleep will create a single .hyp file with 4 header rows and the values presented above for the sleep stages, with the exception that the value assigned to REM sleep will be 5 for compatibility with Elan hypnogram reader.
Alternatively, if you prefer point-per-second encoding, you can save your data in .hyp format, which can be read with any text editor. Sleep will create a single .hyp file with 4 header rows and the values presented above for the vigilance states, with the exception that the value assigned to REM sleep will be 5 for compatibility with Elan hypnogram reader.

This format (as well as EDF format) can only be saved or loaded in Sleep when
using the default configuration for vigilance states.

.. important::
If your hypnogram was created using another software, and is encoded in point-per-second, it is important that Sleep knows which value is associated with each sleep stage (e.g. 2 = N2 sleep, 4 = REM sleep). To do that, you need to create a simple text file in the same directory as the original hypnogram file, named: *HYPNOFILENAME_description.txt*. Checkout this `example <https://drive.google.com/file/d/0B6vtJiCQZUBvYUFnQS1HWHhjSkE/view?usp=sharing>`_.
If your hypnogram was created using another software, and is encoded in point-per-second, it is important that Sleep knows which value is associated with each vigilance state (e.g. 2 = N2 sleep, 4 = REM sleep). To do that, you need to create a simple text file in the same directory as the original hypnogram file, named: *HYPNOFILENAME_description.txt*. Checkout this `example <https://drive.google.com/file/d/0B6vtJiCQZUBvYUFnQS1HWHhjSkE/view?usp=sharing>`_.

**This text file should contain the following information :**

Expand Down Expand Up @@ -595,7 +671,7 @@ Navigation

This is probably the most useful editing method, as it allows scoring while scrolling through your data.

To insert a sleep stage, use the keys below :
To insert a vigilance state, use the keys below :

============== =================
Keys Description
Expand Down Expand Up @@ -663,7 +739,7 @@ The Detection panel offers several semi-automatic algorithms for the detection o
* All : apply detection on all channels (even those that are hidden)

.. note::
After performing one of the detection, go to the *Location* tab to see infos about each detected events (starting and ending points, duration, sleep stage). Select the event to jump to it. Finally, you can export the location table using the File > Save contextual menu.
After performing one of the detection, go to the *Location* tab to see infos about each detected events (starting and ending points, duration, vigilance state). Select the event to jump to it. Finally, you can export the location table using the File > Save contextual menu.

Two examples of automatic event detection are shown below.

Expand Down Expand Up @@ -705,7 +781,7 @@ Perform a peak detection.


.. important::
Please note that the software does not yet allow to automatically score sleep stages. However, if you are interested to collaborate and / or implement your own algorithm, please feel free to contact us.
Please note that the software does not yet allow to automatically score vigilance states. However, if you are interested to collaborate and / or implement your own algorithm, please feel free to contact us.

.. _replace_detection:

Expand Down
45 changes: 45 additions & 0 deletions examples/gui_sleep/example_states_cfg.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
???:
value: 42 # Value on 'sample'-style hypnogram
shortcut: 6 # Single key press
display_order: -3.14 # It's the rank across states that matters
color: yellow # 'matplotlib' colors are accepted. "black" if missing key
Art:
value: -1
shortcut: a
display_order: 0
color: '#8bbf56'
Wake:
value: 0
shortcut: w
display_order: 1
color: '#56bf8b'
REM:
value: 4
shortcut: r
display_order: 2
color: '#bf5656'
N1:
value: 1
shortcut: 1
display_order: 3
color: '#aabcce'
N2:
value: 2
shortcut: 2
display_order: 4
color: '#405c79'
N3:
value: 3
shortcut: 3
display_order: 5
color: '#0b1c2c'
N4:
value: 6
shortcut: 4
display_order: 6
color: lightblue
N5:
value: 7
shortcut: 5
display_order: 7
# color: 'black' #
35 changes: 35 additions & 0 deletions examples/gui_sleep/load_edf_user_states_cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Load EDF file with custom vigilance state configuration
=============

This example demonstrate how to specify custom configuration
for vigilance states.

Required dataset at :
https://www.dropbox.com/s/bj1ra95rbksukro/sleep_edf.zip?dl=1

.. image:: ../../_static/examples/ex_LoadEDF.png
"""
import os
import os.path
from visbrain.gui import Sleep
from visbrain.io import download_file, path_to_visbrain_data

###############################################################################
# LOAD YOUR FILE
###############################################################################
download_file('sleep_edf.zip', unzip=True, astype='example_data')
target_path = path_to_visbrain_data(folder='example_data')

dfile = os.path.join(target_path, 'excerpt2.edf')
cfile = os.path.join(target_path, 'excerpt2_config.txt')

# Path to states_cfg yaml
sfile = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'example_states_cfg.yml'
)

# Open the GUI :
sleep = Sleep(data=dfile, config_file=cfile, states_config_file=sfile)
sleep.show()
10 changes: 9 additions & 1 deletion examples/gui_sleep/plot_hypnogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,13 @@
# Plot the hypnogram. If file is None, the window is displayed otherwise the
# figure is saved

write_fig_hyp(data, sf, grid=grid, ascolor=ascolor, file=file)
# Fill the following for custom states specification
hstates = None
hvalues = None
hcolors = None
hYranks = None

write_fig_hyp(data, sf, grid=grid, ascolor=ascolor, file=file,
hstates=hstates, hvalues=hvalues, hcolors=hcolors,
hYranks=hYranks)
plt.show()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def read(fname):
extras_require={
'full': ["mne", "tensorpac", "pandas", "xlrd", "scikit-image",
"nibabel", "imageio"],
'sleep': ["mne", "tensorpac"],
'sleep': ["mne", "tensorpac", "pyyaml"],
'roi': ["pandas", "xlrd"],
'topo': ["scikit-image"]
},
Expand Down
3 changes: 2 additions & 1 deletion visbrain/gui/sleep/interface/ui_elements/ui_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ def _fcn_info_update(self):
"""Complete the table sleep info."""
table = self._infoTable
# Get sleep stats :
stats = sleepstats(self._hyp.gui_to_hyp(), self._sf)
stats = sleepstats(self._hyp.gui_to_hyp(), self._sf,
self._hstates, self._hvalues)

# Add global informations to stats dict
is_file = isinstance(self._file, str)
Expand Down
Loading