Closed alyssadai closed 1 year ago
Hi @alyssadai, thanks for sharing this! I can replicate this with matplotlib 3.5.0, but not the minimum required matplotlib version (3.4.2; this is also the version for the tutorial builds). This is with python 3.9.7, and the only thing changing is indeed the matplotlib version. So, I am guessing that something changed regarding LinearSegmentedColormap
in more recent matplotlib versions.
I can investigate this further and how to handle it -- matplotlib versioning is a known issue already (see #5). For now, though, could you try downgrading your matplotlib version to 3.4.2? This is likely the best immediate fix while the underlying issue gets solved!
Hi Dan, thanks for the info! Downgrading to matplotlib 3.4.2 does indeed allow me to now use custom colormaps; matplotlib 3.4.3 seems to work as well.
A follow up question on plotting parcellations. I'm not sure if this is expected behaviour, but I noticed that when trying to plot a layer of parcel values only (without region outlines) some of the region borders take on a different color than the rest of the parcel. e.g., (in the central sulcus below there actually seems to be two adjacent outlines, one blue and one bright green)
Code to replicate above figure: (I am also able to replicate the result using flsr surfaces and Schaefer400)
# Python 3.8.3
import nibabel as nib # 3.2.1
from surfplot import Plot
import numpy as np # 1.21.2
import matplotlib.colors as mcolors # matplotlib 3.4.2
from neuromaps.datasets import fetch_civet
from brainspace.datasets import load_parcellation
surfaces = fetch_civet()
lh, rh = surfaces['inflated']
print('left', nib.load(lh).darrays[0].dims) # 40962
dkt_L = np.loadtxt("../PS_Dimensions/CIVET_2.1.0_dkt_left_short.txt")
dkt_R = np.loadtxt("../PS_Dimensions/CIVET_2.1.0_dkt_right_short.txt")
print(len(dkt_L)) # 40962
p = Plot(surf_lh = lh, views='lateral', size=(1000,800))
p.add_layer(dkt_L, cmap="hsv", as_outline=False, cbar=False)
fig = p.build()
Here is the left DKT parcellation file, for reference: CIVET_2.1.0_dkt_left_short.txt
The erroneous region outlines persist for these data when I try to plot >=2 ROIs; in addition, it seems like using a custom LinearSegmentedColormap
or ListedColormap
for ROIs places a (I suppose unsurprising) constraint on the numerical distance between the selected region numbers, where, if the region numbers aren't equally spaced, not all the colors in the colormap are used:
Code to replicate above figure:
region_numbers = [3,4,23]
regions_L = np.where(np.isin(dkt_L, region_numbers), dkt_L, 0)
regions_R = np.where(np.isin(dkt_R, region_numbers), dkt_R, 0)
colors = ['green','red','yellow']
cmap_reg = mcolors.LinearSegmentedColormap.from_list('regions', colors, N=3)
p = Plot(surf_lh = lh_gray, views='lateral', size=(1000,800))
p.add_layer(regions_L, cmap=cmap_reg, as_outline=False, cbar=False)
fig = p.build()
For now I can get around this linear spacing issue by replacing the ROI numbers with random consecutive numbers in the parcellation array (that aren't used in the original region-to-number mapping), but I'm still unsure of how to debug the different-color outlines. Any thoughts on what might be causing this?
Sorry for the long reply--let me know also if this would work better in a separate issue!
Is it possible that the parcellation array accidentally includes slight overlap between adjacent regions? For example, in your last image, could it be that the red strip is equal to the sum of the green and yellow region (7)? I've seen this before when I was customizing a parcellation at one point and accidentally had overlapping regions.
Edit: Nvm, looking more closely at the code, a sum of adjacent regions isn't possible.
What was your code to replicate this with fs_LR surfaces and Schaefer parcellations?
Hi Dan,
Here's the code that reproduced the different-color borders with fsLR + Schaefer for me:
import nibabel as nib
from surfplot import Plot
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from neuromaps.datasets import fetch_fslr
from brainspace.datasets import load_parcellation
surfaces = fetch_fslr()
lh, rh = surfaces['inflated']
lh_parc, rh_parc = load_parcellation('schaefer')
p = Plot(lh, views='lateral', size=(1000,800))
p.add_layer(lh_parc, cmap='hsv', cbar=False) # I also see the borders with viridis and Spectral, but I think they're most obvious with hsv given the wider color range
fig = p.build()
The corresponding plot: Let me know if you are able to replicate this on your end, or spot an error anywhere.
Hmm, I'm a bit stumped on this one. I can reproduce these examples, and just noticed some cases in my own plots. Admittedly, I didn't notice them before because I've been mostly plotting with perceptually linear colormaps using fairly autocorrelated data, so it did a good job masking these adjacent-region-effects. Or, I've been using borders/outlines.
Probing further, it seems a) consistent across different surfaces and b) to be happening at the rendering stage before it's embedded in matplotlib, which would suggest a brainspace
issue. I'll investigate this further throughout this week
Is there a way to provide an array of RGB values of size (N_vert x 3) to directly color points on the surface? I have been trying to create a custom colormap using a list of 10242 RGB tuples and the ListedColormap function, but cant seem to get it to work quite right.
Hi Dan,
Thanks for your great work on surfplot!
I am trying to plot a custom parcellation following Tutorial 6, using a custom LinearSegmentedColormap for the regions, but am encountering an error on the
build()
step. I am using JupyterLab 3.2.1 locally with Python 3.8.3 and matplotlib 3.5.0.Relevant part of my code:
Error:
Any thoughts on what went wrong/how to troubleshoot this would be much appreciated!