Skip to content

Save to .pdf doesn't work in 2.1.0 #9390

Closed

Description

@narimiran

Bug report

Bug summary

fig.savefig(filename.pdf) doesn't work like in the previous versions

Code for reproduction

fig, ax = plt.subplots()
ax.plot([5, 4, 2, 3])
fig.savefig('test.pdf')

Actual outcome

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-5c7237786c15> in <module>()
      1 fig, ax = plt.subplots()
      2 ax.plot([5, 4, 2, 3])
----> 3 fig.savefig('test.pdf')

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\figure.py in savefig(self, fname, **kwargs)
   1812             self.set_frameon(frameon)
   1813 
-> 1814         self.canvas.print_figure(fname, **kwargs)
   1815 
   1816         if frameon:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs)
   2257                 orientation=orientation,
   2258                 bbox_inches_restore=_bbox_inches_restore,
-> 2259                 **kwargs)
   2260         finally:
   2261             if bbox_inches and restore_bbox:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backends\backend_pdf.py in print_pdf(self, filename, **kwargs)
   2590                 RendererPdf(file, image_dpi, height, width),
   2591                 bbox_inches_restore=_bbox_inches_restore)
-> 2592             self.figure.draw(renderer)
   2593             renderer.finalize()
   2594             file.finalize()

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53                 renderer.start_filter()
     54 
---> 55             return draw(artist, renderer, *args, **kwargs)
     56         finally:
     57             if artist.get_agg_filter() is not None:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\figure.py in draw(self, renderer)
   1293 
   1294             mimage._draw_list_compositing_images(
-> 1295                 renderer, self, artists, self.suppressComposite)
   1296 
   1297             renderer.close_group('figure')

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    136     if not_composite or not has_images:
    137         for a in artists:
--> 138             a.draw(renderer)
    139     else:
    140         # Composite any adjacent images together

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53                 renderer.start_filter()
     54 
---> 55             return draw(artist, renderer, *args, **kwargs)
     56         finally:
     57             if artist.get_agg_filter() is not None:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\axes\_base.py in draw(self, renderer, inframe)
   2397             renderer.stop_rasterizing()
   2398 
-> 2399         mimage._draw_list_compositing_images(renderer, self, artists)
   2400 
   2401         renderer.close_group('axes')

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    136     if not_composite or not has_images:
    137         for a in artists:
--> 138             a.draw(renderer)
    139     else:
    140         # Composite any adjacent images together

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53                 renderer.start_filter()
     54 
---> 55             return draw(artist, renderer, *args, **kwargs)
     56         finally:
     57             if artist.get_agg_filter() is not None:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\axis.py in draw(self, renderer, *args, **kwargs)
   1136 
   1137         for tick in ticks_to_draw:
-> 1138             tick.draw(renderer)
   1139 
   1140         # scale up the axis label box to also find the neighbors, not

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53                 renderer.start_filter()
     54 
---> 55             return draw(artist, renderer, *args, **kwargs)
     56         finally:
     57             if artist.get_agg_filter() is not None:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\axis.py in draw(self, renderer)
    280 
    281         if self.label1On:
--> 282             self.label1.draw(renderer)
    283         if self.label2On:
    284             self.label2.draw(renderer)

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53                 renderer.start_filter()
     54 
---> 55             return draw(artist, renderer, *args, **kwargs)
     56         finally:
     57             if artist.get_agg_filter() is not None:

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\text.py in draw(self, renderer)
    797                     textrenderer.draw_tex(gc, x, y, clean_line,
    798                                           textobj._fontproperties, angle,
--> 799                                           mtext=mtext)
    800                 else:
    801                     textrenderer.draw_text(gc, x, y, clean_line,

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backends\backend_pdf.py in draw_tex(self, gc, x, y, s, prop, angle, ismath, mtext)
   1942         for x1, y1, dvifont, glyph, width in page.text:
   1943             if dvifont != oldfont:
-> 1944                 pdfname = self.file.dviFontName(dvifont)
   1945                 seq += [['font', pdfname, dvifont.size]]
   1946                 oldfont = dvifont

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backends\backend_pdf.py in dviFontName(self, dvifont)
    686             return dvi_info.pdfname
    687 
--> 688         psfont = self.texFontMap[dvifont.texname]
    689         if psfont.filename is None:
    690             raise ValueError(

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\dviread.py in __getitem__(self, texname)
    864         fn, enc = result.filename, result.encoding
    865         if fn is not None and not fn.startswith(b'/'):
--> 866             fn = find_tex_file(fn)
    867         if enc is not None and not enc.startswith(b'/'):
    868             enc = find_tex_file(result.encoding)

D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\dviread.py in find_tex_file(filename, format)
   1043     # https://github.com/matplotlib/matplotlib/issues/633
   1044     pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-> 1045                             stderr=subprocess.PIPE)
   1046     result = pipe.communicate()[0].rstrip()
   1047     matplotlib.verbose.report('find_tex_file result: %s' % result,

D:\Programs\Miniconda\envs\py36\lib\subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)
    707                                 c2pread, c2pwrite,
    708                                 errread, errwrite,
--> 709                                 restore_signals, start_new_session)
    710         except:
    711             # Cleanup if the child failed starting.

