GeezerVison is showing github.com — BUG: align custom x tick label baselines by QianyeSu · Pull Request #32423 · matplotlib/matplotlib
Conversation
QianyeSu
commented
Oct 2, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Fixes #32316.
Summary
- Keep the line box used by custom, unrotated x tick labels large enough for the font's
lp metrics.
- This keeps labels with different ascenders (for example,
"pol." and "1") on a common baseline after the text metric changes in 3.11.
- Add a regression test and update the affected image baselines.
The adjustment is limited to labels produced by a FuncFormatter; default numeric tick formatting, fixed labels, and rotated labels retain their existing layout behavior.
Tests
MPLBACKEND=Agg ./.venv/bin/pytest -q lib/matplotlib/tests/test_text.py lib/matplotlib/tests/test_axes.py lib/mpl_toolkits/axes_grid1/tests/test_axes_grid1.py lib/mpl_toolkits/mplot3d/tests/test_axes3d.py lib/matplotlib/tests/test_colorbar.py
python -m compileall -q lib/matplotlib/axis.py lib/matplotlib/text.py lib/matplotlib/tests/test_text.py
git diff --check
The focused Matplotlib test run passed with 1338 passed, 91 skipped.
AI Disclosure
I used an AI coding assistant to help investigate the regression, draft the implementation, and run the tests. I reviewed the changes, the resulting baseline images, and the test output before opening this pull request.
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.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
I pushed commit 3d7365a040 to address the remaining cross-platform image failures.
The first CI run showed that set_ticklabels() internally uses a FuncFormatter, so it was incorrectly included in the new custom-formatter baseline path. This commit marks that internal formatter as fixed-label formatting and leaves its existing layout unchanged. The affected set_get_ticklabels, colorbar, subfigure, and 3D image tests pass locally against the upstream baselines; the regression test for the reported custom formatter still passes.
The free-threaded Linux job had 3 image failures (all baseline/layout comparisons, no Python exceptions). A new CI run is now queued for the narrowed change.
|
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.
This is a complex topic going deep into the internals of matplotlib. I myself have to admit, that I do not understand the root cause or the suitability of the fix without taking the time to dig into the topic.
Since you apprently did, in your own words and without consulting AI (following our AI policy), please explain why this is the correct solution:
- what is the root cause of the issue
- #32316 (comment) states the bisect. Did you confirm that? How does the code here relate to the regession of the stated commit?
- why is the adjustment limited to FuncFormatter?
- how do you justify the design to introducingdynamic attributes
_is_ticklabel and _is_custom_ticklabel_formatter?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Thanks for the detailed questions.
The regression is caused by the change in Text._get_layout() introduced by
97f4943cf279c82a4dc64e40ec52dcb1bcd218fe, which changed how font ascent and
descent are obtained. For top-aligned, single-line labels, strings with
different ascenders, such as "pol." and "1", can consequently receive
different line-box heights and appear with misaligned baselines. I confirmed
that this is the commit identified by the bisect in issue #32316.
The fix is limited to FuncFormatter because it can generate arbitrary text
for each tick and is the direct reproduction case. Fixed labels created by
set_ticklabels() are explicitly excluded, and the existing behavior of
numeric formatters and rotated labels is preserved.
_is_ticklabel limits the layout adjustment to tick-label text objects rather
than all Text instances. _is_custom_ticklabel_formatter distinguishes
user-provided formatters from the internal formatter used by
set_ticklabels().
I agree that dynamic private attributes are not ideal as a long-term design.
They were intended to keep this fix narrowly scoped without changing the
public API, and I am happy to refactor this part if a different internal
mechanism is preferred.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Thanks for the reply. Maybe I'm misunderstanding, but I have the impression that this is rather an operational fix for the given example but not a systematic identification and fix of the root cause.
For example, the issue example uses a FuncFormatter
gca().xaxis.set_major_formatter(lambda x, i: "pol." if x == 0 else str(int(x)))
I would expect - but have not checked yet - that a fixed formatter should render identically
gca().set_xticks([0, 1], labels=['pol.', str(1)])
If that's the case, a specific fix for FuncFormatter is not the way to go. If my assuption is wrong, I'd like to understand why FuncFormatter rendering is different than FixedFormatter rendering.
|
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
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.
|