Beispiel #1
0
    def print_svg(self, filename, *args, **kwargs):
        if is_string_like(filename):
            with io.open(filename, 'w', encoding='utf-8') as svgwriter:
                return self._print_svg(filename, svgwriter, **kwargs)

        if not is_writable_file_like(filename):
            raise ValueError("filename must be a path or a file-like object")

        svgwriter = filename
        filename = getattr(svgwriter, 'name', '')
        if not isinstance(filename, six.string_types):
            filename = ''

        if not isinstance(svgwriter, io.TextIOBase):
            if six.PY3:
                svgwriter = io.TextIOWrapper(svgwriter, 'utf-8')
            else:
                svgwriter = codecs.getwriter('utf-8')(svgwriter)
            detach = True
        else:
            detach = False

        result = self._print_svg(filename, svgwriter, **kwargs)

        # Detach underlying stream from wrapper so that it remains open in the
        # caller.
        if detach:
            if six.PY3:
                svgwriter.detach()
            else:
                svgwriter.reset()
                svgwriter.stream = io.BytesIO()

        return result
    def _print_image(self, filename, format):
        if self.flags() & gtk.REALIZED == 0:
            # for self.window(for pixmap) and has a side effect of altering
            # figure width,height (via configure-event?)
            gtk.DrawingArea.realize(self)

        width, height = self.get_width_height()
        pixmap = gdk.Pixmap (self.window, width, height)
        self._renderer.set_pixmap (pixmap)
        self._render_figure(pixmap, width, height)

        # jpg colors don't match the display very well, png colors match
        # better
        pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height)
        pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(),
                                     0, 0, 0, 0, width, height)

        if is_string_like(filename):
            try:
                pixbuf.save(filename, format)
            except gobject.GError as exc:
                error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
        elif is_writable_file_like(filename):
            if hasattr(pixbuf, 'save_to_callback'):
                def save_callback(buf, data=None):
                    data.write(buf)
                try:
                    pixbuf.save_to_callback(save_callback, format, user_data=filename)
                except gobject.GError as exc:
                    error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
            else:
                raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8")
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #3
0
 def print_svg(self, filename, *args, **kwargs):
     if is_string_like(filename):
         fh_to_close = svgwriter = codecs.open(filename, "w", "utf-8")
     elif is_writable_file_like(filename):
         svgwriter = codecs.EncodedFile(filename, "utf-8")
         fh_to_close = None
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close)
Beispiel #4
0
 def print_svg(self, filename, *args, **kwargs):
     if is_string_like(filename):
         fh_to_close = svgwriter = io.open(filename, 'w', encoding='utf-8')
     elif is_writable_file_like(filename):
         svgwriter = io.TextIOWrapper(filename, encoding='utf-8')
         fh_to_close = None
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close, **kwargs)
Beispiel #5
0
 def print_svgz(self, filename, *args, **kwargs):
     if is_string_like(filename):
         gzipwriter = gzip.GzipFile(filename, "w")
         fh_to_close = svgwriter = codecs.EncodedFile(gzipwriter, "utf-8")
     elif is_writable_file_like(filename):
         fh_to_close = gzipwriter = gzip.GzipFile(fileobj=filename, mode="w")
         svgwriter = codecs.EncodedFile(gzipwriter, "utf-8")
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close)
Beispiel #6
0
    def print_svgz(self, filename, *args, **kwargs):
        if is_string_like(filename):
            options = dict(filename=filename)
        elif is_writable_file_like(filename):
            options = dict(fileobj=filename)
        else:
            raise ValueError("filename must be a path or a file-like object")

        with gzip.GzipFile(mode='w', **options) as gzipwriter:
            return self.print_svg(gzipwriter)
Beispiel #7
0
 def print_svgz(self, filename, *args, **kwargs):
     if is_string_like(filename):
         fh_to_close = gzipwriter = gzip.GzipFile(filename, 'w')
         svgwriter = io.TextIOWrapper(gzipwriter, 'utf-8')
     elif is_writable_file_like(filename):
         fh_to_close = gzipwriter = gzip.GzipFile(fileobj=filename, mode='w')
         svgwriter = io.TextIOWrapper(gzipwriter, 'utf-8')
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close)
 def print_png(self, fname_or_fh, *args, **kwargs):
     """
     Use LaTeX to compile a pgf figure to pdf and convert it to png.
     """
     if is_string_like(fname_or_fh):
         with open(fname_or_fh, "wb") as fh:
             self._print_png_to_fh(fh)
     elif is_writable_file_like(fname_or_fh):
         self._print_png_to_fh(fname_or_fh)
     else:
         raise ValueError("filename must be a path or a file-like object")
 def print_pdf(self, fname_or_fh, *args, **kwargs):
     """
     Use LaTeX to compile a Pgf generated figure to PDF.
     """
     # figure out where the pdf is to be written to
     if is_string_like(fname_or_fh):
         with open(fname_or_fh, "wb") as fh:
             self._print_pdf_to_fh(fh)
     elif is_writable_file_like(fname_or_fh):
         self._print_pdf_to_fh(fname_or_fh)
     else:
         raise ValueError("filename must be a path or a file-like object")
Beispiel #10
0
 def print_svg(self, filename, *args, **kwargs):
     if is_string_like(filename):
         fh_to_close = svgwriter = io.open(filename, "w", encoding="utf-8")
     elif is_writable_file_like(filename):
         if not isinstance(filename, io.TextIOBase):
             if sys.version_info[0] >= 3:
                 svgwriter = io.TextIOWrapper(filename, "utf-8")
             else:
                 svgwriter = codecs.getwriter("utf-8")(filename)
         fh_to_close = None
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close, **kwargs)
Beispiel #11
0
 def print_svg(self, filename, *args, **kwargs):
     if is_string_like(filename):
         fh_to_close = svgwriter = io.open(filename, 'w', encoding='utf-8')
     elif is_writable_file_like(filename):
         if not isinstance(filename, io.TextIOBase):
             if six.PY3:
                 svgwriter = io.TextIOWrapper(filename, 'utf-8')
             else:
                 svgwriter = codecs.getwriter('utf-8')(filename)
         else:
             svgwriter = filename
         fh_to_close = None
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_svg(filename, svgwriter, fh_to_close, **kwargs)
Beispiel #12
0
    def print_png(self, fname_or_fh, *args, **kwargs):
        """
        Use LaTeX to compile a pgf figure to pdf and convert it to png.
        """
        if kwargs.get("dryrun", False):
            self._print_pgf_to_fh(None, *args, **kwargs)
            return

        if isinstance(fname_or_fh, six.string_types):
            with open(fname_or_fh, "wb") as fh:
                self._print_png_to_fh(fh, *args, **kwargs)
        elif is_writable_file_like(fname_or_fh):
            self._print_png_to_fh(fname_or_fh, *args, **kwargs)
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #13
0
 def print_ipe(self, filename, *args, **kwargs):
     if isinstance(filename, string_types):
         fh_to_close = ipewriter = io.open(filename, 'w', encoding='utf-8')
     elif is_writable_file_like(filename):
         if not isinstance(filename, io.TextIOBase):
             if sys.version_info[0] >= 3:
                 ipewriter = io.TextIOWrapper(filename, 'utf-8')
             else:
                 ipewriter = codecs.getwriter('utf-8')(filename)
         else:
             ipewriter = filename
         fh_to_close = None
     else:
         raise ValueError("filename must be a path or a file-like object")
     return self._print_ipe(filename, ipewriter, fh_to_close, **kwargs)
Beispiel #14
0
    def print_pdf(self, fname_or_fh, *args, **kwargs):
        """
        Use LaTeX to compile a Pgf generated figure to PDF.
        """
        if kwargs.get("dryrun", False):
            self._print_pgf_to_fh(None, *args, **kwargs)
            return

        # figure out where the pdf is to be written to
        if isinstance(fname_or_fh, six.string_types):
            with open(fname_or_fh, "wb") as fh:
                self._print_pdf_to_fh(fh, *args, **kwargs)
        elif is_writable_file_like(fname_or_fh):
            self._print_pdf_to_fh(fname_or_fh, *args, **kwargs)
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #15
0
    def print_pgf(self, fname_or_fh, *args, **kwargs):
        """
        Output pgf commands for drawing the figure so it can be included and
        rendered in latex documents.
        """
        if kwargs.get("dryrun", False): return

        # figure out where the pgf is to be written to
        if is_string_like(fname_or_fh):
            with codecs.open(fname_or_fh, "w", encoding="utf-8") as fh:
                self._print_pgf_to_fh(fh)
        elif is_writable_file_like(fname_or_fh):
            raise ValueError("saving pgf to a stream is not supported, " + \
            "consider using the pdf option of the pgf-backend")
        else:
            raise ValueError("filename must be a path")
Beispiel #16
0
    def print_pgf(self, fname_or_fh, *args, **kwargs):
        """
        Output pgf commands for drawing the figure so it can be included and
        rendered in latex documents.
        """
        if kwargs.get("dryrun", False):
            self._print_pgf_to_fh(None, *args, **kwargs)
            return

        # figure out where the pgf is to be written to
        if is_string_like(fname_or_fh):
            with codecs.open(fname_or_fh, "w", encoding="utf-8") as fh:
                self._print_pgf_to_fh(fh, *args, **kwargs)
        elif is_writable_file_like(fname_or_fh):
            fh = codecs.getwriter("utf-8")(fname_or_fh)
            self._print_pgf_to_fh(fh, *args, **kwargs)
        else:
            raise ValueError("filename must be a path")
Beispiel #17
0
    def _print_image(self, filename, format, *args, **kwargs):
        if self.flags() & gtk.REALIZED == 0:
            # for self.window(for pixmap) and has a side effect of altering
            # figure width,height (via configure-event?)
            gtk.DrawingArea.realize(self)

        width, height = self.get_width_height()
        pixmap = gdk.Pixmap(self.window, width, height)
        self._renderer.set_pixmap(pixmap)
        self._render_figure(pixmap, width, height)

        # jpg colors don't match the display very well, png colors match
        # better
        pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height)
        pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, width, height)

        # set the default quality, if we are writing a JPEG.
        # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save
        options = cbook.restrict_dict(kwargs, ["quality"])
        if format in ["jpg", "jpeg"]:
            if "quality" not in options:
                options["quality"] = rcParams["savefig.jpeg_quality"]

            options["quality"] = str(options["quality"])

        if is_string_like(filename):
            try:
                pixbuf.save(filename, format, options=options)
            except gobject.GError as exc:
                error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self)
        elif is_writable_file_like(filename):
            if hasattr(pixbuf, "save_to_callback"):

                def save_callback(buf, data=None):
                    data.write(buf)

                try:
                    pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options)
                except gobject.GError as exc:
                    error_msg_gtk("Save figure failure:\n%s" % (exc,), parent=self)
            else:
                raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8")
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #18
0
    def _print_image(self, filename, format):
        if self.flags() & gtk.REALIZED == 0:
            # for self.window(for pixmap) and has a side effect of altering
            # figure width,height (via configure-event?)
            gtk.DrawingArea.realize(self)

        width, height = self.get_width_height()
        pixmap = gdk.Pixmap(self.window, width, height)
        self._renderer.set_pixmap(pixmap)
        self._render_figure(pixmap, width, height)

        # jpg colors don't match the display very well, png colors match
        # better
        pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height)
        pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0,
                                 width, height)

        if is_string_like(filename):
            try:
                pixbuf.save(filename, format)
            except gobject.GError as exc:
                error_msg_gtk('Save figure failure:\n%s' % (exc, ),
                              parent=self)
        elif is_writable_file_like(filename):
            if hasattr(pixbuf, 'save_to_callback'):

                def save_callback(buf, data=None):
                    data.write(buf)

                try:
                    pixbuf.save_to_callback(save_callback,
                                            format,
                                            user_data=filename)
                except gobject.GError as exc:
                    error_msg_gtk('Save figure failure:\n%s' % (exc, ),
                                  parent=self)
            else:
                raise ValueError(
                    "Saving to a Python file-like object is only supported by PyGTK >= 2.8"
                )
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #19
0
    def _print_image(self, filename, format, *args, **kwargs):
        if self.flags() & gtk.REALIZED == 0:
            # for self.window(for pixmap) and has a side effect of altering
            # figure width,height (via configure-event?)
            gtk.DrawingArea.realize(self)

        width, height = self.get_width_height()
        pixmap = gdk.Pixmap (self.window, width, height)
        self._renderer.set_pixmap (pixmap)
        self._render_figure(pixmap, width, height)

        # jpg colors don't match the display very well, png colors match
        # better
        pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height)
        pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(),
                                     0, 0, 0, 0, width, height)

        # set the default quality, if we are writing a JPEG.
        # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save
        options = {k: kwargs[k] for k in ['quality'] if k in kwargs}
        if format in ['jpg', 'jpeg']:
            options.setdefault('quality', rcParams['savefig.jpeg_quality'])
            options['quality'] = str(options['quality'])

        if isinstance(filename, six.string_types):
            try:
                pixbuf.save(filename, format, options=options)
            except gobject.GError as exc:
                error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
        elif is_writable_file_like(filename):
            if hasattr(pixbuf, 'save_to_callback'):
                def save_callback(buf, data=None):
                    data.write(buf)
                try:
                    pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options)
                except gobject.GError as exc:
                    error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
            else:
                raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8")
        else:
            raise ValueError("filename must be a path or a file-like object")
Beispiel #20
0
    def print_pgf(self, fname_or_fh, *args, **kwargs):
        """
        Output pgf commands for drawing the figure so it can be included and
        rendered in latex documents.
        """
        if kwargs.get("dryrun", False):
            self._print_pgf_to_fh(None, *args, **kwargs)
            return

        # figure out where the pgf is to be written to
        if is_string_like(fname_or_fh):
            with codecs.open(fname_or_fh, "w", encoding="utf-8") as fh:
                self._print_pgf_to_fh(fh, *args, **kwargs)
        elif is_writable_file_like(fname_or_fh):
            if not os.path.exists(fname_or_fh.name):
                warnings.warn("streamed pgf-code does not support raster "
                              "graphics, consider using the pgf-to-pdf option",
                              UserWarning)
            self._print_pgf_to_fh(fname_or_fh, *args, **kwargs)
        else:
            raise ValueError("filename must be a path")
Beispiel #21
0
    def print_pgf(self, fname_or_fh, *args, **kwargs):
        """
        Output pgf commands for drawing the figure so it can be included and
        rendered in latex documents.
        """
        if kwargs.get("dryrun", False):
            self._print_pgf_to_fh(None, *args, **kwargs)
            return

        # figure out where the pgf is to be written to
        if is_string_like(fname_or_fh):
            with codecs.open(fname_or_fh, "w", encoding="utf-8") as fh:
                self._print_pgf_to_fh(fh, *args, **kwargs)
        elif is_writable_file_like(fname_or_fh):
            if not os.path.exists(fname_or_fh.name):
                warnings.warn("streamed pgf-code does not support raster "
                              "graphics, consider using the pgf-to-pdf option",
                              UserWarning)
            self._print_pgf_to_fh(fname_or_fh, *args, **kwargs)
        else:
            raise ValueError("filename must be a path")
Beispiel #22
0
    def _print_figure(
            self, outfile, format, *,
            dpi, dsc_comments, orientation, papertype,
            dryrun=False, bbox_inches_restore=None):
        """
        Render the figure to a filesystem path or a file-like object.

        Parameters are as for `.print_figure`, except that *dsc_comments* is a
        all string containing Document Structuring Convention comments,
        generated from the *metadata* parameter to `.print_figure`.
        """
        is_eps = format == 'eps'
        if isinstance(outfile, (str, os.PathLike)):
            outfile = os.fspath(outfile)
            passed_in_file_object = False
        elif is_writable_file_like(outfile):
            passed_in_file_object = True
        else:
            raise ValueError("outfile must be a path or a file-like object")

        # find the appropriate papertype
        width, height = self.figure.get_size_inches()
        if papertype == 'auto':
            papertype = _get_papertype(
                *orientation.swap_if_landscape((width, height)))
        paper_width, paper_height = orientation.swap_if_landscape(
            papersize[papertype])

        if mpl.rcParams['ps.usedistiller']:
            # distillers improperly clip eps files if pagesize is too small
            if width > paper_width or height > paper_height:
                papertype = _get_papertype(
                    *orientation.swap_if_landscape(width, height))
                paper_width, paper_height = orientation.swap_if_landscape(
                    papersize[papertype])

        # center the figure on the paper
        xo = 72 * 0.5 * (paper_width - width)
        yo = 72 * 0.5 * (paper_height - height)

        llx = xo
        lly = yo
        urx = llx + self.figure.bbox.width
        ury = lly + self.figure.bbox.height
        rotation = 0
        if orientation is _Orientation.landscape:
            llx, lly, urx, ury = lly, llx, ury, urx
            xo, yo = 72 * paper_height - yo, xo
            rotation = 90
        bbox = (llx, lly, urx, ury)

        if dryrun:
            class NullWriter:
                def write(self, *args, **kwargs):
                    pass

            self._pswriter = NullWriter()
        else:
            self._pswriter = StringIO()

        # mixed mode rendering
        ps_renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        renderer = MixedModeRenderer(
            self.figure, width, height, dpi, ps_renderer,
            bbox_inches_restore=bbox_inches_restore)

        self.figure.draw(renderer)

        if dryrun:  # return immediately if dryrun (tightbbox=True)
            return

        def print_figure_impl(fh):
            # write the PostScript headers
            if is_eps:
                print("%!PS-Adobe-3.0 EPSF-3.0", file=fh)
            else:
                print(f"%!PS-Adobe-3.0\n"
                      f"%%DocumentPaperSizes: {papertype}\n"
                      f"%%Pages: 1\n",
                      end="", file=fh)
            print(f"{dsc_comments}\n"
                  f"%%Orientation: {orientation.name}\n"
                  f"%%BoundingBox: {bbox[0]} {bbox[1]} {bbox[2]} {bbox[3]}\n"
                  f"%%EndComments\n",
                  end="", file=fh)

            Ndict = len(psDefs)
            print("%%BeginProlog", file=fh)
            if not mpl.rcParams['ps.useafm']:
                Ndict += len(ps_renderer._character_tracker.used)
            print("/mpldict %d dict def" % Ndict, file=fh)
            print("mpldict begin", file=fh)
            print("\n".join(psDefs), file=fh)
            if not mpl.rcParams['ps.useafm']:
                for font_path, chars \
                        in ps_renderer._character_tracker.used.items():
                    if not chars:
                        continue
                    font = get_font(font_path)
                    glyph_ids = [font.get_char_index(c) for c in chars]
                    fonttype = mpl.rcParams['ps.fonttype']
                    # Can't use more than 255 chars from a single Type 3 font.
                    if len(glyph_ids) > 255:
                        fonttype = 42
                    # The ttf to ps (subsetting) support doesn't work for
                    # OpenType fonts that are Postscript inside (like the STIX
                    # fonts).  This will simply turn that off to avoid errors.
                    if is_opentype_cff_font(font_path):
                        raise RuntimeError(
                            "OpenType CFF fonts can not be saved using "
                            "the internal Postscript backend at this "
                            "time; consider using the Cairo backend")
                    fh.flush()
                    try:
                        convert_ttf_to_ps(os.fsencode(font_path),
                                          fh, fonttype, glyph_ids)
                    except RuntimeError:
                        _log.warning("The PostScript backend does not "
                                     "currently support the selected font.")
                        raise
            print("end", file=fh)
            print("%%EndProlog", file=fh)

            if not is_eps:
                print("%%Page: 1 1", file=fh)
            print("mpldict begin", file=fh)

            print("%s translate" % _nums_to_str(xo, yo), file=fh)
            if rotation:
                print("%d rotate" % rotation, file=fh)
            print("%s clipbox" % _nums_to_str(width*72, height*72, 0, 0),
                  file=fh)

            # write the figure
            print(self._pswriter.getvalue(), file=fh)

            # write the trailer
            print("end", file=fh)
            print("showpage", file=fh)
            if not is_eps:
                print("%%EOF", file=fh)
            fh.flush()

        if mpl.rcParams['ps.usedistiller']:
            # We are going to use an external program to process the output.
            # Write to a temporary file.
            with TemporaryDirectory() as tmpdir:
                tmpfile = os.path.join(tmpdir, "tmp.ps")
                with open(tmpfile, 'w', encoding='latin-1') as fh:
                    print_figure_impl(fh)
                if mpl.rcParams['ps.usedistiller'] == 'ghostscript':
                    _try_distill(gs_distill,
                                 tmpfile, is_eps, ptype=papertype, bbox=bbox)
                elif mpl.rcParams['ps.usedistiller'] == 'xpdf':
                    _try_distill(xpdf_distill,
                                 tmpfile, is_eps, ptype=papertype, bbox=bbox)
                _move_path_to_path_or_stream(tmpfile, outfile)

        else:
            # Write directly to outfile.
            if passed_in_file_object:
                requires_unicode = file_requires_unicode(outfile)

                if not requires_unicode:
                    fh = TextIOWrapper(outfile, encoding="latin-1")
                    # Prevent the TextIOWrapper from closing the underlying
                    # file.
                    fh.close = lambda: None
                else:
                    fh = outfile

                print_figure_impl(fh)
            else:
                with open(outfile, 'w', encoding='latin-1') as fh:
                    print_figure_impl(fh)
Beispiel #23
0
    def _print_figure(self,
                      outfile,
                      format,
                      dpi=72,
                      facecolor='w',
                      edgecolor='w',
                      orientation='portrait',
                      isLandscape=False,
                      papertype=None):
        """
        Render the figure to hardcopy.  Set the figure patch face and
        edge colors.  This is useful because some of the GUIs have a
        gray figure face color background and you'll probably want to
        override this on hardcopy

        If outfile is a string, it is interpreted as a file name.
        If the extension matches .ep* write encapsulated postscript,
        otherwise write a stand-alone PostScript file.

        If outfile is a file object, a stand-alone PostScript file is
        written into this file object.
        """
        isEPSF = format == 'eps'
        passed_in_file_object = False
        if is_string_like(outfile):
            title = outfile
            tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest())
        elif is_writable_file_like(outfile):
            title = None
            tmpfile = os.path.join(gettempdir(),
                                   md5(str(hash(outfile))).hexdigest())
            passed_in_file_object = True
        else:
            raise ValueError("outfile must be a path or a file-like object")
        fh = file(tmpfile, 'w')

        # find the appropriate papertype
        width, height = self.figure.get_size_inches()
        if papertype == 'auto':
            if isLandscape: papertype = _get_papertype(height, width)
            else: papertype = _get_papertype(width, height)

        if isLandscape: paperHeight, paperWidth = papersize[papertype]
        else: paperWidth, paperHeight = papersize[papertype]

        if rcParams['ps.usedistiller'] and not papertype == 'auto':
            # distillers will improperly clip eps files if the pagesize is
            # too small
            if width > paperWidth or height > paperHeight:
                if isLandscape:
                    papertype = _get_papertype(height, width)
                    paperHeight, paperWidth = papersize[papertype]
                else:
                    papertype = _get_papertype(width, height)
                    paperWidth, paperHeight = papersize[papertype]

        # center the figure on the paper
        xo = 72 * 0.5 * (paperWidth - width)
        yo = 72 * 0.5 * (paperHeight - height)

        l, b, w, h = self.figure.bbox.bounds
        llx = xo
        lly = yo
        urx = llx + w
        ury = lly + h
        rotation = 0
        if isLandscape:
            llx, lly, urx, ury = lly, llx, ury, urx
            xo, yo = 72 * paperHeight - yo, xo
            rotation = 90
        bbox = (llx, lly, urx, ury)

        # generate PostScript code for the figure and store it in a string
        origfacecolor = self.figure.get_facecolor()
        origedgecolor = self.figure.get_edgecolor()
        self.figure.set_facecolor(facecolor)
        self.figure.set_edgecolor(edgecolor)

        self._pswriter = StringIO()
        renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        self.figure.draw(renderer)

        self.figure.set_facecolor(origfacecolor)
        self.figure.set_edgecolor(origedgecolor)

        # write the PostScript headers
        if isEPSF: print >> fh, "%!PS-Adobe-3.0 EPSF-3.0"
        else: print >> fh, "%!PS-Adobe-3.0"
        if title: print >> fh, "%%Title: " + title
        print >> fh, ("%%Creator: matplotlib version " + __version__ +
                      ", http://matplotlib.sourceforge.net/")
        print >> fh, "%%CreationDate: " + time.ctime(time.time())
        print >> fh, "%%Orientation: " + orientation
        if not isEPSF: print >> fh, "%%DocumentPaperSizes: " + papertype
        print >> fh, "%%%%BoundingBox: %d %d %d %d" % bbox
        if not isEPSF: print >> fh, "%%Pages: 1"
        print >> fh, "%%EndComments"

        Ndict = len(psDefs)
        print >> fh, "%%BeginProlog"
        if not rcParams['ps.useafm']:
            Ndict += len(renderer.used_characters)
        print >> fh, "/mpldict %d dict def" % Ndict
        print >> fh, "mpldict begin"
        for d in psDefs:
            d = d.strip()
            for l in d.split('\n'):
                print >> fh, l.strip()
        if not rcParams['ps.useafm']:
            for font_filename, chars in renderer.used_characters.values():
                if len(chars):
                    font = FT2Font(font_filename)
                    cmap = font.get_charmap()
                    glyph_ids = []
                    for c in chars:
                        gind = cmap.get(c) or 0
                        glyph_ids.append(gind)
                    # The ttf to ps (subsetting) support doesn't work for
                    # OpenType fonts that are Postscript inside (like the
                    # STIX fonts).  This will simply turn that off to avoid
                    # errors.
                    if is_opentype_cff_font(font_filename):
                        raise RuntimeError(
                            "OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend."
                        )
                    else:
                        fonttype = rcParams['ps.fonttype']
                        convert_ttf_to_ps(font_filename, fh,
                                          rcParams['ps.fonttype'], glyph_ids)
        print >> fh, "end"
        print >> fh, "%%EndProlog"

        if not isEPSF: print >> fh, "%%Page: 1 1"
        print >> fh, "mpldict begin"
        #print >>fh, "gsave"
        print >> fh, "%s translate" % _nums_to_str(xo, yo)
        if rotation: print >> fh, "%d rotate" % rotation
        print >> fh, "%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0)

        # write the figure
        print >> fh, self._pswriter.getvalue()

        # write the trailer
        #print >>fh, "grestore"
        print >> fh, "end"
        print >> fh, "showpage"
        if not isEPSF: print >> fh, "%%EOF"
        fh.close()

        if rcParams['ps.usedistiller'] == 'ghostscript':
            gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)
        elif rcParams['ps.usedistiller'] == 'xpdf':
            xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)

        if passed_in_file_object:
            fh = file(tmpfile)
            print >> outfile, fh.read()
        else:
            shutil.move(tmpfile, outfile)
Beispiel #24
0
 def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
                   orientation='portrait', isLandscape=False, papertype=None,
                   **kwargs):
     """
     Render the figure to hardcopy.  Set the figure patch face and
     edge colors.  This is useful because some of the GUIs have a
     gray figure face color background and you'll probably want to
     override this on hardcopy
     If outfile is a string, it is interpreted as a file name.
     If the extension matches .ep* write encapsulated postscript,
     otherwise write a stand-alone PostScript file.
     If outfile is a file object, a stand-alone PostScript file is
     written into this file object.
     """
     isEPSF = format == 'eps'
     passed_in_file_object = False
     fd, tmpfile = mkstemp()
     if is_string_like(outfile):
         title = outfile
     elif is_writable_file_like(outfile):
         title = None
         passed_in_file_object = True
     else:
         raise ValueError("outfile must be a path or a file-like object")
     os.close(fd)
     fh = file(tmpfile, 'w')
     width, height = self.figure.get_size_inches()
     if papertype == 'auto':
         if isLandscape: papertype = _get_papertype(height, width)
         else: papertype = _get_papertype(width, height)
     if isLandscape: paperHeight, paperWidth = papersize[papertype]
     else: paperWidth, paperHeight = papersize[papertype]
     if rcParams['ps.usedistiller'] and not papertype == 'auto':
         if width>paperWidth or height>paperHeight:
             if isLandscape:
                 papertype = _get_papertype(height, width)
                 paperHeight, paperWidth = papersize[papertype]
             else:
                 papertype = _get_papertype(width, height)
                 paperWidth, paperHeight = papersize[papertype]
     xo = 72*0.5*(paperWidth - width)
     yo = 72*0.5*(paperHeight - height)
     l, b, w, h = self.figure.bbox.bounds
     llx = xo
     lly = yo
     urx = llx + w
     ury = lly + h
     rotation = 0
     if isLandscape:
         llx, lly, urx, ury = lly, llx, ury, urx
         xo, yo = 72*paperHeight - yo, xo
         rotation = 90
     bbox = (llx, lly, urx, ury)
     origfacecolor = self.figure.get_facecolor()
     origedgecolor = self.figure.get_edgecolor()
     self.figure.set_facecolor(facecolor)
     self.figure.set_edgecolor(edgecolor)
     dryrun = kwargs.get("dryrun", False)
     if dryrun:
         class NullWriter(object):
             def write(self, *kl, **kwargs):
                 pass
         self._pswriter = NullWriter()
     else:
         self._pswriter = StringIO()
     _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None)
     ps_renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
     renderer = MixedModeRenderer(self.figure,
         width, height, dpi, ps_renderer,
         bbox_inches_restore=_bbox_inches_restore)
     self.figure.draw(renderer)
     if dryrun: # return immediately if dryrun (tightbbox=True)
         return
     self.figure.set_facecolor(origfacecolor)
     self.figure.set_edgecolor(origedgecolor)
     if isEPSF: print >>fh, "%!PS-Adobe-3.0 EPSF-3.0"
     else: print >>fh, "%!PS-Adobe-3.0"
     if title: print >>fh, "%%Title: "+title
     print >>fh, ("%%Creator: matplotlib version "
                  +__version__+", http://matplotlib.sourceforge.net/")
     print >>fh, "%%CreationDate: "+time.ctime(time.time())
     print >>fh, "%%Orientation: " + orientation
     if not isEPSF: print >>fh, "%%DocumentPaperSizes: "+papertype
     print >>fh, "%%%%BoundingBox: %d %d %d %d" % bbox
     if not isEPSF: print >>fh, "%%Pages: 1"
     print >>fh, "%%EndComments"
     Ndict = len(psDefs)
     print >>fh, "%%BeginProlog"
     if not rcParams['ps.useafm']:
         Ndict += len(ps_renderer.used_characters)
     print >>fh, "/mpldict %d dict def"%Ndict
     print >>fh, "mpldict begin"
     for d in psDefs:
         d=d.strip()
         for l in d.split('\n'):
             print >>fh, l.strip()
     if not rcParams['ps.useafm']:
         for font_filename, chars in ps_renderer.used_characters.values():
             if len(chars):
                 font = FT2Font(font_filename)
                 cmap = font.get_charmap()
                 glyph_ids = []
                 for c in chars:
                     gind = cmap.get(c) or 0
                     glyph_ids.append(gind)
                 if is_opentype_cff_font(font_filename):
                     raise RuntimeError("OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend.")
                 else:
                     fonttype = rcParams['ps.fonttype']
                     convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
     print >>fh, "end"
     print >>fh, "%%EndProlog"
     if not isEPSF: print >>fh, "%%Page: 1 1"
     print >>fh, "mpldict begin"
     print >>fh, "%s translate"%_nums_to_str(xo, yo)
     if rotation: print >>fh, "%d rotate"%rotation
     print >>fh, "%s clipbox"%_nums_to_str(width*72, height*72, 0, 0)
     print >>fh, self._pswriter.getvalue()
     print >>fh, "end"
     print >>fh, "showpage"
     if not isEPSF: print >>fh, "%%EOF"
     fh.close()
     if rcParams['ps.usedistiller'] == 'ghostscript':
         gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)
     elif rcParams['ps.usedistiller'] == 'xpdf':
         xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)
     if passed_in_file_object:
         fh = file(tmpfile)
         print >>outfile, fh.read()
     else:
         shutil.move(tmpfile, outfile)
Beispiel #25
0
class FigureCanvasGTK(gtk.DrawingArea, FigureCanvasBase):
    keyvald = {
        65507: 'control',
        65505: 'shift',
        65513: 'alt',
        65508: 'control',
        65506: 'shift',
        65514: 'alt',
        65361: 'left',
        65362: 'up',
        65363: 'right',
        65364: 'down',
        65307: 'escape',
        65470: 'f1',
        65471: 'f2',
        65472: 'f3',
        65473: 'f4',
        65474: 'f5',
        65475: 'f6',
        65476: 'f7',
        65477: 'f8',
        65478: 'f9',
        65479: 'f10',
        65480: 'f11',
        65481: 'f12',
        65300: 'scroll_lock',
        65299: 'break',
        65288: 'backspace',
        65293: 'enter',
        65379: 'insert',
        65535: 'delete',
        65360: 'home',
        65367: 'end',
        65365: 'pageup',
        65366: 'pagedown',
        65438: '0',
        65436: '1',
        65433: '2',
        65435: '3',
        65430: '4',
        65437: '5',
        65432: '6',
        65429: '7',
        65431: '8',
        65434: '9',
        65451: '+',
        65453: '-',
        65450: '*',
        65455: '/',
        65439: 'dec',
        65421: 'enter',
    }

    # Setting this as a static constant prevents
    # this resulting expression from leaking
    event_mask = (gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK
                  | gdk.EXPOSURE_MASK | gdk.KEY_PRESS_MASK
                  | gdk.KEY_RELEASE_MASK | gdk.ENTER_NOTIFY_MASK
                  | gdk.LEAVE_NOTIFY_MASK | gdk.POINTER_MOTION_MASK
                  | gdk.POINTER_MOTION_HINT_MASK)

    def __init__(self, figure):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        FigureCanvasBase.__init__(self, figure)
        gtk.DrawingArea.__init__(self)

        self._idle_draw_id = 0
        self._need_redraw = True
        self._pixmap_width = -1
        self._pixmap_height = -1
        self._lastCursor = None

        self.connect('scroll_event', self.scroll_event)
        self.connect('button_press_event', self.button_press_event)
        self.connect('button_release_event', self.button_release_event)
        self.connect('configure_event', self.configure_event)
        self.connect('expose_event', self.expose_event)
        self.connect('key_press_event', self.key_press_event)
        self.connect('key_release_event', self.key_release_event)
        self.connect('motion_notify_event', self.motion_notify_event)
        self.connect('leave_notify_event', self.leave_notify_event)
        self.connect('enter_notify_event', self.enter_notify_event)

        self.set_events(self.__class__.event_mask)

        self.set_double_buffered(False)
        self.set_flags(gtk.CAN_FOCUS)
        self._renderer_init()

        self._idle_event_id = gobject.idle_add(self.idle_event)

    def destroy(self):
        #gtk.DrawingArea.destroy(self)
        gobject.source_remove(self._idle_event_id)
        if self._idle_draw_id != 0:
            gobject.source_remove(self._idle_draw_id)

    def scroll_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        x = event.x
        # flipy so y=0 is bottom of canvas
        y = self.allocation.height - event.y
        if event.direction == gdk.SCROLL_UP:
            step = 1
        else:
            step = -1
        FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event)
        return False  # finish event propagation?

    def button_press_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        x = event.x
        # flipy so y=0 is bottom of canvas
        y = self.allocation.height - event.y
        FigureCanvasBase.button_press_event(self,
                                            x,
                                            y,
                                            event.button,
                                            guiEvent=event)
        return False  # finish event propagation?

    def button_release_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        x = event.x
        # flipy so y=0 is bottom of canvas
        y = self.allocation.height - event.y
        FigureCanvasBase.button_release_event(self,
                                              x,
                                              y,
                                              event.button,
                                              guiEvent=event)
        return False  # finish event propagation?

    def key_press_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        key = self._get_key(event)
        if _debug: print "hit", key
        FigureCanvasBase.key_press_event(self, key, guiEvent=event)
        return False  # finish event propagation?

    def key_release_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        key = self._get_key(event)
        if _debug: print "release", key
        FigureCanvasBase.key_release_event(self, key, guiEvent=event)
        return False  # finish event propagation?

    def motion_notify_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        if event.is_hint:
            x, y, state = event.window.get_pointer()
        else:
            x, y, state = event.x, event.y, event.state

        # flipy so y=0 is bottom of canvas
        y = self.allocation.height - y
        FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event)
        return False  # finish event propagation?

    def leave_notify_event(self, widget, event):
        FigureCanvasBase.leave_notify_event(self, event)

    def enter_notify_event(self, widget, event):
        FigureCanvasBase.enter_notify_event(self, event)

    def _get_key(self, event):
        if event.keyval in self.keyvald:
            key = self.keyvald[event.keyval]
        elif event.keyval < 256:
            key = chr(event.keyval)
        else:
            key = None

        ctrl = event.state & gdk.CONTROL_MASK
        shift = event.state & gdk.SHIFT_MASK
        return key

    def configure_event(self, widget, event):
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()
        if widget.window is None:
            return
        w, h = event.width, event.height
        if w < 3 or h < 3:
            return  # empty fig

        # resize the figure (in inches)
        dpi = self.figure.dpi
        self.figure.set_size_inches(w / dpi, h / dpi)
        self._need_redraw = True

        return False  # finish event propagation?

    def draw(self):
        # Note: FigureCanvasBase.draw() is inconveniently named as it clashes
        # with the deprecated gtk.Widget.draw()

        self._need_redraw = True
        if GTK_WIDGET_DRAWABLE(self):
            self.queue_draw()
            # do a synchronous draw (its less efficient than an async draw,
            # but is required if/when animation is used)
            self.window.process_updates(False)

    def draw_idle(self):
        def idle_draw(*args):
            self.draw()
            self._idle_draw_id = 0
            return False

        if self._idle_draw_id == 0:
            self._idle_draw_id = gobject.idle_add(idle_draw)

    def _renderer_init(self):
        """Override by GTK backends to select a different renderer
        Renderer should provide the methods:
            set_pixmap ()
            set_width_height ()
        that are used by
            _render_figure() / _pixmap_prepare()
        """
        self._renderer = RendererGDK(self, self.figure.dpi)

    def _pixmap_prepare(self, width, height):
        """
        Make sure _._pixmap is at least width, height,
        create new pixmap if necessary
        """
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()

        create_pixmap = False
        if width > self._pixmap_width:
            # increase the pixmap in 10%+ (rather than 1 pixel) steps
            self._pixmap_width = max(int(self._pixmap_width * 1.1), width)
            create_pixmap = True

        if height > self._pixmap_height:
            self._pixmap_height = max(int(self._pixmap_height * 1.1), height)
            create_pixmap = True

        if create_pixmap:
            self._pixmap = gdk.Pixmap(self.window, self._pixmap_width,
                                      self._pixmap_height)
            self._renderer.set_pixmap(self._pixmap)

    def _render_figure(self, pixmap, width, height):
        """used by GTK and GTKcairo. GTKAgg overrides
        """
        self._renderer.set_width_height(width, height)
        self.figure.draw(self._renderer)

    def expose_event(self, widget, event):
        """Expose_event for all GTK backends. Should not be overridden.
        """
        if _debug: print 'FigureCanvasGTK.%s' % fn_name()

        if GTK_WIDGET_DRAWABLE(self):
            if self._need_redraw:
                x, y, w, h = self.allocation
                self._pixmap_prepare(w, h)
                self._render_figure(self._pixmap, w, h)
                self._need_redraw = False

            x, y, w, h = event.area
            self.window.draw_drawable(self.style.fg_gc[self.state],
                                      self._pixmap, x, y, x, y, w, h)
        return False  # finish event propagation?

    filetypes = FigureCanvasBase.filetypes.copy()
    filetypes['jpg'] = 'JPEG'
    filetypes['jpeg'] = 'JPEG'
    filetypes['png'] = 'Portable Network Graphics'

    def print_jpeg(self, filename, *args, **kwargs):
        return self._print_image(filename, 'jpeg')

    print_jpg = print_jpeg

    def print_png(self, filename, *args, **kwargs):
        return self._print_image(filename, 'png')

    def _print_image(self, filename, format):
        if self.flags() & gtk.REALIZED == 0:
            # for self.window(for pixmap) and has a side effect of altering
            # figure width,height (via configure-event?)
            gtk.DrawingArea.realize(self)

        width, height = self.get_width_height()
        pixmap = gdk.Pixmap(self.window, width, height)
        self._renderer.set_pixmap(pixmap)
        self._render_figure(pixmap, width, height)

        # jpg colors don't match the display very well, png colors match
        # better
        pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height)
        pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0,
                                 width, height)

        if is_string_like(filename):
            try:
                pixbuf.save(filename, format)
            except gobject.GError, exc:
                error_msg_gtk('Save figure failure:\n%s' % (exc, ),
                              parent=self)
        elif is_writable_file_like(filename):
            if hasattr(pixbuf, 'save_to_callback'):

                def save_callback(buf, data=None):
                    data.write(buf)

                try:
                    pixbuf.save_to_callback(save_callback,
                                            format,
                                            user_data=filename)
                except gobject.GError, exc:
                    error_msg_gtk('Save figure failure:\n%s' % (exc, ),
                                  parent=self)