D:\Programs\Miniconda\envs\py36\lib\subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_start_new_session)
    969 
    970             if not isinstance(args, str):
--> 971                 args = list2cmdline(args)
    972 
    973             # Process startup details

D:\Programs\Miniconda\envs\py36\lib\subprocess.py in list2cmdline(seq)
    459             result.append(' ')
    460 
--> 461         needquote = (" " in arg) or ("\t" in arg) or not arg
    462         if needquote:
    463             result.append('"')

TypeError: a bytes-like object is required, not 'str'

Expected outcome

Saving a figure as a .pdf file.

This has worked in 2.0.2 and all the previous versions.

Matplotlib version

  • Operating system: Windows 8.1
  • Matplotlib version: 2.1.0 (installed from conda)
  • Matplotlib backend (print(matplotlib.get_backend())): module://ipykernel.pylab.backend_inline
  • Python version: 3.6.3
  • Jupyter version (if applicable): 1.0.0

Activity

  1. ImportanceOfBeingErnest commented on Oct 13, 2017

    @ImportanceOfBeingErnest
    Member

    I tested with
    Operating system: Windows 8.1, Matplotlib version: 2.1.0, Python version: 2.7.10
    Matplotlib backend: module://ipykernel.pylab.backend_inline
    Jupyter version: Jupyter QtConsole 4.3.0, IPython 5.3.0

    and the above code generates a pdf without problem and as expected.

  2. anntzer commented on Oct 13, 2017

    @anntzer
    Contributor

    Almost certain it's a Py3 thing only.

  3. added this to the milestone on Oct 13, 2017
  4. added
    Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.
    on Oct 13, 2017
  5. tacaswell commented on Oct 13, 2017

    @tacaswell
    Member

    @narimiran Can you use %debug to extract the value that is causing the problem.

    I am very confused why our CI did not catch this, we save pdf on both travis and appveyor.

  6. Kojoley commented on Oct 13, 2017

    @Kojoley
    Member

    Appveyor does not test svg and pdf currently (no builds with TEST_ALL=yes)

  7. tacaswell commented on Oct 13, 2017

    @tacaswell
    Member

    This is probably better fixed in how we handle the file names in this section rather than patching up the subprocess call.

    D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backends\backend_pdf.py in draw_tex(self, gc, x, y, s, prop, angle, ismath, mtext)
       1942         for x1, y1, dvifont, glyph, width in page.text:
       1943             if dvifont != oldfont:
    -> 1944                 pdfname = self.file.dviFontName(dvifont)
       1945                 seq += [['font', pdfname, dvifont.size]]
       1946                 oldfont = dvifont
    
    D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\backends\backend_pdf.py in dviFontName(self, dvifont)
        686             return dvi_info.pdfname
        687 
    --> 688         psfont = self.texFontMap[dvifont.texname]
        689         if psfont.filename is None:
        690             raise ValueError(
    
    D:\Programs\Miniconda\envs\py36\lib\site-packages\matplotlib\dviread.py in __getitem__(self, texname)
        864         fn, enc = result.filename, result.encoding
        865         if fn is not None and not fn.startswith(b'/'):
    --> 866             fn = find_tex_file(fn)
        867         if enc is not None and not enc.startswith(b'/'):
        868             enc = find_tex_file(result.encoding)
    
  8. narimiran commented on Oct 13, 2017

    @narimiran
    Author

    Can you use %debug to extract the value that is causing the problem.

    I just tried to reproduce this on my Linux machine (@anntzer: it is also Python 3) and I couldn't.

    I'll be back on my Windows machine on Monday, before that I can't give you more insightful answer, sorry.

  9. anntzer commented on Oct 13, 2017

    @anntzer
    Contributor

    @tacaswell I started by trying that (and in fact PEP383 suggests that the "correct" way to store filenames is indeed str, not bytes) but a lot of things in dviread currently assume bytes so it turns out that change is a bit complicated...

  10. cgohlke commented on Oct 14, 2017

    @cgohlke
    Contributor

    Fixed in #9292?

  11. anntzer commented on Oct 17, 2017

    @anntzer
    Contributor

    @tacaswell do you want to restore svg/pdf testing on windows? I have a patch ready that switches ghostscript to single process similarly to #8248 did for inkscape, so that may help quite a bit with the speed.

  12. tacaswell commented on Oct 21, 2017

    @tacaswell
    Member

    @anntzer Yes, lets see how much of a time hit that is.

  13. tacaswell commented on Oct 23, 2017

    @tacaswell
    Member

    Closed by #9292

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions