Esempio n. 1
0
    def save(
        self,
        fname: Optional[str] = None,
        sigma_clip: Optional[float] = None,
        render: bool = True,
    ):
        r"""Saves a rendered image of the Scene to disk.

        Once you have created a scene, this saves an image array to disk with
        an optional filename. This function calls render() to generate an
        image array, unless the render parameter is set to False, in which case
        the most recently rendered scene is used if it exists.

        Parameters
        ----------
        fname: string, optional
            If specified, save the rendering as to the file "fname".
            If unspecified, it creates a default based on the dataset filename.
            The file format is inferred from the filename's suffix.
            Supported formats depend on which version of matplotlib is installed.

            Default: None
        sigma_clip: float, optional
            Image values greater than this number times the standard deviation
            plus the mean of the image will be clipped before saving. Useful
            for enhancing images as it gets rid of rare high pixel values.
            Default: None

            floor(vals > std_dev*sigma_clip + mean)
        render: boolean, optional
            If True, will always render the scene before saving.
            If False, will use results of previous render if it exists.
            Default: True

        Returns
        -------
            Nothing

        Examples
        --------

        >>> import yt
        >>> ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")

        >>> sc = yt.create_scene(ds)
        >>> # Modify camera, sources, etc...
        >>> sc.save("test.png", sigma_clip=4)

        When saving multiple images without modifying the scene (camera,
        sources,etc.), render=False can be used to avoid re-rendering.
        This is useful for generating images at a range of sigma_clip values:

        >>> import yt
        >>> ds = yt.load("IsolatedGalaxy/galaxy0030/galaxy0030")

        >>> sc = yt.create_scene(ds)
        >>> # save with different sigma clipping values
        >>> sc.save("raw.png")  # The initial render call happens here
        >>> sc.save("clipped_2.png", sigma_clip=2, render=False)
        >>> sc.save("clipped_4.png", sigma_clip=4, render=False)

        """
        fname = self._setup_save(fname, render)

        # We can render pngs natively but for other formats we defer to
        # matplotlib.
        if fname.endswith(".png"):
            self._last_render.write_png(fname, sigma_clip=sigma_clip)
        else:
            from matplotlib.figure import Figure

            shape = self._last_render.shape
            fig = Figure((shape[0] / 100.0, shape[1] / 100.0))
            canvas = get_canvas(fig, fname)

            ax = fig.add_axes([0, 0, 1, 1])
            ax.set_axis_off()
            out = self._last_render
            nz = out[:, :, :3][out[:, :, :3].nonzero()]
            max_val = nz.mean() + sigma_clip * nz.std()
            alpha = 255 * out[:, :, 3].astype("uint8")
            out = np.clip(out[:, :, :3] / max_val, 0.0, 1.0) * 255
            out = np.concatenate([out.astype("uint8"), alpha[..., None]],
                                 axis=-1)
            # not sure why we need rot90, but this makes the orientation
            # match the png writer
            ax.imshow(np.rot90(out), origin="lower")
            canvas.print_figure(fname, dpi=100)
Esempio n. 2
0
    def save_annotated(
        self,
        fname: Optional[str] = None,
        label_fmt: Optional[str] = None,
        text_annotate=None,
        dpi: int = 100,
        sigma_clip: Optional[float] = None,
        render: bool = True,
        tf_rect: Optional[List[float]] = None,
    ):
        r"""Saves the most recently rendered image of the Scene to disk,
        including an image of the transfer function and and user-defined
        text.

        Once you have created a scene and rendered that scene to an image
        array, this saves that image array to disk with an optional filename.
        If an image has not yet been rendered for the current scene object,
        it forces one and writes it out.

        Parameters
        ----------
        fname: string, optional
            If specified, save the rendering as a bitmap to the file "fname".
            If unspecified, it creates a default based on the dataset filename.
            Default: None
        sigma_clip: float, optional
            Image values greater than this number times the standard deviation
            plus the mean of the image will be clipped before saving. Useful
            for enhancing images as it gets rid of rare high pixel values.
            Default: None

            floor(vals > std_dev*sigma_clip + mean)
        dpi: integer, optional
            By default, the resulting image will be the same size as the camera
            parameters.  If you supply a dpi, then the image will be scaled
            accordingly (from the default 100 dpi)
        label_fmt : str, optional
           A format specifier (e.g., label_fmt="%.2g") to use in formatting
           the data values that label the transfer function colorbar.
        text_annotate : list of iterables
           Any text that you wish to display on the image.  This should be an
           list containing a tuple of coordinates (in normalized figure
           coordinates), the text to display, and, optionally, a dictionary of
           keyword/value pairs to pass through to the matplotlib text()
           function.

           Each item in the main list is a separate string to write.
        render: boolean, optional
            If True, will render the scene before saving.
            If False, will use results of previous render if it exists.
            Default: True
        tf_rect : sequence of floats, optional
           A rectangle that defines the location of the transfer
           function legend.  This is only used for the case where
           there are multiple volume sources with associated transfer
           functions.  tf_rect is of the form [x0, y0, width, height],
           in figure coordinates.

        Returns
        -------
            Nothing


        Examples
        --------

        >>> sc.save_annotated(
        ...     "fig.png",
        ...     text_annotate=[
        ...         [
        ...             (0.05, 0.05),
        ...             f"t = {ds.current_time.d}",
        ...             dict(horizontalalignment="left"),
        ...         ],
        ...         [
        ...             (0.5, 0.95),
        ...             "simulation title",
        ...             dict(color="y", fontsize="24", horizontalalignment="center"),
        ...         ],
        ...     ],
        ... )

        """
        fname = self._setup_save(fname, render)

        ax = self._show_mpl(self._last_render.swapaxes(0, 1),
                            sigma_clip=sigma_clip,
                            dpi=dpi)

        # number of transfer functions?
        num_trans_func = 0
        for rs in self._get_render_sources():
            if hasattr(rs, "transfer_function"):
                num_trans_func += 1

        # which transfer function?
        if num_trans_func == 1:
            rs = self._get_render_sources()[0]
            tf = rs.transfer_function
            label = rs.data_source.ds._get_field_info(rs.field).get_label()
            self._annotate(ax.axes, tf, rs, label=label, label_fmt=label_fmt)
        else:
            # set the origin and width and height of the colorbar region
            if tf_rect is None:
                tf_rect = [0.80, 0.12, 0.12, 0.9]
            cbx0, cby0, cbw, cbh = tf_rect

            cbh_each = cbh / num_trans_func

            for i, rs in enumerate(self._get_render_sources()):
                ax = self._render_figure.add_axes(
                    [cbx0, cby0 + i * cbh_each, 0.8 * cbw, 0.8 * cbh_each])
                try:
                    tf = rs.transfer_function
                except AttributeError:
                    pass
                else:
                    label = rs.data_source.ds._get_field_info(
                        rs.field).get_label()
                    self._annotate_multi(ax,
                                         tf,
                                         rs,
                                         label=label,
                                         label_fmt=label_fmt)

        # any text?
        if text_annotate is not None:
            f = self._render_figure
            for t in text_annotate:
                xy = t[0]
                string = t[1]
                if len(t) == 3:
                    opt = t[2]
                else:
                    opt = dict()

                # sane default
                if "color" not in opt:
                    opt["color"] = "w"

                ax.axes.text(xy[0],
                             xy[1],
                             string,
                             transform=f.transFigure,
                             **opt)

        self._render_figure.canvas = get_canvas(self._render_figure, fname)
        self._render_figure.tight_layout()
        self._render_figure.savefig(fname, facecolor="black", pad_inches=0)
Esempio n. 3
0
    def save_annotated(
        self,
        fname=None,
        label_fmt=None,
        text_annotate=None,
        dpi=100,
        sigma_clip=None,
        render=True,
    ):
        r"""Saves the most recently rendered image of the Scene to disk,
        including an image of the transfer function and and user-defined
        text.

        Once you have created a scene and rendered that scene to an image
        array, this saves that image array to disk with an optional filename.
        If an image has not yet been rendered for the current scene object,
        it forces one and writes it out.

        Parameters
        ----------
        fname: string, optional
            If specified, save the rendering as a bitmap to the file "fname".
            If unspecified, it creates a default based on the dataset filename.
            Default: None
        sigma_clip: float, optional
            Image values greater than this number times the standard deviation
            plus the mean of the image will be clipped before saving. Useful
            for enhancing images as it gets rid of rare high pixel values.
            Default: None

            floor(vals > std_dev*sigma_clip + mean)
        dpi: integer, optional
            By default, the resulting image will be the same size as the camera
            parameters.  If you supply a dpi, then the image will be scaled
            accordingly (from the default 100 dpi)
        label_fmt : str, optional
           A format specifier (e.g., label_fmt="%.2g") to use in formatting
           the data values that label the transfer function colorbar.
        text_annotate : list of iterables
           Any text that you wish to display on the image.  This should be an
           list containing a tuple of coordinates (in normalized figure
           coordinates), the text to display, and, optionally, a dictionary of
           keyword/value pairs to pass through to the matplotlib text()
           function.

           Each item in the main list is a separate string to write.
        render: boolean, optional
            If True, will render the scene before saving.
            If False, will use results of previous render if it exists.
            Default: True

        Returns
        -------
            Nothing


        Examples
        --------

        >>> sc.save_annotated("fig.png",
        ...                   text_annotate=[[(0.05, 0.05),
        ...                                   "t = {}".format(ds.current_time.d),
        ...                                   dict(horizontalalignment="left")],
        ...                                  [(0.5,0.95),
        ...                                   "simulation title",
        ...                                   dict(color="y", fontsize="24",
        ...                                        horizontalalignment="center")]])

        """
        fname = self._setup_save(fname, render)

        # which transfer function?
        rs = self._get_render_sources()[0]
        tf = rs.transfer_function
        label = rs.data_source.ds._get_field_info(rs.field).get_label()

        ax = self._show_mpl(self._last_render.swapaxes(0, 1),
                            sigma_clip=sigma_clip,
                            dpi=dpi)
        self._annotate(ax.axes, tf, rs, label=label, label_fmt=label_fmt)

        # any text?
        if text_annotate is not None:
            f = self._render_figure
            for t in text_annotate:
                xy = t[0]
                string = t[1]
                if len(t) == 3:
                    opt = t[2]
                else:
                    opt = dict()

                # sane default
                if "color" not in opt:
                    opt["color"] = "w"

                ax.axes.text(xy[0],
                             xy[1],
                             string,
                             transform=f.transFigure,
                             **opt)

        self._render_figure.canvas = get_canvas(self._render_figure, fname)
        self._render_figure.tight_layout()
        self._render_figure.savefig(fname, facecolor="black", pad_inches=0)