def optimize_contrast(self, data): if (self.vmin is not None and self.vmax is not None and not self.auto_contrast): return if 'complex' in data.dtype.name: data = np.log(np.abs(data)) vmin, vmax = contrast_stretching(data, self.saturated_pixels) if self.vmin is None or self.auto_contrast: self.vmin = vmin if self.vmax is None or self.auto_contrast: self.vmax = vmax
def _convert_tia_single_item(self, item, suffix=''): kwargs = {} original_data = item.data.copy() for extension in self.extension_list: item.data = original_data if extension in ['jpg', 'jpeg'] and self.contrast_streching: vmin, vmax = contrast_stretching(item.data, self.saturated_pixels) item.data = self.normalise(item.data, vmin, vmax) if extension in ['tif', 'tiff']: kwargs = self._get_kwargs(item) self.fname_ext = ''.join([os.path.splitext(self.fname)[0], suffix, '.', extension]) if os.path.exists(self.fname_ext) and self.overwrite is None: write_answer = self._ask_confirmation_overwrite() self._save_data(item, overwrite=write_answer, **kwargs) # workaround, currently hyperspy doesn't write file is overwrite=False elif not os.path.exists(self.fname_ext): self._save_data(item, **kwargs) else: self._save_data(item, overwrite=self.overwrite, **kwargs)
def plot_images(images, cmap=None, no_nans=False, per_row=3, label='auto', labelwrap=30, suptitle=None, suptitle_fontsize=18, colorbar='multi', centre_colormap="auto", saturated_pixels=0, scalebar=None, scalebar_color='white', axes_decor='all', padding=None, tight_layout=False, aspect='auto', min_asp=0.1, namefrac_thresh=0.4, fig=None, *args, **kwargs): """Plot multiple images as sub-images in one figure. Parameters ---------- images : list `images` should be a list of Signals (Images) to plot If any signal is not an image, a ValueError will be raised multi-dimensional images will have each plane plotted as a separate image cmap : matplotlib colormap, optional The colormap used for the images, by default read from pyplot no_nans : bool, optional If True, set nans to zero for plotting. per_row : int, optional The number of plots in each row label : None, str, or list of str, optional Control the title labeling of the plotted images. If None, no titles will be shown. If 'auto' (default), function will try to determine suitable titles using Image titles, falling back to the 'titles' option if no good short titles are detected. Works best if all images to be plotted have the same beginning to their titles. If 'titles', the title from each image's metadata.General.title will be used. If any other single str, images will be labeled in sequence using that str as a prefix. If a list of str, the list elements will be used to determine the labels (repeated, if necessary). labelwrap : int, optional integer specifying the number of characters that will be used on one line If the function returns an unexpected blank figure, lower this value to reduce overlap of the labels between each figure suptitle : str, optional Title to use at the top of the figure. If called with label='auto', this parameter will override the automatically determined title. suptitle_fontsize : int, optional Font size to use for super title at top of figure colorbar : {'multi', None, 'single'} Controls the type of colorbars that are plotted. If None, no colorbar is plotted. If 'multi' (default), individual colorbars are plotted for each (non-RGB) image If 'single', all (non-RGB) images are plotted on the same scale, and one colorbar is shown for all centre_colormap : {"auto", True, False} If True the centre of the color scheme is set to zero. This is specially useful when using diverging color schemes. If "auto" (default), diverging color schemes are automatically centred. saturated_pixels: scalar The percentage of pixels that are left out of the bounds. For example, the low and high bounds of a value of 1 are the 0.5% and 99.5% percentiles. It must be in the [0, 100] range. scalebar : {None, 'all', list of ints}, optional If None (or False), no scalebars will be added to the images. If 'all', scalebars will be added to all images. If list of ints, scalebars will be added to each image specified. scalebar_color : str, optional A valid MPL color string; will be used as the scalebar color axes_decor : {'all', 'ticks', 'off', None}, optional Controls how the axes are displayed on each image; default is 'all' If 'all', both ticks and axis labels will be shown If 'ticks', no axis labels will be shown, but ticks/labels will If 'off', all decorations and frame will be disabled If None, no axis decorations will be shown, but ticks/frame will padding : None or dict, optional This parameter controls the spacing between images. If None, default options will be used Otherwise, supply a dictionary with the spacing options as keywords and desired values as values Values should be supplied as used in pyplot.subplots_adjust(), and can be: 'left', 'bottom', 'right', 'top', 'wspace' (width), and 'hspace' (height) tight_layout : bool, optional If true, hyperspy will attempt to improve image placement in figure using matplotlib's tight_layout If false, repositioning images inside the figure will be left as an exercise for the user. aspect : str or numeric, optional If 'auto', aspect ratio is auto determined, subject to min_asp. If 'square', image will be forced onto square display. If 'equal', aspect ratio of 1 will be enforced. If float (or int/long), given value will be used. min_asp : float, optional Minimum aspect ratio to be used when plotting images namefrac_thresh : float, optional Threshold to use for auto-labeling. This parameter controls how much of the titles must be the same for the auto-shortening of labels to activate. Can vary from 0 to 1. Smaller values encourage shortening of titles by auto-labeling, while larger values will require more overlap in titles before activing the auto-label code. fig : mpl figure, optional If set, the images will be plotted to an existing MPL figure *args, **kwargs, optional Additional arguments passed to matplotlib.imshow() Returns ------- axes_list : list a list of subplot axes that hold the images See Also -------- plot_spectra : Plotting of multiple spectra plot_signals : Plotting of multiple signals plot_histograms : Compare signal histograms Notes ----- `interpolation` is a useful parameter to provide as a keyword argument to control how the space between pixels is interpolated. A value of ``'nearest'`` will cause no interpolation between pixels. `tight_layout` is known to be quite brittle, so an option is provided to disable it. Turn this option off if output is not as expected, or try adjusting `label`, `labelwrap`, or `per_row` """ from hyperspy.drawing.widgets import Scale_Bar from hyperspy.misc import rgb_tools from hyperspy.signal import Signal if isinstance(images, Signal) and len(images) is 1: images.plot() ax = plt.gca() return ax elif not isinstance(images, (list, tuple, Signal)): raise ValueError("images must be a list of image signals or " "multi-dimensional signal." " " + repr(type(images)) + " was given.") # Get default colormap from pyplot: if cmap is None: cmap = plt.get_cmap().name elif isinstance(cmap, mpl.colors.Colormap): cmap = cmap.name if centre_colormap == "auto": if cmap in MPL_DIVERGING_COLORMAPS: centre_colormap = True else: centre_colormap = False # If input is >= 1D signal (e.g. for multi-dimensional plotting), # copy it and put it in a list so labeling works out as (x,y) when plotting if isinstance( images, Signal) and images.axes_manager.navigation_dimension > 0: images = [images._deepcopy_with_new_data(images.data)] n = 0 for i, sig in enumerate(images): if sig.axes_manager.signal_dimension != 2: raise ValueError("This method only plots signals that are images. " "The signal dimension must be equal to 2. " "The signal at position " + repr(i) + " was " + repr(sig) + ".") # increment n by the navigation size, or by 1 if the navigation size is # <= 0 n += (sig.axes_manager.navigation_size if sig.axes_manager.navigation_size > 0 else 1) # Sort out the labeling: div_num = 0 all_match = False shared_titles = False user_labels = False if label is None: pass elif label is 'auto': # Use some heuristics to try to get base string of similar titles label_list = [x.metadata.General.title for x in images] # Find the shortest common string between the image titles # and pull that out as the base title for the sequence of images # array in which to store arrays res = np.zeros((len(label_list), len(label_list[0]) + 1)) res[:, 0] = 1 # j iterates the strings for j in range(len(label_list)): # i iterates length of substring test for i in range(1, len(label_list[0]) + 1): # stores whether or not characters in title match res[j, i] = label_list[0][:i] in label_list[j] # sum up the results (1 is True, 0 is False) and create # a substring based on the minimum value (this will be # the "smallest common string" between all the titles if res.all(): basename = label_list[0] div_num = len(label_list[0]) all_match = True else: div_num = int(min(np.sum(res, 1))) basename = label_list[0][:div_num - 1] all_match = False # trim off any '(' or ' ' characters at end of basename if div_num > 1: while True: if basename[len(basename) - 1] == '(': basename = basename[:-1] elif basename[len(basename) - 1] == ' ': basename = basename[:-1] else: break # namefrac is ratio of length of basename to the image name # if it is high (e.g. over 0.5), we can assume that all images # share the same base if len(label_list[0]) > 0: namefrac = float(len(basename)) / len(label_list[0]) else: # If label_list[0] is empty, it means there was probably no # title set originally, so nothing to share namefrac = 0 if namefrac > namefrac_thresh: # there was a significant overlap of label beginnings shared_titles = True # only use new suptitle if one isn't specified already if suptitle is None: suptitle = basename else: # there was not much overlap, so default back to 'titles' mode shared_titles = False label = 'titles' div_num = 0 elif label is 'titles': # Set label_list to each image's pre-defined title label_list = [x.metadata.General.title for x in images] elif isinstance(label, basestring): # Set label_list to an indexed list, based off of label label_list = [label + " " + repr(num) for num in range(n)] elif isinstance(label, list) and all( isinstance(x, basestring) for x in label): label_list = label user_labels = True # If list of labels is longer than the number of images, just use the # first n elements if len(label_list) > n: del label_list[n:] if len(label_list) < n: label_list *= (n / len(label_list)) + 1 del label_list[n:] else: # catch all others to revert to default if bad input print "Did not understand input of labels. Defaulting to image titles." label_list = [x.metadata.General.title for x in images] # Determine appropriate number of images per row rows = int(np.ceil(n / float(per_row))) if n < per_row: per_row = n # Set overall figure size and define figure (if not pre-existing) if fig is None: k = max(plt.rcParams['figure.figsize']) / max(per_row, rows) f = plt.figure(figsize=(tuple(k * i for i in (per_row, rows)))) else: f = fig # Initialize list to hold subplot axes axes_list = [] # Initialize list of rgb tags isrgb = [False] * len(images) # Check to see if there are any rgb images in list # and tag them using the isrgb list for i, img in enumerate(images): if rgb_tools.is_rgbx(img.data): isrgb[i] = True # Determine how many non-rgb Images there are non_rgb = list(itertools.compress(images, [not j for j in isrgb])) if len(non_rgb) is 0 and colorbar is not None: colorbar = None print "Sorry, colorbar is not implemented for RGB images." # Find global min and max values of all the non-rgb images for use with # 'single' scalebar if colorbar is 'single': global_max = max([i.data.max() for i in non_rgb]) global_min = min([i.data.min() for i in non_rgb]) g_vmin, g_vmax = contrast_stretching(i.data, saturated_pixels) if centre_colormap: g_vmin, g_vmax = centre_colormap_values(g_vmin, g_vmax) # Check if we need to add a scalebar for some of the images if isinstance(scalebar, list) and all(isinstance(x, int) for x in scalebar): scalelist = True else: scalelist = False idx = 0 ax_im_list = [0] * len(isrgb) # Loop through each image, adding subplot for each one for i, ims in enumerate(images): # Get handles for the signal axes and axes_manager axes_manager = ims.axes_manager if axes_manager.navigation_dimension > 0: ims = ims._deepcopy_with_new_data(ims.data) for j, im in enumerate(ims): idx += 1 ax = f.add_subplot(rows, per_row, idx) axes_list.append(ax) data = im.data # Enable RGB plotting if rgb_tools.is_rgbx(data): data = rgb_tools.rgbx2regular_array(data, plot_friendly=True) l_vmin, l_vmax = None, None else: data = im.data # Find min and max for contrast l_vmin, l_vmax = contrast_stretching(data, saturated_pixels) if centre_colormap: l_vmin, l_vmax = centre_colormap_values(l_vmin, l_vmax) # Remove NaNs (if requested) if no_nans: data = np.nan_to_num(data) # Get handles for the signal axes and axes_manager axes_manager = im.axes_manager axes = axes_manager.signal_axes # Set dimensions of images xaxis = axes[0] yaxis = axes[1] extent = ( xaxis.low_value, xaxis.high_value, yaxis.high_value, yaxis.low_value, ) if not isinstance(aspect, (int, long, float)) and aspect not in [ 'auto', 'square', 'equal']: print 'Did not understand aspect ratio input. ' \ 'Using \'auto\' as default.' aspect = 'auto' if aspect is 'auto': if float(yaxis.size) / xaxis.size < min_asp: factor = min_asp * float(xaxis.size) / yaxis.size elif float(yaxis.size) / xaxis.size > min_asp ** -1: factor = min_asp ** -1 * float(xaxis.size) / yaxis.size else: factor = 1 asp = np.abs(factor * float(xaxis.scale) / yaxis.scale) elif aspect is 'square': asp = abs(extent[1] - extent[0]) / abs(extent[3] - extent[2]) elif aspect is 'equal': asp = 1 elif isinstance(aspect, (int, long, float)): asp = aspect if ('interpolation' in kwargs.keys()) is False: kwargs['interpolation'] = 'nearest' # Plot image data, using vmin and vmax to set bounds, # or allowing them to be set automatically if using individual # colorbars if colorbar is 'single' and not isrgb[i]: axes_im = ax.imshow(data, cmap=cmap, extent=extent, vmin=g_vmin, vmax=g_vmax, aspect=asp, *args, **kwargs) ax_im_list[i] = axes_im else: axes_im = ax.imshow(data, cmap=cmap, extent=extent, vmin=l_vmin, vmax=l_vmax, aspect=asp, *args, **kwargs) ax_im_list[i] = axes_im # If an axis trait is undefined, shut off : if isinstance(xaxis.units, trait_base._Undefined) or \ isinstance(yaxis.units, trait_base._Undefined) or \ isinstance(xaxis.name, trait_base._Undefined) or \ isinstance(yaxis.name, trait_base._Undefined): if axes_decor is 'all': warnings.warn( 'Axes labels were requested, but one ' 'or both of the ' 'axes units and/or name are undefined. ' 'Axes decorations have been set to ' '\'ticks\' instead.') axes_decor = 'ticks' # If all traits are defined, set labels as appropriate: else: ax.set_xlabel(axes[0].name + " axis (" + axes[0].units + ")") ax.set_ylabel(axes[1].name + " axis (" + axes[1].units + ")") if label: if all_match: title = '' elif shared_titles: title = label_list[i][div_num - 1:] else: if len(ims) == n: # This is true if we are plotting just 1 # multi-dimensional Image title = label_list[idx - 1] elif user_labels: title = label_list[idx - 1] else: title = label_list[i] if ims.axes_manager.navigation_size > 1 and not user_labels: title += " %s" % str(ims.axes_manager.indices) ax.set_title(textwrap.fill(title, labelwrap)) # Set axes decorations based on user input if axes_decor is 'off': ax.axis('off') elif axes_decor is 'ticks': ax.set_xlabel('') ax.set_ylabel('') elif axes_decor is 'all': pass elif axes_decor is None: ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels([]) ax.set_yticklabels([]) # If using independent colorbars, add them if colorbar is 'multi' and not isrgb[i]: div = make_axes_locatable(ax) cax = div.append_axes("right", size="5%", pad=0.05) plt.colorbar(axes_im, cax=cax) # Add scalebars as necessary if (scalelist and i in scalebar) or scalebar is 'all': ax.scalebar = Scale_Bar( ax=ax, units=axes[0].units, color=scalebar_color, ) # If using a single colorbar, add it, and do tight_layout, ensuring that # a colorbar is only added based off of non-rgb Images: if colorbar is 'single': foundim = None for i in range(len(isrgb)): if (not isrgb[i]) and foundim is None: foundim = i if foundim is not None: f.subplots_adjust(right=0.8) cbar_ax = f.add_axes([0.9, 0.1, 0.03, 0.8]) f.colorbar(ax_im_list[foundim], cax=cbar_ax) if tight_layout: # tight_layout, leaving room for the colorbar plt.tight_layout(rect=[0, 0, 0.9, 1]) elif tight_layout: plt.tight_layout() elif tight_layout: plt.tight_layout() # Set top bounds for shared titles and add suptitle if suptitle: f.subplots_adjust(top=0.85) f.suptitle(suptitle, fontsize=suptitle_fontsize) # If we want to plot scalebars, loop through the list of axes and add them if scalebar is None or scalebar is False: # Do nothing if no scalebars are called for pass elif scalebar is 'all': # scalebars were taken care of in the plotting loop pass elif scalelist: # scalebars were taken care of in the plotting loop pass else: raise ValueError("Did not understand scalebar input. Must be None, " "\'all\', or list of ints.") # Adjust subplot spacing according to user's specification if padding is not None: plt.subplots_adjust(**padding) return axes_list
def test_out_of_range(self): contrast_stretching(self.data, -1)
def test_nans(self): data = self.data[:-1] bounds = contrast_stretching(self.data, 1) nose.tools.assert_tuple_equal(bounds, ( np.percentile(data, 0.5), np.percentile(data, 99.5)))
def test_nans(self): data = self.data[:-1] bounds = contrast_stretching(self.data, 1) nose.tools.assert_tuple_equal( bounds, (np.percentile(data, 0.5), np.percentile(data, 99.5)))
def plot_images(images, cmap=None, no_nans=False, per_row=3, label='auto', labelwrap=30, suptitle=None, suptitle_fontsize=18, colorbar='multi', centre_colormap="auto", saturated_pixels=0, scalebar=None, scalebar_color='white', axes_decor='all', padding=None, tight_layout=False, aspect='auto', min_asp=0.1, namefrac_thresh=0.4, fig=None, *args, **kwargs): """Plot multiple images as sub-images in one figure. Parameters ---------- images : list `images` should be a list of Signals (Images) to plot If any signal is not an image, a ValueError will be raised multi-dimensional images will have each plane plotted as a separate image cmap : matplotlib colormap, optional The colormap used for the images, by default read from pyplot no_nans : bool, optional If True, set nans to zero for plotting. per_row : int, optional The number of plots in each row label : None, str, or list of str, optional Control the title labeling of the plotted images. If None, no titles will be shown. If 'auto' (default), function will try to determine suitable titles using Image titles, falling back to the 'titles' option if no good short titles are detected. Works best if all images to be plotted have the same beginning to their titles. If 'titles', the title from each image's metadata.General.title will be used. If any other single str, images will be labeled in sequence using that str as a prefix. If a list of str, the list elements will be used to determine the labels (repeated, if necessary). labelwrap : int, optional integer specifying the number of characters that will be used on one line If the function returns an unexpected blank figure, lower this value to reduce overlap of the labels between each figure suptitle : str, optional Title to use at the top of the figure. If called with label='auto', this parameter will override the automatically determined title. suptitle_fontsize : int, optional Font size to use for super title at top of figure colorbar : {'multi', None, 'single'} Controls the type of colorbars that are plotted. If None, no colorbar is plotted. If 'multi' (default), individual colorbars are plotted for each (non-RGB) image If 'single', all (non-RGB) images are plotted on the same scale, and one colorbar is shown for all centre_colormap : {"auto", True, False} If True the centre of the color scheme is set to zero. This is specially useful when using diverging color schemes. If "auto" (default), diverging color schemes are automatically centred. saturated_pixels: scalar The percentage of pixels that are left out of the bounds. For example, the low and high bounds of a value of 1 are the 0.5% and 99.5% percentiles. It must be in the [0, 100] range. scalebar : {None, 'all', list of ints}, optional If None (or False), no scalebars will be added to the images. If 'all', scalebars will be added to all images. If list of ints, scalebars will be added to each image specified. scalebar_color : str, optional A valid MPL color string; will be used as the scalebar color axes_decor : {'all', 'ticks', 'off', None}, optional Controls how the axes are displayed on each image; default is 'all' If 'all', both ticks and axis labels will be shown If 'ticks', no axis labels will be shown, but ticks/labels will If 'off', all decorations and frame will be disabled If None, no axis decorations will be shown, but ticks/frame will padding : None or dict, optional This parameter controls the spacing between images. If None, default options will be used Otherwise, supply a dictionary with the spacing options as keywords and desired values as values Values should be supplied as used in pyplot.subplots_adjust(), and can be: 'left', 'bottom', 'right', 'top', 'wspace' (width), and 'hspace' (height) tight_layout : bool, optional If true, hyperspy will attempt to improve image placement in figure using matplotlib's tight_layout If false, repositioning images inside the figure will be left as an exercise for the user. aspect : str or numeric, optional If 'auto', aspect ratio is auto determined, subject to min_asp. If 'square', image will be forced onto square display. If 'equal', aspect ratio of 1 will be enforced. If float (or int/long), given value will be used. min_asp : float, optional Minimum aspect ratio to be used when plotting images namefrac_thresh : float, optional Threshold to use for auto-labeling. This parameter controls how much of the titles must be the same for the auto-shortening of labels to activate. Can vary from 0 to 1. Smaller values encourage shortening of titles by auto-labeling, while larger values will require more overlap in titles before activing the auto-label code. fig : mpl figure, optional If set, the images will be plotted to an existing MPL figure *args, **kwargs, optional Additional arguments passed to matplotlib.imshow() Returns ------- axes_list : list a list of subplot axes that hold the images See Also -------- plot_spectra : Plotting of multiple spectra plot_signals : Plotting of multiple signals plot_histograms : Compare signal histograms Notes ----- `interpolation` is a useful parameter to provide as a keyword argument to control how the space between pixels is interpolated. A value of ``'nearest'`` will cause no interpolation between pixels. `tight_layout` is known to be quite brittle, so an option is provided to disable it. Turn this option off if output is not as expected, or try adjusting `label`, `labelwrap`, or `per_row` """ from hyperspy.drawing.widgets import ScaleBar from hyperspy.misc import rgb_tools from hyperspy.signal import Signal if isinstance(images, Signal) and len(images) is 1: images.plot() ax = plt.gca() return ax elif not isinstance(images, (list, tuple, Signal)): raise ValueError("images must be a list of image signals or " "multi-dimensional signal." " " + repr(type(images)) + " was given.") # Get default colormap from pyplot: if cmap is None: cmap = plt.get_cmap().name elif isinstance(cmap, mpl.colors.Colormap): cmap = cmap.name if centre_colormap == "auto": if cmap in MPL_DIVERGING_COLORMAPS: centre_colormap = True else: centre_colormap = False # If input is >= 1D signal (e.g. for multi-dimensional plotting), # copy it and put it in a list so labeling works out as (x,y) when plotting if isinstance(images, Signal) and images.axes_manager.navigation_dimension > 0: images = [images._deepcopy_with_new_data(images.data)] n = 0 for i, sig in enumerate(images): if sig.axes_manager.signal_dimension != 2: raise ValueError("This method only plots signals that are images. " "The signal dimension must be equal to 2. " "The signal at position " + repr(i) + " was " + repr(sig) + ".") # increment n by the navigation size, or by 1 if the navigation size is # <= 0 n += (sig.axes_manager.navigation_size if sig.axes_manager.navigation_size > 0 else 1) # Sort out the labeling: div_num = 0 all_match = False shared_titles = False user_labels = False if label is None: pass elif label is 'auto': # Use some heuristics to try to get base string of similar titles label_list = [x.metadata.General.title for x in images] # Find the shortest common string between the image titles # and pull that out as the base title for the sequence of images # array in which to store arrays res = np.zeros((len(label_list), len(label_list[0]) + 1)) res[:, 0] = 1 # j iterates the strings for j in range(len(label_list)): # i iterates length of substring test for i in range(1, len(label_list[0]) + 1): # stores whether or not characters in title match res[j, i] = label_list[0][:i] in label_list[j] # sum up the results (1 is True, 0 is False) and create # a substring based on the minimum value (this will be # the "smallest common string" between all the titles if res.all(): basename = label_list[0] div_num = len(label_list[0]) all_match = True else: div_num = int(min(np.sum(res, 1))) basename = label_list[0][:div_num - 1] all_match = False # trim off any '(' or ' ' characters at end of basename if div_num > 1: while True: if basename[len(basename) - 1] == '(': basename = basename[:-1] elif basename[len(basename) - 1] == ' ': basename = basename[:-1] else: break # namefrac is ratio of length of basename to the image name # if it is high (e.g. over 0.5), we can assume that all images # share the same base if len(label_list[0]) > 0: namefrac = float(len(basename)) / len(label_list[0]) else: # If label_list[0] is empty, it means there was probably no # title set originally, so nothing to share namefrac = 0 if namefrac > namefrac_thresh: # there was a significant overlap of label beginnings shared_titles = True # only use new suptitle if one isn't specified already if suptitle is None: suptitle = basename else: # there was not much overlap, so default back to 'titles' mode shared_titles = False label = 'titles' div_num = 0 elif label is 'titles': # Set label_list to each image's pre-defined title label_list = [x.metadata.General.title for x in images] elif isinstance(label, basestring): # Set label_list to an indexed list, based off of label label_list = [label + " " + repr(num) for num in range(n)] elif isinstance(label, list) and all( isinstance(x, basestring) for x in label): label_list = label user_labels = True # If list of labels is longer than the number of images, just use the # first n elements if len(label_list) > n: del label_list[n:] if len(label_list) < n: label_list *= (n / len(label_list)) + 1 del label_list[n:] else: # catch all others to revert to default if bad input print "Did not understand input of labels. Defaulting to image titles." label_list = [x.metadata.General.title for x in images] # Determine appropriate number of images per row rows = int(np.ceil(n / float(per_row))) if n < per_row: per_row = n # Set overall figure size and define figure (if not pre-existing) if fig is None: k = max(plt.rcParams['figure.figsize']) / max(per_row, rows) f = plt.figure(figsize=(tuple(k * i for i in (per_row, rows)))) else: f = fig # Initialize list to hold subplot axes axes_list = [] # Initialize list of rgb tags isrgb = [False] * len(images) # Check to see if there are any rgb images in list # and tag them using the isrgb list for i, img in enumerate(images): if rgb_tools.is_rgbx(img.data): isrgb[i] = True # Determine how many non-rgb Images there are non_rgb = list(itertools.compress(images, [not j for j in isrgb])) if len(non_rgb) is 0 and colorbar is not None: colorbar = None print "Sorry, colorbar is not implemented for RGB images." # Find global min and max values of all the non-rgb images for use with # 'single' scalebar if colorbar is 'single': g_vmin, g_vmax = contrast_stretching( np.concatenate([i.data.flatten() for i in non_rgb]), saturated_pixels) if centre_colormap: g_vmin, g_vmax = centre_colormap_values(g_vmin, g_vmax) # Check if we need to add a scalebar for some of the images if isinstance(scalebar, list) and all( isinstance(x, int) for x in scalebar): scalelist = True else: scalelist = False idx = 0 ax_im_list = [0] * len(isrgb) # Loop through each image, adding subplot for each one for i, ims in enumerate(images): # Get handles for the signal axes and axes_manager axes_manager = ims.axes_manager if axes_manager.navigation_dimension > 0: ims = ims._deepcopy_with_new_data(ims.data) for j, im in enumerate(ims): idx += 1 ax = f.add_subplot(rows, per_row, idx) axes_list.append(ax) data = im.data # Enable RGB plotting if rgb_tools.is_rgbx(data): data = rgb_tools.rgbx2regular_array(data, plot_friendly=True) l_vmin, l_vmax = None, None else: data = im.data # Find min and max for contrast l_vmin, l_vmax = contrast_stretching(data, saturated_pixels) if centre_colormap: l_vmin, l_vmax = centre_colormap_values(l_vmin, l_vmax) # Remove NaNs (if requested) if no_nans: data = np.nan_to_num(data) # Get handles for the signal axes and axes_manager axes_manager = im.axes_manager axes = axes_manager.signal_axes # Set dimensions of images xaxis = axes[0] yaxis = axes[1] extent = ( xaxis.low_value, xaxis.high_value, yaxis.high_value, yaxis.low_value, ) if not isinstance(aspect, (int, long, float)) and aspect not in [ 'auto', 'square', 'equal' ]: print 'Did not understand aspect ratio input. ' \ 'Using \'auto\' as default.' aspect = 'auto' if aspect is 'auto': if float(yaxis.size) / xaxis.size < min_asp: factor = min_asp * float(xaxis.size) / yaxis.size elif float(yaxis.size) / xaxis.size > min_asp**-1: factor = min_asp**-1 * float(xaxis.size) / yaxis.size else: factor = 1 asp = np.abs(factor * float(xaxis.scale) / yaxis.scale) elif aspect is 'square': asp = abs(extent[1] - extent[0]) / abs(extent[3] - extent[2]) elif aspect is 'equal': asp = 1 elif isinstance(aspect, (int, long, float)): asp = aspect if ('interpolation' in kwargs.keys()) is False: kwargs['interpolation'] = 'nearest' # Plot image data, using vmin and vmax to set bounds, # or allowing them to be set automatically if using individual # colorbars if colorbar is 'single' and not isrgb[i]: axes_im = ax.imshow(data, cmap=cmap, extent=extent, vmin=g_vmin, vmax=g_vmax, aspect=asp, *args, **kwargs) ax_im_list[i] = axes_im else: axes_im = ax.imshow(data, cmap=cmap, extent=extent, vmin=l_vmin, vmax=l_vmax, aspect=asp, *args, **kwargs) ax_im_list[i] = axes_im # If an axis trait is undefined, shut off : if isinstance(xaxis.units, trait_base._Undefined) or \ isinstance(yaxis.units, trait_base._Undefined) or \ isinstance(xaxis.name, trait_base._Undefined) or \ isinstance(yaxis.name, trait_base._Undefined): if axes_decor is 'all': warnings.warn('Axes labels were requested, but one ' 'or both of the ' 'axes units and/or name are undefined. ' 'Axes decorations have been set to ' '\'ticks\' instead.') axes_decor = 'ticks' # If all traits are defined, set labels as appropriate: else: ax.set_xlabel(axes[0].name + " axis (" + axes[0].units + ")") ax.set_ylabel(axes[1].name + " axis (" + axes[1].units + ")") if label: if all_match: title = '' elif shared_titles: title = label_list[i][div_num - 1:] else: if len(ims) == n: # This is true if we are plotting just 1 # multi-dimensional Image title = label_list[idx - 1] elif user_labels: title = label_list[idx - 1] else: title = label_list[i] if ims.axes_manager.navigation_size > 1 and not user_labels: title += " %s" % str(ims.axes_manager.indices) ax.set_title(textwrap.fill(title, labelwrap)) # Set axes decorations based on user input if axes_decor is 'off': ax.axis('off') elif axes_decor is 'ticks': ax.set_xlabel('') ax.set_ylabel('') elif axes_decor is 'all': pass elif axes_decor is None: ax.set_xlabel('') ax.set_ylabel('') ax.set_xticklabels([]) ax.set_yticklabels([]) # If using independent colorbars, add them if colorbar is 'multi' and not isrgb[i]: div = make_axes_locatable(ax) cax = div.append_axes("right", size="5%", pad=0.05) plt.colorbar(axes_im, cax=cax) # Add scalebars as necessary if (scalelist and i in scalebar) or scalebar is 'all': ax.scalebar = ScaleBar( ax=ax, units=axes[0].units, color=scalebar_color, ) # If using a single colorbar, add it, and do tight_layout, ensuring that # a colorbar is only added based off of non-rgb Images: if colorbar is 'single': foundim = None for i in range(len(isrgb)): if (not isrgb[i]) and foundim is None: foundim = i if foundim is not None: f.subplots_adjust(right=0.8) cbar_ax = f.add_axes([0.9, 0.1, 0.03, 0.8]) f.colorbar(ax_im_list[foundim], cax=cbar_ax) if tight_layout: # tight_layout, leaving room for the colorbar plt.tight_layout(rect=[0, 0, 0.9, 1]) elif tight_layout: plt.tight_layout() elif tight_layout: plt.tight_layout() # Set top bounds for shared titles and add suptitle if suptitle: f.subplots_adjust(top=0.85) f.suptitle(suptitle, fontsize=suptitle_fontsize) # If we want to plot scalebars, loop through the list of axes and add them if scalebar is None or scalebar is False: # Do nothing if no scalebars are called for pass elif scalebar is 'all': # scalebars were taken care of in the plotting loop pass elif scalelist: # scalebars were taken care of in the plotting loop pass else: raise ValueError("Did not understand scalebar input. Must be None, " "\'all\', or list of ints.") # Adjust subplot spacing according to user's specification if padding is not None: plt.subplots_adjust(**padding) return axes_list