Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in postscript backend in Python 3 #1779

Merged
merged 3 commits into from Mar 1, 2013
Merged

Conversation

mdboom
Copy link
Member

@mdboom 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?

@mdboom
Copy link
Member

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.

@astrofrog
Copy link
Contributor Author

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

@astrofrog
Copy link
Contributor Author

@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?

@mdboom
Copy link
Member

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).

@astrofrog
Copy link
Contributor Author

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

@astrofrog
Copy link
Contributor Author

@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.

@mdboom
Copy link
Member

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())

@astrofrog
Copy link
Contributor Author

Looks good, and works for me - thanks!

mdboom added a commit that referenced this pull request Mar 1, 2013
Bug in postscript backend in Python 3
@mdboom mdboom merged commit b25d275 into matplotlib:v1.2.x Mar 1, 2013
@mdboom mdboom deleted the ps/python3 branch August 7, 2014 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants