Skip to content

"savefig" bug with unicode characters (version 2.0.0) #8039

Closed

Description

@photoniker

Bug report

I'm using Python 3.5, Numpy 1.12.0, Miktex 2.9 and Matplotlib 2.0.0.

The plot creation of the example from tex_unicode_demo.py works well.
But if I want to save this figure as a pdf-file using "plt.savefig", I get an
AttributeError: 'str' object has no attribute 'decode'

This Error do not occur with an old matplotlib version (1.5.2)!!!

# -*- coding: utf-8 -*-
"""
This demo is tex_demo.py modified to have unicode. See that file for
more information.
"""

from __future__ import unicode_literals
import numpy as np
import matplotlib
matplotlib.rcParams['text.usetex'] = True
matplotlib.rcParams['text.latex.unicode'] = True
import matplotlib.pyplot as plt

plt.figure(1, figsize=(6, 4))
ax = plt.axes([0.1, 0.1, 0.8, 0.7])
t = np.arange(0.0, 1.0 + 0.01, 0.01)
s = np.cos(2*2*np.pi*t) + 2
plt.plot(t, s)

plt.xlabel(r'\textbf{time (s)}')
plt.ylabel('\\textit{Velocity (\u00B0/sec)}', fontsize=16)
plt.title(r'\TeX\ is Number $\displaystyle\sum_{n=1}^\infty'
          r'\frac{-e^{i\pi}}{2^n}$!', fontsize=16, color='r')
plt.grid(True)
plt.show()

plt.savefig('texDemo.pdf')
  File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\dviread.py", line 701, in __getitem__
    result = self._font[texname.decode('ascii')]
AttributeError: 'str' object has no attribute 'decode'