Beispiel #26
0
    def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
                      orientation='portrait', isLandscape=False, papertype=None):
        """
        Render the figure to hardcopy.  Set the figure patch face and
        edge colors.  This is useful because some of the GUIs have a
        gray figure face color background and you'll probably want to
        override this on hardcopy

        If outfile is a string, it is interpreted as a file name.
        If the extension matches .ep* write encapsulated postscript,
        otherwise write a stand-alone PostScript file.

        If outfile is a file object, a stand-alone PostScript file is
        written into this file object.
        """
        isEPSF = format == 'eps'
        passed_in_file_object = False
        if is_string_like(outfile):
            title = outfile
            tmpfile = os.path.join(gettempdir(), md5(outfile).hexdigest())
        elif is_writable_file_like(outfile):
            title = None
            tmpfile = os.path.join(gettempdir(), md5(str(hash(outfile))).hexdigest())
            passed_in_file_object = True
        else:
            raise ValueError("outfile must be a path or a file-like object")
        fh = file(tmpfile, 'w')

        # find the appropriate papertype
        width, height = self.figure.get_size_inches()
        if papertype == 'auto':
            if isLandscape: papertype = _get_papertype(height, width)
            else: papertype = _get_papertype(width, height)

        if isLandscape: paperHeight, paperWidth = papersize[papertype]
        else: paperWidth, paperHeight = papersize[papertype]

        if rcParams['ps.usedistiller'] and not papertype == 'auto':
            # distillers will improperly clip eps files if the pagesize is
            # too small
            if width>paperWidth or height>paperHeight:
                if isLandscape:
                    papertype = _get_papertype(height, width)
                    paperHeight, paperWidth = papersize[papertype]
                else:
                    papertype = _get_papertype(width, height)
                    paperWidth, paperHeight = papersize[papertype]

        # center the figure on the paper
        xo = 72*0.5*(paperWidth - width)
        yo = 72*0.5*(paperHeight - height)

        l, b, w, h = self.figure.bbox.bounds
        llx = xo
        lly = yo
        urx = llx + w
        ury = lly + h
        rotation = 0
        if isLandscape:
            llx, lly, urx, ury = lly, llx, ury, urx
            xo, yo = 72*paperHeight - yo, xo
            rotation = 90
        bbox = (llx, lly, urx, ury)

        # generate PostScript code for the figure and store it in a string
        origfacecolor = self.figure.get_facecolor()
        origedgecolor = self.figure.get_edgecolor()
        self.figure.set_facecolor(facecolor)
        self.figure.set_edgecolor(edgecolor)

        self._pswriter = StringIO()
        renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        self.figure.draw(renderer)

        self.figure.set_facecolor(origfacecolor)
        self.figure.set_edgecolor(origedgecolor)

        # write the PostScript headers
        if isEPSF: print >>fh, "%!PS-Adobe-3.0 EPSF-3.0"
        else: print >>fh, "%!PS-Adobe-3.0"
        if title: print >>fh, "%%Title: "+title
        print >>fh, ("%%Creator: matplotlib version "
                     +__version__+", http://matplotlib.sourceforge.net/")
        print >>fh, "%%CreationDate: "+time.ctime(time.time())
        print >>fh, "%%Orientation: " + orientation
        if not isEPSF: print >>fh, "%%DocumentPaperSizes: "+papertype
        print >>fh, "%%%%BoundingBox: %d %d %d %d" % bbox
        if not isEPSF: print >>fh, "%%Pages: 1"
        print >>fh, "%%EndComments"

        Ndict = len(psDefs)
        print >>fh, "%%BeginProlog"
        if not rcParams['ps.useafm']:
            Ndict += len(renderer.used_characters)
        print >>fh, "/mpldict %d dict def"%Ndict
        print >>fh, "mpldict begin"
        for d in psDefs:
            d=d.strip()
            for l in d.split('\n'):
                print >>fh, l.strip()
        if not rcParams['ps.useafm']:
            for font_filename, chars in renderer.used_characters.values():
                if len(chars):
                    font = FT2Font(font_filename)
                    cmap = font.get_charmap()
                    glyph_ids = []
                    for c in chars:
                        gind = cmap.get(c) or 0
                        glyph_ids.append(gind)
                    # The ttf to ps (subsetting) support doesn't work for
                    # OpenType fonts that are Postscript inside (like the
                    # STIX fonts).  This will simply turn that off to avoid
                    # errors.
                    if is_opentype_cff_font(font_filename):
                        raise RuntimeError("OpenType CFF fonts can not be saved using the internal Postscript backend at this time.\nConsider using the Cairo backend.")
                    else:
                        fonttype = rcParams['ps.fonttype']
                        convert_ttf_to_ps(font_filename, fh, rcParams['ps.fonttype'], glyph_ids)
        print >>fh, "end"
        print >>fh, "%%EndProlog"

        if not isEPSF: print >>fh, "%%Page: 1 1"
        print >>fh, "mpldict begin"
        #print >>fh, "gsave"
        print >>fh, "%s translate"%_nums_to_str(xo, yo)
        if rotation: print >>fh, "%d rotate"%rotation
        print >>fh, "%s clipbox"%_nums_to_str(width*72, height*72, 0, 0)

        # write the figure
        print >>fh, self._pswriter.getvalue()

        # write the trailer
        #print >>fh, "grestore"
        print >>fh, "end"
        print >>fh, "showpage"
        if not isEPSF: print >>fh, "%%EOF"
        fh.close()

        if rcParams['ps.usedistiller'] == 'ghostscript':
            gs_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)
        elif rcParams['ps.usedistiller'] == 'xpdf':
            xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)

        if passed_in_file_object:
            fh = file(tmpfile)
            print >>outfile, fh.read()
        else:
            shutil.move(tmpfile, outfile)
