Skip to content

Commit

Permalink
Merge branch 'master' into evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
remrama authored Mar 4, 2024
2 parents f3ed7aa + 776a257 commit b2e3624
Show file tree
Hide file tree
Showing 25 changed files with 206 additions and 133 deletions.
249 changes: 136 additions & 113 deletions notebooks/16_EEG-HRV_coupling.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions notebooks/run_visbrain.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""This file shows how to use YASA in combination with Visbrain.
"""

import numpy as np
from visbrain.gui import Sleep
from yasa import spindles_detect, sw_detect
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mne>=1.3
numba>=0.57.1
matplotlib
ipywidgets
seaborn
seaborn>=0.12.0
lspopt
tensorpac>=0.6.5
scikit-learn
Expand Down
1 change: 1 addition & 0 deletions yasa/detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- GitHub: https://github.com/raphaelvallat/yasa
- License: BSD 3-Clause License
"""

import mne
import logging
import numpy as np
Expand Down
1 change: 1 addition & 0 deletions yasa/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
DANGER: This function has not been extensively debugged and validated.
Use at your own risk.
"""

import mne
import yasa
import logging
Expand Down
1 change: 1 addition & 0 deletions yasa/heart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Author: Dr Raphael Vallat <[email protected]>, UC Berkeley.
Date: May 2022
"""

import logging
import numpy as np
import pandas as pd
Expand Down
1 change: 1 addition & 0 deletions yasa/hypno.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Hypnogram-related functions and class.
"""

import mne
import logging

Expand Down
1 change: 1 addition & 0 deletions yasa/io.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Helper functions for YASA (e.g. logger)
"""

import logging


Expand Down
1 change: 1 addition & 0 deletions yasa/numba.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This file contains Numba-accelerated functions used in the main detections.
"""

import numpy as np
from numba import jit

Expand Down
1 change: 1 addition & 0 deletions yasa/others.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
This file contains several helper functions to manipulate 1D and 2D EEG data.
"""

import logging
import numpy as np
from scipy.interpolate import interp1d
Expand Down
32 changes: 26 additions & 6 deletions yasa/plotting.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Plotting functions of YASA.
"""

import mne
import numpy as np
import pandas as pd
Expand All @@ -13,24 +14,39 @@
__all__ = ["plot_hypnogram", "plot_spectrogram", "topoplot"]


def plot_hypnogram(hyp, highlight="REM", fill_color=None, ax=None, **kwargs):
def plot_hypnogram(hyp, sf_hypno=1 / 30, highlight="REM", fill_color=None, ax=None, **kwargs):
"""
Plot a hypnogram.
.. versionadded:: 0.6.0
Parameters
----------
hyp : :py:class:`yasa.Hypnogram`
A YASA hypnogram instance.
hyp : :py:class:`yasa.Hypnogram` or array_like
A YASA hypnogram instance, or a 1D integer array where:
* -2 = Unscored
* -1 = Artefact / Movement
* 0 = Wake
* 1 = N1 sleep
* 2 = N2 sleep
* 3 = N3 sleep
* 4 = REM sleep
sf_hypno : float
The current sampling frequency of the hypnogram, in Hz, e.g.
* 1/30 = 1 value per each 30 seconds of EEG data,
* 1 = 1 value per second of EEG data
This has no impact if `hyp` is a :py:class:`yasa.Hypnogram`.
highlight : str or None
Optional stage to highlight with alternate color.
fill_color : str or None
Optional color to fill space above hypnogram line.
ax : :py:class:`matplotlib.axes.Axes`
Axis on which to draw the plot, optional.
**kwargs : dict
Keyword arguments controlling hypnogram line display (e.g., ``linewidth``, ``linestyle``).
Keyword arguments controlling hypnogram line display (e.g., ``lw``, ``linestyle``).
Passed to :py:func:`matplotlib.pyplot.stairs` and py:func:`matplotlib.pyplot.hlines`.
Returns
Expand Down Expand Up @@ -66,9 +82,13 @@ def plot_hypnogram(hyp, highlight="REM", fill_color=None, ax=None, **kwargs):
>>> hyp_a.plot_hypnogram(lw=1, fill_color="whitesmoke", highlight=None, ax=axes[0])
>>> hyp_b.plot_hypnogram(lw=1, fill_color="whitesmoke", highlight=None, ax=axes[1])
"""
from yasa.hypno import Hypnogram # Avoiding circular import
from yasa.hypno import Hypnogram, hypno_int_to_str # Avoiding circular imports

assert isinstance(hyp, Hypnogram), "`hypno` must be YASA Hypnogram."
if not isinstance(hyp, Hypnogram):
# Convert sampling frequency to pandas timefrequency string (e.g., "30s")
freq_str = pd.tseries.frequencies.to_offset(pd.Timedelta(1 / sf_hypno, "S")).freqstr
# Create Hypnogram instance for plotting
hyp = Hypnogram(hypno_int_to_str(hyp), freq=freq_str)

# Work with a copy of the Hypnogram to not alter the original
hyp = hyp.copy()
Expand Down
1 change: 1 addition & 0 deletions yasa/sleepstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This file contains several helper functions to calculate sleep statistics from
a one-dimensional sleep staging vector (hypnogram).
"""

# import warnings
import numpy as np
import pandas as pd
Expand Down
1 change: 1 addition & 0 deletions yasa/spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This file contains several helper functions to calculate spectral power from
1D and 2D EEG data.
"""

import mne
import logging
import numpy as np
Expand Down
8 changes: 7 additions & 1 deletion yasa/staging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Automatic sleep staging of polysomnography data."""