Activity

  1. photoniker commented on Feb 7, 2017

    @photoniker
    ContributorAuthor

    This problem can be solved if the latex package lmodern is included. But why?

    matplotlib.rcParams['text.latex.preamble'] = [r'\usepackage{lmodern}']
  2. tacaswell commented on Feb 9, 2017

    @tacaswell
    Member

    Can you please include the full traceback, the last line by it's self is not super useful (it lands in a __getitem__ definition).

    What is the value of texname when this happens (try using IPython + %debug).

  3. tacaswell commented on Feb 9, 2017

    @tacaswell
    Member

    I can not reproduce this.

  4. added this to the milestone on Feb 9, 2017
  5. photoniker commented on Feb 10, 2017

    @photoniker
    ContributorAuthor

    This here is the full traceback. Maybe this is some problem with the backend?
    I'm using Matplotlib in the software itom.

    Traceback (most recent call last):
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\dviread.py", line 699, in __getitem__
        result = self._font[texname]
    KeyError: 'tcsi1728'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "c:\users\itokrauter\desktop\matplottest.py", line 27, in <module>
        plt.savefig('texDemo.pdf')
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\pyplot.py", line 697, in savefig
        res = fig.savefig(*args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\figure.py", line 1572, in savefig
        self.canvas.print_figure(*args, **kwargs)
      File "D:/itom/build/itom/itom-packages\mpl_itom\backend_itomagg.py", line 190, in print_figure
        FigureCanvasAgg.print_figure(self, *args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\backend_bases.py", line 2244, in print_figure
        **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2525, in print_pdf
        self.figure.draw(renderer)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
        draw(artist, renderer, *args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\figure.py", line 1143, in draw
        renderer, self, dsu, self.suppressComposite)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\image.py", line 139, in _draw_list_compositing_images
        a.draw(renderer)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
        draw(artist, renderer, *args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\axes\_base.py", line 2409, in draw
        mimage._draw_list_compositing_images(renderer, self, dsu)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\image.py", line 139, in _draw_list_compositing_images
        a.draw(renderer)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
        draw(artist, renderer, *args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\axis.py", line 1150, in draw
        self.label.draw(renderer)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\artist.py", line 63, in draw_wrapper
        draw(artist, renderer, *args, **kwargs)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\text.py", line 798, in draw
        mtext=mtext)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1863, in draw_tex
        psfont = self.tex_font_mapping(dvifont.texname)
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1566, in tex_font_mapping
        return self.tex_font_map[texfont]
      File "C:\Program Files\Python\Python35\lib\site-packages\matplotlib\dviread.py", line 701, in __getitem__
        result = self._font[texname.decode('ascii')]
    AttributeError: 'str' object has no attribute 'decode'
  6. phobson commented on Feb 10, 2017

    @phobson
    Member

    @photoniker what happens if you just run the script from the command line outside of your IDE?

  7. tacaswell commented on Feb 10, 2017

    @tacaswell
    Member

    As a side-bar, the link to itom was very interesting to me (at my day-job I am developing a similar system, but with very different architecture).

    Do you have anything non-standard in your .matplotlibrc? That might help us to reproduce.

    It looks like we still have at least one place where we get the byte vs str distinction wrong.

  8. QuLogic commented on Feb 10, 2017

    @QuLogic
    Member

    This looks related to #6977.

  9. tacaswell commented on Feb 10, 2017

    @tacaswell
    Member

    Ah, I remembered that PR, but thought it was merged and that this was a consequence of it.

  10. jkseppan commented on Feb 11, 2017

    @jkseppan
    Member

    #6977 is waiting for review. It won't exactly fix the actual problem here (which is probably a missing font) but it will make the error message more helpful in tracking down what exactly is missing.

  11. photoniker commented on Feb 13, 2017

    @photoniker
    ContributorAuthor

    @phobson

    @photoniker what happens if you just run the script from the command line outside of your IDE?

    The same result.

    @tacaswell
    What do you mean with non-standard in .matplotlibrc?

  12. jkseppan commented on Feb 13, 2017

    @jkseppan
    Member

    It's very likely a missing PostScript font, but the error message you get is useless because the code is trying to support both strings and bytestrings but it's broken on Python 3. #6977 would fix the error message, but the fix for the underlying problem is to install whatever font is missing.

  13. photoniker commented on Feb 13, 2017

    @photoniker
    ContributorAuthor

    @jkseppan
    in this example here I'm using the unicode command for the degree ° characters. This one should be in every font?!

  14. 1 remaining item

  15. modified the milestones: , on May 3, 2017
  16. jkseppan commented on Sep 7, 2017

    @jkseppan
    Member

    @JakobJakobson Does grep cmr10 $(kpsewhich pdftex.map) print out a line resembling "cmr10 CMR10 <cmr10.pfb"? Does kpsewhich cmr10.pfb print out a path to cmr10.pfb? If either fails, the Type-1 file for the font is not installed or the TeX font maps have not been updated to include the font, as in #8259.

  17. modified the milestones: , on Oct 9, 2017
  18. cbnfreitas commented on Nov 28, 2017

    @cbnfreitas

    I'm using Windows 10, Anaconda3-5.0.1-Windows-x86_64 and basic-miktex-2.9.6520-x64.exe, but
    fig.savefig('dummy.pdf') still does not work for me in Jupyter, for instance:

    import matplotlib
    matplotlib.rcParams.update({'font.size': 14})
    %matplotlib inline
    
    import matplotlib.pyplot as plt
    plt.rc('text', usetex=True)
    
    fig, ax = plt.subplots(1, 1, figsize=(8, 8))
    ax.plot([0,1,2,3,4], [4,3,2,1,0])
    fig.savefig('dummy.pdf')
    

    I've checked
    C:\Users\<uder>\AppData\Local\MiKTeX\2.9\pdftex\config\pdftex.map,
    and it already contains

    cmr10 CMR10 <cmr10.pfb
    cmr12 CMR12 <cmr12.pfb
    

    And kpsewhich cmr10.pfb points to
    C:/Program Files/MiKTeX 2.9/fonts/type1/public/amsfonts/cm/cmr10.pfb

    This is the error shown in Jupyter:

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-17-7021e6e2dcbe> in <module>()
          8 fig, ax = plt.subplots(1, 1, figsize=(8, 8))
          9 ax.plot([0,1,2,3,4], [4,3,2,1,0])
    ---> 10 fig.savefig('dummy.pdf')
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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()
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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')
    
    ~\Anaconda3\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
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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')
    
    ~\Anaconda3\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
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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)
    
    ~\Anaconda3\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:
    
    ~\Anaconda3\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,
    
    ~\Anaconda3\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
    
    ~\Anaconda3\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(
    
    ~\Anaconda3\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)
    
    ~\Anaconda3\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,
    
    ~\Anaconda3\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.
    
    ~\Anaconda3\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
    
    ~\Anaconda3\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'
    

    Any clue? Thanks!

  19. jklymak commented on Nov 28, 2017

    @jklymak
    Member

    I think #9292 should have fixed this. Looks the same. I'll close, but re-open if you think I'm mistaken. This will be in release 2.1.1.

  20. modified the milestones: , v2.2.0 on Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions