def plot_colorbar(cax, cmap, hue_norm, cnorm=None, label=None, orientation='vertical', labelsize=4, linewidth=0.5): if isinstance(cmap, str): cmap = copy.copy(get_cmap(cmap)) if cnorm is None: cnorm = Normalize(vmin=hue_norm[0], vmax=hue_norm[1]) from .utilities import smart_number_format colorbar = ColorbarBase(cax, cmap=cmap, norm=cnorm, format=ticker.FuncFormatter(smart_number_format), orientation=orientation, extend='both') colorbar.locator = ticker.MaxNLocator(nbins=3) colorbar.update_ticks() colorbar.set_label(label, fontsize=labelsize) colorbar.outline.set_linewidth(linewidth) colorbar.ax.tick_params(size=labelsize, labelsize=labelsize, width=linewidth) return cax
def display_displacements(simulation_folder, lower_percentile=70, upper_percentile=99.7, save_plot = True, arrow_factor=4): """ show the total displacement field or the masked range of displacements by size simulation_folder: path to simulation folder lower_percentile and upper_percentile give range of deformationsize which is used as a mask save_plot: option to save the plot to the simulation folder arrow_factor: scales the arrow length in the plot To increase plotting speed you might increase the lower percentile (e.g 30 instead 0) """ # load in deformations and coordinates r = np.genfromtxt(os.path.join(simulation_folder, "R.dat")) # positions u = np.genfromtxt(os.path.join(simulation_folder, "Ufound.dat")) #deformations uabs = np.sqrt(np.sum(u ** 2., axis=1)) # absolute values for filtering # filter displacements by absolute size mask = (uabs > np.percentile(uabs, lower_percentile)) & (uabs < np.percentile(uabs, upper_percentile)) r2 = r[mask] u2 = u[mask] uabs2 = uabs[mask] # plot the masked deformation fig = plt.figure() ax1 = fig.gca(projection='3d', label='fitted-displ', rasterized=True) color_bounds1 = np.array([np.percentile(uabs2, 0), np.percentile(uabs2, 99.8)]) * 10 ** 6 np.random.seed(1234) for r2i, u2i, uabs2i in tqdm(zip(r2 * 10 ** 6, u2 * 10 ** 6, uabs2 * (10 ** 6))): # if np.random.uniform(0, 1) < 0.2: # uabs2i/u_upper: color = plt.cm.jet(((uabs2i - color_bounds1[0]) / (color_bounds1[1] - color_bounds1[0]))) alpha = 1. - (r2i[0] - r2i[1]) / (270. * 0.5) if alpha > 1: alpha = 1. if alpha < 0: alpha = 0. plt.quiver(r2i[0], r2i[1], r2i[2], u2i[0], u2i[1], u2i[2], length=uabs2i * arrow_factor , color=color, arrow_length_ratio=0, alpha=alpha, pivot='tip', linewidth=0.5) # plot colorbar --------------------------------------------------------- cbaxes = fig.add_axes([0.15, 0.1, 0.125, 0.010]) cmap = plt.cm.jet norm = plt.Normalize(vmin=color_bounds1[0], vmax=color_bounds1[1]) cb1 = ColorbarBase(cbaxes, cmap=cmap, norm=norm, orientation='horizontal') cb1.set_label('Displacements [µm]') tick_locator = ticker.MaxNLocator(nbins=3) cb1.locator = tick_locator cb1.update_ticks() ax1.w_xaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) ax1.w_yaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) ax1.w_zaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) if save_plot: plt.savefig( os.path.join(simulation_folder,'deformations_plot_lower_{}_upper_{}.png'.format(lower_percentile, upper_percentile)), dpi=500, bbox_inches="tight", pad_inches=0) return
class PanelColourBar(wx.Panel): def __init__(self, parent, colourMap): wx.Panel.__init__(self, parent) dpi = wx.ScreenDC().GetPPI()[0] figure = Figure(facecolor='white', dpi=dpi) figure.set_size_inches(200.0 / dpi, 25.0 / dpi) self.canvas = FigureCanvas(self, -1, figure) axes = figure.add_subplot(111) figure.subplots_adjust(0, 0, 1, 1) norm = Normalize(vmin=0, vmax=1) self.bar = ColorbarBase(axes, norm=norm, orientation='horizontal', cmap=cm.get_cmap(colourMap)) axes.xaxis.set_visible(False) def set_map(self, colourMap): self.bar.set_cmap(colourMap) self.bar.update_ticks() self.bar.draw_all() self.canvas.draw()
def create_colorbar(cax, cmap_range=(0, 1), cmap_name="jet", colorbar_title="", colorbar_loc="top", ticksize=8, num_ticks=None): """ create colorbar see https://matplotlib.org/devdocs/tutorials/colors/colorbar_only.html Parameters ---------- cax: matplotlib.axes.Axes cmap_name: str cmap_range: tuple colorbar_title: str colorbar_loc: str 'top' or 'bottom' ticksize: int """ assert colorbar_loc == "top" or colorbar_loc == "bottom" norm = Normalize(vmin=cmap_range[0], vmax=cmap_range[1]) cmap = get_cmap(cmap_name) cbar = ColorbarBase(cax, cmap=cmap, norm=norm, orientation="horizontal", label=colorbar_title, ticklocation=colorbar_loc, extend="both") #tick_locator = ticker.MaxNLocator(nbins=5) if num_ticks is not None: tick_locator = ticker.LinearLocator(numticks=num_ticks) cbar.locator = tick_locator cbar.update_ticks() cax.tick_params(labelsize=ticksize) return cbar
class BaseSlicer(object): """ The main purpose of these class is to have auto adjust of axes size to the data with different layout of cuts. """ # This actually encodes the figsize for only one axe _default_figsize = [2.2, 2.6] _axes_class = CutAxes def __init__(self, cut_coords, axes=None, black_bg=False, **kwargs): """ Create 3 linked axes for plotting orthogonal cuts. Parameters ---------- cut_coords: 3 tuple of ints The cut position, in world space. axes: matplotlib axes object, optional The axes that will be subdivided in 3. black_bg: boolean, optional If True, the background of the figure will be put to black. If you wish to save figures with a black background, you will need to pass "facecolor='k', edgecolor='k'" to pylab's savefig. """ self.cut_coords = cut_coords if axes is None: axes = pl.axes((0., 0., 1., 1.)) axes.axis('off') self.frame_axes = axes axes.set_zorder(1) bb = axes.get_position() self.rect = (bb.x0, bb.y0, bb.x1, bb.y1) self._black_bg = black_bg self._colorbar = False self._colorbar_width = 0.05 * bb.width self._colorbar_margin = dict(left=0.25 * bb.width, right=0.02 * bb.width, top=0.05 * bb.height, bottom=0.05 * bb.height) self._init_axes(**kwargs) @staticmethod def find_cut_coords(img=None, threshold=None, cut_coords=None): # Implement this as a staticmethod or a classmethod when # subclassing raise NotImplementedError @classmethod def init_with_figure(cls, img, threshold=None, cut_coords=None, figure=None, axes=None, black_bg=False, leave_space=False, colorbar=False, **kwargs): # deal with "fake" 4D images if img is not None and img is not False: img = _utils.check_niimg(img, ensure_3d=True) cut_coords = cls.find_cut_coords(img, threshold, cut_coords) facecolor = 'k' if black_bg else 'w' if isinstance(axes, pl.Axes) and figure is None: figure = axes.figure # axes.set_axis_bgcolor(facecolor) if not isinstance(figure, pl.Figure): # Make sure that we have a figure figsize = cls._default_figsize[:] # Adjust for the number of axes figsize[0] *= len(cut_coords) # Make space for the colorbar if colorbar: figsize[0] += .7 if leave_space: figsize[0] += 3.4 figure = pl.figure(figure, figsize=figsize, facecolor=facecolor) if isinstance(axes, pl.Axes): assert axes.figure is figure, ("The axes passed are not " "in the figure") if axes is None: axes = [0., 0., 1., 1.] if leave_space: axes = [0.3, 0, .7, 1.] if operator.isSequenceType(axes): axes = figure.add_axes(axes) # People forget to turn their axis off, or to set the zorder, and # then they cannot see their slicer axes.axis('off') return cls(cut_coords, axes, black_bg, **kwargs) def title(self, text, x=0.01, y=0.99, size=15, color=None, bgcolor=None, alpha=1, **kwargs): """ Write a title to the view. Parameters ---------- text: string The text of the title x: float, optional The horizontal position of the title on the frame in fraction of the frame width. y: float, optional The vertical position of the title on the frame in fraction of the frame height. size: integer, optional The size of the title text. color: matplotlib color specifier, optional The color of the font of the title. bgcolor: matplotlib color specifier, optional The color of the background of the title. alpha: float, optional The alpha value for the background. kwargs: Extra keyword arguments are passed to matplotlib's text function. """ if color is None: color = 'k' if self._black_bg else 'w' if bgcolor is None: bgcolor = 'w' if self._black_bg else 'k' if hasattr(self, '_cut_displayed'): first_axe = self._cut_displayed[0] else: first_axe = self.cut_coords[0] ax = self.axes[first_axe].ax ax.text(x, y, text, transform=self.frame_axes.transAxes, horizontalalignment='left', verticalalignment='top', size=size, color=color, bbox=dict(boxstyle="square,pad=.3", ec=bgcolor, fc=bgcolor, alpha=alpha), zorder=1000, **kwargs) ax.set_zorder(1000) def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs): """ Plot a 3D map in all the views. Parameters ----------- img: Niimg-like object See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. If it is a masked array, only the non-masked part will be plotted. threshold : a number, None If None is given, the maps are not thresholded. If a number is given, it is used to threshold the maps: values below the threshold (in absolute value) are plotted as transparent. colorbar: boolean, optional If True, display a colorbar on the right of the plots. kwargs: Extra keyword arguments are passed to imshow. """ if colorbar and self._colorbar: raise ValueError("This figure already has an overlay with a " "colorbar.") else: self._colorbar = colorbar img = _utils.check_niimg(img, ensure_3d=True) if threshold is not None: data = img.get_data() if threshold == 0: data = np.ma.masked_equal(data, 0, copy=False) else: data = np.ma.masked_inside(data, -threshold, threshold, copy=False) img = nibabel.Nifti1Image(data, img.get_affine()) # To make sure that add_overlay has a consistant default behavior # with plot_stat_map kwargs.setdefault('interpolation', 'nearest') ims = self._map_show(img, type='imshow', **kwargs) if colorbar: self._colorbar_show(ims[0], threshold) pl.draw_if_interactive() def add_contours(self, img, **kwargs): """ Contour a 3D map in all the views. Parameters ----------- img: Niimg-like object See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. Provides image to plot. kwargs: Extra keyword arguments are passed to contour, see the documentation of pylab.contour Useful, arguments are typical "levels", which is a list of values to use for plotting a contour, and "colors", which is one color or a list of colors for these contours. """ self._map_show(img, type='contour', **kwargs) pl.draw_if_interactive() def _map_show(self, img, type='imshow', resampling_interpolation='continuous', **kwargs): img = reorder_img(img, resample=resampling_interpolation) affine = img.get_affine() data = img.get_data() data_bounds = get_bounds(data.shape, affine) (xmin, xmax), (ymin, ymax), (zmin, zmax) = data_bounds xmin_, xmax_, ymin_, ymax_, zmin_, zmax_ = \ xmin, xmax, ymin, ymax, zmin, zmax if hasattr(data, 'mask') and isinstance(data.mask, np.ndarray): not_mask = np.logical_not(data.mask) xmin_, xmax_, ymin_, ymax_, zmin_, zmax_ = \ get_mask_bounds(nibabel.Nifti1Image(not_mask.astype(np.int), affine)) data_2d_list = [] for display_ax in self.axes.itervalues(): try: data_2d = display_ax.transform_to_2d(data, affine) except IndexError: # We are cutting outside the indices of the data data_2d = None data_2d_list.append(data_2d) if 'vmin' not in kwargs: kwargs['vmin'] = min(d.min() for d in data_2d_list if d is not None) if 'vmax' not in kwargs: kwargs['vmax'] = max(d.max() for d in data_2d_list if d is not None) bounding_box = (xmin_, xmax_), (ymin_, ymax_), (zmin_, zmax_) ims = [] to_iterate_over = zip(self.axes.values(), data_2d_list) for display_ax, data_2d in to_iterate_over: if data_2d is not None: im = display_ax.draw_2d(data_2d, data_bounds, bounding_box, type=type, **kwargs) ims.append(im) return ims def _colorbar_show(self, im, threshold): if threshold is None: offset = 0 else: offset = threshold if offset > im.norm.vmax: offset = im.norm.vmax # create new axis for the colorbar figure = self.frame_axes.figure _, y0, x1, y1 = self.rect height = y1 - y0 x_adjusted_width = self._colorbar_width / len(self.axes) x_adjusted_margin = self._colorbar_margin['right'] / len(self.axes) lt_wid_top_ht = [ x1 - (x_adjusted_width + x_adjusted_margin), y0 + self._colorbar_margin['top'], x_adjusted_width, height - (self._colorbar_margin['top'] + self._colorbar_margin['bottom']) ] self._colorbar_ax = figure.add_axes(lt_wid_top_ht, axis_bgcolor='w') our_cmap = im.cmap # edge case where the data has a single value # yields a cryptic matplotlib error message # when trying to plot the color bar nb_ticks = 5 if im.norm.vmin != im.norm.vmax else 1 ticks = np.linspace(im.norm.vmin, im.norm.vmax, nb_ticks) bounds = np.linspace(im.norm.vmin, im.norm.vmax, our_cmap.N) # some colormap hacking cmaplist = [our_cmap(i) for i in range(our_cmap.N)] istart = int(im.norm(-offset) * (our_cmap.N - 1)) istop = int(im.norm(offset) * (our_cmap.N - 1)) for i in range(istart, istop): cmaplist[i] = (0.5, 0.5, 0.5, 1.) # just an average gray color our_cmap = our_cmap.from_list('Custom cmap', cmaplist, our_cmap.N) self._cbar = ColorbarBase(self._colorbar_ax, ticks=ticks, norm=im.norm, orientation='vertical', cmap=our_cmap, boundaries=bounds, spacing='proportional') self._cbar.set_ticklabels(["%.2g" % t for t in ticks]) self._colorbar_ax.yaxis.tick_left() tick_color = 'w' if self._black_bg else 'k' for tick in self._colorbar_ax.yaxis.get_ticklabels(): tick.set_color(tick_color) self._colorbar_ax.yaxis.set_tick_params(width=0) self._cbar.update_ticks() def add_edges(self, img, color='r'): """ Plot the edges of a 3D map in all the views. Parameters ----------- map: 3D ndarray The 3D map to be plotted. If it is a masked array, only the non-masked part will be plotted. affine: 4x4 ndarray The affine matrix giving the transformation from voxel indices to world space. color: matplotlib color: string or (r, g, b) value The color used to display the edge map """ img = reorder_img(img) data = img.get_data() affine = img.get_affine() single_color_cmap = colors.ListedColormap([color]) data_bounds = get_bounds(data.shape, img.get_affine()) # For each ax, cut the data and plot it for display_ax in self.axes.itervalues(): try: data_2d = display_ax.transform_to_2d(data, affine) edge_mask = _edge_map(data_2d) except IndexError: # We are cutting outside the indices of the data continue display_ax.draw_2d(edge_mask, data_bounds, data_bounds, type='imshow', cmap=single_color_cmap) pl.draw_if_interactive() def annotate(self, left_right=True, positions=True, size=12, **kwargs): """ Add annotations to the plot. Parameters ---------- left_right: boolean, optional If left_right is True, annotations indicating which side is left and which side is right are drawn. positions: boolean, optional If positions is True, annotations indicating the positions of the cuts are drawn. size: integer, optional The size of the text used. kwargs: Extra keyword arguments are passed to matplotlib's text function. """ kwargs = kwargs.copy() if not 'color' in kwargs: if self._black_bg: kwargs['color'] = 'w' else: kwargs['color'] = 'k' for display_ax in self.axes.values(): if self._black_bg: # Remove transparency to avoid slice lines intersecting w/label bg_color = (display_ax.ax.get_axis_bgcolor() or display_ax.ax.get_figure().get_facecolor()) else: bg_color = None if left_right: display_ax.draw_left_right(size=size, bg_color=bg_color, **kwargs) if positions: display_ax.draw_position(size=size, bg_color=bg_color, **kwargs) def close(self): """ Close the figure. This is necessary to avoid leaking memory. """ pl.close(self.frame_axes.figure.number) def savefig(self, filename, dpi=None): """ Save the figure to a file Parameters ========== filename: string The file name to save to. It's extension determines the file type, typically '.png', '.svg' or '.pdf'. dpi: None or scalar The resolution in dots per inch. """ facecolor = edgecolor = 'k' if self._black_bg else 'w' self.frame_axes.figure.savefig(filename, dpi=dpi, facecolor=facecolor, edgecolor=edgecolor)
class BaseSlicer(object): """ The main purpose of these class is to have auto adjust of axes size to the data with different layout of cuts. """ # This actually encodes the figsize for only one axe _default_figsize = [2.2, 2.6] _axes_class = CutAxes def __init__(self, cut_coords, axes=None, black_bg=False, **kwargs): """ Create 3 linked axes for plotting orthogonal cuts. Parameters ---------- cut_coords: 3 tuple of ints The cut position, in world space. axes: matplotlib axes object, optional The axes that will be subdivided in 3. black_bg: boolean, optional If True, the background of the figure will be put to black. If you wish to save figures with a black background, you will need to pass "facecolor='k', edgecolor='k'" to pylab's savefig. """ self.cut_coords = cut_coords if axes is None: axes = plt.axes((0., 0., 1., 1.)) axes.axis('off') self.frame_axes = axes axes.set_zorder(1) bb = axes.get_position() self.rect = (bb.x0, bb.y0, bb.x1, bb.y1) self._black_bg = black_bg self._colorbar = False self._colorbar_width = 0.05 * bb.width self._colorbar_margin = dict(left=0.25 * bb.width, right=0.02 * bb.width, top=0.05 * bb.height, bottom=0.05 * bb.height) self._init_axes(**kwargs) @staticmethod def find_cut_coords(img=None, threshold=None, cut_coords=None): # Implement this as a staticmethod or a classmethod when # subclassing raise NotImplementedError @classmethod def init_with_figure(cls, img, threshold=None, cut_coords=None, figure=None, axes=None, black_bg=False, leave_space=False, colorbar=False, **kwargs): # deal with "fake" 4D images if img is not None and img is not False: img = _utils.check_niimg_3d(img) cut_coords = cls.find_cut_coords(img, threshold, cut_coords) if isinstance(axes, plt.Axes) and figure is None: figure = axes.figure if not isinstance(figure, plt.Figure): # Make sure that we have a figure figsize = cls._default_figsize[:] # Adjust for the number of axes figsize[0] *= len(cut_coords) # Make space for the colorbar if colorbar: figsize[0] += .7 facecolor = 'k' if black_bg else 'w' if leave_space: figsize[0] += 3.4 figure = plt.figure(figure, figsize=figsize, facecolor=facecolor) if isinstance(axes, plt.Axes): assert axes.figure is figure, ("The axes passed are not " "in the figure") if axes is None: axes = [0., 0., 1., 1.] if leave_space: axes = [0.3, 0, .7, 1.] if isinstance(axes, collections.Sequence): axes = figure.add_axes(axes) # People forget to turn their axis off, or to set the zorder, and # then they cannot see their slicer axes.axis('off') return cls(cut_coords, axes, black_bg, **kwargs) def title(self, text, x=0.01, y=0.99, size=15, color=None, bgcolor=None, alpha=1, **kwargs): """ Write a title to the view. Parameters ---------- text: string The text of the title x: float, optional The horizontal position of the title on the frame in fraction of the frame width. y: float, optional The vertical position of the title on the frame in fraction of the frame height. size: integer, optional The size of the title text. color: matplotlib color specifier, optional The color of the font of the title. bgcolor: matplotlib color specifier, optional The color of the background of the title. alpha: float, optional The alpha value for the background. kwargs: Extra keyword arguments are passed to matplotlib's text function. """ if color is None: color = 'k' if self._black_bg else 'w' if bgcolor is None: bgcolor = 'w' if self._black_bg else 'k' if hasattr(self, '_cut_displayed'): first_axe = self._cut_displayed[0] else: first_axe = self.cut_coords[0] ax = self.axes[first_axe].ax ax.text(x, y, text, transform=self.frame_axes.transAxes, horizontalalignment='left', verticalalignment='top', size=size, color=color, bbox=dict(boxstyle="square,pad=.3", ec=bgcolor, fc=bgcolor, alpha=alpha), zorder=1000, **kwargs) ax.set_zorder(1000) def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs): """ Plot a 3D map in all the views. Parameters ----------- img: Niimg-like object See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. If it is a masked array, only the non-masked part will be plotted. threshold : a number, None If None is given, the maps are not thresholded. If a number is given, it is used to threshold the maps: values below the threshold (in absolute value) are plotted as transparent. colorbar: boolean, optional If True, display a colorbar on the right of the plots. kwargs: Extra keyword arguments are passed to imshow. """ if colorbar and self._colorbar: raise ValueError("This figure already has an overlay with a " "colorbar.") else: self._colorbar = colorbar img = _utils.check_niimg_3d(img) if threshold is not None: data = img.get_data() if threshold == 0: data = np.ma.masked_equal(data, 0, copy=False) else: data = np.ma.masked_inside(data, -threshold, threshold, copy=False) img = new_img_like(img, data, img.get_affine()) # Make sure that add_overlay shows consistent default behavior # with plot_stat_map kwargs.setdefault('interpolation', 'nearest') ims = self._map_show(img, type='imshow', **kwargs) if colorbar: self._colorbar_show(ims[0], threshold) plt.draw_if_interactive() def add_contours(self, img, **kwargs): """ Contour a 3D map in all the views. Parameters ----------- img: Niimg-like object See http://nilearn.github.io/building_blocks/manipulating_mr_images.html#niimg. Provides image to plot. kwargs: Extra keyword arguments are passed to contour, see the documentation of pylab.contour Useful, arguments are typical "levels", which is a list of values to use for plotting a contour, and "colors", which is one color or a list of colors for these contours. """ self._map_show(img, type='contour', **kwargs) plt.draw_if_interactive() def _map_show(self, img, type='imshow', resampling_interpolation='continuous', **kwargs): img = reorder_img(img, resample=resampling_interpolation) affine = img.get_affine() data = img.get_data() data_bounds = get_bounds(data.shape, affine) (xmin, xmax), (ymin, ymax), (zmin, zmax) = data_bounds xmin_, xmax_, ymin_, ymax_, zmin_, zmax_ = \ xmin, xmax, ymin, ymax, zmin, zmax if hasattr(data, 'mask') and isinstance(data.mask, np.ndarray): not_mask = np.logical_not(data.mask) xmin_, xmax_, ymin_, ymax_, zmin_, zmax_ = \ get_mask_bounds(new_img_like(img, not_mask, affine)) data_2d_list = [] for display_ax in self.axes.values(): try: data_2d = display_ax.transform_to_2d(data, affine) except IndexError: # We are cutting outside the indices of the data data_2d = None data_2d_list.append(data_2d) if 'vmin' not in kwargs: kwargs['vmin'] = min(d.min() for d in data_2d_list if d is not None) if 'vmax' not in kwargs: kwargs['vmax'] = max(d.max() for d in data_2d_list if d is not None) bounding_box = (xmin_, xmax_), (ymin_, ymax_), (zmin_, zmax_) ims = [] to_iterate_over = zip(self.axes.values(), data_2d_list) for display_ax, data_2d in to_iterate_over: if data_2d is not None: im = display_ax.draw_2d(data_2d, data_bounds, bounding_box, type=type, **kwargs) ims.append(im) return ims def _colorbar_show(self, im, threshold): if threshold is None: offset = 0 else: offset = threshold if offset > im.norm.vmax: offset = im.norm.vmax # create new axis for the colorbar figure = self.frame_axes.figure _, y0, x1, y1 = self.rect height = y1 - y0 x_adjusted_width = self._colorbar_width / len(self.axes) x_adjusted_margin = self._colorbar_margin['right'] / len(self.axes) lt_wid_top_ht = [x1 - (x_adjusted_width + x_adjusted_margin), y0 + self._colorbar_margin['top'], x_adjusted_width, height - (self._colorbar_margin['top'] + self._colorbar_margin['bottom'])] self._colorbar_ax = figure.add_axes(lt_wid_top_ht, axis_bgcolor='w') our_cmap = im.cmap # edge case where the data has a single value # yields a cryptic matplotlib error message # when trying to plot the color bar nb_ticks = 5 if im.norm.vmin != im.norm.vmax else 1 ticks = np.linspace(im.norm.vmin, im.norm.vmax, nb_ticks) bounds = np.linspace(im.norm.vmin, im.norm.vmax, our_cmap.N) # some colormap hacking cmaplist = [our_cmap(i) for i in range(our_cmap.N)] istart = int(im.norm(-offset, clip=True) * (our_cmap.N - 1)) istop = int(im.norm(offset, clip=True) * (our_cmap.N - 1)) for i in range(istart, istop): cmaplist[i] = (0.5, 0.5, 0.5, 1.) # just an average gray color if im.norm.vmin == im.norm.vmax: # len(np.unique(data)) == 1 ? return else: our_cmap = our_cmap.from_list('Custom cmap', cmaplist, our_cmap.N) self._cbar = ColorbarBase( self._colorbar_ax, ticks=ticks, norm=im.norm, orientation='vertical', cmap=our_cmap, boundaries=bounds, spacing='proportional') self._cbar.set_ticklabels(["%.2g" % t for t in ticks]) self._colorbar_ax.yaxis.tick_left() tick_color = 'w' if self._black_bg else 'k' for tick in self._colorbar_ax.yaxis.get_ticklabels(): tick.set_color(tick_color) self._colorbar_ax.yaxis.set_tick_params(width=0) self._cbar.update_ticks() def add_edges(self, img, color='r'): """ Plot the edges of a 3D map in all the views. Parameters ----------- map: 3D ndarray The 3D map to be plotted. If it is a masked array, only the non-masked part will be plotted. affine: 4x4 ndarray The affine matrix giving the transformation from voxel indices to world space. color: matplotlib color: string or (r, g, b) value The color used to display the edge map """ img = reorder_img(img) data = img.get_data() affine = img.get_affine() single_color_cmap = colors.ListedColormap([color]) data_bounds = get_bounds(data.shape, img.get_affine()) # For each ax, cut the data and plot it for display_ax in self.axes.values(): try: data_2d = display_ax.transform_to_2d(data, affine) edge_mask = _edge_map(data_2d) except IndexError: # We are cutting outside the indices of the data continue display_ax.draw_2d(edge_mask, data_bounds, data_bounds, type='imshow', cmap=single_color_cmap) plt.draw_if_interactive() def annotate(self, left_right=True, positions=True, size=12, **kwargs): """ Add annotations to the plot. Parameters ---------- left_right: boolean, optional If left_right is True, annotations indicating which side is left and which side is right are drawn. positions: boolean, optional If positions is True, annotations indicating the positions of the cuts are drawn. size: integer, optional The size of the text used. kwargs: Extra keyword arguments are passed to matplotlib's text function. """ kwargs = kwargs.copy() if not 'color' in kwargs: if self._black_bg: kwargs['color'] = 'w' else: kwargs['color'] = 'k' bg_color = ('k' if self._black_bg else 'w') if left_right: for display_ax in self.axes.values(): display_ax.draw_left_right(size=size, bg_color=bg_color, **kwargs) if positions: for display_ax in self.axes.values(): display_ax.draw_position(size=size, bg_color=bg_color, **kwargs) def close(self): """ Close the figure. This is necessary to avoid leaking memory. """ plt.close(self.frame_axes.figure.number) def savefig(self, filename, dpi=None): """ Save the figure to a file Parameters ========== filename: string The file name to save to. It's extension determines the file type, typically '.png', '.svg' or '.pdf'. dpi: None or scalar The resolution in dots per inch. """ facecolor = edgecolor = 'k' if self._black_bg else 'w' self.frame_axes.figure.savefig(filename, dpi=dpi, facecolor=facecolor, edgecolor=edgecolor)
def display_forces(simulation_folder, lower_percentile=97.5, upper_percentile=99, save_plot = True, arrow_factor=5): """ show the force density field of the masked force components simulation_folder: path to simulation folder lower_percentile and upper_percentile give range of forces which is used as a mask save_plot: option to save the plot to the simulation folder arrow_factor: scales the arrow length in the plot """ # load in forces and coordinates r = np.genfromtxt(os.path.join(simulation_folder, "R.dat")) # positions f = np.genfromtxt(os.path.join(simulation_folder, "Fden.dat")) # force densities fabs = np.sqrt(np.sum(f ** 2., axis=1)) # absolute values for filtering # filter mask = (fabs > np.percentile(fabs, lower_percentile)) & (fabs < np.percentile(fabs, upper_percentile)) r2 = r[mask] f2 = f[mask] fabs2 = fabs[mask] # Force fig2 = plt.figure() ax2 = fig2.gca(projection='3d', label='fitted-forces', rasterized=True) color_bounds2 = np.array([np.percentile(fabs2, 0.1), np.percentile(fabs2, 99.9)]) * 10 ** -6 for r2i, f2i, fabs2i in tqdm(zip(r2 * 10 ** 6, f2 * 10 ** -6, fabs2 * (10 ** -6))): #*f_scale color = plt.cm.hot(((fabs2i - color_bounds2[0]) / (color_bounds2[1] - color_bounds2[0]))) # alpha = 1. - (r2i[0] - r2i[1]) / (270. * 1.25) # if alpha > 1: # alpha = 1. alpha = 1. ax2.quiver(r2i[0], r2i[1], r2i[2], f2i[0], f2i[1], f2i[2], length=fabs2i * arrow_factor , color=color, arrow_length_ratio=0, alpha=alpha, pivot='tip', linewidth=0.5) # plot colorbar --------------------------------------------------------- cbaxes = fig2.add_axes([0.15, 0.1, 0.125, 0.010]) cmap = plt.cm.hot norm = plt.Normalize(vmin=color_bounds2[0], vmax=color_bounds2[1]) cb1 = ColorbarBase(cbaxes, cmap=cmap, norm=norm, orientation='horizontal') cb1.set_label('Force Den. [pN/µm³]') tick_locator = ticker.MaxNLocator(nbins=3) cb1.locator = tick_locator cb1.update_ticks() # ------------------------------------------------------------------------- #ax2.set_xlim([-150, 150]) can be used to make an individual plot #ax2.set_ylim([-150, 150]) #ax2.set_zlim([-150, 150]) #ax2.set_xticks([-100, -50, 0, 50, 100]) #ax2.set_yticks([-100, -50, 0, 50, 100]) #ax2.set_zticks([-100, -50, 0, 50, 100]) # ax2.set_xticklabels(['']*5) # ax2.set_yticklabels(['']*5) # ax2.set_zticklabels(['']*5) ax2.w_xaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) ax2.w_yaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) ax2.w_zaxis.set_pane_color((0.2, 0.2, 0.2, 1.0)) if save_plot: plt.savefig( os.path.join(simulation_folder,'force_density_plot_lower_{}_upper_{}.png'.format(lower_percentile, upper_percentile)), dpi=500 , bbox_inches="tight", pad_inches=0) return