Skip to content

[Bug]: savefig pdf produces AttributeError: module 'unicodedata2' has no attribute 'ucnhash_CAPI' with matplotlib 3.5.0 #21711

@guidov

Description

@guidov

Bug summary

upgrading from matplotlib 3.4.3 to matplotlib 3.5.0

the save figure command produces an error when saving .pdf but not png

AttributeError: module 'unicodedata2' has no attribute 'ucnhash_CAPI'

Downgrading back to 3.4.3 and the problem disappears.

Code for reproduction

import matplotlib.pyplot as plt
plt.savefig("figure.pdf")

Actual outcome

---> 84     plt.savefig("figure.pdf")

~/anaconda3/lib/python3.8/site-packages/matplotlib/pyplot.py in savefig(*args, **kwargs)
    956 def savefig(*args, **kwargs):
    957     fig = gcf()
--> 958     res = fig.savefig(*args, **kwargs)
    959     fig.canvas.draw_idle()   # need this if 'transparent=True' to reset colors
    960     return res

~/anaconda3/lib/python3.8/site-packages/matplotlib/figure.py in savefig(self, fname, transparent, **kwargs)
   3010                         ax.patch._cm_set(facecolor='none', edgecolor='none'))
   3011 
-> 3012             self.canvas.print_figure(fname, **kwargs)
   3013 
   3014     def ginput(self, n=1, timeout=30, show_clicks=True,

~/anaconda3/lib/python3.8/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2312                 # force the figure dpi to 72), so we need to set it again here.
   2313                 with cbook._setattr_cm(self.figure, dpi=dpi):
-> 2314                     result = print_method(
   2315                         filename,
   2316                         facecolor=facecolor,

~/anaconda3/lib/python3.8/site-packages/matplotlib/backend_bases.py in wrapper(*args, **kwargs)
   1641             kwargs.pop(arg)
   1642 
-> 1643         return func(*args, **kwargs)
   1644 
   1645     return wrapper

~/anaconda3/lib/python3.8/site-packages/matplotlib/_api/deprecation.py in wrapper(*inner_args, **inner_kwargs)
    384             # Early return in the simple, non-deprecated case (much faster than
    385             # calling bind()).
--> 386             return func(*inner_args, **inner_kwargs)
    387         arguments = signature.bind(*inner_args, **inner_kwargs).arguments
    388         if is_varargs and arguments.get(name):

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in print_pdf(self, filename, dpi, bbox_inches_restore, metadata)
   2786             renderer.finalize()
   2787             if not isinstance(filename, PdfPages):
-> 2788                 file.finalize()
   2789         finally:
   2790             if isinstance(filename, PdfPages):  # finish off this page

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in finalize(self)
    792         self.endStream()
    793         self._write_annotations()
--> 794         self.writeFonts()
    795         self.writeExtGSTates()
    796         self._write_soft_mask_groups()

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in writeFonts(self)
    925                 chars = self._character_tracker.used.get(filename)
    926                 if chars:
--> 927                     fonts[Fx] = self.embedTTF(filename, chars)
    928         self.writeObject(self.fontObject, fonts)
    929 

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in embedTTF(self, filename, characters)
   1422 
   1423         if fonttype == 3:
-> 1424             return embedTTFType3(font, characters, descriptor)
   1425         elif fonttype == 42:
   1426             return embedTTFType42(font, characters, descriptor)

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in embedTTFType3(font, characters, descriptor)
   1150                 # the missing glyphs may not even be used in the actual string.
   1151                 warnings.filterwarnings("ignore")
-> 1152                 widths = [get_char_width(charcode)
   1153                           for charcode in range(firstchar, lastchar+1)]
   1154             descriptor['MaxWidth'] = max(widths)

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in <listcomp>(.0)
   1150                 # the missing glyphs may not even be used in the actual string.
   1151                 warnings.filterwarnings("ignore")
-> 1152                 widths = [get_char_width(charcode)
   1153                           for charcode in range(firstchar, lastchar+1)]
   1154             descriptor['MaxWidth'] = max(widths)

~/anaconda3/lib/python3.8/site-packages/matplotlib/backends/backend_pdf.py in get_char_width(charcode)
   1141             def get_char_width(charcode):
   1142                 s = ord(cp1252.decoding_table[charcode])
-> 1143                 width = font.load_char(
   1144                     s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING).horiAdvance
   1145                 return cvt(width)

~/anaconda3/lib/python3.8/site-packages/matplotlib/_text_helpers.py in warn_on_missing_glyph(codepoint)
     17         "Glyph {} ({}) missing from current font.".format(
     18             codepoint,
---> 19             chr(codepoint).encode("ascii", "namereplace").decode("ascii")))
     20     block = ("Hebrew" if 0x0590 <= codepoint <= 0x05ff else
     21              "Arabic" if 0x0600 <= codepoint <= 0x06ff else

AttributeError: module 'unicodedata2' has no attribute 'ucnhash_CAPI'

[@tacaswell edited to add markup]

Expected outcome

Figure plotted

Additional information

No response

Operating system

Ubuntu

Matplotlib Version

3.5.0

Matplotlib Backend

module://matplotlib_inline.backend_inline

Python version

3.8.12

Jupyter version

3.2.4

Installation

conda

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions