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

Phase-slope index using spectral_connectivity_time instead of spectral_connectivity_epochs #210

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

seqasim
Copy link

@seqasim seqasim commented Jun 28, 2024

Thanks for contributing. If this is your first time,
make sure to read contributing.md

PR Description

Currently, the function for computing phase-slope index is hard-coded to be computed over epochs to produce time-resolved PSI, and there's no option for computing the phase-slope index over time to produce PSI per epoch. This would be useful if you think the average directionality between two signals over the entire timecourse is informative. You could compute this by binning your trials into categories (i.e. good trials v. bad trials) and then computing PSI, but there's no way to compute PSI per epoch and relate it to continuous trial-level predictors.

Here, I add a new function phase_slope_index_time to mne_connectivity.effective that compute PSI over time. I should note that I wasn't able to test this function directly as I'm having trouble getting the forked repo installed, in editable mode, with all necessary dependencies, but have written a test function in tests.test_effective to facilitate this.

Merge checklist

Maintainer, please confirm the following before merging:

  • All comments resolved
  • This is not your own PR
  • All CIs are happy
  • PR title starts with [MRG]
  • whats_new.rst is updated
  • PR description includes phrase "closes <#issue-number>"

@tsbinns
Copy link
Collaborator

tsbinns commented Aug 1, 2024

Hi @seqasim, thanks for the PR and sorry for not getting back to you sooner on this. I have a few comments/suggestions which I'll post below, but it's a really good start!

If this is something you're still interested in working on, your contributions are of course very welcome, however I realise it's been a while. If you're not able to invest time into this anymore and you don't want your hard work to go to waste, I can pick things up and we can make sure the changes are added.

Just let us know. Cheers!

@tsbinns
Copy link
Collaborator

tsbinns commented Aug 1, 2024

Just need to make sure that the new cohy method is described in the docstring for spectral_connectivity_time():

method : str | list of str
Connectivity measure(s) to compute. These can be ``['coh', 'cacoh',
'mic', 'mim', 'plv', 'ciplv', 'pli', 'wpli', 'gc', 'gc_tr']``. These
are:


And also an equation entry like for coh:

**Supported Connectivity Measures**
The connectivity method(s) is specified using the ``method`` parameter. The
following methods are supported (note: ``E[]`` denotes average over
epochs). Multiple measures can be computed at once by using a list/tuple,
e.g., ``['coh', 'pli']`` to compute coherence and PLI.
'coh' : Coherence given by::
| E[Sxy] |
C = ---------------------
sqrt(E[Sxx] * E[Syy])

@tsbinns
Copy link
Collaborator

tsbinns commented Aug 1, 2024

A more general comment for the new phase_slope_index_time: Even if we are not averaging over epochs in the call to spectral_connectivity_time(), do you think it makes sense to add an average option which would allow averaging over epochs after PSI has been computed?

Copy link
Collaborator

@tsbinns tsbinns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just pretty minor comments. There are a couple formatting things (mainly line length) that I would have thought pre-commit would sort (if you've set that up). Would recommend doing so otherwise getting that CI check to pass will be very tedious...

mne_connectivity/spectral/time.py Outdated Show resolved Hide resolved
mne_connectivity/spectral/time.py Show resolved Hide resolved
mne_connectivity/effective.py Show resolved Hide resolved
mne_connectivity/effective.py Outdated Show resolved Hide resolved
mne_connectivity/effective.py Outdated Show resolved Hide resolved
mne_connectivity/effective.py Show resolved Hide resolved
mne_connectivity/effective.py Outdated Show resolved Hide resolved
mne_connectivity/effective.py Outdated Show resolved Hide resolved

Parameters
----------
data : array-like, shape=(n_epochs, n_signals, n_times)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also include Epochs (again, I realise you took this from the existing function which doesn't have this, so should change there too).

mne_connectivity/tests/test_effective.py Show resolved Hide resolved
@seqasim
Copy link
Author

seqasim commented Aug 2, 2024

Hi @seqasim, thanks for the PR and sorry for not getting back to you sooner on this. I have a few comments/suggestions which I'll post below, but it's a really good start!

If this is something you're still interested in working on, your contributions are of course very welcome, however I realise it's been a while. If you're not able to invest time into this anymore and you don't want your hard work to go to waste, I can pick things up and we can make sure the changes are added.

Just let us know. Cheers!

Hey,

Thanks for reviewing things! It's super illuminating for me to see the details I missed. I sadly won't have time to follow through on this for a few months, so if you feel you can wrap it up quickly, please don't wait for me! But if not, I'm happy to pick it up with all your helpful comments later in the year.

@tsbinns
Copy link
Collaborator

tsbinns commented Aug 2, 2024

But if not, I'm happy to pick it up with all your helpful comments later in the year.

Yeah sounds good, there's no rush!

@seqasim
Copy link
Author

seqasim commented Oct 31, 2024

I think I addressed everything here (including adding verbose arg) but tests still failing

@tsbinns
Copy link
Collaborator

tsbinns commented Nov 11, 2024

Thanks for the changes @seqasim! I am quite busy at the moment, but I will try to do another round of reviews soon.
Looking at the CI logs, seems like the failures come from the verbose and fill_doc decorators not being completely redundant here, but from a quick look I'm not sure why.

@seqasim
Copy link
Author

seqasim commented Nov 12, 2024

Ok, I think I resolved all failures. There were some dimension issues with the way I was extracting the cohy results, which are now fixed.

Comment on lines +58 to +75
# conn = phase_slope_index_time(data, mode="fourier", sfreq=sfreq, freqs=np.arange(4))

# assert conn.get_data(output="dense")[1, 0, 0] < 0
# assert conn.get_data(output="dense")[2, 0, 0] > 0

# # only compute for a subset of the indices
indices = (np.array([0]), np.array([1]))
# conn_2 = phase_slope_index_time(data, mode="fourier", sfreq=sfreq, freqs=np.arange(4), indices=indices)

# # the measure is symmetric (sign flip)
# assert_array_almost_equal(
# conn_2.get_data()[0, 0], -conn.get_data(output="dense")[1, 0, 0]
# )

freqs = np.arange(5.0, 20, 0.5)
conn_cwt = phase_slope_index_time(
data, mode="cwt_morlet", sfreq=sfreq, freqs=freqs, indices=indices
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including some of the things commented here would be nice to better reflect the checks happening for the regular PSI function.

So as well as checking that seed -> target connectivity is > 0, should also check that target -> seed connectivity is < 0 and they are identical but just sign-flipped.

Copy link
Collaborator

@tsbinns tsbinns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have pushed some changes to formatting and also documentation updates to reflect the spec_conn_time more. Also added the new function to the API file and main init file.

One thing which I think is still outstanding is an average parameter that controls averaging over epochs, since this behaviour can be controlled with spec_conn_time.
It should be a pretty simple case of just updating the documentation and adding the extra behaviour of packaging the PSI data in a SpectralConnectivity container (just like for spec_conn_time).
The current implementation of computing PSI from coherency should already be flexible w.r.t. an epoch dimension or not, but this could also be added as a check in the unit test.

I also still think it makes sense to expose the spec_conn_time smoothing options (sm_times, sm_freqs, and sm_kernel).
This would just be a simple case of just updating the docstring.

Once that's added and the other point about the unit test being extended, I think this would be ready!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants