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)
Beispiel #2
0
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
Beispiel #3
0
    def show_overview(self):
        """Show the main 2D plane, taken as a z-plane."""
        # assume colorbar already shown if set and image previously displayed
        colorbar = (config.roi_profile["colorbar"]
                    and len(self.axes.images) < 1)
        self.axes.clear()
        self.hline = None
        self.vline = None

        # prep 2D image from main image, assumed to be an intensity image
        imgs2d = [self._get_img2d(0, self.img3d, self.max_intens_proj)]
        self._channels = [config.channel]
        cmaps = [config.cmaps]
        alphas = [config.alphas[0]]
        shapes = [self._img3d_shapes[0][1:3]]
        vmaxs = [None]
        vmins = [None]
        if self._plot_ax_imgs:
            # use settings from previously displayed images if available
            vmaxs[0] = [a.ax_img.norm.vmax for a in self._plot_ax_imgs[0]]
            vmins[0] = [a.ax_img.norm.vmin for a in self._plot_ax_imgs[0]]

        if self.img3d_labels is not None:
            # prep labels with discrete colormap and prior alpha if available
            imgs2d.append(self._get_img2d(1, self.img3d_labels))
            self._channels.append([0])
            cmaps.append(self.cmap_labels)
            alphas.append(self._ax_img_labels.get_alpha() if self.
                          _ax_img_labels else self.alpha)
            shapes.append(self._img3d_shapes[1][1:3])
            vmaxs.append(None)
            vmins.append(None)

        if self.img3d_borders is not None:
            # prep borders image, which may have an extra channels
            # dimension for multiple sets of borders
            img2d = self._get_img2d(2, self.img3d_borders)
            channels = img2d.ndim if img2d.ndim >= 3 else 1
            for i, channel in enumerate(range(channels - 1, -1, -1)):
                # show first (original) borders image last so that its
                # colormap values take precedence to highlight original bounds
                img_add = img2d[..., channel] if channels > 1 else img2d
                imgs2d.append(img_add)
                self._channels.append([0])
                cmaps.append(self.cmap_borders[channel])
                alphas.append(libmag.get_if_within(config.alphas, 2 + i, 1))
                shapes.append(self._img3d_shapes[2][1:3])
                vmaxs.append(None)
                vmins.append(None)

        if self.img3d_extras is not None:
            for i, img in enumerate(self.img3d_extras):
                # prep additional intensity image
                imgi = 3 + i
                imgs2d.append(self._get_img2d(imgi, img))
                self._channels.append([0])
                cmaps.append(("Greys", ))
                alphas.append(0.4)
                shapes.append(self._img3d_shapes[imgi][1:3])
                vmaxs.append(None)
                vmins.append(None)

        # overlay all images and set labels for footer value on mouseover;
        # if first time showing image, need to check for images with single
        # value since they fail to update on subsequent updates for unclear
        # reasons
        ax_imgs = plot_support.overlay_images(
            self.axes,
            self.aspect,
            self.origin,
            imgs2d,
            self._channels,
            cmaps,
            alphas,
            vmins,
            vmaxs,
            check_single=(self._ax_img_labels is None))
        if colorbar:
            self.axes.figure.colorbar(ax_imgs[0][0], ax=self.axes)
        self.axes.format_coord = pixel_display.PixelDisplay(
            imgs2d, ax_imgs, shapes, cmap_labels=self.cmap_labels)

        # trigger actual display through slider or call update directly
        if self.plane_slider:
            self.plane_slider.set_val(self.coord[0])
        else:
            self._update_overview(self.coord[0])
        self.show_roi()
        if self.scale_bar:
            plot_support.add_scale_bar(self.axes, self._downsample[0])

        # store displayed images
        if len(ax_imgs) > 1: self._ax_img_labels = ax_imgs[1][0]
        self._plot_ax_imgs = [[PlotAxImg(img) for img in imgs]
                              for imgs in ax_imgs]

        if self.xlim is not None and self.ylim is not None:
            # restore pan/zoom view
            self.axes.set_xlim(self.xlim)
            self.axes.set_ylim(self.ylim)
        if not self.connected:
            # connect once get AxesImage
            self.connect()
        # text label with color for visibility on axes plus fig background
        self.region_label = self.axes.text(0,
                                           0,
                                           "",
                                           color="k",
                                           bbox=dict(facecolor="xkcd:silver",
                                                     alpha=0.5))
        self.circle = None
Beispiel #4
0
    def show_overview(self):
        """Show the main 2D plane, taken as a z-plane."""
        self.axes.clear()
        self.hline = None
        self.vline = None

        # prep 2D image from main image, assumed to be an intensity image,
        # with settings for each channel within this main image
        imgs2d = [self._get_img2d(0, self.img3d, self.max_intens_proj)]
        self._channels = [config.channel]
        cmaps = [config.cmaps]
        alphas = [config.alphas[0]]
        alpha_blends = [None]
        shapes = [self._img3d_shapes[0][1:3]]
        vmaxs = [None]
        vmins = [None]
        brightnesses = [None]
        contrasts = [None]
        if self._plot_ax_imgs:
            # use vmin/vmax from norm values in previously displayed images
            # if available; None specifies auto-scaling
            vmaxs[0] = [
                p.vmax if p.vmax is None else p.ax_img.norm.vmax
                for p in self._plot_ax_imgs[0]
            ]
            vmins[0] = [
                p.vmin if p.vmin is None else p.ax_img.norm.vmin
                for p in self._plot_ax_imgs[0]
            ]

            # use opacity, brightness, anc contrast from prior images
            alphas[0] = [p.alpha for p in self._plot_ax_imgs[0]]
            alpha_blends[0] = [p.alpha_blend for p in self._plot_ax_imgs[0]]
            brightnesses[0] = [p.brightness for p in self._plot_ax_imgs[0]]
            contrasts[0] = [p.contrast for p in self._plot_ax_imgs[0]]

        if self.img3d_labels is not None:
            # prep labels with discrete colormap and prior alpha if available
            imgs2d.append(self._get_img2d(1, self.img3d_labels))
            self._channels.append([0])
            cmaps.append(self.cmap_labels)
            alphas.append(self._ax_img_labels.get_alpha() if self.
                          _ax_img_labels else self.alpha)
            alpha_blends.append(None)
            shapes.append(self._img3d_shapes[1][1:3])
            vmaxs.append(None)
            vmins.append(None)

        if self.img3d_borders is not None:
            # prep borders image, which may have an extra channels
            # dimension for multiple sets of borders
            img2d = self._get_img2d(2, self.img3d_borders)
            channels = img2d.ndim if img2d.ndim >= 3 else 1
            for i, channel in enumerate(range(channels - 1, -1, -1)):
                # show first (original) borders image last so that its
                # colormap values take precedence to highlight original bounds
                img_add = img2d[..., channel] if channels > 1 else img2d
                imgs2d.append(img_add)
                self._channels.append([0])
                cmaps.append(self.cmap_borders[channel])

                # get alpha for last corresponding borders plane if available
                ax_img = libmag.get_if_within(self._plot_ax_imgs, 2 + i, None)
                alpha = (ax_img[i].alpha if ax_img else libmag.get_if_within(
                    config.alphas, 2 + i, 1))
                alphas.append(alpha)
                alpha_blends.append(None)

                shapes.append(self._img3d_shapes[2][1:3])
                vmaxs.append(None)
                vmins.append(None)

        if self.img3d_extras is not None:
            for i, img in enumerate(self.img3d_extras):
                # prep additional intensity image
                imgi = 3 + i
                imgs2d.append(self._get_img2d(imgi, img))
                self._channels.append([0])
                cmaps.append(("Greys", ))
                alphas.append(0.4)
                alpha_blends.append(None)
                shapes.append(self._img3d_shapes[imgi][1:3])
                vmaxs.append(None)
                vmins.append(None)

        # overlay all images and set labels for footer value on mouseover;
        # if first time showing image, need to check for images with single
        # value since they fail to update on subsequent updates for unclear
        # reasons
        ax_imgs = plot_support.overlay_images(
            self.axes,
            self.aspect,
            self.origin,
            imgs2d,
            self._channels,
            cmaps,
            alphas,
            vmins,
            vmaxs,
            check_single=(self._ax_img_labels is None),
            alpha_blends=alpha_blends)

        # add or update colorbar
        colobar_prof = config.roi_profile["colorbar"]
        if self._colorbar:
            self._colorbar.update_normal(ax_imgs[0][0])
        elif colobar_prof:
            # store colorbar since it's tied to the artist, which will be
            # replaced with the next display and cannot be further accessed
            self._colorbar = self.axes.figure.colorbar(ax_imgs[0][0],
                                                       ax=self.axes,
                                                       **colobar_prof)

        # display coordinates and label values for each image
        self.axes.format_coord = pixel_display.PixelDisplay(
            imgs2d, ax_imgs, shapes, cmap_labels=self.cmap_labels)

        # trigger actual display through slider or call update directly
        if self.plane_slider:
            self.plane_slider.set_val(self.coord[0])
        else:
            self._update_overview(self.coord[0])
        self.show_roi()
        if self.scale_bar:
            plot_support.add_scale_bar(self.axes, self._downsample[0])

        # store displayed images in the PlotAxImg container class and update
        # displayed brightness/contrast
        if len(ax_imgs) > 1: self._ax_img_labels = ax_imgs[1][0]
        self._plot_ax_imgs = []
        for i, imgs in enumerate(ax_imgs):
            plot_ax_imgs = []
            for j, img in enumerate(imgs):
                plot_ax_img = PlotAxImg(img)
                if i == 0:
                    # specified vmin/vmax, in contrast to the AxesImages's
                    # norm, which holds the values used for the displayed image
                    plot_ax_img.vmin = libmag.get_if_within(vmins[i], j)
                    plot_ax_img.vmax = libmag.get_if_within(vmaxs[i], j)

                    # set brightness/contrast
                    self.change_brightness_contrast(
                        plot_ax_img, libmag.get_if_within(brightnesses[i], j),
                        libmag.get_if_within(contrasts[i], j))
                plot_ax_img.alpha = libmag.get_if_within(alphas[i], j)
                plot_ax_img.alpha_blend = libmag.get_if_within(
                    alpha_blends[i], j)
                plot_ax_imgs.append(plot_ax_img)
            self._plot_ax_imgs.append(plot_ax_imgs)

        if self.xlim is not None and self.ylim is not None:
            # restore pan/zoom view
            self.axes.set_xlim(self.xlim)
            self.axes.set_ylim(self.ylim)
        if not self.connected:
            # connect once get AxesImage
            self.connect()
        # text label with color for visibility on axes plus fig background
        self.region_label = self.axes.text(0,
                                           0,
                                           "",
                                           color="k",
                                           bbox=dict(facecolor="xkcd:silver",
                                                     alpha=0.5))
        self.circle = None