-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add functionality to export to EEGLAB .set #9192
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
Conversation
|
Seems like the tests are failing due to the lack of docstrings. Should I add them? |
|
Welcome on your first mne PR, @jackz314!
Yes, we follow the numpy docstring format. Take a look around in the codebase - you will see the pattern. The docstrings are required for all public functions. |
|
thx @jackz314 for the work we should discuss how to approach this. So far we have been reluctant to support writing for something different from .fif as it's very likely that the save to something else will not persist to disk all the informations in the mne instance. Also you add a lot of public functions to mne and we are support careful about this. Should i had started this PR I would have tried to support writing without any new public function: just use .save method and detect the file extension to know what to do. |
|
Nice job, @jackz314! Also I'm wondering if instead of adding |
|
Thanks guys. I'm currently writing tests on this, but my expertise in both EEGLAB and MNE is limited, so I would probably need help from other people to test this more thoroughly - As I'm writing these tests, I'm already discovering multiple bugs in my code. I agree maybe merging The only two user-facing functions would probably be As for information loss, unfortunately, it seems like there will be some unavoidable info loss, so far from my limited testing, things like re-reference, baseline, and high/low pass freq info are lost when converting between the two. For re-referencing and hi/lo pass, the modified data is preserved, but in EEGLAB there's no way of knowing what kind of re-referencing is done, and when converting back to MNE, there's no way of getting the filtering parameters. Info lost is definitely not ideal, but in a lot of cases it's tolerable (as long as data is intact and as expected), so I think maybe some warning could be given to users who try to export as set files, that way they are aware of the info lost, but can still benefit from the conversion. I'm currently working with a lab where EEGLAB is heavily used, but they also want to use Python as well, since some things like ML is easier on Python, this is why I wrote these functions, and I think other people in similar situations would benefit from this as well. |
This one should probably also be integrated into |
I just realized that channel location data in MNE is called Montage, I will integrate it into |
This actually sounds like a good idea!! |
|
I also would like to know where I should put the tests for these functions. Currently, I put the tests for Epochs' save set to |
|
I noticed that channel location data is actually stored in the format of -y, x, z instead of x, y, z. Is there a particular reason for this? Additionally, is this a standard that applies to all location data or specific to some formats like EEGLAB set files? |
…cation to tests. Add raw save_set test.
|
Hello @jackz314, I briefly talked with @agramfort about this effort and we had the feeling that adding support for writing to new formats could end up as opening Pandora's box: it would be very challenging to ensure that no data is lost (or even to quantify as to which data is lost, specifically) during an I/O roundtrip. We felt that maybe this functionality would be better suited in an external package, which could very well be maintained under the MNE umbrella ( Another idea I had and which is kind of contradictory to what I said above is adding a new method for exports that possibly lead to data loss. This is essentially what GIMP does: "save/save as" saves to their native format; "export" converts the data, possibly losing information. So I would vote for calling a method that exports to non-FIFF files I'd love to hear your and the other developers' thoughts! |
|
Personally, I think this feature would be helpful even if there is some data loss, like I mentioned above, I think it would be better to provide warnings to users who use this function (and maybe on relevant docs as well) about potential data loss than to not provide the feature at all. As you said, I think using a separate and distinct name like Some data will be lost unfortunately due to some features being implemented very differently in EEGLAB and MNE (e.g., reference channel/method, filtering configuration, etc.). However, since the core data and some other fields like events/trials/epochs/annotations (the events "family") and channel info can mostly be exchanged without data loss, exporting will still be helpful even if other fields might not survive the i/o cycle. I'm leaning more towards your second idea, because I feel like since other functions that read from EEGLAB are already maintained in the main MNE package, any changes to EEGLAB that requires any updates to MNE's I/O should occur naturally together. I also think that maintaining a separate package just for exporting to EEGLAB seems a bit overkill and shouldn't be necessary, especially since reading from EEGLAB is already in MNE. Still, I'm also fine with starting a new package, if the consensus later agrees that this feature should be in a separate package, I'd be happy to port my code over. |
|
Pinging @larsoner, @jasmainak, @adam2392, @sappelhoff, and @cbrnr |
|
i hear you Jack but it's a non-trivial maintenance cost and I anticipate a
lot of complaints because some data was lost during
IO round trip and user "did not read the warning".
it also means a lot of CI time for testing as suddenly we need to duplicate
many IO tests to guarantee nothing breaks
when people save to .set files.
|
|
Don't we have a "pybv" package for brainvision? Perhaps we have:
Maybe "raw.export" just calls these underlying packages? Unit testing should primarily be in those sub packages to address @agramfort objection? the only reason I even use eeglab is cuz their ICA is more advanced then mne. Don't use them for anything else :p. Imo these kinds of write/export functionality will be very attractive for cross-platform usage. Could even have things like: Pypersyst ? This can be useful for mne-bids too for writing other supported BIDS formats of EEG/IEEG. |
|
+1 for a pyeeglab package now regarding the export I am not convinced
|
Yeah that sounds like a possibility.
It's off-topic alright, but could you elaborate? Do you mean the interactive exploration of components..? |
|
They have this nice feature which plugs into a database of features I think that can automatically estimate ICA labels in case you have 100s of subjects and can't feasibly run manual ICA, they actually have a cool feature that will match it against known labels to try to estimate if it's eye blink, heart beat, etc. Sorry off topic yeah :p. |
Ah, that one. Yes we should add this to MNE too. Actually shouldn't be too difficult, I believe! We already do have a pattern matching infrastructure. |
hoechenberger
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two more nitpicks and then I'm happy 😃
mne/utils/check.py
Outdated
|
|
||
| if fmt not in supported_formats: | ||
| raise ValueError(f"Format '{fmt}' is not supported. " | ||
| f"Supported formats are {supported_formats}.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only want to print the keys here, separated by commas, i.e. something like
', '.join(supported_formats.keys()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well someone could attempt to use file extensions to infer automatically, and if the extension is not supported I think printing out the dictionary might be more helpful compared to just the formats.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can also print the dictionary in a better way (e.g. eeglab (.set), brainvision (.eeg, .vmrk, ...))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea!
Co-authored-by: Richard Höchenberger <richard.hoechenberger@gmail.com>
hoechenberger
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌👌👌👌👌👌👌❤️
| Supported formats: EEGLAB (set, uses :mod:`eeglabio`) | ||
| %(export_warning)s | ||
| %(export_params_base)s | ||
| fmt : 'auto' | 'eeglab' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| fmt : 'auto' | 'eeglab' |
| Supported formats: EEGLAB (set, uses :mod:`eeglabio`) | ||
| %(export_warning)s | ||
| %(export_params_base)s | ||
| fmt : 'auto' | 'eeglab' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| fmt : 'auto' | 'eeglab' |
|
@hoechenberger can you check what needs to be done for @agramfort's latest comments? I think we're not yet ready. |
Yeah I removed the redundant code but I'm not sure about the docstring part. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good, just minor suggestions really!
However, I don't think we should merge until this is solved, i.e., eeglabio makes a PyPi release:
$ pip install --user eeglabio
ERROR: Could not find a version that satisfies the requirement eeglabio
ERROR: No matching distribution found for eeglabio
and then we add eeglabio to github_actions_dependencies.sh in the same place as nitimerequirements_testing_extra.txt. I suspect that none of these lines are really being tested by CIs, and codecov agrees:
codecov/patch — 22.32% of diff hit (target 95.00%)
I know that there is already a pip install -i https://test.pypi.org/simple/ eeglabio in the eeglabio instructions, but I think users will rightly assume they should be able to pip install eeglabio, and we should wait until that's available. Also you might consider setting up a conda-forge recipe for it, maybe @hoechenberger can help with that end?
I moved eeglabio from Test PyPI to PyPI and added it as an requirement. The tests should now run on CIs as well. |
|
Thanks for this @jackz314 ! |
Reference issue
N/A
What does this implement/fix?
This adds the ability to export Raw or Epochs instances as EEGLAB set files. As well as the ability to import channel location data from separate CSV files or another file (using
read_raw).Additional information
The exported to set function (
save_set) was based on mnelab'swrite_set. I added channel location export and events/epochs data export so that Epochs exports can be read by EEGLAB.The channel location expansion function (xyz to all, used for
save_set) referenced MATLAB's cart2sph, as well as EEGLAB's relevant functions.It has been roughly tested on a few data sets on both EEGLAB and MNE.