Beispiel #27
0
    def _print_figure(self,
                      fmt,
                      outfile,
                      *,
                      dpi,
                      dsc_comments,
                      orientation,
                      papertype,
                      bbox_inches_restore=None):
        """
        Render the figure to a filesystem path or a file-like object.

        Parameters are as for `.print_figure`, except that *dsc_comments* is a
        all string containing Document Structuring Convention comments,
        generated from the *metadata* parameter to `.print_figure`.
        """
        is_eps = fmt == 'eps'
        if not (isinstance(outfile, (str, os.PathLike))
                or is_writable_file_like(outfile)):
            raise ValueError("outfile must be a path or a file-like object")

        # find the appropriate papertype
        width, height = self.figure.get_size_inches()
        if papertype == 'auto':
            papertype = _get_papertype(
                *orientation.swap_if_landscape((width, height)))
        paper_width, paper_height = orientation.swap_if_landscape(
            papersize[papertype])

        if mpl.rcParams['ps.usedistiller']:
            # distillers improperly clip eps files if pagesize is too small
            if width > paper_width or height > paper_height:
                papertype = _get_papertype(
                    *orientation.swap_if_landscape((width, height)))
                paper_width, paper_height = orientation.swap_if_landscape(
                    papersize[papertype])

        # center the figure on the paper
        xo = 72 * 0.5 * (paper_width - width)
        yo = 72 * 0.5 * (paper_height - height)

        llx = xo
        lly = yo
        urx = llx + self.figure.bbox.width
        ury = lly + self.figure.bbox.height
        rotation = 0
        if orientation is _Orientation.landscape:
            llx, lly, urx, ury = lly, llx, ury, urx
            xo, yo = 72 * paper_height - yo, xo
            rotation = 90
        bbox = (llx, lly, urx, ury)

        self._pswriter = StringIO()

        # mixed mode rendering
        ps_renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        renderer = MixedModeRenderer(self.figure,
                                     width,
                                     height,
                                     dpi,
                                     ps_renderer,
                                     bbox_inches_restore=bbox_inches_restore)

        self.figure.draw(renderer)

        def print_figure_impl(fh):
            # write the PostScript headers
            if is_eps:
                print("%!PS-Adobe-3.0 EPSF-3.0", file=fh)
            else:
                print(
                    f"%!PS-Adobe-3.0\n"
                    f"%%DocumentPaperSizes: {papertype}\n"
                    f"%%Pages: 1\n",
                    end="",
                    file=fh)
            print(
                f"{dsc_comments}\n"
                f"%%Orientation: {orientation.name}\n"
                f"{get_bbox_header(bbox)[0]}\n"
                f"%%EndComments\n",
                end="",
                file=fh)

            Ndict = len(psDefs)
            print("%%BeginProlog", file=fh)
            if not mpl.rcParams['ps.useafm']:
                Ndict += len(ps_renderer._character_tracker.used)
            print("/mpldict %d dict def" % Ndict, file=fh)
            print("mpldict begin", file=fh)
            print("\n".join(psDefs), file=fh)
            if not mpl.rcParams['ps.useafm']:
                for font_path, chars \
                        in ps_renderer._character_tracker.used.items():
                    if not chars:
                        continue
                    fonttype = mpl.rcParams['ps.fonttype']
                    # Can't use more than 255 chars from a single Type 3 font.
                    if len(chars) > 255:
                        fonttype = 42
                    fh.flush()
                    if fonttype == 3:
                        fh.write(_font_to_ps_type3(font_path, chars))
                    else:  # Type 42 only.
                        _font_to_ps_type42(font_path, chars, fh)
            print("end", file=fh)
            print("%%EndProlog", file=fh)

            if not is_eps:
                print("%%Page: 1 1", file=fh)
            print("mpldict begin", file=fh)

            print("%s translate" % _nums_to_str(xo, yo), file=fh)
            if rotation:
                print("%d rotate" % rotation, file=fh)
            print("%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0),
                  file=fh)

            # write the figure
            print(self._pswriter.getvalue(), file=fh)

            # write the trailer
            print("end", file=fh)
            print("showpage", file=fh)
            if not is_eps:
                print("%%EOF", file=fh)
            fh.flush()

        if mpl.rcParams['ps.usedistiller']:
            # We are going to use an external program to process the output.
            # Write to a temporary file.
            with TemporaryDirectory() as tmpdir:
                tmpfile = os.path.join(tmpdir, "tmp.ps")
                with open(tmpfile, 'w', encoding='latin-1') as fh:
                    print_figure_impl(fh)
                if mpl.rcParams['ps.usedistiller'] == 'ghostscript':
                    _try_distill(gs_distill,
                                 tmpfile,
                                 is_eps,
                                 ptype=papertype,
                                 bbox=bbox)
                elif mpl.rcParams['ps.usedistiller'] == 'xpdf':
                    _try_distill(xpdf_distill,
                                 tmpfile,
                                 is_eps,
                                 ptype=papertype,
                                 bbox=bbox)
                _move_path_to_path_or_stream(tmpfile, outfile)

        else:  # Write directly to outfile.
            with cbook.open_file_cm(outfile, "w", encoding="latin-1") as file:
                if not file_requires_unicode(file):
                    file = codecs.getwriter("latin-1")(file)
                print_figure_impl(file)
Beispiel #28
0
    def _print_figure_tex(self,
                          outfile,
                          format,
                          dpi,
                          facecolor,
                          edgecolor,
                          orientation,
                          papertype,
                          *,
                          metadata=None,
                          dryrun=False,
                          bbox_inches_restore=None,
                          **kwargs):
        """
        If text.usetex is True in rc, a temporary pair of tex/eps files
        are created to allow tex to manage the text layout via the PSFrags
        package. These files are processed to yield the final ps or eps file.

        metadata must be a dictionary. Currently, only the value for
        the key 'Creator' is used.
        """
        is_eps = format == 'eps'
        if is_writable_file_like(outfile):
            title = None
        else:
            try:
                title = os.fspath(outfile)
            except TypeError:
                raise ValueError(
                    "outfile must be a path or a file-like object")

        self.figure.dpi = 72  # ignore the dpi kwarg
        width, height = self.figure.get_size_inches()
        xo = 0
        yo = 0

        l, b, w, h = self.figure.bbox.bounds
        llx = xo
        lly = yo
        urx = llx + w
        ury = lly + h
        bbox = (llx, lly, urx, ury)

        # generate PostScript code for the figure and store it in a string
        origfacecolor = self.figure.get_facecolor()
        origedgecolor = self.figure.get_edgecolor()
        self.figure.set_facecolor(facecolor)
        self.figure.set_edgecolor(edgecolor)

        if dryrun:

            class NullWriter:
                def write(self, *args, **kwargs):
                    pass

            self._pswriter = NullWriter()
        else:
            self._pswriter = StringIO()

        # mixed mode rendering
        ps_renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        renderer = MixedModeRenderer(self.figure,
                                     width,
                                     height,
                                     dpi,
                                     ps_renderer,
                                     bbox_inches_restore=bbox_inches_restore)

        self.figure.draw(renderer)

        if dryrun:  # return immediately if dryrun (tightbbox=True)
            return

        self.figure.set_facecolor(origfacecolor)
        self.figure.set_edgecolor(origedgecolor)

        # check for custom metadata
        if metadata is not None and 'Creator' in metadata:
            creator_str = metadata['Creator']
        else:
            creator_str = \
                f"matplotlib version {mpl.__version__}, http://matplotlib.org/"

        # write to a temp file, we'll move it to outfile when done

        with TemporaryDirectory() as tmpdir:
            tmpfile = os.path.join(tmpdir, "tmp.ps")
            # get source date from SOURCE_DATE_EPOCH, if set
            # See https://reproducible-builds.org/specs/source-date-epoch/
            source_date_epoch = os.getenv("SOURCE_DATE_EPOCH")
            if source_date_epoch:
                source_date = datetime.datetime.utcfromtimestamp(
                    int(source_date_epoch)).strftime("%a %b %d %H:%M:%S %Y")
            else:
                source_date = time.ctime()
            pathlib.Path(tmpfile).write_text(f"""\
%!PS-Adobe-3.0 EPSF-3.0
{f'''%%Title: {title}
''' if title else ""}\
%%Creator: {creator_str}
%%CreationDate: {source_date}
%%BoundingBox: {bbox[0]} {bbox[1]} {bbox[2]} {bbox[3]}
%%EndComments
%%BeginProlog
/mpldict {len(psDefs)} dict def
mpldict begin
{"".join(psDefs)}
end
%%EndProlog
mpldict begin
{_nums_to_str(xo, yo)} translate
{_nums_to_str(width*72, height*72)} 0 0 clipbox
{self._pswriter.getvalue()}
end
showpage
""",
                                             encoding="latin-1")

            if orientation is _Orientation.landscape:  # now, ready to rotate
                width, height = height, width
                bbox = (lly, llx, ury, urx)

            # set the paper size to the figure size if is_eps. The
            # resulting ps file has the given size with correct bounding
            # box so that there is no need to call 'pstoeps'
            if is_eps:
                paper_width, paper_height = orientation.swap_if_landscape(
                    self.figure.get_size_inches())
            else:
                temp_papertype = _get_papertype(width, height)
                if papertype == 'auto':
                    papertype = temp_papertype
                    paper_width, paper_height = papersize[temp_papertype]
                else:
                    paper_width, paper_height = papersize[papertype]

            texmanager = ps_renderer.get_texmanager()
            font_preamble = texmanager.get_font_preamble()
            custom_preamble = texmanager.get_custom_preamble()

            psfrag_rotated = convert_psfrags(tmpfile, ps_renderer.psfrag,
                                             font_preamble, custom_preamble,
                                             paper_width, paper_height,
                                             orientation.name)

            if (mpl.rcParams['ps.usedistiller'] == 'ghostscript'
                    or mpl.rcParams['text.usetex']):
                gs_distill(tmpfile,
                           is_eps,
                           ptype=papertype,
                           bbox=bbox,
                           rotated=psfrag_rotated)
            elif mpl.rcParams['ps.usedistiller'] == 'xpdf':
                xpdf_distill(tmpfile,
                             is_eps,
                             ptype=papertype,
                             bbox=bbox,
                             rotated=psfrag_rotated)

            _move_path_to_path_or_stream(tmpfile, outfile)
