Quality assurance with MNE report
Let’s say we want to analyze 100 subjects.
How do we do quality assurancy in a scalable manner?
MNE report
from mne.report import Report
A report contains: * Figures * Images * Custom HTML * Sliders
First, let us generate some figures for the report.
%matplotlib inline
import mne
from mne.datasets import sample
data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
raw = mne.io.read_raw_fif(raw_fname, preload=True)
Opening raw data file /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sample_audvis_raw.fif...
Read a total of 3 projection items:
PCA-v1 (1 x 102) idle
PCA-v2 (1 x 102) idle
PCA-v3 (1 x 102) idle
Range : 25800 ... 192599 = 42.956 ... 320.670 secs
Ready.
Current compensation grade : 0
Reading 0 ... 166799 = 0.000 ... 277.714 secs...
Now let’s pretend this data came from 3 different subjects
raw1 = raw.copy().crop(0, 20)
raw2 = raw.copy().crop(20, 40)
raw3 = raw.copy().crop(40, 60)
raw1.save(data_path + '/MEG/sample/sub-01_raw.fif', overwrite=True)
raw2.save(data_path + '/MEG/sample/sub-02_raw.fif', overwrite=True)
raw3.save(data_path + '/MEG/sample/sub-03_raw.fif', overwrite=True)
Overwriting existing file.
Writing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-01_raw.fif
Closing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-01_raw.fif [done]
Overwriting existing file.
Writing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-02_raw.fif
Closing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-02_raw.fif [done]
Overwriting existing file.
Writing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-03_raw.fif
Closing /home/mainak/Desktop/projects/github_repos/mne-python/examples/MNE-sample-data/MEG/sample/sub-03_raw.fif [done]
Now, we can have a function to go from raw to evoked
event_id = {'Auditory/Left': 3, 'Auditory/Right': 4}
def raw_to_evoked(raw_fname, tmin=-0.1, tmax=0.5):
raw = mne.io.read_raw_fif(data_path + '/MEG/sample/' + raw_fname, preload=True)
fig1 = raw.plot();
raw.filter(0, 40.)
events = mne.find_events(raw, stim_channel='STI 014')
epochs = mne.Epochs(raw, events, event_id, tmin, tmax)
fig2 = epochs.plot();
evoked_l = epochs['Left'].average();
fig3 = evoked_l.plot_topomap()
fig4 = evoked_l.plot();
return [fig1, fig2, fig3, fig4]
Now, we can get all the figure handles:
%%capture
figs = raw_to_evoked('sub-01_raw.fif')
Now comes the actual report
rep = Report()
Embedding : jquery-1.10.2.min.js
Embedding : jquery-ui.min.js
Embedding : bootstrap.min.js
Embedding : jquery-ui.min.css
Embedding : bootstrap.min.css
captions = ['Raw', 'Epochs', 'Topomap', 'Butterfly']
rep.add_figs_to_section(figs, captions=captions)
rep.save('report_raw_to_evoked.html')
Report already exists at location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_raw_to_evoked.html. Overwrite it (y/[n])? y
Saving report to location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_raw_to_evoked.html
Rendering : Table of Contents
custom
... Raw
... Epochs
... Topomap
... Butterfly
'/home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_raw_to_evoked.html'
The report can be found here
We can go even more fancy. Let’s try to process all the three subjects.
%%capture
rep = Report()
for idx, r in enumerate(['sub-01_raw.fif', 'sub-02_raw.fif', 'sub-03_raw.fif']):
figs = raw_to_evoked(r)
rep.add_figs_to_section(figs, captions=captions, section='Subject %02d' % idx)
rep.save('report_raw_to_evoked.html', overwrite=True)
There are tabs for each subject!
Parallel processing
def raw_to_evoked(raw_fname, tmin=-0.1, tmax=0.5):
raw = mne.io.read_raw_fif(data_path + '/MEG/sample/' + raw_fname, preload=True)
raw.filter(0, 40.)
events = mne.find_events(raw, stim_channel='STI 014')
epochs = mne.Epochs(raw, events, event_id, tmin, tmax)
evoked_l = epochs['Left'].average();
from mne.parallel import parallel_func
fnames = ['sub-01_raw.fif', 'sub-02_raw.fif', 'sub-03_raw.fif']
parallel, myfunc, _ = parallel_func(raw_to_evoked, n_jobs=3)
parallel(myfunc(fname) for fname in fnames);
BEM sliders
What else can you do? You can inspect quality of the BEM with sliders.
subjects_dir = data_path + '/subjects'
rep = Report()
rep.add_bem_to_section(subject='sample', subjects_dir=subjects_dir, decim=36)
rep.save('report_bem.html')
Embedding : jquery-1.10.2.min.js
Embedding : jquery-ui.min.js
Embedding : bootstrap.min.js
Embedding : jquery-ui.min.css
Embedding : bootstrap.min.css
Report already exists at location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_bem.html. Overwrite it (y/[n])? y
Saving report to location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_bem.html
Rendering : Table of Contents
bem
... BEM
'/home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_bem.html'
Check out the report here
Custom HTML
We can even add custom htmls. For example, we can say:
html = """
<table class="table table-hover">
<tr>
<th>Meas time range</th>
<th>Sampling freq</th>
</tr>
<tr>
<td> %0.2f to %0.2f </td>
<td> %0.2f </td>
</tr>
</table>
"""
rep.add_htmls_to_section(html % (raw.times[0], raw.times[-1], raw.info['sfreq']), captions='Info table')
rep.save('report_bem.html', overwrite=True)
Saving report to location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_bem.html
Rendering : Table of Contents
custom
... Raw
... Epochs
... Topomap
... Butterfly
... Info table
'/home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_bem.html'
Here is the report.
Custom sliders
And we can make our own sliders
import matplotlib.pyplot as plt
fname = data_path + '/MEG/sample/sample_audvis-ave.fif'
evoked = mne.read_evokeds(fname, condition='Left Auditory',
baseline=(None, 0), verbose=False)
rep = Report()
figs = list()
times = evoked.times[::4]
for time in times:
figs.append(evoked.plot_topomap(time, vmin=-300, vmax=300,
res=100, show=False))
plt.close(figs[-1])
rep.add_slider_to_section(figs, times, 'Evoked Response')
rep.save('report_slider.html')
Embedding : jquery-1.10.2.min.js
Embedding : jquery-ui.min.js
Embedding : bootstrap.min.js
Embedding : jquery-ui.min.css
Embedding : bootstrap.min.css
Saving report to location /home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_slider.html
Rendering : Table of Contents
Evoked Response
... Evoked Response
'/home/mainak/Desktop/projects/mne-workshop-brown/content/preprocessing/report_slider.html'
To learn more about quality assurance, check out this paper
Exercise
1) Can you think of creative ways to use the report for your own analysis?
Here are some ideas:
- sections with subject names instead of preprocessing step- custom html/javascript to get quality labels
- sliders to browse through the raw data