GeezerVison is showing github.com — Fix usetex path optical sizing by krishsinghhura · Pull Request #32392 · matplotlib/matplotlib
Conversation
PR summary
Closes #32389
Problem
In usetex mode, TextToPath.get_glyphs_tex hardcoded LaTeX compilation to a fixed FONT_SCALE = 100 pt. Because TeX fonts have size-specific optical designs, TeX selected the large 17 pt design (CMSS17) and scaled it down, while layout measurement (TexManager.get_text_width_height_descent) typeset at the actual text size (e.g. CMSS8 for 6–8 pt).
This caused:
- Font mismatch: SVG output used
CMSS17 while PDF output used CMSS8.
- Alignment errors: Right-aligned text with
path_effects was narrower than its layout box and ended short of the alignment boundary.
TextPath(size=...) issue: TextPath accepted size separately without propagating it to prop.
Solution
- Updated
TextToPath.get_glyphs_tex to typeset at the requested font size (fontsize = prop.get_size_in_points()) and rescale DVI coordinates and boxes back to FONT_SCALE units via scale = self.FONT_SCALE / fontsize.
- Normalizes
prop via FontProperties._from_any(prop) for defensive input handling.
- Forwards explicit
size in TextPath.__init__ to a copy of prop.
- Added unit tests in
test_usetex.py covering optical font selection and TextPath size propagation.
Reproduction & Verification
Click to view reproduction code
import re
import matplotlib as mpl
import matplotlib.patheffects as pe
import matplotlib.pyplot as plt
mpl.rcParams["text.usetex"] = True
s = "Hamburgefonstiv"
# 1. 6 pt text saved as SVG and as PDF
fig = plt.figure(figsize=(2, 1))
fig.text(0.1, 0.5, s, fontsize=6)
fig.savefig("usetex.svg")
fig.savefig("usetex.pdf")
with open("usetex.svg", encoding="utf-8") as f:
svg = f.read()
with open("usetex.pdf", "rb") as f:
pdf = f.read()
print("SVG fonts:", sorted(set(re.findall(r'id="(CM[A-Z]+\d+)-', svg))))
print("PDF fonts:", sorted({m.decode() for m in re.findall(rb"/BaseFont\s*/(?:[A-Z]{6}\+)?(\w+)", pdf)}))
# 2. Right-aligned 8 pt text on Agg, without and with path effects
fig = plt.figure(figsize=(1.6, 0.5), dpi=600)
fig.add_artist(plt.Line2D([0.93, 0.93], [0, 1], lw=0.3, color="tab:red"))
fig.text(0.93, 0.62, s, fontsize=8, ha="right", va="center")
fig.text(0.93, 0.25, s, fontsize=8, ha="right", va="center", path_effects=[pe.Normal()])
fig.savefig("usetex_path_effects.png")
Expected Results with this PR:
- Output:
SVG fonts: ['CMSS8']
PDF fonts: ['CMSS8']
(Before: SVG used ['CMSS17'])
- Image: In
usetex_path_effects.png, both lines of text align flush with the red guide line.
Tests Run:
pytest lib/matplotlib/tests/test_usetex.py -k "optical_sizing or textpath_size" (Passed)
- Regression suite:
test_mathdefault, test_multiline_eqnarray, test_usetex_with_underscore, test_usetex_fallback, test_rotation, test_unicode_sizing (All passed)
- Code checks:
git diff --check passed, no trailing whitespace or lint issues.
AI Disclosure
I used AI assistance to investigate the issue, trace relevant rendering paths, draft the implementation and tests, and help analyze test output. I reviewed the resulting changes, ran verification steps, and am responsible for the final contribution.
PR quality check
- Use an expressive title (e.g.
Fix usetex path font optical sizing and alignment)
- New and changed code is tested
- [N/A] Plotting related features are demonstrated in an example
- [N/A] New features and API changes have release notes
- Documentation complies with general and docstring guidelines
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks. We also ask that you please finish addressing any review comments on this PR and wait for it to be merged (or closed) before opening a new one, as it can be a valuable learning experience to go through the review process.
You can also join us on discourse chat for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide.
Please let us know if (and how) you use AI, it will help us give you better feedback on your PR.
We strive to be a welcoming and open project. Please follow our Code of Conduct.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Hey @iccir I’ve added the AI disclosure.
I also investigated the CI failures: every failed matrix job is the same expected-image mismatch in test_rotation[svg]. The optical-sizing correction intentionally changes the SVG TeX glyph geometry, leaving the existing rotation.svg baseline stale. I regenerated and updated that SVG baseline; the Linux x64 and ARM outputs are pixel-identical.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
@iccir I updated the rotation.svg baseline for the corrected TeX sizing. CI is not fully green yet: the remaining AppVeyor job timed out at its 60-minute limit around 80% through the Windows suite, without reporting a failed test or traceback. Please let me know if you prefer a rerun or targeted Windows verification.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
The AppVeyor job frequently times out and should hopefully be fixed by #32395.
|
krishsinghhura reacted with thumbs up emoji
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A path created at 6 pt and changed to 17 pt retains CMSS8 rather than selecting CMSS17. Could we regenerate the TeX path when the size changes, or explicitly define and test the intended fixed-optical-design behaviour?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
if self._tex_prop is not None and self._tex_size != self._size:
|
|
|
prop = self._tex_prop.copy()
|
|
|
prop.set_size(self._size)
|
|
|
self._vertices, self._codes = text_to_path.get_text_path(
|
xakep8
Oct 2, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last change sorry, we should change this to
path = Path(*text_to_path.get_text_path(
prop, self._tex_s, ismath="TeX"), readonly=True)
self._vertices, self._codes = path.vertices, path.codes
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xakep8 Thanks... fixed it by restoring the readonly Path invariant after TeX path regeneration, with regression coverage
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
xakep8 reacted with rocket emoji
|
Hi @iccir, following up on this PR—I've addressed the review feedback, and the original reporter has confirmed the fix against their reproduction and curved-text: #32389 (comment). Could a maintainer take a look, or help find someone familiar with this area? Happy to address any further changes needed.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This branch has not been deployed
No deployments
Reviewers
1 more reviewer
xakep8
xakep8 approved these changes
Reviewers whose approvals may not affect merge requirements
At least 1 approving review is required to merge this pull request.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|