Skip to content

[ENH]: Optional axes-aware text wrapping for wrap=True #31655

Open

Description

@deepali-cg

Problem

When creating multi-axes figures with subplots (e.g. dashboards,
reports, side-by-side comparisons), using ax.text() with wrap=True
causes text to wrap based on the figure boundary instead of the axes
boundary. This means text overflows outside its axes into adjacent
axes or outside the figure entirely, making the plot look broken.

Example: A 2-column subplot figure where a long annotation in the
left axes spills into the right axes area.

Proposed solution

Add an option for wrap=True to respect the axes boundary when text
is placed inside an axes, so annotations stay visually contained
within their axes.

This could be implemented by checking whether the text object belongs
to an axes (self.axes is not None) in the _get_wrap_line_width()
method of text.py, and using the axes boundary instead of the figure
boundary when calculating the available wrap width.

Activity

  1. anushkadas-coder commented on May 13, 2026

    @anushkadas-coder

    Hi @codegnan-dm, I see you already have PR #31633 linked for this enhancement. This looks like a super useful feature! Let me know if you need any help testing it out on different subplot configurations or if there is anything I can do to help get it reviewed.

  2. deepali-cg commented on May 13, 2026

    @deepali-cg
    Author

    Hi @anushkadas-coder, thank you so much! That's really kind of you.

    Yes, it would be really helpful if you could test it on different
    subplot configurations and share your results as a comment on PR #31633.

    Any testing or feedback you can share on the PR would help strengthen
    the case for the maintainers to review and merge it. Thanks again!

  3. rcomer commented on May 15, 2026

    @rcomer
    Member

    This means text overflows outside its axes into adjacent axes or outside the figure entirely

    If you have an example where you set wrap=True and the text still went outside the figure, please raise that as a bug report.

    If the problem is only that text goes into the next axes, can you get what you want with subfigures?

    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=(6, 4))
    sfig1, sfig2 = fig.subfigures(ncols=2)
    ax1 = sfig1.subplots()
    ax2 = sfig2.subplots()
    
    ax1.set_title("Left Axes")
    ax1.text(0.05, 0.5,
             "This is a very long string that should wrap within the axes boundary and not overflow outside it",
             wrap=True, transform=ax1.transAxes, va='center')
    
    ax2.set_title("Right Axes")
    ax2.text(0.05, 0.5,
             "This is a very long string that should wrap within the axes boundary and not overflow outside it",
             wrap=True, transform=ax2.transAxes, va='center')
    
    plt.show()
    Image
  4. deepali-cg commented on May 19, 2026

    @deepali-cg
    Author

    @rcomer Thank you for the subfigures suggestion — I tested it and
    it does work correctly. The text wraps within each subfigure boundary
    as expected.

    However, I think the axes-aware wrapping in PR #31633 still adds value
    for the following reasons:

    1. Discoverability — users who use ax.text() with wrap=True expect
      wrapping to "just work" within their axes. Requiring subfigures as
      a workaround is not obvious and is hard to find in documentation.

    2. Simplicity — plt.subplots() is the most common way to create
      multi-axes figures. Requiring users to restructure their code to
      use fig.subfigures() just to get correct text wrapping adds
      unnecessary complexity.

    3. Consistency — if wrap=True is set on text inside an axes, it is
      reasonable to expect wrapping to respect the axes boundary by default.

    That said, I completely understand if the maintainers feel the
    subfigures workaround is sufficient and the PR is not needed. Happy
    to close the PR if that is the preferred direction.

  5. timhoffm commented on May 19, 2026

    @timhoffm
    Member

    I agree that wrapping text in an Axes is a desirable feature.

    If text in an Axes is wrapped, it should by default be wrapped within the Axes box. Crossing the spine is almost always visually ugly (see also the current example: https://matplotlib.org/stable/gallery/text_labels_and_annotations/autowrap.html).

  6. deepali-cg commented on May 19, 2026

    @deepali-cg
    Author

    @timhoffm Thank you for the support! That is exactly the problem
    I encountered — the current behavior almost always produces visually
    broken output when using wrap=True inside axes.

    PR #31633 implements this fix by checking whether the text belongs
    to an axes in _get_wrap_line_width() and using the axes boundary
    instead of the figure boundary when calculating wrap width. The fix
    preserves full backward compatibility — figure-level text like
    fig.suptitle() still falls back to the figure boundary.

    Before/after screenshots are attached to the PR showing the
    improvement. Happy to make any adjustments based on your feedback!

  7. rcomer commented on May 19, 2026

    @rcomer
    Member

    Interestingly, our current implementation was originally based on a StackOverflow answer that did wrap to the axes #3418. From a quick scan of the PR I don't see an explanation for why it changed to wrapping to the figure #4342.

    I note that annotations are often placed outside an axes, even if they use an axes method (example). In fact I guess that would be more common if you have a lot of text, because you don't want the text to obscure the data you have plotted. So I think this would need more careful design than just checking whether the text object has an axes attribute.

  8. rcomer commented on May 19, 2026

    @rcomer
    Member

    OTOH axes titles are an example where, if you have subplots, you probably want to wrap to the width of the axes even though the text is outside it.

  9. timhoffm commented on May 19, 2026

    @timhoffm
    Member

    This means we actually need control via a parameter wrap_boundary with values "axes" / "figure".

    Default for Text would be "figure", and Axes.text() would override the default to "axes". Possibly some other text-related plotting functions like bar_label should too.

  10. rcomer commented on May 19, 2026

    @rcomer
    Member

    If you are passing long strings in bar_label, wouldn't you want to wrap to the bars?

  11. story645 commented on May 19, 2026

    @story645
    Member

    via a parameter wrap_boundary with values "axes" / "figure".

    What about allowing wrap to take "axes" and "figure" in addition to True/False?

  12. timhoffm commented on May 19, 2026

    @timhoffm
    Member

    @rcomer Yes let's leave bar_label aside that's more involved.

    @story645 good idea. We don't need a new parameter. Enriching the semantics of wrap from bool to different values makes sense. For backward-compatibility and simplicity, wrap=True should be synonym to wrap="figure".

  13. deepali-cg commented on May 20, 2026

    @deepali-cg
    Author

    Thank you all for the detailed design discussion! I understand the
    consensus is to enrich wrap to accept "axes" / "figure" string values
    in addition to True/False, with wrap=True remaining as figure boundary
    for backward compatibility. I will update PR #31633 accordingly.

  14. deepali-cg commented on May 20, 2026

    @deepali-cg
    Author

    I have opened PR #31716 which implements the agreed design — extending wrap to accept 'axes' and 'figure' string values, with wrap=True remaining as figure boundary for backward compatibility.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions