Skip to content

savefig to pdf: 'str' object has no attribute 'decode' #6516

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

Closed
horribleheffalump opened this issue May 31, 2016 · 11 comments
Closed

savefig to pdf: 'str' object has no attribute 'decode' #6516

horribleheffalump opened this issue May 31, 2016 · 11 comments

Comments

@horribleheffalump
Copy link

The following script:

# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
import math

from matplotlib import rc
rc('font',**{'family':'serif'})
rc('text', usetex=True)
rc('text.latex',unicode=True)
rc('text.latex',preamble=r'\usepackage[utf8]{inputenc}')
rc('text.latex',preamble=r'\usepackage[russian]{babel}')

def figsize(wcm,hcm): plt.figure(figsize=(wcm/2.54,hcm/2.54))
figsize(13,9)

x = np.linspace(0,2*math.pi,100)
y = np.sin(x)
plt.plot(x,y,'-')
plt.xlabel(u"Ось абсцисс")
plt.show()

works fine and shows the figure, but saving to pdf results in the following error:

Traceback (most recent call last):
  File "C:\Path\rus pics\___test_rus.py", line 22, in <module>
    plt.savefig(u"c:/fig.pdf")
  File "C:\Python35\lib\site-packages\matplotlib\pyplot.py", line 688, in savefig
    res = fig.savefig(*args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\figure.py", line 1565, in savefig
    self.canvas.print_figure(*args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\backend_bases.py", line 2232, in print_figure
    **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2536, in print_pdf
    self.figure.draw(renderer)
  File "C:\Python35\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\figure.py", line 1159, in draw
    func(*args)
  File "C:\Python35\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\axes\_base.py", line 2324, in draw
    a.draw(renderer)
  File "C:\Python35\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\axis.py", line 1120, in draw
    self.label.draw(renderer)
  File "C:\Python35\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python35\lib\site-packages\matplotlib\text.py", line 792, in draw
    mtext=mtext)
  File "C:\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1866, in draw_tex
    psfont = self.tex_font_mapping(dvifont.texname)
  File "C:\Python35\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1568, in tex_font_mapping
    return self.tex_font_map[texfont]
  File "C:\Python35\lib\site-packages\matplotlib\dviread.py", line 701, in __getitem__
    result = self._font[texname.decode('ascii')]
AttributeError: 'str' object has no attribute 'decode'

The error arises only if cyrillic letters are used in labels.
Matplotlib 1.5.1, Python 3.5, OS Windows 10
Stackoverflow question link

@horribleheffalump horribleheffalump changed the title savefig tp pdf: 'str' object has no attribute 'decode' savefig to pdf: 'str' object has no attribute 'decode' May 31, 2016
@tacaswell tacaswell added this to the 2.0.1 (next bug fix release) milestone May 31, 2016
@tacaswell
Copy link
Member

I get different errors, but I assume I am missing the required russian specific tex packages.

Can you drop into the debugger and get what the font name is? It looks like this is a work-around to getting bytestrings that need to be decoded to str but it is already getting in a str.

attn @mdboom

@tacaswell
Copy link
Member

also @jkseppan

@jkseppan
Copy link
Member

jkseppan commented Jun 1, 2016

I'm guessing that the Cyrillic font does not have an entry in pdftex.map, which would make this another instance of #4167.

@horribleheffalump
Copy link
Author

I've tried the same code under Python 2.7 and got another error:

Traceback (most recent call last):
  File "D:\Path\___git.py", line 20, in <module>
    plt.savefig(u"d:/fig1.pdf")
  File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 561, in savefig
    return fig.savefig(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1421, in savefig
    self.canvas.print_figure(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 2220, in print_figure
    **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 1952, in print_pdf
    return pdf.print_pdf(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2352, in print_pdf
    self.figure.draw(renderer)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1034, in draw
    func(*args)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 2086, in draw
    a.draw(renderer)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\axis.py", line 1105, in draw
    self.label.draw(renderer)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\text.py", line 594, in draw
    self._fontproperties, angle, mtext=self)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1739, in draw_tex
    psfont = self.tex_font_mapping(dvifont.texname)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1469, in tex_font_mapping
    return self.tex_font_map[texfont]
  File "C:\Python27\lib\site-packages\matplotlib\dviread.py", line 705, in __getitem__
    result = self._font[texname.decode('ascii')]
KeyError: u'larm1200'

larm1200 that's the font name

@jkseppan
Copy link
Member

I don't get this error on current master, but the line of text is cut off in the middle.
issue6516screenshot

@jkseppan
Copy link
Member

FWIW, I've got TeX Live 2015 on OS X 10.11. The font called larm1200 by TeX is supplied in the file sfrm1200.pfb.

% grep larm1200 $(kpsewhich pdftex.map)    
larm1200 SFRM1200 " T2AEncoding ReEncodeFont " <cm-super-t2a.enc <sfrm1200.pfb
% kpsewhich sfrm1200.pfb
/usr/local/texlive/2015/texmf-dist/fonts/type1/public/cm-super/sfrm1200.pfb

@horribleheffalump: Do you have an entry for larm1200 in pdftex.map? Is there a corresponding pfa or pfb file?

@horribleheffalump
Copy link
Author

@jkseppan Yes! That was the problem. I've installed sfrm1200.pfb as a part of cm-super package, and now it all works fine. Thank you!

@cwberardi
Copy link

cwberardi commented Aug 25, 2016

The following script is giving me the same error:

# -*- coding: utf-8 -*-
import matplotlib as mpl
mpl.rcParams['backend'] = 'pdf'
mpl.rc('font',**{'family':'serif'})
mpl.rc('text', usetex=True)
mpl.rc('text.latex',unicode=True)

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import FuncFormatter

millionFormatter        = FuncFormatter(lambda x, pos:'\$%1.0fM' % (x*1e-6))
percentFormatter        = FuncFormatter(lambda x, pos:'{:.2%}'.format(x))

errorDF = pd.DataFrame({'% Diff':[ -6.12256893e-13,   1.27849915e-12,   6.29839396e-06,
                                  3.38728472e-05,   6.23072435e-06,   5.03582306e-06,
                                  -1.09295890e-05,   2.04080118e-04],
                        'Difference': [ -2.43408203e-01,   4.77478027e-01,   2.31911964e+06,
                                       1.26799125e+07,   2.25939726e+06,   1.55594653e+06,
                                       -3.10751878e+06,   5.58644987e+07]}
                       ,index = np.arange(2008,2016))

sns.set_style('ticks')
fig = plt.figure(figsize=(5,2))
ax = fig.add_subplot(111)
ax2 = ax.twinx()
errorDF['% Diff'].plot(kind='bar', position=1, ax=ax, color = 'r', legend=True, label = 'Percent Error',ylim=(0,0.0005), **{'width':0.3})
errorDF.Difference.plot(kind='bar', position=0, ax=ax2,ylim=(0,80000000), legend=True, label = 'Absolute Error [secondary y-axis]', **{'width':0.3})
ax2.legend(loc= 'upper left')
ax.set_xlabel('')
ax2.set_xlabel('')
ax.legend(bbox_to_anchor= (0.286,0.85))
ax.yaxis.set_major_formatter(percentFormatter)
ax2.yaxis.set_major_formatter(millionFormatter)
ax.yaxis.set_ticks([0,0.0001,0.0002,0.0003, 0.0004])
ax2.yaxis.set_ticks([0,20000000,40000000,60000000])
fig.savefig(r'C:\ . . .\dataerrors.pdf', bbox_inches='tight')

Which produces the following error:

Traceback (most recent call last):
  File "<ipython-input-46-ee8c792b07cc>", line 21, in <module>
    fig.savefig(r'C:\Users\Chris\Documents\MIT\Dissertation\FPDS\Visualizations\USASpending\dataerrors.pdf', bbox_inches='tight',dpi=150)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\figure.py", line 1565, in savefig
    self.canvas.print_figure(*args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\backend_bases.py", line 2180, in print_figure
    **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2536, in print_pdf
    self.figure.draw(renderer)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\figure.py", line 1159, in draw
    func(*args)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\axes\_base.py", line 2324, in draw
    a.draw(renderer)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\axis.py", line 1111, in draw
    tick.draw(renderer)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\axis.py", line 254, in draw
    self.label2.draw(renderer)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\artist.py", line 61, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\text.py", line 792, in draw
    mtext=mtext)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1866, in draw_tex
    psfont = self.tex_font_mapping(dvifont.texname)
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\backends\backend_pdf.py", line 1568, in tex_font_mapping
    return self.tex_font_map[texfont]
  File "C:\Users\Chris\Anaconda3\envs\py34\lib\site-packages\matplotlib\dviread.py", line 701, in __getitem__
    result = self._font[texname.decode('ascii')]
AttributeError: 'str' object has no attribute 'decode'

However, I am not using any special characters except [ '%', '$'], which I have escaped. The figure will show fine on the console. The error occurs when I attempt to save as a .pdf.

Matplotlib 1.5.1, Python 3.4, OS Windows 7

jkseppan added a commit to jkseppan/matplotlib that referenced this issue Aug 25, 2016
Dvi is a binary format that includes some ASCII strings such as
TeX names of some fonts. The associated files such as psfonts.map
need to be ASCII too. This patch changes their handling to keep
them as binary strings all the time.

This avoids the ugly workaround

        try:
            result = some_mapping[texname]
        except KeyError:
            result = some_mapping[texname.decode('ascii')]

which is essentially saying that texname is sometimes a string,
sometimes a bytestring. The workaround masks real KeyErrors,
leading to incomprehensible error messages such as in matplotlib#6516.
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Aug 25, 2016
So if you follow the troubleshooting instructions and rerun
with --verbose-helpful you get a hint about the usual reason
for matplotlib#6516.
@cwberardi
Copy link

@jkseppan thanks for quick review. Stackoverflow link should you have any suggestions an a temporary work around.

@jkseppan
Copy link
Member

jkseppan commented Aug 26, 2016

See pull request #6977 for a fix that improves the error message so you know which font is missing. You probably need to install some PS font package in your TeX package manager.

jkseppan added a commit to jkseppan/matplotlib that referenced this issue Dec 27, 2016
Dvi is a binary format that includes some ASCII strings such as
TeX names of some fonts. The associated files such as psfonts.map
need to be ASCII too. This patch changes their handling to keep
them as binary strings all the time.

This avoids the ugly workaround

        try:
            result = some_mapping[texname]
        except KeyError:
            result = some_mapping[texname.decode('ascii')]

which is essentially saying that texname is sometimes a string,
sometimes a bytestring. The workaround masks real KeyErrors,
leading to incomprehensible error messages such as in matplotlib#6516.
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Dec 27, 2016
So if you follow the troubleshooting instructions and rerun
with --verbose-helpful you get a hint about the usual reason
for matplotlib#6516.
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Jan 29, 2017
Dvi is a binary format that includes some ASCII strings such as
TeX names of some fonts. The associated files such as psfonts.map
need to be ASCII too. This patch changes their handling to keep
them as binary strings all the time.

This avoids the ugly workaround

        try:
            result = some_mapping[texname]
        except KeyError:
            result = some_mapping[texname.decode('ascii')]

which is essentially saying that texname is sometimes a string,
sometimes a bytestring. The workaround masks real KeyErrors,
leading to incomprehensible error messages such as in matplotlib#6516.
jkseppan added a commit to jkseppan/matplotlib that referenced this issue Jan 29, 2017
So if you follow the troubleshooting instructions and rerun
with --verbose-helpful you get a hint about the usual reason
for matplotlib#6516.
@QuLogic QuLogic modified the milestones: 2.0.1 (next bug fix release), 2.0.2 (next bug fix release) May 3, 2017
@tacaswell
Copy link
Member

This was fixed by #6977 and went out with 2.1

@tacaswell tacaswell modified the milestones: v2.1.1, 2.1 (next point release) Oct 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants