Skip to content

Commit 76d114f

Browse files
QuLogictacaswell
authored andcommitted
Merge pull request #16476 from anntzer/fix-usetex-baseline
Fix baseline alignment when using usetex. Conflicts: lib/matplotlib/tests/test_usetex.py - import np and formatting issues on decorator
1 parent ed20fc1 commit 76d114f

File tree

6 files changed

+59
-14
lines changed

6 files changed

+59
-14
lines changed

lib/matplotlib/backends/backend_ps.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None):
543543
r'\psfrag{%s}[Bl][Bl][1][%f]{\fontsize{%f}{%f}%s}' % (
544544
thetext, angle, fontsize, fontsize*1.25, tex))
545545
else:
546-
# Stick to the bottom alignment, but this may give incorrect
547-
# baseline some times.
546+
# Stick to the bottom alignment.
548547
pos = _nums_to_str(x-corr, y-bl)
549548
self.psfrag.append(
550549
r'\psfrag{%s}[bl][bl][1][%f]{\fontsize{%f}{%f}%s}' % (

lib/matplotlib/dviread.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ def _output(self):
269269
maxx = max(maxx, x + w)
270270
maxy = max(maxy, y + e)
271271
maxy_pure = max(maxy_pure, y)
272+
if self._baseline_v is not None:
273+
maxy_pure = self._baseline_v # This should normally be the case.
274+
self._baseline_v = None
275+
276+
if not self.text and not self.boxes: # Avoid infs/nans from inf+/-inf.
277+
return Page(text=[], boxes=[], width=0, height=0, descent=0)
272278

273279
if self.dpi is None:
274280
# special case for ease of debugging: output raw dvi coordinates
@@ -296,9 +302,24 @@ def _read(self):
296302
Read one page from the file. Return True if successful,
297303
False if there were no more pages.
298304
"""
305+
# Pages appear to start with the sequence
306+
# bop (begin of page)
307+
# xxx comment
308+
# down
309+
# push
310+
# down, down
311+
# push
312+
# down (possibly multiple)
313+
# push <= here, v is the baseline position.
314+
# etc.
315+
# (dviasm is useful to explore this structure.)
316+
self._baseline_v = None
299317
while True:
300318
byte = self.file.read(1)[0]
301319
self._dtable[byte](self, byte)
320+
if (self._baseline_v is None
321+
and len(getattr(self, "stack", [])) == 3):
322+
self._baseline_v = self.v
302323
if byte == 140: # end of page
303324
return True
304325
if self.state is _dvistate.post_post: # end of file
-47.9 KB
Binary file not shown.
4.08 KB
Loading

lib/matplotlib/tests/test_usetex.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import numpy as np
12
import pytest
23
import platform
34

@@ -11,22 +12,38 @@
1112
pytestmark = pytest.mark.skip('Missing TeX of Ghostscript or dvipng')
1213

1314

14-
@image_comparison(baseline_images=['test_usetex'],
15-
extensions=['pdf', 'png'],
16-
tol={'aarch64': 2.868}.get(platform.machine(), 0.3))
15+
@image_comparison(
16+
baseline_images=['test_usetex'],
17+
extensions=['pdf', 'png'],
18+
style="mpl20")
1719
def test_usetex():
1820
mpl.rcParams['text.usetex'] = True
1921
fig = plt.figure()
2022
ax = fig.add_subplot(111)
21-
ax.text(0.1, 0.2,
23+
kwargs = {"verticalalignment": "baseline", "size": 24,
24+
"bbox": dict(pad=0, edgecolor="k", facecolor="none")}
25+
ax.text(0.2, 0.7,
2226
# the \LaTeX macro exercises character sizing and placement,
2327
# \left[ ... \right\} draw some variable-height characters,
2428
# \sqrt and \frac draw horizontal rules, \mathrm changes the font
2529
r'\LaTeX\ $\left[\int\limits_e^{2e}'
2630
r'\sqrt\frac{\log^3 x}{x}\,\mathrm{d}x \right\}$',
27-
fontsize=24)
28-
ax.set_xticks([])
29-
ax.set_yticks([])
31+
**kwargs)
32+
ax.text(0.2, 0.3, "lg", **kwargs)
33+
ax.text(0.4, 0.3, r"$\frac{1}{2}\pi$", **kwargs)
34+
ax.text(0.6, 0.3, "$p^{3^A}$", **kwargs)
35+
ax.text(0.8, 0.3, "$p_{3_2}$", **kwargs)
36+
for x in {t.get_position()[0] for t in ax.texts}:
37+
ax.axvline(x)
38+
for y in {t.get_position()[1] for t in ax.texts}:
39+
ax.axhline(y)
40+
ax.set_axis_off()
41+
42+
43+
@check_figures_equal()
44+
def test_empty(fig_test, fig_ref):
45+
mpl.rcParams['text.usetex'] = True
46+
fig_test.text(.5, .5, "% a comment")
3047

3148

3249
@check_figures_equal()

lib/matplotlib/texmanager.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ def make_tex(self, tex, fontsize):
228228
%s
229229
\pagestyle{empty}
230230
\begin{document}
231-
\fontsize{%f}{%f}%s
231+
%% The empty hbox ensures that a page is printed even for empty inputs.
232+
\fontsize{%f}{%f}\hbox{}%s
232233
\end{document}
233234
""" % (self._get_preamble(), fontsize, fontsize * 1.25, tex)
234235
with open(texfile, 'wb') as fh:
@@ -388,9 +389,16 @@ def make_png(self, tex, fontsize, dpi):
388389
# see get_rgba for a discussion of the background
389390
if not os.path.exists(pngfile):
390391
dvifile = self.make_dvi(tex, fontsize)
391-
self._run_checked_subprocess(
392-
["dvipng", "-bg", "Transparent", "-D", str(dpi),
393-
"-T", "tight", "-o", pngfile, dvifile], tex)
392+
cmd = ["dvipng", "-bg", "Transparent", "-D", str(dpi),
393+
"-T", "tight", "-o", pngfile, dvifile]
394+
# When testing, disable FreeType rendering for reproducibility; but
395+
# dvipng 1.16 has a bug (fixed in f3ff241) that breaks --freetype0
396+
# mode, so for it we keep FreeType enabled; the image will be
397+
# slightly off.
398+
if (getattr(mpl, "_called_from_pytest", False)
399+
and mpl._get_executable_info("dvipng").version != "1.16"):
400+
cmd.insert(1, "--freetype0")
401+
self._run_checked_subprocess(cmd, tex)
394402
return pngfile
395403

396404
def get_grey(self, tex, fontsize=None, dpi=None):
@@ -443,7 +451,7 @@ def get_text_width_height_descent(self, tex, fontsize, renderer=None):
443451
return width, height + depth, depth
444452

445453
else:
446-
# use dviread. It sometimes returns a wrong descent.
454+
# use dviread.
447455
dvifile = self.make_dvi(tex, fontsize)
448456
with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:
449457
page, = dvi

0 commit comments

Comments
 (0)