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

[ENH] Multiple improvements to spectral_connectivity_time: ciPLV, and efficient computation of multiple metrics #115

Merged
merged 34 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ec58673
Add ciPLV
ruuskas Oct 28, 2022
3130672
Speed up computation
ruuskas Oct 31, 2022
996cf46
Add logging
ruuskas Oct 31, 2022
6e6fa88
Add the option to specify freqs in all modes
ruuskas Nov 1, 2022
26561be
BUG: Average over CSD instead of connectivity
ruuskas Nov 10, 2022
a50053f
Add option to use part of signal as padding
ruuskas Nov 14, 2022
5c778c1
Fix test bug, use 'freqs' instead of 'cwt_freqs'
ruuskas Nov 17, 2022
8f37ae6
Fix bug with dpss windows
ruuskas Nov 24, 2022
4496bce
Only show progress bar if verbosity level is DEBUG
ruuskas Nov 24, 2022
a768038
Improve doc
ruuskas Nov 24, 2022
c95b0cd
Fix style to make flake happy
ruuskas Nov 24, 2022
c510204
Fix whitespace
ruuskas Nov 24, 2022
6ca2aa6
Fix style
ruuskas Nov 25, 2022
11cdeb0
Merge branch 'mne-tools:main' into spectral_time
ruuskas Dec 1, 2022
ba3bad2
Refactor connectivity methods
ruuskas Oct 31, 2022
71d1259
Fix parallelization
ruuskas Dec 8, 2022
7ea1af8
Add docstring
ruuskas Dec 8, 2022
5215fbe
Require freqs in all tfr modes
ruuskas Jan 5, 2023
8d0223f
Add error checks for padding
ruuskas Jan 6, 2023
ee08bba
Add test for padding
ruuskas Jan 6, 2023
107dbb3
Change whitespace
ruuskas Jan 6, 2023
5ea3c49
Update whats_new.rst
ruuskas Jan 6, 2023
dd45898
Fix indentation and sphinx version
adam2392 Jan 6, 2023
ca3a8f6
Update doc
ruuskas Jan 6, 2023
f985ae0
Merge branch 'spectral_time' of github.com:ruuskas/mne-connectivity i…
adam2392 Jan 6, 2023
157ad2b
Check for specific value error
ruuskas Jan 9, 2023
726232b
Add note on padding
ruuskas Jan 9, 2023
4dd6214
Remove cs
ruuskas Jan 9, 2023
6391560
Add ciplv in doc
ruuskas Jan 9, 2023
04426de
Require mne>=1.3
ruuskas Jan 9, 2023
3a54f99
Update doc
ruuskas Jan 9, 2023
0d6a1c4
Update private function docstrings
ruuskas Jan 10, 2023
1c6e48a
Merge branch 'spectral_time' of github.com:ruuskas/mne-connectivity i…
ruuskas Jan 10, 2023
fb8720e
Merge branch 'main' into spectral_time
adam2392 Jan 10, 2023
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: 2 additions & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Enhancements
- Improve the documentation of :func:`mne_connectivity.spectral_connectivity_time` by `Santeri Ruuskanen`_ (:gh:`104`).
- Add the option to average connectivity across epochs and frequencies in :func:`mne_connectivity.spectral_connectivity_time` by `Santeri Ruuskanen`_ (:gh:`104`).
- Select multitaper frequencies automatically in :func:`mne_connectivity.spectral_connectivity_time` similarly to :func:`mne_connectivity.spectral_connectivity_epochs` by `Santeri Ruuskanen`_ (:gh:`104`).
- Add the ``ciPLV`` method in :func:`mne_connectivity.spectral_connectivity_time` by `Santeri Ruuskanen`_ (:gh:`115`).
- Add the option to use the edges of each epoch as padding in :func:`mne_connectivity.spectral_connectivity_time` by `Santeri Ruuskanen`_ (:gh:`115`).

Bug
~~~
Expand Down
86 changes: 72 additions & 14 deletions mne_connectivity/spectral/tests/test_spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def test_epochs_tmin_tmax(kind):
assert len(w) == 1 # just one even though there were multiple epochs


