Bug in postscript backend in Python 3 #1779

Merged
merged 3 commits into from Mar 1, 2013

Conversation

Projects
None yet
2 participants
Contributor

mdboom commented Feb 25, 2013

The following examples demonstrates the issue:

In [1]: import matplotlib

In [2]: matplotlib.__version__
Out[2]: '1.2.0'

In [3]: from matplotlib import pyplot as plt

In [4]: fig = plt.figure()

In [5]: ax = fig.add_subplot(1,1,1)

In [6]: import numpy as np

In [7]: ax.imshow(np.zeros((128, 128)))
Out[7]: <matplotlib.image.AxesImage at 0x105085ed0>

In [8]: fig.savefig('test.ps')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-d877e517da66> in <module>()
----> 1 fig.savefig('test.ps')

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/figure.py in savefig(self, *args, **kwargs)
   1362             kwargs.setdefault('edgecolor', rcParams['savefig.edgecolor'])
   1363 
-> 1364         self.canvas.print_figure(*args, **kwargs)
   1365 
   1366         if transparent:

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs)
   2091                 orientation=orientation,
   2092                 bbox_inches_restore=_bbox_inches_restore,
-> 2093                 **kwargs)
   2094         finally:
   2095             if bbox_inches and restore_bbox:

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backend_bases.py in print_ps(self, *args, **kwargs)
   1858         from .backends.backend_ps import FigureCanvasPS # lazy import
   1859         ps = self.switch_backends(FigureCanvasPS)
-> 1860         return ps.print_ps(*args, **kwargs)
   1861 
   1862     def print_raw(self, *args, **kwargs):

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backends/backend_ps.py in print_ps(self, outfile, *args, **kwargs)
    969 
    970     def print_ps(self, outfile, *args, **kwargs):
--> 971         return self._print_ps(outfile, 'ps', *args, **kwargs)
    972 
    973     def print_eps(self, outfile, *args, **kwargs):

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backends/backend_ps.py in _print_ps(self, outfile, format, *args, **kwargs)
   1005             self._print_figure(outfile, format, imagedpi, facecolor, edgecolor,
   1006                                orientation, isLandscape, papertype,
-> 1007                                **kwargs)
   1008 
   1009     def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backends/backend_ps.py in _print_figure(self, outfile, format, dpi, facecolor, edgecolor, orientation, isLandscape, papertype, **kwargs)
   1098             bbox_inches_restore=_bbox_inches_restore)
   1099 
-> 1100         self.figure.draw(renderer)
   1101 
   1102         if dryrun: # return immediately if dryrun (tightbbox=True)

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/figure.py in draw(self, renderer)
    998         dsu.sort(key=itemgetter(0))
    999         for zorder, a, func, args in dsu:
-> 1000             func(*args)
   1001 
   1002         renderer.close_group('figure')

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/axes.py in draw(self, renderer, inframe)
   2086 
   2087         for zorder, a in dsu:
-> 2088             a.draw(renderer)
   2089 
   2090         renderer.close_group('axes')

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     53     def draw_wrapper(artist, renderer, *args, **kwargs):
     54         before(artist, renderer)
---> 55         draw(artist, renderer, *args, **kwargs)
     56         after(artist, renderer)
     57 

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/image.py in draw(self, renderer, *args, **kwargs)
    364             im._url = self.get_url()
    365             im._gid = self.get_gid()
--> 366             renderer.draw_image(gc, l, b, im)
    367         gc.restore()
    368 

/opt/local/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/site-packages/matplotlib/backends/backend_ps.py in draw_image(self, gc, x, y, im, dx, dy, transform)
    470 
    471         h, w, bits, imagecmd = self._get_image_h_w_bits_command(im)
--> 472         hexlines = '\n'.join(self._hex_lines(bits))
    473 
    474         if dx is None:

TypeError: sequence item 0: expected str instance, bytes found

In the mean time, is there a workaround?

Owner

mdboom commented Feb 25, 2013

The included patch seems to fix this for me.

I'm not sure what workarounds are available, other than perhaps using the Cairo backend, or outputting PDF and converting to PS after the fact.

Contributor

astrofrog commented Feb 27, 2013

@mdboom - thanks! Unfortunately, I can't test this due to install issues on MacOS X: #1791

Contributor

astrofrog commented Feb 27, 2013

@mdboom - I'm still testing this (applying the fix from #1791 too) but I'm seeing issues if I write to a StringIO object (which normally works):

In [1]: from io import StringIO

In [2]: s = StringIO()

In [3]: plt.figure()
Out[3]: <matplotlib.figure.Figure at 0x1052e6d90>

In [4]: plt.subplot(111)
Out[4]: <matplotlib.axes.AxesSubplot at 0x1052f8210>

In [5]: plt.savefig(s, format='ps')

In [6]: s.seek(0)
Out[6]: 0

In [7]: s.read(10)
Out[7]: "b'%!PS-Ado"

Note that the output is a string that contains b' so it looks like the repr of a bytes sequence was converted to a string?

Owner

mdboom commented Feb 27, 2013

Did a StringIO ever work on Python 3? I'd be surprised if it did. You would need to use a BytesIO (or a cStringIO.StringIO on Python 2, which is functionally the same thing).

Contributor

astrofrog commented Feb 27, 2013

@mdboom - I think it was working with 1.2.0, but I'll double-check that.

Contributor

astrofrog commented Feb 28, 2013

@mdboom - ignore me, apparently StringIO didn't ever work with Python 3

The attached patch does get rid of the error for me. However, the PS/EPS files produced don't show any content if opened. If I compare a PS file made in Python 3.2 vs 2.7, the one from 3.2 is missing a whole load of content. If you can't reproduce this, I can send you the files.

Owner

mdboom commented Feb 28, 2013

In trying this, I did discover another bug (with a fix now attached). The following works for me, with identical content in Python 2 and 3 (modulo some dictionary ordering differences)

import io
from matplotlib import pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
import numpy as np
ax.imshow(np.zeros((128, 128)))
b = io.BytesIO()
fig.savefig(b, format='ps')
open("test.ps", "wb").write(b.getvalue())
Contributor

astrofrog commented Mar 1, 2013

Looks good, and works for me - thanks!

mdboom merged commit b25d275 into matplotlib:v1.2.x Mar 1, 2013

1 check passed

default The Travis build passed
Details

mdboom deleted the mdboom:ps/python3 branch Aug 7, 2014

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