Repository: mne-tools/mne-python

Issue:
ENH: Allow retrieval of GFP
#2538 added the ability to plot GFPs. Currently, the GFP is [only temporarily calculated for plotting](https://github.com/Eric89GXL/mne-python/blob/7f8c69bae49041bb4f0507539ccda1bda7f0b394/mne/viz/evoked.py#L397), and the user has no easy way to access the data. 

 In our EEG workflow, we typically calculate GFPs for every single participant and condition, and average conditions across participants for plotting; or we compute statistics based on the GFP differences. It is therefore highly important for us to have easy access to the GFPs. We resorted to doing the calculations manually based on `Evoked.data`, but this is cumbersome as one has to "leave" the MNE sphere and implement the operations by hand via NumPy and/or Pandas -- which is not easy for beginners and error-prone, as Pandas by default [uses the unbiased estimator](http://stackoverflow.com/questions/24984178/different-std-in-pandas-vs-numpy) for standard deviation and NumPy doesn't.

I can try to implement a GFP function, but I would need assistance in doing so. I don't really know where to start or where to put that code: should it be a method of the `Evoked` class? Potentially exposed as a property, so it could be accessed via `Evoked.gfp`? Or should it be an entirely new class? Would it have to have its own plotting method? etc. pp. Any help and suggestions would be greatly appreciated.


Discussion:
I would make it a function

gfp = mne.global_field_power(evoked, ch_type='eeg' l 'grad' | 'mag' |
'seeg' | 'ecog')

where gfp is an array and then you can just do

plt.plot(evoked.times, gfp)

wdyt?

Alex you're getting tired :) Let me ask why ```gfp = evoked.std(0)```
or ```gfp = evoked.copy().pick_types(eeg=True).std(0)``` would not do it.

On Sat, Feb 18, 2017 at 11:32 AM Alexandre Gramfort <
notifications@github.com> wrote:

> I would make it a function
>
> gfp = mne.global_field_power(evoked, ch_type='eeg' l 'grad' | 'mag' |
> 'seeg' | 'ecog')
>
> where gfp is an array and then you can just do
>
> plt.plot(evoked.times, gfp)
>
> wdyt?
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/mne-tools/mne-python/issues/4002#issuecomment-280836868>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AB0fiphQ3RCsTDXb3-Nz3TPklWBZaZrLks5rdsiqgaJpZM4MFECM>
> .
>

@dengemann, what the heck, it is *that* simple?? That's awesome! Still, I would propose to create a small wrapper function to make this more accessible. Or if you're opposed to that, I could extend the documentation?
Oh. That was a proposal, not an existing method. Never mind! Guess I got too little sleep last night. @dengemann, sounds good to me! What is the parameter supposed to mean? ddof?
Hey Richard, not sure what you have tried but these two expression that I
shared should be valid MNE-Python code. Yes adding more documentation on
these things is a very good idea. My concern with interfaces for things
that you can get in one line is that they add maintanance overhead for very
low return. And ideally we should teach newcomers where the MNE API ends
and where the standard scientific Python toolstack begins. As you see,
computing the global field power is not complicated at all once you have
the underlying data. On the other hand an interface may be good if we want
to provide different flavors of GFP, e.g. whitened GFP as used in
```evoked.plot_white```. But then again let's not do this unless we have
the impression that it solved a real problem for many. For example, to add
a function that creates a grand average ERP/ERF was in my personal view not
urgently needed, as it is both easy and readable to compute a grand average
in a few lines of Python. I personally rarely use MNE Python once I have
done my single subject processing. I just use the remaining other tools
that you have in Python to process and visualize numpy arrays. Maybe we
should have a doc page for common numpy/scipy recipes and make more
explicit. Since this desire for interfaces to relatively simple operations
is a recurrent one it would be good to get some feedback from new comers
what could be improved in our dcoumentation, communication, etc. to
encourage using Python for such tasks.

On Sat, Feb 18, 2017 at 1:34 PM Richard Höchenberger <
notifications@github.com> wrote:

> Oh. That was a proposal, not an existing method. Never mind! Guess I got
> too little sleep last night. @dengemann <https://github.com/dengemann>,
> sounds good to me! What is the parameter supposed to mean? ddof?
>
> —
> You are receiving this because you were mentioned.
>
>
> Reply to this email directly, view it on GitHub
> <https://github.com/mne-tools/mne-python/issues/4002#issuecomment-280842864>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AB0fii6ZVtttB0BPsycUkoQnw7GFzAmxks5rduVLgaJpZM4MFECM>
> .
>

+1 for adding GFP documentation in tutorials.evoked.

On 18 February 2017 at 08:50, Denis A. Engemann <notifications@github.com>
wrote:

> Hey Richard, not sure what you have tried but these two expression that I
> shared should be valid MNE-Python code. Yes adding more documentation on
> these things is a very good idea. My concern with interfaces for things
> that you can get in one line is that they add maintanance overhead for very
> low return. And ideally we should teach newcomers where the MNE API ends
> and where the standard scientific Python toolstack begins. As you see,
> computing the global field power is not complicated at all once you have
> the underlying data. On the other hand an interface may be good if we want
> to provide different flavors of GFP, e.g. whitened GFP as used in
> ```evoked.plot_white```. But then again let's not do this unless we have
> the impression that it solved a real problem for many. For example, to add
> a function that creates a grand average ERP/ERF was in my personal view not
> urgently needed, as it is both easy and readable to compute a grand average
> in a few lines of Python. I personally rarely use MNE Python once I have
> done my single subject processing. I just use the remaining other tools
> that you have in Python to process and visualize numpy arrays. Maybe we
> should have a doc page for common numpy/scipy recipes and make more
> explicit. Since this desire for interfaces to relatively simple operations
> is a recurrent one it would be good to get some feedback from new comers
> what could be improved in our dcoumentation, communication, etc. to
> encourage using Python for such tasks.
>
> On Sat, Feb 18, 2017 at 1:34 PM Richard Höchenberger <
> notifications@github.com> wrote:
>
> > Oh. That was a proposal, not an existing method. Never mind! Guess I got
> > too little sleep last night. @dengemann <https://github.com/dengemann>,
> > sounds good to me! What is the parameter supposed to mean? ddof?
> >
> > —
> > You are receiving this because you were mentioned.
> >
> >
> > Reply to this email directly, view it on GitHub
> > <https://github.com/mne-tools/mne-python/issues/4002#
> issuecomment-280842864>,
> > or mute the thread
> > <https://github.com/notifications/unsubscribe-auth/
> AB0fii6ZVtttB0BPsycUkoQnw7GFzAmxks5rduVLgaJpZM4MFECM>
>
> > .
> >
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/mne-tools/mne-python/issues/4002#issuecomment-280846751>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AEp7DOTFEhS7inZATJegZCnlCdC3TH_oks5rdvcOgaJpZM4MFECM>
> .
>

>
> Alex you're getting tired :) Let me ask why ```gfp = evoked.std(0)```
> or ```gfp = evoked.copy().pick_types(eeg=True).std(0)``` would not do it.
>

then I would say just do:

gfp = evoked.copy().pick_types(eeg=True).data.std(0)

and not a single line of new code is needed... :)

