def setup_plot_ed(axis, gs_spec): # set up a PlotEditor for the given axis # subplot grid, with larger height preference for plot for # each increased row to make sliders of approx equal size and # align top borders of top images rows_cols = gs_spec.get_rows_columns() extra_rows = rows_cols[3] - rows_cols[2] gs_plot = gridspec.GridSpecFromSubplotSpec( 2, 1, subplot_spec=gs_spec, height_ratios=(1, 10 + 14 * extra_rows), hspace=0.1 / (extra_rows * 1.4 + 1)) # transform arrays to the given orthogonal direction ax = fig.add_subplot(gs_plot[1, 0]) plot_support.hide_axes(ax) plane = config.PLANE[axis] arrs_3d, aspect, origin, scaling = \ plot_support.setup_images_for_plane( plane, (self.image5d[0], self.labels_img, self.borders_img)) img3d_transposed = arrs_3d[0] labels_img_transposed = libmag.get_if_within(arrs_3d, 1) borders_img_transposed = libmag.get_if_within(arrs_3d, 2) # slider through image planes ax_scroll = fig.add_subplot(gs_plot[0, 0]) plane_slider = Slider(ax_scroll, plot_support.get_plane_axis(plane), 0, len(img3d_transposed) - 1, valfmt="%d", valinit=0, valstep=1) # plot editor max_size = max_sizes[axis] if max_sizes else None plot_ed = plot_editor.PlotEditor( ax, img3d_transposed, labels_img_transposed, cmap_labels, plane, aspect, origin, self.update_coords, self.refresh_images, scaling, plane_slider, img3d_borders=borders_img_transposed, cmap_borders=cmap_borders, fn_show_label_3d=self.fn_show_label_3d, interp_planes=self.interp_planes, fn_update_intensity=self.update_color_picker, max_size=max_size, fn_status_bar=self.fn_status_bar) return plot_ed
def handle_extracted_plane(): # get sub-plot and hide x/y axes ax = axs if libmag.is_seq(ax): ax = axs[imgi] plot_support.hide_axes(ax) # multiple artists can be shown at each frame by collecting # each group of artists in a list; overlay_images returns # a nested list containing a list for each image, which in turn # contains a list of artists for each channel ax_imgs = plot_support.overlay_images(ax, self.aspect, self.origin, imgs, None, cmaps_all, ignore_invis=True, check_single=True) if (colorbar is not None and len(ax_imgs) > 0 and len(ax_imgs[0]) > 0 and imgi == 0): # add colorbar with scientific notation if outside limits cbar = ax.figure.colorbar(ax_imgs[0][0], ax=ax, **colorbar) plot_support.set_scinot(cbar.ax, lbls=None, units=None) plotted_imgs[imgi] = np.array(ax_imgs).flatten() if libmag.is_seq(text_pos) and len(text_pos) > 1: # write plane index in axes rather than data coordinates text = ax.text(*text_pos[:2], "{}-plane: {}".format( plot_support.get_plane_axis(config.plane), self.start_planei + imgi), transform=ax.transAxes, color="w") plotted_imgs[imgi] = [*plotted_imgs[imgi], text] if scale_bar: plot_support.add_scale_bar(ax, 1 / self.rescale, config.plane)
def plot_clusters_by_label(path, z, suffix=None, show=True, scaling=None): """Plot separate sets of clusters for each label. Args: path (str): Base path to blobs file with clusters. z (int): z-plane to plot. suffix (str): Suffix for ``path``; defaults to None. show (bool): True to show; defaults to True. scaling (List): Sequence of scaling from blobs' coordinate space to that of :attr:`config.labels_img`. """ mod_path = path if suffix is not None: mod_path = libmag.insert_before_ext(path, suffix) blobs = np.load(libmag.combine_paths(mod_path, config.SUFFIX_BLOB_CLUSTERS)) label_ids = np.unique(blobs[:, 3]) fig, gs = plot_support.setup_fig( 1, 1, config.plot_labels[config.PlotLabels.SIZE]) ax = fig.add_subplot(gs[0, 0]) plot_support.hide_axes(ax) # plot underlying atlas np_io.setup_images(mod_path) if config.reg_suffixes[config.RegSuffixes.ATLAS]: # use atlas if explicitly set img = config.image5d else: # default to black background img = np.zeros_like(config.labels_img)[None] stacker = export_stack.setup_stack(img, mod_path, slice_vals=(z, z + 1), labels_imgs=(config.labels_img, config.borders_img)) stacker.build_stack(ax, config.plot_labels[config.PlotLabels.SCALE_BAR]) # export_stack.reg_planes_to_img( # (np.zeros(config.labels_img.shape[1:], dtype=int), # config.labels_img[z]), ax=ax) if scaling is not None: print("scaling blobs cluster coordinates by", scaling) blobs = blobs.astype(float) blobs[:, :3] = np.multiply(blobs[:, :3], scaling) blobs[:, 0] = np.floor(blobs[:, 0]) # plot nuclei by label, colored based on cluster size within each label colors = colormaps.discrete_colormap(len(np.unique(blobs[:, 4])), prioritize_default="cn") / 255. col_noise = (1, 1, 1, 1) for label_id in label_ids: if label_id == 0: # skip blobs in background continue # sort blobs within label by cluster size (descending order), # including clusters within all z-planes to keep same order across zs blobs_lbl = blobs[blobs[:, 3] == label_id] clus_lbls, clus_lbls_counts = np.unique(blobs_lbl[:, 4], return_counts=True) clus_lbls = clus_lbls[np.argsort(clus_lbls_counts)][::-1] blobs_lbl = blobs_lbl[blobs_lbl[:, 0] == z] for i, (clus_lbl, color) in enumerate(zip(clus_lbls, colors)): blobs_clus = blobs_lbl[blobs_lbl[:, 4] == clus_lbl] if len(blobs_clus) < 1: continue # default to small, translucent dominant cluster points size = 0.1 alpha = 0.5 if clus_lbl == -1: # color all noise points the same and emphasize points color = col_noise size = 0.5 alpha = 1 print(label_id, clus_lbl, color, len(blobs_clus)) ax.scatter(blobs_clus[:, 2], blobs_clus[:, 1], color=color, s=size, alpha=alpha) plot_support.save_fig(mod_path, config.savefig, "_clusplot") if show: plot_support.show()
def _build_stack(ax, images, process_fnc, rescale=1, aspect=None, origin=None, cmaps_labels=None, scale_bar=True, start_planei=0): """Builds a stack of Matploblit 2D images. Uses multiprocessing to load or resize each image. Args: images: Sequence of images. For import, each "image" is a path to and image file. For export, each "image" is a sequence of planes, with the first sequence assumed to an atlas, followed by labels-based images, each consisting of corresponding planes. process_fnc: Function to process each image through multiprocessing, where the function should take an index and image and return the index and processed plane. rescale (float): Rescale factor; defaults to 1. cmaps_labels: Sequence of colormaps for labels-based images; defaults to None. Length should be equal to that of ``images`` - 1. scale_bar: True to include scale bar; defaults to True. start_planei (int): Index of start plane, used for labeling the plane; defaults to 0. The plane is only annotated when :attr:`config.plot_labels[config.PlotLabels.TEXT_POS]` is given to specify the position of the text in ``x,y`` relative to the axes. Returns: :List[List[:obj:`matplotlib.image.AxesImage`]]: Nested list of axes image objects. The first list level contains planes, and the second level are channels within each plane. """ # number of image types (eg atlas, labels) and corresponding planes num_image_types = len(images) if num_image_types < 1: return None num_images = len(images[0]) if num_images < 1: return None # Matplotlib figure for building the animation plot_support.hide_axes(ax) # import the images as Matplotlib artists via multiprocessing plotted_imgs = [None] * num_images img_shape = images[0][0].shape target_size = np.multiply(img_shape, rescale).astype(int) multichannel = images[0][0].ndim >= 3 if multichannel: print("building stack for channel: {}".format(config.channel)) target_size = target_size[:-1] StackPlaneIO.set_data(images) pool = chunking.get_mp_pool() pool_results = [] for i in range(num_images): # add rotation argument if necessary pool_results.append( pool.apply_async(process_fnc, args=(i, target_size))) # setup imshow parameters colorbar = config.roi_profile["colorbar"] cmaps_all = [config.cmaps, *cmaps_labels] img_size = None text_pos = config.plot_labels[config.PlotLabels.TEXT_POS] for result in pool_results: i, imgs = result.get() if img_size is None: img_size = imgs[0].shape # multiple artists can be shown at each frame by collecting # each group of artists in a list; overlay_images returns # a nested list containing a list for each image, which in turn # contains a list of artists for each channel ax_imgs = plot_support.overlay_images(ax, aspect, origin, imgs, None, cmaps_all, ignore_invis=True, check_single=True) if colorbar and len(ax_imgs) > 0 and len(ax_imgs[0]) > 0: # add colorbar with scientific notation if outside limits cbar = ax.figure.colorbar(ax_imgs[0][0], ax=ax, shrink=0.7) plot_support.set_scinot(cbar.ax, lbls=None, units=None) plotted_imgs[i] = np.array(ax_imgs).flatten() if libmag.is_seq(text_pos) and len(text_pos) > 1: # write plane index in axes rather than data coordinates text = ax.text(*text_pos[:2], "{}-plane: {}".format( plot_support.get_plane_axis(config.plane), start_planei + i), transform=ax.transAxes, color="w") plotted_imgs[i] = [*plotted_imgs[i], text] pool.close() pool.join() if scale_bar: plot_support.add_scale_bar(ax, 1 / rescale, config.plane) return plotted_imgs