@pytest.mark.parametrize('method', ['coh', 'plv', 'pli', 'wpli'])
@pytest.mark.parametrize('method', ['coh', 'plv', 'pli', 'wpli', 'ciplv'])
adam2392 marked this conversation as resolved.
Show resolved Hide resolved
@pytest.mark.parametrize(
'mode', ['cwt_morlet', 'multitaper'])
@pytest.mark.parametrize('data_option', ['sync', 'random'])
Expand Down Expand Up @@ -504,11 +504,11 @@ def test_spectral_connectivity_time_phaselocked(method, mode, data_option):
# hypothesized "connection"
freq_band_low_limit = (8.)
freq_band_high_limit = (13.)
cwt_freqs = np.arange(freq_band_low_limit, freq_band_high_limit + 1)
con = spectral_connectivity_time(data, method=method, mode=mode,
freqs = np.arange(freq_band_low_limit, freq_band_high_limit + 1)
con = spectral_connectivity_time(data, freqs, method=method, mode=mode,
sfreq=sfreq, fmin=freq_band_low_limit,
fmax=freq_band_high_limit,
cwt_freqs=cwt_freqs, n_jobs=1,
n_jobs=1,
faverage=True, average=True, sm_times=0)
assert con.shape == (n_channels ** 2, len(con.freqs))
con_matrix = con.get_data('dense')[..., 0]
Expand All @@ -526,12 +526,13 @@ def test_spectral_connectivity_time_phaselocked(method, mode, data_option):
assert np.all(con_matrix) <= 0.5


@pytest.mark.parametrize('method', ['coh', 'plv', 'pli', 'wpli'])
@pytest.mark.parametrize('method', ['coh', 'plv', 'pli', 'wpli', 'ciplv'])
@pytest.mark.parametrize(
'cwt_freqs', [[8., 10.], [8, 10], 10., 10])
def test_spectral_connectivity_time_cwt_freqs(method, cwt_freqs):
'freqs', [[8., 10.], [8, 10], 10., 10])
@pytest.mark.parametrize('mode', ['cwt_morlet', 'multitaper'])
def test_spectral_connectivity_time_freqs(method, freqs, mode):
"""Test time-resolved spectral connectivity with int and float values for
cwt_freqs."""
freqs."""
rng = np.random.default_rng(0)
n_epochs = 5
n_channels = 3
Expand All @@ -552,10 +553,10 @@ def test_spectral_connectivity_time_cwt_freqs(method, cwt_freqs):
data[i, c] = np.squeeze(np.sin(x))
# the frequency band should contain the frequency at which there is a
# hypothesized "connection"
con = spectral_connectivity_time(data, method=method, mode='cwt_morlet',
sfreq=sfreq, fmin=np.min(cwt_freqs),
fmax=np.max(cwt_freqs),
cwt_freqs=cwt_freqs, n_jobs=1,
con = spectral_connectivity_time(data, freqs, method=method,
mode=mode, sfreq=sfreq,
fmin=np.min(freqs),
fmax=np.max(freqs), n_jobs=1,
faverage=True, average=True, sm_times=0)
assert con.shape == (n_channels ** 2, len(con.freqs))
con_matrix = con.get_data('dense')[..., 0]
Expand Down Expand Up @@ -588,12 +589,12 @@ def test_spectral_connectivity_time_resolved(method, mode):
info = create_info(ch_names=ch_names, sfreq=sfreq, ch_types='eeg')
data = EpochsArray(data, info)

# define some frequencies for cwt
# define some frequencies for tfr
freqs = np.arange(3, 20.5, 1)

# run connectivity estimation
con = spectral_connectivity_time(
data, sfreq=sfreq, cwt_freqs=freqs, method=method, mode=mode,
data, freqs, sfreq=sfreq, method=method, mode=mode,
n_cycles=5)
assert con.shape == (n_epochs, n_signals ** 2, len(con.freqs))
assert con.get_data(output='dense').shape == \
Expand All @@ -613,6 +614,63 @@ def test_spectral_connectivity_time_resolved(method, mode):
for idx, jdx in triu_inds)


@pytest.mark.parametrize('method', ['coh', 'plv', 'pli', 'wpli'])
@pytest.mark.parametrize(
'mode', ['cwt_morlet', 'multitaper'])
@pytest.mark.parametrize('padding', [0, 1, 5])
def test_spectral_connectivity_time_padding(method, mode, padding):
"""Test time-resolved spectral connectivity with padding."""
sfreq = 50.
n_signals = 3
n_epochs = 2
n_times = 300
trans_bandwidth = 2.
tmin = 0.
tmax = (n_times - 1) / sfreq
# 5Hz..15Hz
fstart, fend = 5.0, 15.0
data, _ = create_test_dataset(
sfreq, n_signals=n_signals, n_epochs=n_epochs, n_times=n_times,
tmin=tmin, tmax=tmax,
fstart=fstart, fend=fend, trans_bandwidth=trans_bandwidth)
ch_names = np.arange(n_signals).astype(str).tolist()
info = create_info(ch_names=ch_names, sfreq=sfreq, ch_types='eeg')
data = EpochsArray(data, info)

# define some frequencies for tfr
freqs = np.arange(3, 20.5, 1)

# run connectivity estimation
if padding == 5:
adam2392 marked this conversation as resolved.
Show resolved Hide resolved
with pytest.raises(ValueError, match='Padding cannot be larger than '
'half of data length'):
con = spectral_connectivity_time(
data, freqs, sfreq=sfreq, method=method, mode=mode,
n_cycles=5, padding=padding)
return
else:
con = spectral_connectivity_time(
data, freqs, sfreq=sfreq, method=method, mode=mode,
n_cycles=5, padding=padding)

assert con.shape == (n_epochs, n_signals ** 2, len(con.freqs))
assert con.get_data(output='dense').shape == \
(n_epochs, n_signals, n_signals, len(con.freqs))

# test the simulated signal
triu_inds = np.vstack(np.triu_indices(n_signals, k=1)).T

# average over frequencies
conn_data = con.get_data(output='dense').mean(axis=-1)

# the indices at which there is a correlation should be greater
# then the rest of the components
for epoch_idx in range(n_epochs):
high_conn_val = conn_data[epoch_idx, 0, 1]
assert all(high_conn_val >= conn_data[epoch_idx, idx, jdx]
for idx, jdx in triu_inds)


def test_save(tmp_path):
"""Test saving results of spectral connectivity."""
rng = np.random.RandomState(0)
Expand Down
Loading