@hoechenberger can you find the time to make a PR to improve `tutorials/plot_object_evoked.py`, and/or add it elsewhere in the documentation? I guess we could add a one-liner note to `plot_evoked` and `evoked.plot` since that's where people will also look at/for GFP.
@Eric89GXL, sorry for the late response. Yes, I can certainly do that. Probably won't happen before mid-April, though!
@hoechenberger we are after mid-april :)
We could just add a line for the ERP GFP to @dengemann 's example here:

https://mne-tools.github.io/dev/auto_examples/time_frequency/plot_time_frequency_global_field_power.html#sphx-glr-auto-examples-time-frequency-plot-time-frequency-global-field-power-py

Resolving patch:
diff --git a/tutorials/plot_object_evoked.py b/tutorials/plot_object_evoked.py
--- a/tutorials/plot_object_evoked.py
+++ b/tutorials/plot_object_evoked.py
@@ -8,9 +8,11 @@
 averaged data over trials. In MNE the evoked objects are usually created by
 averaging epochs data with :func:`mne.Epochs.average`.
 """
+# sphinx_gallery_thumbnail_number = 2
 
 import os.path as op
 
+import matplotlib.pyplot as plt
 import mne
 
 ###############################################################################
@@ -63,6 +65,16 @@
 print('Data from channel {0}:'.format(evoked.ch_names[10]))
 print(data[10])
 
+###############################################################################
+# In the same vein, we can quickly extract (and, e.g., plot) the GFP as the
+# standard deviation across channels, here shown just for EEG.
+
+gfp = evoked.copy().pick_types(eeg=True, meg=False).data.std(axis=0)
+fig, ax = plt.subplots(1)
+ax.plot(evoked.times, gfp / 1e6)  # scale to uV
+ax.set(xlabel='Time (sec)', ylabel='GFP (uV)')
+fig.tight_layout()
+
 ###############################################################################
 # If you want to import evoked data from some other system and you have it in a
 # numpy array you can use :class:`mne.EvokedArray` for that. All you need is


Test patch: