Skip to content

[Bug]: Re-adding annotation texts to the axes causes them to be obscured #31748

Open

Description

@williamlus

Bug summary

When annotation texts are removed and re-added to the axes, they become obscured in the second plot.

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

linestyles = [
     ('Solid', 'solid'),      
     ('Dotted', 'dotted'),    
     ('Dashed', 'dashed'),    
     ('Dashdot', 'dashdot')]  

fig, ax = plt.subplots()

ax.set(ylim=(-0.5, len(linestyles)-0.5), yticks=np.arange(len(linestyles)), yticklabels=[name for name, _ in linestyles])

texts = []
for i, (name, linestyle) in enumerate(linestyles):
    text = ax.annotate(repr(linestyle), xy=(0.0, i), xycoords=ax.get_yaxis_transform(), xytext=(-6, -12), textcoords='offset points', ha='center', fontsize=12, color='blue')
    texts.append(text)

plt.savefig('plot1.png')

for text in texts: text.remove()
for text in texts: ax.add_artist(text)

plt.savefig('plot2.png')

Actual outcome

plot1.png

Image

plot2.png

Image

Expected outcome

plot1.png

Image

plot2.png

Image

Additional information

No response

Operating system

No response

Matplotlib Version

0.2.0.dev54528+unknown.gf4cf12592

Matplotlib Backend

No response

Python version

No response

Jupyter version

No response

Installation

None

Activity

  1. rcomer commented on May 26, 2026

    @rcomer
    Member

    add_artist automatically sets a clip path

    if a.get_clip_path() is None:
    a.set_clip_path(self.patch)

    If you really need to do this, you can explicitly turn clipping off

    for text in texts: text.set_clip_on(False)

    But, as stated in your previous issue, you may get what you want by just toggling the visibility rather than removing and re-adding artists.

  2. BiswasNehaa commented on May 26, 2026

    @BiswasNehaa

    Hi! I'm a first-time contributor and I would love to work on this issue. Since add_artist automatically sets a clip path on the text annotations, I can look into modifying axes/_base.py to handle this better, or update the behavior for text artists. Could you please assign this to me?

  3. jklymak commented on May 26, 2026

    @jklymak
    Member

    This seems to be an error in clipping? Surely the clippibg logic should check if a._clipon is true or not. I'm clear why setting the clip box would or should make this clip. Conversely perhaps annotate is relying on the box rather than toggling clipping.

  4. rcomer commented on May 26, 2026

    @rcomer
    Member

    Yes, annotate only sets the box if the user actively set clip_on to True

    if kwargs.get('clip_on', False) and a.get_clip_path() is None:
    a.set_clip_path(self.patch)

    Artist clip_on defaults to True. I guess having the default True allows the user to set a clip box/path without having to also toggle it on.

  5. jklymak commented on May 26, 2026

    @jklymak
    Member

    Yeah, but that means there are two toggles for clipping - if the path is None, or if a._clipon is False. It seems that if clipon is False the artist should still not be clipped, even if it does have a clip path. That seems to be the bug to me, not necessarily adding a default clip path?

  6. rcomer commented on May 26, 2026

    @rcomer
    Member

    Sorry, I'm not following. In the example, the user didn't specify clip_on, so it got set to True, but also annotate didn't set the box because clip_on wasn't in kwargs.

    Then add_artist gets something that has clip_on True but no box set. So it adds the axes box because that makes sense for the majority of artists.

  7. BiswasNehaa commented on May 26, 2026

    @BiswasNehaa

    Thanks for the feedback and for taking a look at this! I see what you mean regarding how annotate initializes clip_on as True by default, and the broader point about how the rendering engine evaluates clip_on vs. the presence of a path.

    I'll keep an eye on your discussion here and am happy to update this PR's implementation or shift it to a different file based on what you decide makes the most sense architecturally!

  8. jklymak commented on May 26, 2026

    @jklymak
    Member

    Sorry, I'm not following. In the example, the user didn't specify clip_on, so it got set to True, but also annotate didn't set the box because clip_on wasn't in kwargs.

    Then add_artist gets something that has clip_on True but no box set. So it adds the axes box because that makes sense for the majority of artists.

    Right, so I'm claiming that is buggy, probably because the clipping API wasn't fully developed when annotate was made.

    • Most artists: clip_on=True, clip_path=axes box
    • Annotate: clip_on=True (always!), clip_path=None unless annotation_clip=True and then it is axes box.

    I'd argue instead that Annotate should default to clip_on=False, but have that be togglable, and set the clip_path like every other artist.

  9. rcomer commented on May 27, 2026

    @rcomer
    Member

    I guess if you default to clip_on=False, then any edge case where someone does want clipping in an annotation is a little more awkward because they have to set two things instead of one. I don’t know how likely it is that someone does that, but I also don’t know how likely it is that someone removes an annotation and re-adds it.

  10. jklymak commented on May 27, 2026

    @jklymak
    Member

    I would recommend setting the default clip box like we do for every other artist but just default to clip_on=False instead of clip_on=True. But maybe there is a subtlety I'm missing

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