nipy / PySurfer

Cortical neuroimaging visualization in Python
https://pysurfer.github.io/
BSD 3-Clause "New" or "Revised" License
243 stars 97 forks source link

Displaying multiple source estimates mixes up different colormaps #260

Closed hichamjanati closed 5 years ago

hichamjanati commented 5 years ago

Hi,

I'm trying to display source estimates of different subjects on the same brain surface using different colormaps. However, some sources appear to switch colors during the process. brain.add_data calls do not seem to be independent. In this snippet, I simulate sources on both hemispheres for 2 subjects. I plot sources independently for each subject and then jointly on the same brain surface. 2 red sources (up) get colored in blue when displayed on the same brain. Sources are taken to be non-overlapping across subjects.

import numpy as np  # noqa
import mne
import os

from mne.datasets.sample import data_path
from mayavi import mlab  # noqa
from surfer import Brain  # noqa

data_path = data_path()
subjects_dir = data_path + "/subjects/"
os.environ['SUBJECTS_DIR'] = subjects_dir

subject = "fsaverage"
fname_fs = subjects_dir + "fsaverage/bem/fsaverage-ico-5-src.fif"
src_fs = mne.read_source_spaces(fname_fs)
nv = 1000  # keep only n_v vertices per hemi
vertices = [src_fs[0]["vertno"][:nv], src_fs[1]["vertno"][:nv]]

n_subjects = 2
sources_l = np.zeros((nv, n_subjects))
sources_r = np.zeros((nv, n_subjects))

# subject 1
sources_l[:10, 0] = 5
sources_r[:10, 0] = 3

# subject 2
sources_l[100:110, 1] = 2
sources_r[100:110, 1] = 5

sources = [sources_l, sources_r]
colormaps = ["Reds", "Blues"]

def plot_sources(sources, sub_id=[0, 1], order=1):
    fmax = 5
    brain = Brain(subject, hemi="both", surf="inflated", views="dorsal")
    hemis = ["lh", "rh"]
    for sources_h, v, h in zip(sources[::order], vertices[::order],
                               hemis[::order]):
        for data, colormap in zip(sources_h.T[sub_id],
                                  np.array(colormaps)[sub_id]):
                brain.add_data(data, colormap=colormap, vertices=v,
                               verbose=False, colorbar=False,
                               smoothing_steps=10,
                               time_label=None, hemi=h, alpha=0.8,
                               min=0., mid=fmax / 5, max=fmax,
                               transparent=True)
    return brain
screen shot 2018-10-25 at 12 25 40

Done with pysurfer 0.10.dev0 and mayavi 4.5.1.dev0.

This behavior oddly disappears when changing the order of display of hemispheres by calling plot_sources with order = -1

agramfort commented 5 years ago

I can replicate the pb. See the blue dots on right hemi while the tiny ones should be red.

the pb seems to be in _scale_mayavi_lut function. If I skip the call to _scale_mayavi_lut i loose transparency but it stays red.

@larsoner or @mwaskom any idea? I did not write this LUT magic code...

larsoner commented 5 years ago

I can take a look. It probably is modifying the wrong LUT

hichamjanati commented 5 years ago

On live display, It seems that colormaps get applied on both hemispheres before a "colormap correction" is applied before the final rendering. This leads to bugs when the number of calls per hemi is not the same (which is the case if sources of one subject are all in one of the hemispheres).

import numpy as np  # noqa
import mne
import os
import time

from mne.datasets.sample import data_path
from mayavi import mlab  # noqa
from surfer import Brain  # noqa

data_path = data_path()
subjects_dir = data_path + "/subjects/"
os.environ['SUBJECTS_DIR'] = subjects_dir

subject = "fsaverage"
fname_src = subjects_dir + "%s/bem/%s-ico-5-src.fif" % (subject, subject)
src = mne.read_source_spaces(fname_src)
label_fname = "rh.entorhinal.label"
label_fname = subjects_dir + "fsaverage/label/%s" % (label_fname)
label = mne.read_label(label_fname, subject)
label = label.morph(subject_to=subject, grade=4)
nv = label.vertices.size  # keep only n_v vertices per hemi in label
vertices = [src[0]["vertno"][label.vertices][:nv],
            src[1]["vertno"][label.vertices][:nv]]

n_subjects = 3
sources_l = np.zeros((nv, n_subjects))
sources_r = np.zeros((nv, n_subjects))

# subject 1 - sources on both hemis
sources_l[:3, 0] = 5
sources_r[:3, 0] = 5

# subject 2 - sources on both hemis
sources_l[3:6, 1] = 5
sources_r[3:6, 1] = 5

# subject 3 - sources on both hemis, comment second row to see bug
sources_l[6:9, 2] = 5
sources_r[6:9, 2] = 5 

sources = [sources_l, sources_r]
colormaps = ["Reds", "Blues", "Greens"]

def plot_sources(sources, order=1):
    fmax = 5
    brain = Brain(subject, hemi="both", surf="inflated", views="ventral")
    hemis = ["lh", "rh"]
    for sources_h, v, h in zip(sources[::order], vertices[::order],
                               hemis[::order]):
        for data, colormap in zip(sources_h.T, colormaps):
                if data.any():
                    brain.add_data(data, colormap=colormap, vertices=v,
                                   verbose=False, colorbar=False,
                                   smoothing_steps=5,
                                   time_label=None, hemi=h, alpha=0.8,
                                   min=0., mid=fmax / 5, max=fmax,
                                   transparent=True)
                    time.sleep(1)

    return brain

plot_sources(sources)

2l8dec

On this gif you can see that when plotting on the right hemi, even sources on left hemi are wrongly colored before the final correction.

Now if the green subject has only sources on left hemi, by commenting sources_r[6:9, 2] = 5 its sources keep the wrong blue color:

bad

larsoner commented 5 years ago

@hichamjanati can you look at the fix / changes in #261 and see if you can make a follow-up PR to fix the issue?