Skip to content

Conversation

@ephathaway
Copy link
Member

This PR is the pre-PR so that we can review the code amongst BEL engineers before submitting the actual PR to mne-tools.

In this PR, we begin to address mne-tools#8038 by implementing reading of averaged MFF files. We add a function mne.io.read_evokeds_mff which takes in an averaged MFF file and returns an EvokedArray object with the data for each condition specified. Reading of signal data and some metadata is done through mffpy, which is made a dependency of mne.

There are a few things we will need to sort out before this is ready to merge that I will list right off the bat.

  1. mne testing datasets are stored in a separate repo. I am not sure what their process is for adding new test datasets, so for now I include my test averaged MFF file in this repository.
  2. Right now there is no check to make sure the input MFF file is averaged. This will be important for preventing users from trying to read a segmented file with the mne.io.read_evokeds_mff function. I suggest we use the information in history.xml, which contains info on all of the tools run on the MFF file. We currently don't have a way to parse history.xml, so I suggest we first implement this capability in mffpy and then use it to read the info in mne.
  3. The number of segments comprising each average is specified in categories.xml in an averaged MFF file, but again, we do not currently have the ability to parse this info. I suggest we implement this capability in mffpy as well.

Copy link

@ianbrown9475 ianbrown9475 left a comment

Choose a reason for hiding this comment

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

Nice work, I ran the tests and it looks like the ones you added/modified are passing but there are others that aren't. I think some of them were already failing in the upstream code though. Could you look at fixing the CI action that's failing and fixing the linter errors? Looks like there's some more information on all of this here.

@ephathaway
Copy link
Member Author

CIs appear to be passing now. I ran flake8 and docstyle tests and those look good. Some tests failing on my end as well, but they all look unrelated to my additions. Looks like they have to do with missing test files, so I might just be missing some tests datasets that I was supposed to install.

Copy link
Collaborator

@jusjusjus jusjusjus left a comment

Choose a reason for hiding this comment

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

Hi Evan, well done. You definitely hit the mark wrt their code base, but I would like this commit to be a little different here an there.

  • when including mffpy as a dependency, it would have been awesome if cached-property-bel automatically is added as a sub-dependency. Let's hear what they say about this, but get ready to include that into the pip wheel. We should also edit the "server_environment.yml"

  • The test data you added is good, and it's great that you check that mffpy actually reads it. I think we might need to clean up some of the viewer configuration files though, which are unnecessary for mffpy, e.g. "lastSettings.xml", "recordingSettings.xml". I don't think we support reading these.

  • You rightly named the child read_evokeds_..., b/c it returns mutliple. Instead of messing around with a list or an instance I would just return a list with one element. The branch (if else) will cause downstream branches by the guy that uses the API, otherwise.

  • It's good that you check the function input which immediately enhances the usability of the API. If a user inputs a wrong file than it'll come around and tell him. It's good to make these error messages very precise; tell the user what he did wrong. Also, throw a ValueError instead of an AssertionError (https://docs.python.org/3/library/exceptions.html#ValueError).

  • That's a matter of taste, but in general i'm not a big fan of abbreviations. If you want to avoid long names, then, one might be able to use context. One thing that would help in creating this context are functions. I think one could split _read_evoked_mff into 3-4 sub-functions that a called in sequence. In essence you do this, and you even write little documentation strings for each function, but by not actually creating a function your code always drags the whole context with it.

@ephathaway
Copy link
Member Author

  • You rightly named the child read_evokeds_..., b/c it returns mutliple. Instead of messing around with a list or an instance I would just return a list with one element. The branch (if else) will cause downstream branches by the guy that uses the API, otherwise.

I decided to return a single Evoked_Array if just reading one dataset instead of a list to stay consistent with mne.read_evokeds (for reading evoked .fif files).

Copy link
Collaborator

@jusjusjus jusjusjus left a comment

Choose a reason for hiding this comment

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

Thanks for addressing my comments. Let's see what they say about this.

Copy link

@ianbrown9475 ianbrown9475 left a comment

Choose a reason for hiding this comment

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

Looks good to me!

@ephathaway
Copy link
Member Author

  • Right now there is no check to make sure the input MFF file is averaged. This will be important for preventing users from trying to read a segmented file with the mne.io.read_evokeds_mff function. I suggest we use the information in history.xml, which contains info on all of the tools run on the MFF file. We currently don't have a way to parse history.xml, so I suggest we first implement this capability in mffpy and then use it to read the info in mne.
  • The number of segments comprising each average is specified in categories.xml in an averaged MFF file, but again, we do not currently have the ability to parse this info. I suggest we implement this capability in mffpy as well.

@ianbrown9475 @jusjusjus thank you both for reviewing this! Your feedback was very helpful. Before I submit a PR to mne-tools, I would like to address the above issues. I will do some work on mffpy next week and hopefully have PR submitted by Friday.

@jusjusjus
Copy link
Collaborator

Hey Evan, I think you would be right to check if the file is averaged beforehand.

Copy link
Collaborator

@jusjusjus jusjusjus left a comment

Choose a reason for hiding this comment

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

Looks good, great job.

Copy link

@ianbrown9475 ianbrown9475 left a comment

Choose a reason for hiding this comment

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

Nice, looks good

@ephathaway ephathaway force-pushed the read-mff-evoked branch 5 times, most recently from c60dad5 to 3ffb351 Compare October 28, 2020 19:27
@ephathaway ephathaway force-pushed the read-mff-evoked branch 3 times, most recently from 9bd1a44 to 981f199 Compare November 6, 2020 22:56
Copy link
Collaborator

@jusjusjus jusjusjus left a comment

Choose a reason for hiding this comment

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

Looks good

@ephathaway
Copy link
Member Author

Looks good

Thanks. I still think we should merge this into mne-tools/mne-python master branch when it's approved and then pull those changes into our master.

@ianbrown9475
Copy link

@ephathaway Yeah I think that's pretty common for these kind of situations. Are you going to open a PR in mne-tools/mne-python?

@ephathaway
Copy link
Member Author

@ephathaway Yeah I think that's pretty common for these kind of situations. Are you going to open a PR in mne-tools/mne-python?

It's been open for a while now. Gone through several rounds of review, but I think it's close. mne-tools#8354

@jusjusjus
Copy link
Collaborator

Looks good

Thanks. I still think we should merge this into mne-tools/mne-python master branch when it's approved and then pull those changes into our master.

Sure, I think we discussed in detail how we should have done it.

  • fork upstream/master -> (our) origin/master
  • develop in a branch origin/feature
  • PR origin/feature -> origin/master for internal review
  • rebase origin/master on top of upstream/master
  • PR origin/master -> upstream/master
  • rebase as needed until merged

It's at your discretion how to continue on the current path though. I'm happy to discuss options.

@ephathaway
Copy link
Member Author

It's at your discretion how to continue on the current path though. I'm happy to discuss options.

Yeah, I think it makes sense to continue on the current path this time around since it's almost ready to merge. In my opinion, it's nice to submit the PR with origin/feature_branch -> upstream/master because then it's easy to push requested changes directly to origin/feature_branch instead of heaving to create a new branch every time we want to make changes if we were doing origin/master -> upstream/master.

Here we add a function `mne.io.read_evokeds_mff`
to read averaged MFF files. This function works
similarly to `mne.evoked.read_evokeds` by returning
the averaged data and metadata from one or more
specified `condition`(s).

We make use of the mffpy[https://github.com/BEL-Public/mffpy]
package for reading the signal data and some of
the metadata in the MFF file.
@ephathaway ephathaway closed this Nov 24, 2020
@ephathaway ephathaway deleted the read-mff-evoked branch November 24, 2020 18:25
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.

4 participants