-
Notifications
You must be signed in to change notification settings - Fork 576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Surface plots #2477
Surface plots #2477
Changes from 20 commits
0201b22
78bec87
ea0dd3f
55fb7a7
4d87ae9
d334693
867a01e
983745b
f31bd3c
f32e614
1ce4aad
e4e7a9e
1388051
31a7991
648fa94
7bdd9c1
2dc314f
35e30c3
66c2a47
14fac1a
e2dd639
1a50359
fc0aaa1
63129da
05d2510
a1895fc
a62f0fc
5eaad19
d4cb770
74c016e
d4c1a88
c0c4f58
56de47c
6db1144
e3e993b
7f55423
962e13f
ebb7e6f
e95c882
c150fdf
d218a82
bb118d7
942fa0f
3034054
1c617f2
f6ccb9f
03a2e78
9ede345
b357672
da9d243
44646f4
ac23a61
3c84edc
5f5d3e8
9f8fbc6
52794d6
d7daa31
6feb6ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,8 @@ | |
from matplotlib.cm import ScalarMappable, get_cmap | ||
from matplotlib.colors import Normalize, LinearSegmentedColormap | ||
|
||
from ..surface import load_surf_data, load_surf_mesh | ||
from ..surface import load_surf_data, load_surf_mesh, vol_to_surf, check_mesh | ||
from .._utils import check_niimg_3d | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nilearn project is switching to absolute imports for all new & amended imports. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
from .img_plotting import _get_colorbar_and_data_ranges, _crop_colorbar | ||
|
||
|
||
|
@@ -422,6 +423,264 @@ def plot_surf_stat_map(surf_mesh, stat_map, bg_map=None, | |
return display | ||
|
||
|
||
def _check_display_mode(display_mode): | ||
"""Checks whether the display_mode string passed to plot_img_on_surf | ||
is meaningful. | ||
|
||
display_mode: str | ||
Any combination of 'lateral', 'medial', 'dorsal', 'ventral', | ||
'anterior', 'posterior', united by a '+'. Ex.: 'dorsal+lateral' | ||
""" | ||
|
||
available_modes = {'lateral', 'medial', | ||
'dorsal', 'ventral', | ||
'anterior', 'posterior'} | ||
|
||
desired_modes = display_mode.split('+') | ||
|
||
wrong_modes = set(desired_modes).difference(available_modes) | ||
if wrong_modes: | ||
msg = 'display_mode given: {}, available modes: {}' | ||
msg = msg.format(wrong_modes, available_modes) | ||
raise ValueError(msg) | ||
|
||
return desired_modes | ||
|
||
|
||
def _check_hemisphere(hemisphere): | ||
"""Checks whether the hemisphere in plot_img_on_surf is correct. | ||
|
||
display_mode: str | ||
Any combination of 'left', 'right' | ||
""" | ||
desired_hemispheres = hemisphere.split('+') | ||
ZviBaratz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
wrong_hemisphere = set(desired_hemispheres).difference({'left', 'right'}) | ||
if wrong_hemisphere: | ||
raise ValueError('hemisphere only accepts left and right.') | ||
if len(desired_hemispheres) > 2: | ||
ZviBaratz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
raise ValueError('Currently only supports plotting 2 hemispheres.') | ||
|
||
return desired_hemispheres | ||
|
||
|
||
def _colorbar_from_array(array, vmax, | ||
threshold, symmetric_cbar, | ||
kwargs, | ||
cmap='cold_hot'): | ||
""" Generate a custom colorbar for an array. | ||
|
||
Internal function used by plot_img_on_surf | ||
|
||
array: Any 3D array | ||
|
||
vmax : float, optional (default=None) | ||
upper bound for plotting of stat_map values. | ||
|
||
threshold : float, optional (default=None) | ||
If None is given, the colorbar is not thresholded. | ||
If a number is given, it is used to threshold the colorbar. | ||
Absolute values lower than threshold are shown in gray. | ||
|
||
symmetric_cbar : bool or 'auto', optional, default 'auto' | ||
Specifies whether the colorbar should range from -vmax to vmax | ||
or from vmin to vmax. Setting to 'auto' will select the latter | ||
if the range of the whole image is either positive or negative. | ||
Note: The colormap will always range from -vmax to vmax. | ||
|
||
kwargs: extra arguments passed to _get_colorbar_and_data_ranges | ||
|
||
cmap: str, optional (default='cold_hot') | ||
the name of a matplotlib or nilearn colormap. | ||
""" | ||
|
||
cbar_vmin, cbar_vmax, vmin, vmax = _get_colorbar_and_data_ranges( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can use cbar_vmin and cbar_vmax for symmetric_cbar to have an effect (or not expose a symmetric_cbar parameter) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand exactly what you mean, please see the updated code and elaborate in case any changes are still required. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant that as we are not taking it into account, we should probably remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sorry but I'm still not sure I understand - There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when regarding the call to so to summarize I suggest: no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes that is what I meant, thank you for bearing with me |
||
array, vmax, symmetric_cbar, kwargs) | ||
|
||
norm = Normalize(vmin=vmin, vmax=vmax) | ||
cmaplist = [cmap(i) for i in range(cmap.N)] | ||
|
||
if threshold is None: | ||
threshold = 0. | ||
|
||
# set colors to grey for absolute values < threshold | ||
istart = int(norm(-threshold, clip=True) * (cmap.N - 1)) | ||
istop = int(norm(threshold, clip=True) * (cmap.N - 1)) | ||
for i in range(istart, istop): | ||
cmaplist[i] = (0.5, 0.5, 0.5, 1.) | ||
our_cmap = LinearSegmentedColormap.from_list('Custom cmap', | ||
cmaplist, cmap.N) | ||
sm = plt.cm.ScalarMappable(cmap=our_cmap, | ||
norm=plt.Normalize(vmin=vmin, vmax=vmax)) | ||
# fake up the array of the scalar mappable. | ||
sm._A = [] | ||
|
||
return sm | ||
|
||
|
||
def plot_img_on_surf(stat_map, surf_mesh=None, mask_img=None, | ||
hemisphere='left+right', | ||
inflate=False, display_mode='lateral+medial', | ||
output_file=None, title=None, colorbar=True, | ||
vmax=None, threshold=None, symmetric_cbar='auto', | ||
cmap='cold_hot', **kwargs): | ||
"""Convenience function to plot multiple views of plot_surf_stat_map | ||
in a single figure. It projects stat_map into meshes and plots views of | ||
left and right hemispheres. The display_mode argument defines the views | ||
that are shown. This function returns the fig, axes elements from | ||
matplotlib unless kwargs sets and output_file, in which case nothing | ||
is returned. | ||
|
||
stat_map : str or Niimg-like object, 3d. | ||
See http://nilearn.github.io/manipulating_images/input_output.html | ||
|
||
surf_mesh: str, dictionary, or None, optional (default=None) | ||
If str, either one of the two: | ||
'fsaverage5': the low-resolution fsaverage5 mesh (10242 nodes) | ||
'fsaverage': the high-resolution fsaverage mesh (163842 nodes) | ||
If dictionary, a dictionary with keys: | ||
['infl_left', 'infl_right', | ||
'pial_left', 'pial_right', | ||
'sulc_left', 'sulc_right'], | ||
where values are surface mesh geometries as accepted | ||
by plot_surf_stat_map. | ||
If None, plot_img_on_surf will use Freesurfer's 'fsaverage5'. | ||
|
||
mask_img : Niimg-like object or None, optional (default=None) | ||
The mask is passed to vol_to_surf. | ||
Samples falling out of this mask or out of the image are ignored | ||
during projection of the volume to the surface. | ||
If ``None``, don't apply any mask. | ||
|
||
inflate: bool, optional (default=False) | ||
If True, display images in inflated brain. | ||
If False, display images in pial surface. | ||
|
||
display_mode: str, optional (default='lateral+medial') | ||
A string containing all views to display, separated by '+'. | ||
Available views: {'lateral', 'medial', | ||
'dorsal', 'ventral', | ||
'anterior', 'posterior'} | ||
The montage will contain as many rows as views specified by | ||
display mode. Order is preserved, and left and right hemispheres | ||
are shown on the left and right sides of the figure. | ||
|
||
output_file: str, optional (default=None) | ||
The name of an image file to export plot to. Valid extensions | ||
are .png, .pdf, .svg. If output_file is not None, the plot | ||
is saved to a file, and the display is closed. | ||
Plot_img_to_surf then returns None. | ||
|
||
title: str, optional (default=None) | ||
Place a title on the upper center of the figure. | ||
|
||
colorbar : bool, optional (default=True) | ||
If True, a symmetric colorbar of the statistical map is displayed. | ||
|
||
vmax : float, optional (default=None) | ||
upper bound for plotting of stat_map values. | ||
|
||
threshold : float, optional (default=None) | ||
If None is given, the image is not thresholded. | ||
If a number is given, it is used to threshold the image, | ||
values below the threshold (in absolute value) are plotted | ||
as transparent. | ||
|
||
symmetric_cbar : bool or 'auto', optional, default 'auto' | ||
ZviBaratz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Specifies whether the colorbar should range from -vmax to vmax | ||
or from vmin to vmax. Setting to 'auto' will select the latter | ||
if the range of the whole image is either positive or negative. | ||
Note: The colormap will always range from -vmax to vmax. | ||
|
||
cmap: str, optional (default='cold_hot') | ||
the name of a matplotlib or nilearn colormap. | ||
|
||
kwargs: keyword arguments passed to plot_surf_stat_map | ||
|
||
See Also | ||
-------- | ||
nilearn.datasets.fetch_surf_fsaverage : For surface data object to be | ||
used as the default background map for this plotting function. | ||
|
||
nilearn.surface.vol_to_surf : For info on the generation of surfaces. | ||
|
||
nilearn.plotting.plot_surf_stat_map : For info on kwargs options | ||
accepted by plot_img_on_surf. | ||
""" | ||
for arg in ('figure', 'axes'): | ||
if arg in kwargs: | ||
raise ValueError(('plot_img_on_surf does not' | ||
' accept %s as an argument' % arg)) | ||
|
||
if surf_mesh is None: | ||
ZviBaratz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
surf_mesh = 'fsaverage5' | ||
|
||
stat_map = check_niimg_3d(stat_map, dtype='auto') | ||
modes = _check_display_mode(display_mode) | ||
hemis = _check_hemisphere(hemisphere) | ||
surf_mesh = check_mesh(surf_mesh) | ||
|
||
surf = { | ||
'left': | ||
surf_mesh['infl_left'] if inflate else surf_mesh['pial_left'], | ||
'right': | ||
surf_mesh['infl_right'] if inflate else surf_mesh['pial_right'] | ||
} | ||
|
||
texture = { | ||
'left': vol_to_surf(stat_map, surf_mesh['pial_left'], | ||
mask_img=mask_img), | ||
'right': vol_to_surf(stat_map, surf_mesh['pial_right'], | ||
mask_img=mask_img) | ||
} | ||
|
||
fig, axes = plt.subplots(nrows=len(modes), ncols=len(hemis), | ||
figsize=plt.figaspect(len(modes) / 2.), | ||
subplot_kw={'projection': '3d'}) | ||
|
||
axes = np.atleast_2d(axes) | ||
|
||
if len(hemis) == 1: | ||
axes = axes.T | ||
|
||
for index_mode, mode in enumerate(modes): | ||
for index_hemi, hemi in enumerate(hemis): | ||
bg_map = surf_mesh['sulc_%s' % hemi] | ||
plot_surf_stat_map(surf[hemi], texture[hemi], | ||
view=mode, hemi=hemi, | ||
bg_map=bg_map, | ||
axes=axes[index_mode, index_hemi], | ||
colorbar=False, # Colorbar created externally. | ||
vmax=vmax, | ||
threshold=threshold, | ||
symmetric_cbar=symmetric_cbar, | ||
cmap=cmap, | ||
**kwargs) | ||
|
||
for ax in axes.flatten(): | ||
# We increase this value to better position the camera of the | ||
# 3D projection plot. The default value makes meshes look too small. | ||
ax.dist = 6 | ||
|
||
if colorbar: | ||
sm = _colorbar_from_array(stat_map.get_data(), | ||
vmax, threshold, symmetric_cbar, kwargs, | ||
get_cmap(cmap)) | ||
|
||
cbar_ax = fig.add_subplot(32, 1, 32) | ||
fig.colorbar(sm, cax=cbar_ax, orientation='horizontal') | ||
|
||
fig.subplots_adjust(wspace=-0.02, hspace=0.0) | ||
|
||
if title is not None: | ||
fig.suptitle(title) | ||
|
||
if output_file is not None: | ||
fig.savefig(output_file) | ||
plt.close(fig) | ||
else: | ||
return fig, axes | ||
|
||
|
||
def plot_surf_roi(surf_mesh, roi_map, bg_map=None, | ||
hemi='left', view='lateral', threshold=1e-14, | ||
alpha='auto', vmin=None, vmax=None, cmap='gist_ncar', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still have the problem that the generated image looks distorted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry it's taking so long.
I tried to run:
but when I navigate to example 9.2.14.7 I'm seeing an older title (Plotting EPI image with function plot_epi), so I figured I need to
make html-strict
but that keeps raising:I haven't had much time to try to understand what exactly is happening here. Hopefully I'll have some time to figure it out Monday/Tuesday.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is actually on 9.2.15.7; you can see the image here: https://5819-1235740-gh.circle-artifacts.com/0/doc/_build/html/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html#plot-multiple-views-of-the-3d-volume-on-a-surface
The title seems correct, there ! It's just the images that look distorted. Let me know if we can help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops - I was using Gael's link from above.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The aspect ratio looks better to me, now: https://5846-1235740-gh.circle-artifacts.com/0/doc/_build/html/auto_examples/01_plotting/plot_3d_map_to_surface_projection.html#plot-multiple-views-of-the-3d-volume-on-a-surface