Beispiel #29
0
    def _print_figure(self,
                      outfile,
                      format,
                      dpi,
                      facecolor,
                      edgecolor,
                      orientation,
                      papertype,
                      *,
                      metadata=None,
                      dryrun=False,
                      bbox_inches_restore=None,
                      **kwargs):
        """
        Render the figure to hardcopy.  Set the figure patch face and
        edge colors.  This is useful because some of the GUIs have a
        gray figure face color background and you'll probably want to
        override this on hardcopy

        If outfile is a string, it is interpreted as a file name.
        If the extension matches .ep* write encapsulated postscript,
        otherwise write a stand-alone PostScript file.

        If outfile is a file object, a stand-alone PostScript file is
        written into this file object.

        metadata must be a dictionary. Currently, only the value for
        the key 'Creator' is used.
        """
        is_eps = format == 'eps'
        if isinstance(outfile, (str, os.PathLike)):
            outfile = title = os.fspath(outfile)
            title = title.encode("ascii", "replace").decode("ascii")
            passed_in_file_object = False
        elif is_writable_file_like(outfile):
            title = None
            passed_in_file_object = True
        else:
            raise ValueError("outfile must be a path or a file-like object")

        # find the appropriate papertype
        width, height = self.figure.get_size_inches()
        if papertype == 'auto':
            papertype = _get_papertype(
                *orientation.swap_if_landscape((width, height)))
        paper_width, paper_height = orientation.swap_if_landscape(
            papersize[papertype])

        if mpl.rcParams['ps.usedistiller']:
            # distillers improperly clip eps files if pagesize is too small
            if width > paper_width or height > paper_height:
                papertype = _get_papertype(
                    *orientation.swap_if_landscape(width, height))
                paper_width, paper_height = orientation.swap_if_landscape(
                    papersize[papertype])

        # center the figure on the paper
        xo = 72 * 0.5 * (paper_width - width)
        yo = 72 * 0.5 * (paper_height - height)

        l, b, w, h = self.figure.bbox.bounds
        llx = xo
        lly = yo
        urx = llx + w
        ury = lly + h
        rotation = 0
        if orientation is _Orientation.landscape:
            llx, lly, urx, ury = lly, llx, ury, urx
            xo, yo = 72 * paper_height - yo, xo
            rotation = 90
        bbox = (llx, lly, urx, ury)

        # generate PostScript code for the figure and store it in a string
        origfacecolor = self.figure.get_facecolor()
        origedgecolor = self.figure.get_edgecolor()
        self.figure.set_facecolor(facecolor)
        self.figure.set_edgecolor(edgecolor)

        if dryrun:

            class NullWriter:
                def write(self, *args, **kwargs):
                    pass

            self._pswriter = NullWriter()
        else:
            self._pswriter = StringIO()

        # mixed mode rendering
        ps_renderer = RendererPS(width, height, self._pswriter, imagedpi=dpi)
        renderer = MixedModeRenderer(self.figure,
                                     width,
                                     height,
                                     dpi,
                                     ps_renderer,
                                     bbox_inches_restore=bbox_inches_restore)

        self.figure.draw(renderer)

        if dryrun:  # return immediately if dryrun (tightbbox=True)
            return

        self.figure.set_facecolor(origfacecolor)
        self.figure.set_edgecolor(origedgecolor)

        # check for custom metadata
        if metadata is not None and 'Creator' in metadata:
            creator_str = metadata['Creator']
        else:
            creator_str = \
                f"matplotlib version {mpl.__version__}, http://matplotlib.org/"

        def print_figure_impl(fh):
            # write the PostScript headers
            if is_eps:
                print("%!PS-Adobe-3.0 EPSF-3.0", file=fh)
            else:
                print(
                    f"%!PS-Adobe-3.0\n"
                    f"%%DocumentPaperSizes: {papertype}\n"
                    f"%%Pages: 1\n",
                    end="",
                    file=fh)
            if title:
                print("%%Title: " + title, file=fh)
            # get source date from SOURCE_DATE_EPOCH, if set
            # See https://reproducible-builds.org/specs/source-date-epoch/
            source_date_epoch = os.getenv("SOURCE_DATE_EPOCH")
            if source_date_epoch:
                source_date = datetime.datetime.utcfromtimestamp(
                    int(source_date_epoch)).strftime("%a %b %d %H:%M:%S %Y")
            else:
                source_date = time.ctime()
            print(
                f"%%Creator: {creator_str}\n"
                f"%%CreationDate: {source_date}\n"
                f"%%Orientation: {orientation.name}\n"
                f"%%BoundingBox: {bbox[0]} {bbox[1]} {bbox[2]} {bbox[3]}\n"
                f"%%EndComments\n",
                end="",
                file=fh)

            Ndict = len(psDefs)
            print("%%BeginProlog", file=fh)
            if not mpl.rcParams['ps.useafm']:
                Ndict += len(ps_renderer._character_tracker.used)
            print("/mpldict %d dict def" % Ndict, file=fh)
            print("mpldict begin", file=fh)
            for d in psDefs:
                d = d.strip()
                for l in d.split('\n'):
                    print(l.strip(), file=fh)
            if not mpl.rcParams['ps.useafm']:
                for font_path, chars \
                        in ps_renderer._character_tracker.used.items():
                    if not chars:
                        continue
                    font = get_font(font_path)
                    glyph_ids = [font.get_char_index(c) for c in chars]
                    fonttype = mpl.rcParams['ps.fonttype']
                    # Can't use more than 255 chars from a single Type 3 font.
                    if len(glyph_ids) > 255:
                        fonttype = 42
                    # The ttf to ps (subsetting) support doesn't work for
                    # OpenType fonts that are Postscript inside (like the STIX
                    # fonts).  This will simply turn that off to avoid errors.
                    if is_opentype_cff_font(font_path):
                        raise RuntimeError(
                            "OpenType CFF fonts can not be saved using "
                            "the internal Postscript backend at this "
                            "time; consider using the Cairo backend")
                    fh.flush()
                    try:
                        convert_ttf_to_ps(os.fsencode(font_path), fh, fonttype,
                                          glyph_ids)
                    except RuntimeError:
                        _log.warning("The PostScript backend does not "
                                     "currently support the selected font.")
                        raise
            print("end", file=fh)
            print("%%EndProlog", file=fh)

            if not is_eps:
                print("%%Page: 1 1", file=fh)
            print("mpldict begin", file=fh)

            print("%s translate" % _nums_to_str(xo, yo), file=fh)
            if rotation:
                print("%d rotate" % rotation, file=fh)
            print("%s clipbox" % _nums_to_str(width * 72, height * 72, 0, 0),
                  file=fh)

            # write the figure
            content = self._pswriter.getvalue()
            if not isinstance(content, str):
                content = content.decode('ascii')
            print(content, file=fh)

            # write the trailer
            print("end", file=fh)
            print("showpage", file=fh)
            if not is_eps:
                print("%%EOF", file=fh)
            fh.flush()

        if mpl.rcParams['ps.usedistiller']:
            # We are going to use an external program to process the output.
            # Write to a temporary file.
            with TemporaryDirectory() as tmpdir:
                tmpfile = os.path.join(tmpdir, "tmp.ps")
                with open(tmpfile, 'w', encoding='latin-1') as fh:
                    print_figure_impl(fh)
                if mpl.rcParams['ps.usedistiller'] == 'ghostscript':
                    gs_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox)
                elif mpl.rcParams['ps.usedistiller'] == 'xpdf':
                    xpdf_distill(tmpfile, is_eps, ptype=papertype, bbox=bbox)
                _move_path_to_path_or_stream(tmpfile, outfile)

        else:
            # Write directly to outfile.
            if passed_in_file_object:
                requires_unicode = file_requires_unicode(outfile)

                if not requires_unicode:
                    fh = TextIOWrapper(outfile, encoding="latin-1")
                    # Prevent the TextIOWrapper from closing the underlying
                    # file.
                    fh.close = lambda: None
                else:
                    fh = outfile

                print_figure_impl(fh)
            else:
                with open(outfile, 'w', encoding='latin-1') as fh:
                    print_figure_impl(fh)