import os
import mne
import glob
Expand Down Expand Up @@ -201,7 +202,12 @@ def __init__(self, raw, eeg_name, *, eog_name=None, emg_name=None, metadata=None

# Extract duration of recording in minutes
duration_minutes = data.shape[1] / sf / 60
assert duration_minutes >= 5, "At least 5 minutes of data is required."
if duration_minutes < 5:
msg = (
"Insufficient data. A minimum of 5 minutes of data is recommended "
"otherwise results may be unreliable."
)
logger.warning(msg)

# Add to self
self.sf = sf
Expand Down
21 changes: 11 additions & 10 deletions yasa/tests/test_detection.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in yasa/spectral.py."""

import mne
import pytest
import unittest
Expand Down Expand Up @@ -73,7 +74,7 @@ def test_spindles_detect(self):
sp.get_mask()
sp.get_sync_events()
sp.get_sync_events(time_before=10) # Invalid time window
sp.plot_average(ci=None, filt=(None, 30)) # Skip bootstrapping
sp.plot_average(errorbar=None, filt=(None, 30)) # Skip bootstrapping
np.testing.assert_array_equal(np.squeeze(sp._data), data)
# Compare channels return dataframe with single cell
assert sp.compare_channels().shape == (1, 1)
Expand Down Expand Up @@ -153,7 +154,7 @@ def test_spindles_detect(self):
sp.get_sync_events(filt=(12, 15))
sp.summary()
sp.summary(grp_chan=True)
sp.plot_average(ci=None)
sp.plot_average(errorbar=None)
sp.get_coincidence_matrix()
sp.get_coincidence_matrix(scaled=False)
sp.plot_detection()
Expand Down Expand Up @@ -188,8 +189,8 @@ def test_spindles_detect(self):
sp.summary(grp_chan=False, grp_stage=True, aggfunc="median")
sp.summary(grp_chan=True, grp_stage=False)
sp.summary(grp_chan=True, grp_stage=True, sort=False)
sp.plot_average(ci=None)
sp.plot_average(hue="Stage", ci=None)
sp.plot_average(errorbar=None)
sp.plot_average(hue="Stage", errorbar=None)
sp.plot_detection()

# Test compare_channels function
Expand Down Expand Up @@ -233,7 +234,7 @@ def test_sw_detect(self):
sw.summary()
sw.get_mask()
sw.get_sync_events()
sw.plot_average(ci=None)
sw.plot_average(errorbar=None)
sw.plot_detection()
np.testing.assert_array_equal(np.squeeze(sw._data), data_sw)
np.testing.assert_array_equal(sw._hypno, hypno_sw)
Expand All @@ -258,7 +259,7 @@ def test_sw_detect(self):
sw = sw_detect(data_full, sf, chan_full)
sw.get_mask()
sw.get_sync_events()
sw.plot_average(ci=None)
sw.plot_average(errorbar=None)
sw.plot_detection()
sw.get_coincidence_matrix()
sw.get_coincidence_matrix(scaled=False)
Expand All @@ -275,8 +276,8 @@ def test_sw_detect(self):
sw.summary(grp_chan=False, grp_stage=True, aggfunc="median")
sw.summary(grp_chan=True, grp_stage=False)
sw.summary(grp_chan=True, grp_stage=True, sort=False)
sw.plot_average(ci=None)
sw.plot_average(hue="Stage", ci=None)
sw.plot_average(errorbar=None)
sw.plot_average(hue="Stage", errorbar=None)
sw.plot_detection()
# Check coupling
sw_sum = sw.summary()
Expand Down Expand Up @@ -334,8 +335,8 @@ def test_rem_detect(self):
rem.summary()
rem.get_mask()
rem.get_sync_events()
rem.plot_average(ci=None)
rem.plot_average(filt=(0.5, 5), ci=None)
rem.plot_average(errorbar=None)
rem.plot_average(filt=(0.5, 5), errorbar=None)

# With REM hypnogram
hypno_rem = 4 * np.ones_like(loc)
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_heart.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/heart.py file."""

import unittest
import numpy as np
from yasa.heart import hrv_stage
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_hypno.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/hypno.py file."""

import mne
import pytest
import unittest
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_hypnoclass.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the class Hypnogram."""

import mne
import pytest
import unittest
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_io.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test I/O."""

import pytest
import logging
import unittest
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_numba.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/numba.py file."""

import unittest
import numpy as np
from scipy.signal import detrend
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_others.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/others.py file."""

import mne
import unittest
import numpy as np
Expand Down
8 changes: 6 additions & 2 deletions yasa/tests/test_plotting.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/plotting.py file."""

import pytest
import unittest
import numpy as np
Expand Down Expand Up @@ -37,9 +38,12 @@ def test_topoplot(self):

def test_plot_hypnogram(self):
"""Test plot_hypnogram function."""
# Old format: array of integer
hypno = np.loadtxt("notebooks/data_full_6hrs_100Hz_hypno_30s.txt")
_ = plot_hypnogram(hypno)
# Error because of input is not a yasa.Hypnogram
with pytest.raises(AssertionError):
_ = plot_hypnogram(np.repeat([0, 1, 2, 3, 4, -2, -1, -3], 120))
# with pytest.raises(AssertionError):
# _ = plot_hypnogram(np.repeat([0, 1, 2, 3, 4, -2, -1, -3], 120))
# Default parameters
hyp5 = simulate_hypnogram(n_stages=5)
hyp2 = simulate_hypnogram(n_stages=2)
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_sleepstats.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/sleepstats.py file."""

import unittest
import numpy as np
import pandas as pd
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_spectral.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in the yasa/spectral.py file."""

import mne
import pytest
import unittest
Expand Down
1 change: 1 addition & 0 deletions yasa/tests/test_staging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the functions in yasa/staging.py."""

import mne
import unittest
import numpy as np
Expand Down

0 comments on commit b2e3624

Please sign in to comment.