WIP: Added tutorial for fNIRS data#4257
Conversation
Codecov Report
@@ Coverage Diff @@
## master #4257 +/- ##
=========================================
- Coverage 86.2% 86.1% -0.11%
=========================================
Files 346 346
Lines 64639 64639
Branches 9907 9907
=========================================
- Hits 55725 55660 -65
- Misses 6197 6266 +69
+ Partials 2717 2713 -4 |
larsoner
left a comment
There was a problem hiding this comment.
Looks like a good start, thanks for working on this
tutorials/Working_with_fNIRS_data.py
Outdated
|
|
||
| import mne | ||
|
|
||
| raw_ndarray = np.load('/home/matteo/raw_ndarray.npy') |
There was a problem hiding this comment.
Can you make a PR to add this to mne.datasets.misc here? It will be necessary for CircleCI to run, and for anybody to run your tutorial.
There was a problem hiding this comment.
@mcaffini what did you have to do to get this file? there is no real file format? what would an MNE user have to do to get such a file?
There was a problem hiding this comment.
Yes, @Eric89GXL that would be an option. If @agramfort still prefers a public dataset, I'll stick with him and adapt the tutorial.
BTW, the real file format is a csv file with fluences data, I manually crunched it to get HbO and HbR concentrations and then saved it in numpy format.
There was a problem hiding this comment.
It might be worth going from the raw CSV data, then.
tutorials/Working_with_fNIRS_data.py
Outdated
| # Usually in fNIRS one looks for brain responses to external sensorial | ||
| # stimulations (visual, acoustic, etc.). In order to do so, block design | ||
| # studies are usually employed and data are later epoched to get evoked | ||
| # responses. |
There was a problem hiding this comment.
This would be good to put in the triple-quoted section above.
tutorials/Working_with_fNIRS_data.py
Outdated
| # fNIRS raw data come in various formats and the best way to dive into MNE is | ||
| # to deal with your own format first and fit your data into a 2D numpy array | ||
| # [channels x samples]. Once you prepared your time series for HbO and HbR | ||
| # concentrations, you can create a RawArray instance from the data array using |
There was a problem hiding this comment.
see other tutorials -- you can/should do
:class:`mne.io.RawArray`
and the like to make nice links for people. And then you don't even need the tail end of the sentence here "using mne.io.RawArray"
tutorials/Working_with_fNIRS_data.py
Outdated
| # | ||
| # In this tutorial, I don't preprocess the data. If your fNIRS device outputs | ||
| # data in the form of photon fluences at detectors, you can compute HbO and HbR | ||
| # concentrations using the modified Lambert-Beer model. |
There was a problem hiding this comment.
Can you provide some link either to a paper (in References section) or e.g. Wikipedia?
tutorials/Working_with_fNIRS_data.py
Outdated
| # concentrations using the modified Lambert-Beer model. | ||
| # | ||
| # In the following example we have data from 20 channels plus one events | ||
| # channel and we end up # with 20 HbO time series, 20 HbR time series and one |
tutorials/Working_with_fNIRS_data.py
Outdated
| raw_data.filter(l_freq, h_freq) | ||
|
|
||
| ############################################################################### | ||
| # In order to have a general glimpse of the dataset, I start by plotting all |
There was a problem hiding this comment.
use first-person plural "we" or second-person "you"
tutorials/Working_with_fNIRS_data.py
Outdated
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) | ||
| fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, ' | ||
| + str(h_freq) + ' Hz]' | ||
| plot_colors = dict(hbo='r', hbr='b', stim='k') |
There was a problem hiding this comment.
Maybe we should just change the default colors in raw.plot. Are these standard colors for fNIRS?
There was a problem hiding this comment.
Yes, red for HbO and blue for HbR are accepted standards.
There was a problem hiding this comment.
Okay we should change the defaults in raw.plot, then.
tutorials/Working_with_fNIRS_data.py
Outdated
| # events data using red, blue and black respectively. I also mark color-coded | ||
| # events positions, using the same colors previously used in | ||
| # mne.viz.plot_events. | ||
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) |
There was a problem hiding this comment.
Again about standardization -- are these standard for fNIRS?
There was a problem hiding this comment.
Not exactly standard, but reasonable. Signal dynamics may be affected by for many factors such as stimuli type, skull thickness, superficial artifacts, ...
tutorials/Working_with_fNIRS_data.py
Outdated
| ############################################################################### | ||
| # I can later dive into the dataset and look at the raw time series more | ||
| # closely. Same color-codes through the plots is usually a good idea. | ||
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) |
tutorials/Working_with_fNIRS_data.py
Outdated
| # I can later dive into the dataset and look at the raw time series more | ||
| # closely. Same color-codes through the plots is usually a good idea. | ||
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) | ||
| fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, ' |
There was a problem hiding this comment.
we usually use % pattern like 'fNIRS raw bandpass filtered %s Hz - %s Hz' % (l_freq, h_freq)
tutorials/Working_with_fNIRS_data.py
Outdated
| #'hbo' or 'hbr' channel type to your channel. | ||
| nChannels = 20 # number of physical channels | ||
| sampling_frequency = 15.625 | ||
| channel_names_fnirs = ['HbO '+"%.2d" % i for i in range(1,nChannels+1)] + |
|
It might be worth going from the raw CSV data, then.
+1
|
|
yes
|
|
I integrated most of the comments, I still have to work on the raw file load-parse-crunch part. |
tutorials/Working_with_fNIRS_data.py
Outdated
| # :func:`mne.viz.plot_events`. | ||
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) | ||
| fig_title = 'fNIRS Raw Bandpass filtered [' + str(l_freq) + ' Hz, ' + | ||
| str(h_freq) + ' Hz]' |
| # We can later dive into the dataset and look at the raw time series more | ||
| # closely. Same color-codes through the plots is usually a good idea. | ||
| fig_title = 'fNIRS raw bandpass filtered %s Hz - %s Hz' % (l_freq, h_freq) | ||
| plot_colors = dict(hbo='r', hbr='b', stim='k') |
There was a problem hiding this comment.
Please update these (and possibly the scalings) here:
https://github.com/mne-tools/mne-python/blob/master/mne/defaults.py#L13
We should probably explicitly pick some aesthetically nice red/blue from here instead of using 'r' and 'b' (which change from 1.+ -> 2.+ of mpl):
| # events data using red, blue and black respectively. We also add color-coded | ||
| # events positions, using the same colors previously used in | ||
| # :func:`mne.viz.plot_events`. | ||
| scalings = dict(hbo=10e-6, hbr=10e-6, stim=1) |
There was a problem hiding this comment.
And assuming you're using what can be considered a standard processing setup with standard signals, let's fix the scalings in the same file. We can add it to whats_new.rst as a bugfix.
tutorials/Working_with_fNIRS_data.py
Outdated
| Use MNE with fNIRS data | ||
| ======================= | ||
|
|
||
| MNE Python was implemented with EEG and MEG in mind, but can be useful to |
There was a problem hiding this comment.
originally implemented
(nowadays we try to implement things with a broader scope)
tutorials/Working_with_fNIRS_data.py
Outdated
| ======================= | ||
|
|
||
| MNE Python was implemented with EEG and MEG in mind, but can be useful to | ||
| process fNIRS data as #well. A common fNIRS data set (similarly to EEG and |
| @@ -0,0 +1,123 @@ | |||
| """ | |||
There was a problem hiding this comment.
change filename to plot_fnirs_data.py, and add it to the documentation.rst somewhere.
|
@mcaffini how are we doing here? Any chance you can work on this in the next week or so? We're working on pushing out a release soon and it would be great to have this tutorial |
|
Hi @larsoner and sorry for the late reply, I was off work for a long time. Yes, let's finish this in the next days. |
|
@mcaffini do you still plan to complete this? |
|
Oops I've seen this just now, sorry. |
|
never too late :)
|
|
@mcaffini any time for this in the near future? If not, I know another fNIRS person who might be able to take over |
|
@larsoner I can't make it in the near future and I'd be happy if someone takes over :-) |
|
@mcaffini do you have the original raw data (light intensity measurements) that were used to generate the chroma concentrations (HBo / HBr)? It would be best if we could also add code to do this processing step, and having the original data + knowing what you did to convert it would help. |
|
@larsoner that specific dataset was exported from our fNIRS device in the form of HbO and HbR concentrations. The conversion from raw intensity to concentration depends on the type of instrument, for CW (continuous-wave) it can be a simple modified Lambert-Beer model, but for FD (frequency-domain) and TD (time-domain) it may be more complicated. |
|
IMO it is sufficient to start from HbO/HbR signals because this is what most devices spit out. |
|
Thoughts @rob-luke ? |
|
I agree with @mcaffini that the complexity of converting from intensity to concentration is dependent on the type of instrument. And its interesting to hear from @cbrnr that the majority of devices directly export HbO/HbR, are you in an engineering heavy field? or is this in general? My experience is predominantly in the auditory domain. All the devices I have used are CW and export raw intensity. The devices I have interacted with are NIRX (Macquarie Uni, Bionics Institute, U California), TechEn (NIJT), and Hitachi (UCL). I also attended the last sfNIRS conference and most of the research I saw had to deal with this conversion to concentration. Perhaps the reason I have seen lots of intensity exporting machines is that I am working in less engineering heavy domains, and these CW machines may be cheaper. I think if you want MNE fNIRS analysis to be available to as many users as possible starting with a CW intensity to concentration conversion step sounds like a good plan. @mcaffini suggestion to split this discussion to a different issue makes sense to me. |
|
I've worked with fNIRS signals in the BCI field occasionally, but I'm by no means an expert. Maybe the signals I received were even preprocessed, I'm not sure. It sounds like a conversion step is definitely necessary. |
|
As a first step to getting HbO/HbR I will raise a PR to read NIRX files. Then we can worry about the conversion steps. We can move this discussion when I open the PR. |
|
Sounds good to me. |
|
Closing in favor of #6674 |
I started a tutorial to process fNIRS data. It's super basic so this is definitely WIP, but we can work it out together to align this to the other tutorials and to add features of potential interest.
For now, the numpy file with test data can be found here, but we could make use of a public dataset as @agramfort previously suggested.