mne-tools / mne-python

MNE: Magnetoencephalography (MEG) and Electroencephalography (EEG) in Python
https://mne.tools
BSD 3-Clause "New" or "Revised" License
2.66k stars 1.31k forks source link

Plot topomap without any interpolation between sensors? #2210

Closed choldgraf closed 7 years ago

choldgraf commented 9 years ago

This is another one that is probably mostly useful for ecog. I'm trying to plot sensor activations on a brain plot. There are already a few functions to create custom electrode layouts and such, though I haven't found a good way to just plot a scatterplot with one point for each electrode.

For example, I was playing around with doing ICA on a few grids to see if consistent noise could be cleaned out. I wanted to look at the weights for components across the electrodes. However, the plot_components function does a bunch of field interpolation between electrodes (which makes sense with eeg/meg, but not so much with ecog I think). E.g. I get something like this:

image

What would be great is if rather than interpolating cold/hot spaces, it would just have an option to not perform any interpolation, and just give a scatterplot with x/y positions for the electrodes, where color represents values we care about. e.g., something like this:

image

Does some functionality like this already exist, or is there any desire from anyone else for it?

kingjr commented 9 years ago

I'm quite surprised of the low amount of correspondance between the interpolated images and the scatter plots. Is this expected? Is one of them based on a Laplacian transform / current source density and not the other?

However, the plot_components function does a bunch of field interpolation between electrodes (which makes sense with eeg/meg, but not so much with ecog I think)

Why not?

Just to throw some more ideas, I think it'd be great to have an option to add a mask that surrounds the electrode arrays using a concave hull. Typically, this would be useful when 1) ECoG strips and grids have huge gaps for which it's not really meaningful to interpolate data (or is it?) and 2) avoid these huge color effects at the electrode border.

choldgraf commented 9 years ago

The scatterplots and interpolated images shouldn't be directly compared, because I haven't made sure that I did it correctly (it was just a quick plot). Here's the code I used to make the scatterplot:

ica_elec_weights = np.dot(ica.mixing_matrix_.T, ica.pca_components_)
f, axs = plt.subplots(5, 5, figsize=(15, 15))
for i, (ax, plot_ica) in enumerate(zip(axs.ravel(), ica_elec_weights.T)):
    plot_ica = scale(plot_ica)
    ax.scatter(x_pos, y_pos, s=100, c=plot_ica, vmin=-1, vmax=1, cmap=cm.RdBu_r)
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
    ax.set_title('Component {0}'.format(i))

As for the interpolation stuff. I'm not too familiar with how the fields are generated from the sensor traces in eeg/meg. I assume that things would be distributed around the cortical surface in a way that would be different than how they'd spread across the scalp, but maybe it's not such a big deal?

But actually, the main reason I didn't think it made sense because of the points you bring up. Ecog grids are irregularly spaced oftentimes, and they also have a relatively large border around them, which doesn't make sense when the weights spread way outside of the grid area. I think some sort of concave hull algorithm would be pretty cool.

choldgraf commented 9 years ago

I think I did find my bug in the scatterplot code. I was transposing the ica weight matrix when I shouldn't have done so. It would be helpful in the docstring to say what the dimensions of the mixing matrix mean (e.g., if rows are features or components)

Here with fixed code: image

And here is the topomap plot

image

kingjr commented 9 years ago

As for the interpolation stuff. I'm not too familiar with how the fields are generated from the sensor traces in eeg/meg. I assume that things would be distributed around the cortical surface in a way that would be different than how they'd spread across the scalp

My understanding is that the interpolation are just performed at the last computing stage and is just for vizualization purposes. It is not informed by the actual underlying physics. Plus, EEG should be similar whether it's performed epi/subdurally or at scalp, shouldn't it?

I am not so fan of the scatter plots; I think we should incline the user towards pretty graphs ;). But it's true that sometimes interpolation just doesn't make sense: typically when one only has one or a few sparsely located depth electrodes (linear arrays that target deep structures).

