mne-tools / mne-python

MNE: Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python
https://mne.tools
BSD 3-Clause "New" or "Revised" License
2.72k stars 1.32k forks source link

Snirf files not readable #11194

Open Carlafrenzel opened 2 years ago

Carlafrenzel commented 2 years ago

Hi,

I am creating snirf files with pysnirf2 based on data collected with LSL in xdf format. I then want to preprocess the data in the snirf files with MNE. If I create the snirf files, the nirs group is an indexed group. So the key will be 'nirs1' as indexing starts with 1 in h5py, I believe. In the snirf documentation (https://github.com/fNIRS/snirf/blob/master/snirf_specification.md#nirsiprobesourcepos2d) the nirs group should also be an indexed group. In Homer3 the created snirf files are readable.

However, with MNE I get an error that the file does not have the nirs element. This is expected as it searches for 'nirs' as a key but the key is actually 'nirs1'.

KeyError: "Unable to open object (object 'nirs' doesn't exist)"

And opening with h5py:

<KeysViewHDF5 ['nirs1']>

My question is, if anyone has any suggestions how to fix this or if there is an quick fix for my problem so that I can actually use my files in MNE?

Another question is, how to generally handle the nirs group. As far as I understand the snirf format is based on hdf5 format and indexing generally starts at 1? Snirf files created with the aurora directly use 'nirs' as a key. Is there any standard which way it should be?

I also attached the file. subj3_mt_loc.snirf.zip

Thanks, Carla

welcome[bot] commented 2 years ago

Hello! πŸ‘‹ Thanks for opening your first issue here! ❀️ We will try to get back to you soon. πŸš΄πŸ½β€β™‚οΈ

larsoner commented 2 years ago

@rob-luke any ideas?

drammock commented 2 years ago

Hi @Carlafrenzel, thanks for reporting (and thanks for including the problematic file!)

As for a quick fix, you could try this:

import h5py
import mne
with h5py.File('subj3_mt_loc.snirf', 'r+') as dat:
    dat.move('nirs1', 'nirs')

raw = mne.io.read_raw_snirf('subj3_mt_loc.snirf')

but for me at least, that just yields a different error about the MeasurmentTime being None.

Carlafrenzel commented 2 years ago

Hi,

thanks for the quick reply and fix. Your suggestion does work:)

The file I attached does indeed lack the measurementTime data. I didn't notice before. After fixing my mistake the suggested solution does work and I am now able to open the modified snirf file in MNE.

Thanks again:)

rob-luke commented 2 years ago

Hi @Carlafrenzel, thanks for taking the time to raise this issue.

I just took a read of the SNIRF spec, and as you say, it supports /nirs# as valid naming. See...

All SNIRF data elements are associated with a unique HDF5 location path in the form of /root/parent/.../name. All paths must use /nirs or /nirs# (indexed group array). Note that the root /nirs can be either indexed or a non-indexed single entry.

MNE does not yet support all features of the SNIRF specification. For example, multiple measurements in one file, DCS data types etc. And the edge case you report is also not yet supported.

Further, I do not believe any manufacturers use the indexing /nirs#, every manufacturer file I have got my hands on uses /nirs.

As you are writing your own files, I suggest you use /nirs rather than /nirs1 unless you have a great reason to. But, as you seem technically capable, I think the best solution would be for you to open a small PR to MNE-Python to enable reading either naming with our SNIRF reader. Can you contribute a PR?

Carlafrenzel commented 2 years ago

Hi @rob-luke,

just to clarify, I do not use /nirs1 or /nirs# on purpose. This rather is an issue with creating own snirf files as pysnirf2 creates nirs as an indexed group. Similarly, if I create an .h5 file and define nirs as an indexed group I end up with /nirs1 again. The one thing I could try, which I haven't yet, is to create an .h5 file and do not create an indexed nirs group. With all other ways related to writing own snirf files with pysnirf2 and/or h5py I end up with the nirs1 problem. But now thanks to @drammock I have a solution. At least for now this works for my files and in the future I can still come up with a more elegant solution:)

Further, I do not believe any manufacturers use the indexing /nirs#, every manufacturer file I have got my hands on uses /nirs.

I really think this will be more of an issue for people who want to use data that is not coming straight from the device. In our case, for example, we used LSL as we have multiple data streams that need to be synchronized.

But, as you seem technically capable, I think the best solution would be for you to open a small PR to MNE-Python to enable reading either naming with our SNIRF reader. Can you contribute a PR?

Yes, I can definitely attempt to contribute but it's probably going to take a couple of days or so.

rob-luke commented 2 years ago

This rather is an issue with creating own snirf files as pysnirf2

Thanks for clarifying! This is great to know. We should definitely make sure we include support for this in MNE then.

Yes, I can definitely attempt to contribute but it's probably going to take a couple of days or so.

Great! We can guide you through the process if you need help at any point. Just yell out πŸ˜„

Carlafrenzel commented 2 years ago

Great! We can guide you through the process if you need help at any point. Just yell out πŸ˜„

That would definitely be great and appreciated:)

rob-luke commented 2 years ago

Relevant info here: https://github.com/BUNPC/pysnirf2/issues/35