mne-python icon indicating copy to clipboard operation
mne-python copied to clipboard

viz.plot_sensors('3d') doesn't handle mouse clicks to reveal sensor names correctly

Open hoechenberger opened this issue 3 years ago • 9 comments

MWE:

from pathlib import Path
import matplotlib
import mne

matplotlib.use('Qt5Agg')

sample_dir = Path(mne.datasets.sample.data_path())
sample_fname = sample_dir / 'MEG' / 'sample' / 'sample_audvis_raw.fif'

raw = mne.io.read_raw_fif(sample_fname, preload=False)
raw.plot_sensors('3d')

Clicking on the frontal sensors reveals names of channels someplace else.

https://user-images.githubusercontent.com/2046265/115535014-a6acc000-a298-11eb-881d-bacf661ee57d.mov

When show_names=True is passed, the channels are labeled correctly, though, leading me to believe that the odd behavior described above is related to click -> channel mapping

Screen Shot 2021-04-21 at 11 55 09

For completeness, here's a 2D sensor plot: Screen Shot 2021-04-21 at 11 54 48

macOS with Qt5 backend.

hoechenberger avatar Apr 21 '21 09:04 hoechenberger

Oh, yes, I experienced it too. I think this worked correctly some time ago but I'm not sure.

mmagnuski avatar Apr 21 '21 11:04 mmagnuski

I remember it being like this for a while now, always forgot to file an issue report…

hoechenberger avatar Apr 21 '21 12:04 hoechenberger

I played around a bit and have concluded that the event.ind returned by the matplotlib pick event is not deterministic and not stable before/after a click-drag rotation of the axes. Try it out: click on a point that you like, keep your eye on it while you rotate the axes, then click on that point again.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
plt.ion()


def onpick(event):
    ind = event.ind
    print(f'index: {ind}')


x = np.tile(np.linspace(0, 1, 5), 3*7)
y = np.repeat(np.linspace(0, 1, 7), 3*5)
z = np.tile(np.linspace(0, 1, 3), 5*7)
c = np.linspace(0, 1, 3*5*7)
s = np.full(3*5*7, 100)

fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
ax.scatter(x, y, z, s=s, c=c, picker=True)
fig.canvas.mpl_connect('pick_event', onpick)

drammock avatar Apr 21 '21 19:04 drammock

@drammock Wow, this seems like an actual bug in Matplotlib then… 💩

hoechenberger avatar Apr 21 '21 20:04 hoechenberger

I'm not sure if they would consider it a bug. efficiently plotting 2D shapes in 3D space is not easy; I'm not surprised there's no guarantee that the points are drawn in the same order every time. I guess maybe you could say it's a bug that they're allowed to be pickable?

drammock avatar Apr 21 '21 20:04 drammock

I guess maybe you could say it's a bug that they're allowed to be pickable?

Yes, if their index is conditional on axis orientation, even though one is clearly referring to the same entity, then I would say it's a bug. If the index is mutable, it probably shouldn't be exposed in the first place.

Question is, how are we going to deal with this? The current behavior is not great. I suppose we could manually deduce from the current viewport orientation and channel montage which channel the user most likely intended to click on. But it sounds like a lot of work to get right :(

hoechenberger avatar Apr 21 '21 20:04 hoechenberger

Question is, how are we going to deal with this?

Step 1 is checking if they're already aware of this, and if not, opening an upstream issue.

suppose we could manually deduce from the current viewport orientation and channel montage which channel the user most likely intended to click on.

Something based on solution 5 on this page might work. Want to give it a try?

drammock avatar Apr 21 '21 20:04 drammock

I'd open a matplotlob issue first. My guess it that they have (or should have) some form of this logic in place already. In particular they might do the 3d to 2d projection internally, in which case there's potentially a problem with 2d marker or path collection picking. We can do the viewport gymnastics ourselves if we need to, but it would be good to hear them tell us that we should need to first.

larsoner avatar Apr 21 '21 21:04 larsoner

I'm going to push to 0.24 since it seems like it might take a while to figure out the right solution here

larsoner avatar Apr 23 '21 18:04 larsoner