choldgraf commented 9 years ago

Ha, fair enough. I do a lot of scatter plots when I'm showing model R2 and stuff like that, but that's easy enough to do with ax.scatter and ax.imshow. In this case it seems like restricting the interpolation stuff to a window that covers the ecog grid would be enough.

larsoner commented 9 years ago

I think the interpolation code makes some assumption of smoothness that is satisfied for EEG but violated for ECoG. I wonder if we could somehow have a mode that drew it with nearest-neighbor interpolation instead. That would probably be more appropriate for ECoG.

choldgraf commented 9 years ago

Yeah I think that it'd work best if colors just moved isotropically away from the ecog sensors until they hit the field of another sensor. And if they didn't hit anything, they'd decay away relatively quickly.

kingjr commented 9 years ago

Yeah I think that it'd work best if colors just moved isotropically away from the ecog sensors until they hit the field of another sensor. And if they didn't hit anything, they'd decay away relatively quickly.

I've never encountered this option, so I would be a bit reluctant except if you have a reference? Note that this option requires the specification of the decay parameter.

There exists multiple ways of interpolating. You can indeed take a nearest neighbor approach, although I prefer cubic interpolations so as to avoid artificial edges.

See http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html

larsoner commented 9 years ago

Sure, whatever approach leads to the most intelligible data (nearest neighbor, bilinear, cubic, etc.) is fine by me, so long as we can (optionally) enforce that the values at sensor locations actually achieve their measured values. I don't think what we do now does it.

choldgraf commented 9 years ago

OK - I don't have much experience with interpolation, I usually just plot values as scatterplots right on the electrodes since I don't have any underlying model for how I think things will spread across the cortex. It sounds like you guys know more about this than I do though...

On Wed, Jun 17, 2015 at 11:15 AM, Eric Larson notifications@github.com wrote:

Sure, whatever approach leads to the most intelligible data (nearest neighbor, bilinear, cubic, etc.) is fine by me, so long as we can (optionally) enforce that the values at sensor locations actually achieve their measured values. I don't think what we do now does it.

— Reply to this email directly or view it on GitHub https://github.com/mne-tools/mne-python/issues/2210#issuecomment-112901542 .

kingjr commented 9 years ago

Sure, whatever approach leads to the most intelligible data (nearest neighbor, bilinear, cubic, etc.) is fine by me, so long as we can (optionally) enforce that the values at sensor locations actually achieve their measured values.

Absolutely.

I don't think what we do now does it.

No? I though it was using the ax.imshow() with a bilinear interpolation by default. Is there some other tricks than here (Line 470)?

OK - I don't have much experience with interpolation, I usually just plot values as scatterplots right on the electrodes since I don't have any underlying model for how I think things will spread across the cortex. It sounds like you guys know more about this than I do though...

I think that if you plot ERPs, it's generally good practice to do a current source density transform first, because you officially cannot do an average reference (unlike EEG, ECoG does not follow a sphere), and it's generally difficult to know what you should reference to. This is why most people only look at high gamma / broadband signals that are quite localized (i.e. there s not a consistant phase across channels), and therefore bypass the issue of referencing.

larsoner commented 9 years ago

The topomap plot above does not match the scatter plot above to my eye. But maybe it's just a colormap limits issue...?

choldgraf commented 9 years ago

@kingjr thanks for the clarification. Up to now I've only been using broadband high-gamma, though more often than not when I make brain plots I'm not actually plotting activations, but things like model R2 etc. I'm starting to get into more low-frequency and ERP analysis so I appreciate the info

kingjr commented 9 years ago

Sure, no problem. However, note that plotting statistical metrics (p values, AUC, R², Baysien factors etc) as opposed to the actual data (ERF, alpha phase, gamma power etc) is an independent issue. If you do a F test on ERF, plotting the F statistics is still going to be affected the type of reference, but the F test on gamma power won't (that much).

Anyway, could you confirm that the discrepency between the scatter plots and the interpolated images is due to a color limit?

choldgraf commented 9 years ago

Sure, I'll check into the discrepancy a little bit later today.

As you say, that's the reason that I've been sticking with HG activity, as it's relatively safer to treat each electrode as independent of the others. I know plotting statistics and such is an independent issue, but still useful to be able to visualize on the brain which is why I mentioned plotting topomaps without any kind of interpolation / spread in between them

On Wed, Jun 17, 2015 at 11:45 AM, J-R King notifications@github.com wrote:

Sure, no problem. However, note that plotting statistical metrics (p values, AUC, R², Baysien factors etc) as opposed to the actual data (ERF, alpha phase, gamma power etc) is an independent issue. If you do a F test on ERF, plotting the F statistics is still going to be affected the type of reference, but the F test on gamma power won't (that much).

Anyway, could you confirm that the discrepency between the scatter plots and the interpolated images is due to a color limit?

— Reply to this email directly or view it on GitHub https://github.com/mne-tools/mne-python/issues/2210#issuecomment-112911133 .

choldgraf commented 9 years ago

I'm pretty sure it was a color scaling issue (more or less, anyway). I forgot that on the scatterplots I was z-scoring each component first, and then plotting. Here they are with original values and their own colormaps:

image

choldgraf commented 9 years ago

although some of them do seem to be off still

agramfort commented 9 years ago

first thing we could do is set to NaN values outside of convex hull of electrodes. Then use interpolation='nearest'.

my 2c

kingjr commented 9 years ago

first thing we could do is set to NaN values outside of convex hull of electrodes. Then use interpolation='nearest'.

If it's not already the case, I think the best is to use a common plotting function for EEG, MEG and ECoG: ie. while passing a different layout each time. Then, you would just need to write a function that generates the ECoG mask.

@agramfort I think the convex hull is only good for a start, but doesn't fit ECoG that much (but yes, we should start with easy). It's very common to have weirdly shaped and disjoint sets of electrodes (e.g. one strip over parietal, one strip down to temporo ventral) between which you probably shouldn't interpolate:

alpha_shape_convex_hull

Just some more remarks for future reference. One could think of

If anyone hasn't dealt with these visualizations problems, I'll have to implement them in about... a year. Yes, I'm a long term planner

larsoner commented 9 years ago

+1 for convex hull to start. The second is better, but I expect to be much harder to get right in practice. Although the link you post makes it seem pretty simple, assuming the equivalent functions are present in a Python lib, which I think they are. @kingjr do you want to try?

kingjr commented 9 years ago

@Eric89GXL I do, but not before a while...

larsoner commented 9 years ago

No rush from my end. @choldgraf did you want to try? You could go with the simpler convex-hull solution first, or the more complete clustering one.

choldgraf commented 9 years ago

I can give it a shot sometime soon. What I've been doing for my common average reference is to define a grouping of electrodes (e.g. group the grid together, group strips together independently, etc). You might be able to do a similar kind of thing for the convex hull, though it'd get wonky for things like a 1-d strip.

Either way, I can put this on my radar and maybe ask a few of the scikit image guys about it (though that may have to wait a little bit as one of them is getting married this weekend :) )

On Thu, Jun 18, 2015 at 7:03 AM, Eric Larson notifications@github.com wrote:

No rush from my end. @choldgraf https://github.com/choldgraf did you want to try? You could go with the simpler convex-hull solution first, or the more complete clustering one.

— Reply to this email directly or view it on GitHub https://github.com/mne-tools/mne-python/issues/2210#issuecomment-113166920 .

choldgraf commented 7 years ago

I think the recent 3d scatterplotting stuff is a good enough solution for ECoG, so I propose closing this for now. Topoplots would still be nice w/ ECoG, but it's an atypical visualization for the field, and it still isn't well-understood how the activity in electrodes would spread across the cortical surface. If somebody wants to keep this open lemme know and I can reopen.