SourceEstimatefunctions would diverge quite a lot from the handling of usual data. So
poweras well as possibly other params like
return_itcwould be needed to be False for SourceEstimates and the users need to manually create the power field. And this additional expense for the user would be only implemented because of a "marginal" case, since for fully (non-kernelized) SourceEstimates (which i'd say are the only ones really used atm) all this wouldn't even pose a problem...
SourceTFR.dataand then do the implementation i described above?
I'm at a point now where most stuff works fine for single stcs and morlet, multitaper & stockwell.
However, there's one bigger step left in the data processing, which is the introduction of 'epoched' SourceTFR.
If we want to be able to return the Inter-Trial-Coherence, we need to be able to feed multiple SourceEstimates, in the form of lists, to tfr_functions.
my vision of doing this would be taking lists of equal data types into the tfr_function, and concatenating their contents to a single data array at a very early stage, so that the data is treated like an epochs field. For stcs with a data field of (kernel, sens_data) this process would lead to a data array similar to a usual epochs data array. However, for stcs with fully represented data, this can lead to quite huge data arrays. Of course, we warn the user of this, and advise him to use kernelized data in order to save memory.
Still, i wanted to hear your opinion on this.
Another thing that has me hesitating is that @agramfort mentioned to take into mind the implications that the processing of lists might have. I think 'epoching up' the data at an early stage and from then on treating the data like epochs should be quite safe for stcs as well as standard epochs/average data. Still, i could of course be missing some important implications (e.g. implications this might have for epochs and average data). That's why i wanted to ask you: Is there something i should take care of when allowing tfr_functions to take lists as input?
Of course i can rely on the tests telling me if anything went wrong, but i still thought it's better to ask.
So, in short: What's your opinion on making tfr_functions take list as input?
and: Are there some special implications we should be aware of?
Hey, just for your information:
Yesterday, I created 2 very brute attempts to feed lists and generators into tfr functions.
In this first approach, i tried to process each list element subsequently in order to save memory, as @larsoner suggested. This 'fast and dirty' hack worked for tfr_morlet, but didn't for multitapers. The problem is, that if we want to do this properly, we need to pass the lists/gens waaaay down through
_time_frequency_loop, or alternatively pull the loop that iterates over the different taper functions way up from
_tfr_aux. Since there is a lot of data handling that would e.g. require to get the length of the generator object before starting to loop through it, this task simply looks to my like entirely restructuring those three functions.
Of course this can be done, but it will require some time. Because i would really try to make things work for Source Space first as the primary objective, i then implemented the second approach:
This is the simple approach I named before. It just takes the list at the beginning of
_tfr_aux and concatenates it to one big data field. From then on, it works exactly the same as usual data. (I.e. works fine for epochs/average lists/generators of morlet/multitaper). Of course, this kind of misses the memory saving point of having a list at all, but it serves well enough to start working with SourceEstimates.
So for now, i'd carry on with the second approach, and when we got the rest of the SourceTFR stuff working, i'd say we can approach the first problem.
Please note that until then, we still would have the kernel trick to work for us in order to save memory, so that effectively, memory used for transforming stcs would not exceed the memory used for an epochs object.
Sorry for not yet pushing the time_frequency with SourceTFR commits. I had quite some trouble with the combination of multiple tapers and lists/gens, especially the subsequent processing of the generator objects and calculating the inter-trial-coherence correctly. I kind of needed to change everything and introduced a separate function
tfr_loop_list in order to make this work.
But it's running all smooth now, which means that morlet, multitaper and stockwell work correctly with single stcs/lists/generators, normal/vector ori, return_itc (as well as average for morlet & multitapers).
Other good news are that - at least for multitapers and morlet- the single list elements are now computed subsequently, which means we can actually save memory when using generators, and won't need to create huge data fields first.
Bad news are that enabling all this to work for lists/generators AND kernelized data fields will still involve a lot of additional work, especially since i got the impression that most of the computation needs to be transferred from the tfr_functions to the SourceTFR objects, when stfr.data is called. I'll show you the problems later, and hope that there's an efficient solution for this.
So for now, i'll just clean up the list stuff a little bit and make it ready for a PR, and then focus on the Kernel stuff later.
git diff master..MY_BRANCHto check what's in the diff.
git diff master.. --names-onlyshows this changes:
doc/_static/institution_logos/Aalto.svg doc/_static/institution_logos/BU.svg doc/_static/institution_logos/Inserm.svg doc/_static/institution_logos/Julich.svg doc/_static/institution_logos/MGH.svg doc/_static/institution_logos/MIT.svg doc/_templates/layout.html doc/data_formats.rst doc/precision.rst doc/units.rst mne/minimum_norm/inverse.py mne/minimum_norm/tests/test_inverse.py mne/source_estimate.py mne/source_tfr.py mne/tests/test_source_tfr.py mne/time_frequency/_stockwell.py mne/time_frequency/tests/test_stockwell.py mne/time_frequency/tests/test_tfr.py mne/time_frequency/tfr.py mne/viz/_brain/_brain.py mne/viz/_brain/view.py mne/viz/epochs.py mne/viz/raw.py mne/viz/utils.py tutorials/raw/plot_10_raw_overview.py
I now got the first simple implementation for plotting SourceTFR. When @agramfort and I discussed the project, he said that the minimum would be to be able to convert the SourceTFR into stcs, and then plot these. Based on this, I implemented
stfr.plot(fmin=0, fmax=None, epoch=0, **plot_params).
def plot(self,fmin=0, fmax=None, epoch=0, **plot_params): freq_idx = _freq_mask(self.freqs, self.sfreq, fmin, fmax) #FIXME: sum over average? sum is easier to interprete, but will result in bad color scalings data_cropped = np.mean(self.data[..., freq_idx, :], axis=-2) if "epochs" in self.dims: data_cropped = data_cropped[..., epoch, :, :] if self._src_type == "volume": # use the magnitude only if it's a VolVectorSourceEstimate (see _BaseVectorSourceEstimate.plot) if "orientations" in self.dims: data_cropped = np.linalg.norm(data_cropped, axis=1) brain = plot_volume_source_estimates( VolSourceEstimate(data_cropped, self.vertices, self.tmin, self.tstep, self.subject), **plot_params) elif "orientations" in self.dims: brain = plot_vector_source_estimates( VectorSourceEstimate(data_cropped, self.vertices, self.tmin, self.tstep, self.subject), **plot_params) else: brain = plot_source_estimates( SourceEstimate(data_cropped, self.vertices, self.tmin, self.tstep, self.subject), **plot_params) return brain
With this plot method, you can choose the frequencies you want to include. These frequencies are then selected by
utils._freq_mask and averaged. If the SourceTRF has an "epochs" dimension, the
epoch param is used as index on which frequency to plot. Then this data plotted, using the according [Vol/Vector]SourceEstimate plot function. The plot params here are the respective params of
plot[_volume/vector]_source_estimate, and therefore will differ, depending on the plotting function used.
Of course, this is just some kind of hack, but It works fine and looks pretty clean to me.
As a further goal, I wanted to do a proper SourceTFR plotting function, that includes stuff like a "Time-Frequency Viewer" (as compared to the "Time Viewer" Plot), where you can skim through the time axis as well as the frequency axis in the plotting GUI. However, i realize, that building a function that unites the plotting functionality of all source types (Note that this also should be done for two types of plots: The normal surface/vector plots, and the volume plots) will require a good amount of work again.
That's why i wanted to ask you for advice, if you have some ideas how (or maybe even if) we should implemented this. Maybe there is some point where we could tweak the existing plotting structures, and integrate the functionality they provide with the new SourceTFR-specific tasks?
concerning the plotting:
I checked a little deeper into the plotting stuff last week, and I think that if we want to build a more elaborate plotting function for SourceTFRs, we will probably need some time after the GSoC to do so. I think that if we wanted to create a GUI, where users can not only switch along the time axis, but also along the freq axis, the best thing would be to copy FreeSurfer's
TimeViewer, and generalize it to an
AxisViewer, where one ore more axes can be manipulated in the same way as the time axis now. Likewise, for the Volume Plots, we could add a second window to the SourceTFR plotting function, which allows frequency indexing, just as the time window currently does. But as said, this will be a lot of work and I'd say that we should add this separately after GSoC (since I would rather spend the last week giving a final polish to what we've accomplished so far).
I also wanted to talk to you about the final project page for GSoC:
Last week, I started a GitHub gist that contains information, links and a summary of the project. I thought that this would be a simple, but good looking way of presenting the results of this GSoC. I tried to write it in a way that satisfies Google's requirements, but at the same is readable for the general public (so I could for example publish it on social media).
I already wrote down most of the stuff, so you can get an idea on how it would look like if it's done.
Here it is:
Please have a look at it and tell me if it looks okay to you and if you're missing anything!