Visitar URL original
BUG: align custom x tick label baselines by QianyeSu · Pull Request #32423 · matplotlib/matplotlib · GitHub
Skip to content

BUG: align custom x tick label baselines - #32423

Open
QianyeSu wants to merge 2 commits into
matplotlib:mainfrom
QianyeSu:fix/32316-xticklabel-baselines
Open

QianyeSu wants to merge 2 commits into
matplotlib:mainfrom
QianyeSu:fix/32316-xticklabel-baselines

Conversation

@QianyeSu

@QianyeSu QianyeSu commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

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.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 09:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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.

@QianyeSu
QianyeSu force-pushed the fix/32316-xticklabel-baselines branch 2 times, most recently from 44a5dff to 09d21bf Compare October 2, 2026 09:52
@QianyeSu
QianyeSu force-pushed the fix/32316-xticklabel-baselines branch from 09d21bf to 96340c1 Compare October 2, 2026 11:21
@QianyeSu

QianyeSu commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

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.

@timhoffm timhoffm left a comment

Copy link
Copy Markdown
Member

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?

@QianyeSu

QianyeSu commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

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.

@timhoffm

timhoffm commented Oct 5, 2026

Copy link
Copy Markdown
Member

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.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: misaligned between xticklabel baselines

3 participants