Thanks to visit codestin.com
Credit goes to github.com

Skip to content

pgf can not write to BytesIO [back port to 1.4.x] #3982

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

Merged
merged 2 commits into from
Jan 9, 2015
Merged

pgf can not write to BytesIO [back port to 1.4.x] #3982

merged 2 commits into from
Jan 9, 2015

Conversation

pwuertz
Copy link
Contributor

@pwuertz pwuertz commented Jan 8, 2015

Discovered as part of #3981

@pwuertz
Copy link
Contributor

pwuertz commented Jan 8, 2015

Support pgf code output to non-file/in-memory streams or anything else that has a write method. Emit a warning (no raster graphics) if there is no file-name attribute or the target filename is invalid.

@blink1073
Copy link
Member

As mentioned in #3979, we then get the following error:

Traceback (most recent call last):
  File "/home/afrl/anaconda/lib/python2.7/site-packages/tornado/web.py", line 1332, in _execute
    result = method(*self.path_args, **self.path_kwargs)
  File "/home/afrl/workspace/matplotlib/lib/matplotlib/backends/backend_webagg.py", line 207, in get
    manager.canvas.print_figure(buff, format=fmt)
  File "/home/afrl/workspace/matplotlib/lib/matplotlib/backend_bases.py", line 2216, in print_figure
    **kwargs)
  File "/home/afrl/workspace/matplotlib/lib/matplotlib/backends/backend_pgf.py", line 843, in print_pgf
    self._print_pgf_to_fh(fname_or_fh, *args, **kwargs)
  File "/home/afrl/workspace/matplotlib/lib/matplotlib/backends/backend_pgf.py", line 805, in _print_pgf_to_fh
    fh.write(header_text)
TypeError: 'unicode' does not have the buffer interface

@pwuertz
Copy link
Contributor

pwuertz commented Jan 8, 2015

I cannot reproduce that error when saving to a BytesIO() instance via plt.savefig(buf, format="pgf"). You only see this when saving from webagg?

@pwuertz
Copy link
Contributor

pwuertz commented Jan 8, 2015

Seems like a py2 / py3 problem, but for me it's the other way around. Here, python2 works as expected, with python3 I'm getting

TypeError: 'str' does not support the buffer interface

Is this a common problem when porting from 2to3?

@tacaswell
Copy link
Member Author

We should not have 2to3 anywhere is the code base (we support) anymore. The conversion to using six was done on the 1.4 release.

Or I am very confused by what you meant 🐑

@pwuertz
Copy link
Contributor

pwuertz commented Jan 8, 2015

Oh sorry, I just meant the general porting/transition process from python 2 to python 3, I didn't intend to refer to the 2to3tool.

@blink1073
Copy link
Member

I think this will do it (I get a RuntimeError: Error starting process 'xelatex' on both Python 2.7 and Python 3.4 with this):

diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py
index 915ad59..d16bd13 100644
--- a/lib/matplotlib/backends/backend_pgf.py
+++ b/lib/matplotlib/backends/backend_pgf.py
@@ -138,8 +138,8 @@ def common_texification(text):
 def writeln(fh, line):
     # every line of a file included with \input must be terminated with %
     # if not, latex will create additional vertical spaces for some reason
-    fh.write(line)
-    fh.write("%\n")
+    fh.write(line.encode('utf-8'))
+    fh.write("%\n".encode('utf-8'))


 def _font_properties_str(prop):
@@ -801,10 +801,10 @@ class FigureCanvasPgf(FigureCanvasBase):
         w, h = self.figure.get_figwidth(), self.figure.get_figheight()
         dpi = self.figure.get_dpi()

 def _font_properties_str(prop):
@@ -801,10 +801,10 @@ class FigureCanvasPgf(FigureCanvasBase):
         w, h = self.figure.get_figwidth(), self.figure.get_figheight()

-        # create pgfpicture environment and write the pgf code
-        fh.write(header_text)
-        fh.write(header_info_preamble)
-        fh.write("\n")
+        # create pgfpicture environment and write the pgf code 
+        fh.write(header_text.encode('utf-8'))
+        fh.write(header_info_preamble.encode('utf-8'))
+        fh.write("\n".encode('utf-8'))
         writeln(fh, r"\begingroup")
         writeln(fh, r"\makeatletter")
         writeln(fh, r"\begin{pgfpicture}")

@tacaswell
Copy link
Member Author

Recently came across something similar at work, we added a helper function

def encoding_writer(fh, input_str, encoding='utf-8'):
    fh.write(input_str.encode(encoding))

which at least seems less obnoxious to use that throwing .encode('utf-8') everythere.

@blink1073
Copy link
Member

You're obnoxious 😄

@blink1073
Copy link
Member

I installed xelatex, but ran into this: Metric (TFM) file or installed font not found.

@blink1073
Copy link
Member

New diff that gets me to the same point:

diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py
index 915ad59..3bec6dc 100644
--- a/lib/matplotlib/backends/backend_pgf.py
+++ b/lib/matplotlib/backends/backend_pgf.py
@@ -135,11 +135,15 @@ def common_texification(text):
     return "".join(parts)


+def encoding_writer(fh, input_str, encoding='utf-8'):
+    fh.write(input_str.encode(encoding))
+
+
 def writeln(fh, line):
     # every line of a file included with \input must be terminated with %
     # if not, latex will create additional vertical spaces for some reason
-    fh.write(line)
-    fh.write("%\n")
+    encoding_writer(fh, line)
+    encoding_writer(fh, "%\n")


 def _font_properties_str(prop):
@@ -801,10 +805,10 @@ class FigureCanvasPgf(FigureCanvasBase):
         w, h = self.figure.get_figwidth(), self.figure.get_figheight()
         dpi = self.figure.get_dpi()

-        # create pgfpicture environment and write the pgf code
-        fh.write(header_text)
-        fh.write(header_info_preamble)
-        fh.write("\n")
+        # create pgfpicture environment and write the pgf code      
+        encoding_writer(fh, header_text)
+        encoding_writer(fh, header_info_preamble)
+        encoding_writer(fh, "\n")
         writeln(fh, r"\begingroup")
         writeln(fh, r"\makeatletter")
         writeln(fh, r"\begin{pgfpicture}")

@pwuertz
Copy link
Contributor

pwuertz commented Jan 9, 2015

Ah ok, the stream output path is missing an output encoder. When saving to a file, the file is opened using codecs.open(fname_or_fh, "w", encoding="utf-8"), so no encoding is supposed to take place elsewhere.. lets see if the codecs module has some transcoder for objects with write().

@pwuertz
Copy link
Contributor

pwuertz commented Jan 9, 2015

Solution now tested with python2 and python3. Added a second commit that adds pgf to the list of output options in webagg_core again.

@blink1073
Copy link
Member

Tested on Python3 with webagg, 👍

@tacaswell tacaswell changed the title pgf can not write to BytesIO pgf can not write to BytesIO [back port to 1.4.x] Jan 9, 2015
pelson added a commit that referenced this pull request Jan 9, 2015
pgf can not write to `BytesIO` [back port to 1.4.x]
@pelson pelson merged commit 174b126 into matplotlib:master Jan 9, 2015
@pwuertz pwuertz deleted the fix_3982 branch July 9, 2015 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants