You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Backgroundcolor of text is set in a too wide range #29874
Backgroundcolor of text is set in a too wide range when setting it for the first time.
Problem: Border of first color remains when backgroundcolor is set again.
Code for reproduction
''' Backgroundcolor of text is set in a too wide range when setting it for the first time. Problem: Border of first color remains when backgroundcolor is set again.'''# windows 11# Python version 3.13.2# Matplotlib version 3.10.1importmatplotlib.pyplotaspltfig, ax=plt.subplots(1, 1)
fig.set_dpi(100)
txt=ax.text(0.1, 0.8, 'There should not be a red border around this text !')
##txt.set(backgroundcolor='none') # Uncomment this line as workaround to avoid red bordertxt.set(backgroundcolor='red') # Set backgroundcolor for the first timetxt.set(backgroundcolor='none') # Cannot reset backgroundcolor of text completely, red border remainsplt.show()
Actual outcome
Text with red border, see picture above.
Expected outcome
Text without red border.
Additional information
There is a workaround for the first, but not a fix, see Python program above.
The background is realized through an internal FancyBboxPatch (Text._bbox_patch). It is initally None and only created if you want a background or border around the text.
What happens here is that the patch is created with finite linewidth 1 and the edgecolor is the same as the facecolor (One can debate whether that behavior is reasonable, but it likely needs a closer look to handle all potential cases reasonably). To completely undo txt.set(backgroundcolor='red') you should remove the background patch via txt.set(bbox=None) instead of making the patch transparent.
There is a need to do something about the edge because by default rcParams["patch.linewidth"] is 1. The alternative to setting edgecolor to the same color as facecolor would be to set linewidth=0. That might be the slightly better approach. OTOH it will lead to subsequent txt.set_bbox(edgecolor=...) have on visual effect. So that's not ideal either. Overall, I believe it's not worth changing the behavior and the improved documentation in #29875 should suffice.
For an user of matplotlib like me it is hard to guess, that the problem of the red border results from the initialization of the text object and how to work around.
At least you should point out in the manual, that "txt.set(backgroundcolor='none')" as a command before is a simple workaround. Or something like this.
I got another problem, probably caused by the initialization of text object, which is more hard to understand for the user.
It appears when you try to get the width of the text. Sometime it works, sometimes there is an exception:
----------------------------
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
fig.set_dpi(100)
txt = ax.text(0.1, 0.8, 'My Text ...')
try:
width = txt.get_bbox_patch().get_width() # You will get an AttributeError:
except AttributeError:
print("'NoneType' object has no attribute 'get_width'")
Make it work with the "workaround of backgroundcolor":
txt.set(backgroundcolor='none')
width = txt.get_bbox_patch().get_width() # Now you will get the width
There is a need to do something about the edge because by default rcParams["patch.linewidth"] is 1. The alternative to setting edgecolor to the same color as facecolor would be to set linewidth=0. That might be the slightly better approach. OTOH it will lead to subsequent txt.set_bbox(edgecolor=...) have on visual effect. So that's not ideal either. Overall, I believe it's not worth changing the behavior and the improved documentation in #29875 should suffice.
Could we instead set edgecolor to "none"? If I understand correctly, that is the default for a patch these days anyway (though it is black in classic mode).
That would be a bit counter-intuitive to me. My mental model is that the text background color is only the fill and does not affect the frame. E.g. when I have
I'm planning on updating Text.set_backgroundcolor so that when the color is 'none', the _bbox_patch’s edgecolor is also set to 'none' to remove the unwanted border. Will add a test for this behavior.
I'm planning on updating Text.set_backgroundcolor so that when the color is 'none', the _bbox_patch’s edgecolor is also set to 'none' to remove the unwanted border. Will add a test for this behavior.
That doesn't sound like the right solution. I think we can just leave out edgecolor but t.b.c.
Activity
timhoffm commentedon Apr 6, 2025
The background is realized through an internal
FancyBboxPatch(Text._bbox_patch). It is initallyNoneand only created if you want a background or border around the text.What happens here is that the patch is created with finite linewidth 1 and the edgecolor is the same as the facecolor (One can debate whether that behavior is reasonable, but it likely needs a closer look to handle all potential cases reasonably). To completely undo
txt.set(backgroundcolor='red')you should remove the background patch viatxt.set(bbox=None)instead of making the patch transparent.timhoffm commentedon Apr 6, 2025
Note: The behavior is due to
matplotlib/lib/matplotlib/text.py
Line 995 in 33dbc47
There is a need to do something about the edge because by default
rcParams["patch.linewidth"]is 1. The alternative to setting edgecolor to the same color as facecolor would be to setlinewidth=0. That might be the slightly better approach. OTOH it will lead to subsequenttxt.set_bbox(edgecolor=...)have on visual effect. So that's not ideal either. Overall, I believe it's not worth changing the behavior and the improved documentation in #29875 should suffice.siegbert7 commentedon Apr 6, 2025
Thanks for your reply.
For an user of matplotlib like me it is hard to guess, that the problem of the red border results from the initialization of the text object and how to work around.
At least you should point out in the manual, that "txt.set(backgroundcolor='none')" as a command before is a simple workaround. Or something like this.
I got another problem, probably caused by the initialization of text object, which is more hard to understand for the user.
It appears when you try to get the width of the text. Sometime it works, sometimes there is an exception:
----------------------------
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
fig.set_dpi(100)
txt = ax.text(0.1, 0.8, 'My Text ...')
try:
width = txt.get_bbox_patch().get_width() # You will get an AttributeError:
except AttributeError:
print("'NoneType' object has no attribute 'get_width'")
Make it work with the "workaround of backgroundcolor":
txt.set(backgroundcolor='none')
width = txt.get_bbox_patch().get_width() # Now you will get the width
plt.show()
rcomer commentedon Apr 6, 2025
Could we instead set edgecolor to "none"? If I understand correctly, that is the default for a patch these days anyway (though it is black in classic mode).
timhoffm commentedon Apr 6, 2025
Thanks, that's a good idea and probably the correct solution.
The only downside is that the size of the box changes (left half is edgecolor none):
This is a breaking change. It's probably still worth doing so and communicating it as a fix.
rcomer commentedon Apr 7, 2025
Another option might be to set the edgecolor to match facecolor here
matplotlib/lib/matplotlib/text.py
Line 997 in 33dbc47
Then
set_backgroundcolorwould be the same asset_colordirectly on the patchmatplotlib/lib/matplotlib/patches.py
Lines 406 to 420 in 6fc8169
timhoffm commentedon Apr 7, 2025
That would be a bit counter-intuitive to me. My mental model is that the text background color is only the fill and does not affect the frame. E.g. when I have
I would expect that the black frame stays.
I also like that the box has sharp color edges when no edge line is used. The boundary line is antialiased and blurs the edges.
codingabhiroop commentedon Jan 1, 2026
Hi!
I’d like to take on this issue.
I'm planning on updating
Text.set_backgroundcolorso that when the color is'none', the_bbox_patch’sedgecoloris also set to'none'to remove the unwanted border. Will add a test for this behavior.timhoffm commentedon Jan 2, 2026
That doesn't sound like the right solution. I think we can just leave out
edgecolorbut t.b.c.