Skip to content

Skip hidden y-axis offset text when positioning titles (fix #31881)#31885

Open
gaoflow wants to merge 1 commit into
matplotlib:mainfrom
gaoflow:fix-31881-hidden-offset-title-nan
Open

Skip hidden y-axis offset text when positioning titles (fix #31881)#31885
gaoflow wants to merge 1 commit into
matplotlib:mainfrom
gaoflow:fix-31881-hidden-offset-title-nan

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 12, 2026

Copy link
Copy Markdown

PR summary

Fixes #31881plt.subplots(1, 2, sharey=True, tight_layout=True) with per-subplot titles and large y-values raised ValueError: cannot convert float NaN to integer on draw. Regression in 3.11.0, bisected by @ksunden to #31285.

Root cause

On the inner subplot the y axis is shared, so its offset text is hidden (set_visible(False)) but still carries text (e.g. '1e53'). Axes._update_title_position decides whether to lift the title above the offset text by checking only offsetText.get_text(), not its visibility:

if ax.yaxis.offsetText.get_text():
    bb = ax.yaxis.offsetText.get_tightbbox(renderer)
    if bb.intersection(title.get_tightbbox(renderer), bb):
        top = bb.ymax

Since #31285, Text.get_tightbbox returns Bbox.null() for hidden/empty text. Bbox.null() is [[inf, inf], [-inf, -inf]], which has xmin=-inf, xmax=+inf — so it behaves as an infinite box under intersection, making the guard pass and setting top = bb.ymax = inf. The title is then placed at y = inf; its window extent feeds tight_layout, which computes a NaN subplot position, and the subsequent YAxis.get_tick_space does int(np.floor(NaN)) → the error.

Fix

A hidden offset text is not drawn, so it should not influence the title position. Only consider it when it is visible. This also fixes the (silently broken) title placement that occurs without tight_layout — the title was being moved to infinity there too, just without a downstream crash.

Test

test_title_above_hidden_offset reproduces the issue and asserts the title and subplot positions stay finite. It fails on main (raises the original ValueError) and passes with the fix. The existing test_title_above_offset covers the visible-offset case, which is unchanged.

I verified the change against an installed 3.11.0 build by patching the single edited file (the change is pure-Python).

The y-axis offset text of an inner subplot that shares its y axis is
hidden but still carries text. _update_title_position only checked
get_text(), so since matplotlib#31285 (which makes a hidden text report a null,
non-finite tight bbox) the offset text pushed the title -- and the
subplot position computed by tight_layout -- to inf/NaN. Drawing then
raised "cannot convert float NaN to integer".

Only consider the offset text for title placement when it is visible.
@github-actions

Copy link
Copy Markdown

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.

@gaoflow

gaoflow commented Jun 13, 2026

Copy link
Copy Markdown
Author

Thanks for the welcome! To answer the AI question directly: yes, this PR was written with AI assistance (Claude), working under my direction and review.

I drove the debugging — reproducing the crash headlessly, bisecting it to #31285, and tracing the NaN back through tight_layout to _update_title_position, where a hidden y-axis offset text still contributed its (now non-finite) Bbox.null() tight bbox and pushed the title to infinity. I verified the fix and the regression test myself (red on main, green with the change) by patching the single edited pure-Python file over an installed 3.11 build.

Happy to adjust the approach, comment, or test if you'd prefer a different fix location (e.g. guarding the bbox itself rather than the visibility check).

@gaoflow

gaoflow commented Jun 13, 2026

Copy link
Copy Markdown
Author

Note on CI: the one red job (Azure Main Pytest Windows_py313) failed on test_agg_filter_alpha[gif] with an ImageMagick _ConverterErrormagick.exe: improper image header ... agg_filter_alpha-expected.gif while converting the baseline GIF. That's a test-infrastructure/image-conversion issue on the Windows runner, unrelated to this change (which only touches title positioning). All 8878 other tests pass on that job, and the full GitHub Actions matrix is green. Happy to rebase if a re-run is wanted.

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

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Bug]: ValueError ("cannot convert float NaN to integer") when trying to show horizontally-stacked subplots

2 participants