-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
WIP: Added tutorial for fNIRS data #4257
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth going from the raw CSV data, then.
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.
OK 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
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.
errant #
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should just change the default colors in raw.plot. Are these standard colors for fNIRS?
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.
Yes, red for HbO and blue for HbR are accepted standards.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again about standardization -- are these standard for fNIRS?
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.
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) |
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.
no need to redefine
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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)] + |
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.
"HbO %.2d" % i
is enough
|
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]' |
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.
use %s and not str +
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.
like just below
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.
ops sorry fixing this now
| # 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
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.
no #
| @@ -0,0 +1,123 @@ | |||
| """ | |||
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.
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.