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]: Matplotlib not work with MiKTeX. #28212

Open
cesaryuan opened this issue May 12, 2024 · 9 comments
Open

[Bug]: Matplotlib not work with MiKTeX. #28212

cesaryuan opened this issue May 12, 2024 · 9 comments

Comments

@cesaryuan
Copy link

cesaryuan commented May 12, 2024

Bug summary

ax.xaxis.set_major_locator will let matplotlib throw a font not found error. But if we remove ax.xaxis.set_major_locator, the error disappears.

Code for reproduction

from matplotlib import ticker
import matplotlib.pyplot as plt

plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = 'Times'

fig, ax = plt.subplots()
ax.plot([1, 2, 3])

#!!!!! If we comment out the following line, the code will run without error
ax.xaxis.set_major_locator(ticker.LinearLocator(numticks=5))

fig.savefig('test.pdf')

Actual outcome

Throws error:

Traceback (most recent call last):
  File "e:\research\article\\bug.py", line 14, in <module>
    fig.savefig('test.pdf')
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\figure.py", line 3390, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backend_bases.py", line 2193, in print_figure
    result = print_method(
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backend_bases.py", line 2043, in <lambda>
    print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2807, in print_pdf
    self.figure.draw(renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\figure.py", line 3154, in draw
    mimage._draw_list_compositing_images(
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\axes\_base.py", line 3070, in draw
    mimage._draw_list_compositing_images(
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\axis.py", line 1391, in draw
    tick.draw(renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\axis.py", line 295, in draw
    artist.draw(renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\text.py", line 793, in draw
    textrenderer.draw_tex(gc, x, y, clean_line,
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2267, in draw_tex
    pdfname = self.file.dviFontName(dvifont)
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 938, in dviFontName
    psfont = tex_font_map[dvifont.texname]
  File "E:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\dviread.py", line 905, in __getitem__
    raise LookupError(
LookupError: An associated PostScript font (required by Matplotlib) could not be found for TeX font 'zptmcm7y' in 'E:/scoop/apps/miktex/current/texmfs/data/fonts/map/pdftex/pdftex.map'; this problem can often be solved by installing a suitable PostScript font package in your TeX package manager

Expected outcome

No error.

Additional information

MiKTeX version

TeX is a trademark of the American Mathematical Society.
using bzip2 version 1.0.8, 13-Jul-2019
compiled with curl version 8.4.0; using libcurl/8.4.0 Schannel
compiled with expat version 2.5; using expat_2.5.0
compiled with jpeg version 9.5
compiled with liblzma version 50040002; using 50040002
compiled with libpng version 1.6.39; using 1.6.39
compiled with libressl version LibreSSL 3.8.1; using LibreSSL 3.8.1
compiled with MiKTeX Application Framework version 4.8; using 4.8
compiled with MiKTeX Core version 4.24; using 4.24
compiled with MiKTeX Archive Extractor version 4.1; using 4.1
compiled with MiKTeX Package Manager version 4.10; using 4.10
compiled with uriparser version 0.9.7
compiled with xpdf version 4.04
compiled with zlib version 1.2.13; using 1.2.13

Operating system

Windows

Matplotlib Version

3.8.4

Matplotlib Backend

TkAgg

Python version

Python 3.9.19

Jupyter version

No response

Installation

pip

@anntzer
Copy link
Contributor

anntzer commented May 13, 2024

  1. Do you get the same error with the following?
from matplotlib import ticker
import matplotlib.pyplot as plt

plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = 'Times'

plt.figtext(.5, .5, "$-1$")

fig.savefig('test.pdf')
  1. In either case, insert plt.set_loglevel("debug") immediately after setting the rcparams and re-run the failing code. In the output you should see lines of the form DEBUG:matplotlib.dviread:Dvi: /path/to/.matplotlib/tex.cache/bd/69/bd69c059493a3cf42a641ebfa844039e.dvi (with a different filename). (If the code in 1) also fails for you it may be easier to use it as there will be fewer files to try.) For each such dvi file, try running from the terminal (not python) python -m matplotlib.dviread /path/to/the/dvifile.dvi and post the output.

@cesaryuan
Copy link
Author

cesaryuan commented May 13, 2024

@anntzer Thanks so much for you reply.

  1. Also get the same error.

  2. original output

(all) PS D:\user\Desktop\matplotlib-bug> & D:/scoop/apps/miniconda3/current/envs/all/python.exe d:/user/Desktop/matplotlib-bug/bug.py
DEBUG:matplotlib.pyplot:Loaded backend tkagg version 8.6.
DEBUG:matplotlib.texmanager:family: serif, font: Times, info: \usepackage{mathptmx}
DEBUG:matplotlib.texmanager:DejaVu Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: sans-serif, font: Computer Modern Sans Serif, info: \usepackage{type1ec}
DEBUG:matplotlib.texmanager:Apple Chancery font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Textile font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: cursive, font: Zapf Chancery, info: \usepackage{chancery}
DEBUG:matplotlib.texmanager:DejaVu Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: monospace, font: Computer Modern Typewriter, info: \usepackage{type1ec}
DEBUG:matplotlib.dviread:Dvi: C:\Users\cesar\.matplotlib\tex.cache\28\05\280592a6cb87d0a6f07f2be6c239ff4c.dvi
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: header=l3backend-dvips.pro
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: papersize=5203.43999pt,5203.43999pt
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/adobe/times/ptmr7t.tfm
DEBUG:matplotlib.dviread:lh=18, bc=0, ec=170, nw=21, nh=16, nd=16
DEBUG:matplotlib.dviread:Dvi: D:/scoop/apps/miktex/current/texmfs/install/fonts/vf/adobe/times/ptmr7t.vf
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/adobe/times/ptmr8r.tfm
DEBUG:matplotlib.dviread:lh=18, bc=1, ec=255, nw=34, nh=16, nd=16
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Gamma'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Delta'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Theta'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Lambda'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Xi'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Pi'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Sigma'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Upsilon'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Phi'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Psi'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `Omega'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `dotlessj'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `lslashslash'
DEBUG:matplotlib.texmanager:family: serif, font: Times, info: \usepackage{mathptmx}
DEBUG:matplotlib.texmanager:DejaVu Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: sans-serif, font: Computer Modern Sans Serif, info: \usepackage{type1ec}
DEBUG:matplotlib.texmanager:Apple Chancery font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Textile font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: cursive, font: Zapf Chancery, info: \usepackage{chancery}
DEBUG:matplotlib.texmanager:DejaVu Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: monospace, font: Computer Modern Typewriter, info: \usepackage{type1ec}
DEBUG:matplotlib.dviread:Dvi: C:\Users\cesar\.matplotlib\tex.cache\af\1f\af1f4e0a95d1cb3284108346197a266e.dvi
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: header=l3backend-dvips.pro
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: papersize=5203.43999pt,5203.43999pt
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/adobe/times/zptmcm7y.tfm
DEBUG:matplotlib.dviread:lh=18, bc=0, ec=127, nw=45, nh=16, nd=16
DEBUG:matplotlib.dviread:Dvi: D:/scoop/apps/miktex/current/texmfs/install/fonts/vf/adobe/times/zptmcm7y.vf
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/public/cm/cmsy10.tfm
DEBUG:matplotlib.dviread:lh=18, bc=0, ec=127, nw=44, nh=15, nd=16
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/adobe/symbol/psyr.tfm
DEBUG:matplotlib.dviread:lh=17, bc=32, ec=254, nw=52, nh=16, nd=16
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/adobe/times/zptmcm7t.tfm
DEBUG:matplotlib.dviread:lh=18, bc=0, ec=170, nw=33, nh=16, nd=16
DEBUG:matplotlib.dviread:Dvi: D:/scoop/apps/miktex/current/texmfs/install/fonts/vf/adobe/times/zptmcm7t.vf
DEBUG:matplotlib.dviread:opening tfm file D:/scoop/apps/miktex/current/texmfs/install/fonts/tfm/public/cm/cmr10.tfm
DEBUG:matplotlib.dviread:lh=18, bc=0, ec=127, nw=36, nh=16, nd=10
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `dotlessj'
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: Warning: missing glyph `lslashslash'
DEBUG:matplotlib.texmanager:family: serif, font: Times, info: \usepackage{mathptmx}
DEBUG:matplotlib.texmanager:DejaVu Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: sans-serif, font: Computer Modern Sans Serif, info: \usepackage{type1ec}
DEBUG:matplotlib.texmanager:Apple Chancery font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Textile font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: cursive, font: Zapf Chancery, info: \usepackage{chancery}
DEBUG:matplotlib.texmanager:DejaVu Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:Bitstream Vera Sans Mono font is not compatible with usetex.
DEBUG:matplotlib.texmanager:family: monospace, font: Computer Modern Typewriter, info: \usepackage{type1ec}
DEBUG:matplotlib.dviread:Dvi: C:\Users\cesar\.matplotlib\tex.cache\af\1f\af1f4e0a95d1cb3284108346197a266e.dvi
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: header=l3backend-dvips.pro
DEBUG:matplotlib.dviread:Dvi._xxx: encountered special: papersize=5203.43999pt,5203.43999pt
DEBUG:matplotlib.dviread:Dvi: D:/scoop/apps/miktex/current/texmfs/install/fonts/vf/adobe/times/zptmcm7y.vf
Traceback (most recent call last):
  File "d:\user\Desktop\matplotlib-bug\bug.py", line 10, in <module>
    plt.savefig('test.pdf')
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\pyplot.py", line 1134, in savefig
    res = fig.savefig(*args, **kwargs)  # type: ignore[func-returns-value]
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\figure.py", line 3390, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backend_bases.py", line 2193, in print_figure
    result = print_method(
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backend_bases.py", line 2043, in <lambda>
    print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2807, in print_pdf
    self.figure.draw(renderer)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\figure.py", line 3154, in draw
    mimage._draw_list_compositing_images(
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\image.py", line 132, in _draw_list_compositing_images
    a.draw(renderer)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\text.py", line 793, in draw
    textrenderer.draw_tex(gc, x, y, clean_line,
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 2267, in draw_tex
    pdfname = self.file.dviFontName(dvifont)
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\backends\backend_pdf.py", line 938, in dviFontName
    psfont = tex_font_map[dvifont.texname]
  File "D:\scoop\apps\miniconda3\current\envs\all\lib\site-packages\matplotlib\dviread.py", line 905, in __getitem__
    raise LookupError(
LookupError: An associated PostScript font (required by Matplotlib) could not be found for TeX font 'zptmcm7y' in 'D:/scoop/apps/miktex/current/texmfs/data/fonts/map/pdftex/pdftex.map'; this problem can often be solved by installing a suitable PostScript font package in your TeX package manager

matplotlib.dviread output:

(all) PS D:\user\Desktop\matplotlib-bug> python -m matplotlib.dviread C:\Users\cesar\.matplotlib\tex.cache\28\05\280592a6cb87d0a6f07f2be6c239ff4c.dvi
=== new page === (w: 509863, h: 444328, d: 141880)
font: 'ptmr8r'  scale: 0.625
x       y       glyph   chr     w       (glyphs)
983040  1441792 108     l       182183
1165223 1441792 112     p       327680
(all) PS D:\user\Desktop\matplotlib-bug> python -m matplotlib.dviread C:\Users\cesar\.matplotlib\tex.cache\af\1f\af1f4e0a95d1cb3284108346197a266e.dvi
=== new page === (w: 836888, h: 444328, d: 54392)
font: 'zptmcm7y'        scale: 0.625
x       y       glyph   chr     w       (glyphs)
983040  1441792 0       .       509208
font: 'ptmr8r'  scale: 0.625
x       y       glyph   chr     w       (glyphs)
1492248 1441792 49      1       327680

@cesaryuan
Copy link
Author

cesaryuan commented May 14, 2024

Updates: I created a pure Windows 11 virtual machine. And install MiKTeX and Miniconda 3 from scratch. The bug can still be reproduced.

Then, I tried TexLive, and it works. So the bug is that MiKTeX does not work well with Matplotlib?

@anntzer
Copy link
Contributor

anntzer commented May 14, 2024

Possibly, though we should still try to fix that! I suspect this may be due to misconfiguration on your side (so perhaps the fix would be a better error message), but will need to investigate more (likely not in the very short term).

@cesaryuan
Copy link
Author

I suspect this may be due to misconfiguration on your side.

For this, I created a virtual machine with VMware (to control variables, I'm even using the English Windows version instead of the locale one I'm on). Install MiKTex and Python with its official installer.

VMware reproduce steps:

  1. create Window 11 vm by its iso: https://software.download.prss.microsoft.com/dbazure/Win11_23H2_English_x64v2.iso
  2. install Python: https://www.python.org/downloads/release/python-3119/
  3. install MiKTeX: https://miktex.org/download
  4. check miktex updates and install updates
  5. pip install matplotlib
  6. python bug.py
from matplotlib import ticker
import matplotlib.pyplot as plt

plt.rcParams['text.usetex'] = True
plt.rcParams['font.family'] = 'serif'
plt.rcParams['font.serif'] = 'Times'
# plt.set_loglevel("debug")
plt.figtext(.5, .5, "$-1$")

plt.savefig('test.pdf')

I compare the dvi file generated by texlive and miktex. Here is the result:
MiKTeX: (another thing to be noted is I can compile to pdf successfully by MiKTeX.)

=== new page === (w: 836888, h: 444328, d: 54392)
font: 'zptmcm7y'        scale: 0.625
x       y       glyph   chr     w       (glyphs)
983040  1441792 0       .       509208
font: 'ptmr8r'  scale: 0.625
x       y       glyph   chr     w       (glyphs)
1492248 1441792 49      1       327680

TeXLive:

=== new page === (w: 836888, h: 444328, d: 0)
font: 'cmsy10'  scale: 0.625
x       y       glyph   chr     w       (glyphs)
983040  1441792 0       .       509726
font: 'ptmr8r'  scale: 0.625
x       y       glyph   chr     w       (glyphs)
1492248 1441792 49      1       327680

image

@cesaryuan cesaryuan changed the title [Bug]: ax.xaxis.set_major_locator will let matplotlib to throw error. [Bug]: Matplotlib does not work well with MiKTeX. May 14, 2024
@cesaryuan cesaryuan changed the title [Bug]: Matplotlib does not work well with MiKTeX. [Bug]: Matplotlib not work with MiKTeX. May 14, 2024
@anntzer
Copy link
Contributor

anntzer commented May 14, 2024

Thanks. I have repro'd the issue (you can also install miktex on mac/linux) and the fix is not obvious :/

@anntzer
Copy link
Contributor

anntzer commented May 29, 2024

OK, I think I figured this out. The short writeup is that zptmcm7y is a so-called Virtual Font (vf), which is basically a kind of dvi file where each glyph is represented by a dvi page where glyph(s) from other "real" font(s) are drawn. zptmcm7y.vf uses some glyphs from obscure "real" fonts (in this case, rsfs10.tfm) to represent some obscure glyphs, and these other fonts don't get installed by default. This is not needed by TeX & friends, likely because they only load these other glyphs on demand. On the contrary, Matplotlib's dvi parser (which is reused as a vf parser) tries to load everything immediately. This ultimately leads to trying to load rsfs10.tfm, which is not present, causes a FileNotFoundError, which bubbles out and makes Matplotlib believe wrongly that zptmcm7y.vf is absent. Matplotlib then interprets this as meaning that zptmcm7y is a real font itself, but the pdf renderer then fails to load it (as it indeed doesn't exist), hence the crash.

The fix seems likely to involve turning the Vf parser into something that lazy-loads the glyphs on demand (we can't really do that for the Dvi parser itself I think), which is a bit annoying work but should probably(?) not involve big technical difficulties...

@anntzer anntzer added Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues topic: text/usetex labels May 29, 2024
@anntzer
Copy link
Contributor

anntzer commented May 29, 2024

Actually, looking at it again it wasn't that bad, the following patch fixes the issue, I believe (can you confirm?):

diff --git i/lib/matplotlib/dviread.py w/lib/matplotlib/dviread.py
index 82f43b5629..7d61367fd6 100644
--- i/lib/matplotlib/dviread.py
+++ w/lib/matplotlib/dviread.py
@@ -230,6 +230,7 @@ class Dvi:
         self.dpi = dpi
         self.fonts = {}
         self.state = _dvistate.pre
+        self._missing_font = None
 
     def __enter__(self):
         """Context manager enter method, does nothing."""
@@ -337,6 +338,8 @@ class Dvi:
         while True:
             byte = self.file.read(1)[0]
             self._dtable[byte](self, byte)
+            if self._missing_font:
+                raise self._missing_font
             name = self._dtable[byte].__name__
             if name == "_push":
                 down_stack.append(down_stack[-1])
@@ -364,11 +367,15 @@ class Dvi:
     @_dispatch(min=0, max=127, state=_dvistate.inpage)
     def _set_char_immediate(self, char):
         self._put_char_real(char)
+        if isinstance(self.fonts[self.f], FileNotFoundError):
+            return
         self.h += self.fonts[self.f]._width_of(char)
 
     @_dispatch(min=128, max=131, state=_dvistate.inpage, args=('olen1',))
     def _set_char(self, char):
         self._put_char_real(char)
+        if isinstance(self.fonts[self.f], FileNotFoundError):
+            return
         self.h += self.fonts[self.f]._width_of(char)
 
     @_dispatch(132, state=_dvistate.inpage, args=('s4', 's4'))
@@ -382,7 +389,9 @@ class Dvi:
 
     def _put_char_real(self, char):
         font = self.fonts[self.f]
-        if font._vf is None:
+        if isinstance(font, FileNotFoundError):
+            self._missing_font = font
+        elif font._vf is None:
             self.text.append(Text(self.h, self.v, font, char,
                                   font._width_of(char)))
         else:
@@ -486,7 +495,16 @@ class Dvi:
     def _fnt_def_real(self, k, c, s, d, a, l):
         n = self.file.read(a + l)
         fontname = n[-l:].decode('ascii')
-        tfm = _tfmfile(fontname)
+        try:
+            tfm = _tfmfile(fontname)
+        except FileNotFoundError as exc:
+            # Explicitly allow defining missing fonts for Vf support; we only
+            # register an error when trying to load a glyph from a missing font
+            # and throw that error in Dvi._read.  For Vf, _finalize_packet
+            # checks whether a missing glyph has been used, and in that case
+            # skips the glyph definition.
+            self.fonts[k] = exc
+            return
         if c != 0 and tfm.checksum != 0 and c != tfm.checksum:
             raise ValueError('tfm checksum mismatch: %s' % n)
         try:
@@ -712,12 +730,14 @@ class Vf(Dvi):
         self.h, self.v, self.w, self.x, self.y, self.z = 0, 0, 0, 0, 0, 0
         self.stack, self.text, self.boxes = [], [], []
         self.f = self._first_font
+        self._missing_font = None
         return self.file.tell() + pl
 
     def _finalize_packet(self, packet_char, packet_width):
-        self._chars[packet_char] = Page(
-            text=self.text, boxes=self.boxes, width=packet_width,
-            height=None, descent=None)
+        if not self._missing_font:  # Otherwise we don't have full glyph definition.
+            self._chars[packet_char] = Page(
+                text=self.text, boxes=self.boxes, width=packet_width,
+                height=None, descent=None)
         self.state = _dvistate.outer
 
     def _pre(self, i, x, cs, ds):

(Overloading Dvi.fonts to also record exceptions is a bit ugly, but the quickest solution I found.)

Assuming this works, turning this into a PR is left as an exercise to the reader.

@anntzer anntzer removed Difficulty: Medium https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues Difficulty: Hard https://matplotlib.org/devdocs/devel/contribute.html#good-first-issues labels May 29, 2024
@cesaryuan
Copy link
Author

can you confirm?

It did work now! Thanks so much.

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

2 participants