Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 74c0cd0

Browse files
authored
Merge pull request #25775 from stevezhang1999/text-object-antialias
Support customizing antialiasing for text and annotation
2 parents 26224d9 + 95e0709 commit 74c0cd0

File tree

7 files changed

+166
-6
lines changed

7 files changed

+166
-6
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Default antialiasing behavior changes for ``Text`` and ``Annotation``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
``matplotlib.pyplot.annotate()`` and ``matplotlib.pyplot.text()`` now support parameter *antialiased* when initializing.
5+
Examples:
6+
7+
.. code-block::
8+
9+
mpl.text.Text(.5, .5, "foo\nbar", antialiased=True)
10+
plt.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True)
11+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), antialiased=False)
12+
13+
See "What's New" for more details on usage.
14+
15+
With this new feature, you may want to make sure that you are creating and saving/showing the figure under the same context::
16+
17+
# previously this was a no-op, now it is what works
18+
with rccontext(text.antialiased=False):
19+
fig, ax = plt.subplots()
20+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5))
21+
fig.savefig('/tmp/test.png')
22+
23+
# previously this had an effect, now this is a no-op
24+
fig, ax = plt.subplots()
25+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5))
26+
with rccontext(text.antialiased=False):
27+
fig.savefig('/tmp/test.png')
28+
29+
Also note that antialiasing for tick labels will be set with :rc:`text.antialiased` when they are created (usually when a ``Figure`` is created) - This means antialiasing for them can no longer be changed by modifying :rc:`text.antialiased`.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Support customizing antialiasing for text and annotation
2+
--------------------------------------------------------
3+
``matplotlib.pyplot.annotate()`` and ``matplotlib.pyplot.text()`` now support parameter *antialiased*.
4+
When *antialiased* is set to ``True``, antialiasing will be applied to the text.
5+
When *antialiased* is set to ``False``, antialiasing will not be applied to the text.
6+
When *antialiased* is not specified, antialiasing will be set by :rc:`text.antialiased` at the creation time of ``Text`` and ``Annotation`` object.
7+
Examples:
8+
9+
.. code-block::
10+
11+
mpl.text.Text(.5, .5, "foo\nbar", antialiased=True)
12+
plt.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True)
13+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), antialiased=False)
14+
15+
If the text contains math expression, then antialiasing will be set by :rc:`text.antialiased`, and *antialiased* will have no effect
16+
This applies to the whole text.
17+
Examples:
18+
19+
.. code-block::
20+
21+
# no part will be antialiased for the text below
22+
plt.text(0.5, 0.25, r"$I'm \sqrt{x}$", antialiased=False)
23+
24+
Also note that antialiasing for tick labels will be set with :rc:`text.antialiased` when they are created (usually when a ``Figure`` is created) and cannot be changed afterwards.
25+
26+
Furthermore, with this new feature, you may want to make sure that you are creating and saving/showing the figure under the same context::
27+
28+
# previously this was a no-op, now it is what works
29+
with rccontext(text.antialiased=False):
30+
fig, ax = plt.subplots()
31+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5))
32+
fig.savefig('/tmp/test.png')
33+
34+
35+
# previously this had an effect, now this is a no-op
36+
fig, ax = plt.subplots()
37+
ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5))
38+
with rccontext(text.antialiased=False):
39+
fig.savefig('/tmp/test.png')

lib/matplotlib/backends/backend_agg.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
206206
# space) in the following call to draw_text_image).
207207
font.set_text(s, 0, flags=get_hinting_flag())
208208
font.draw_glyphs_to_bitmap(
209-
antialiased=mpl.rcParams['text.antialiased'])
209+
antialiased=gc.get_antialiased())
210210
d = font.get_descent() / 64.0
211211
# The descent needs to be adjusted for the angle.
212212
xo, yo = font.get_bitmap_offset()

lib/matplotlib/backends/backend_cairo.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"cairo backend requires that pycairo>=1.14.0 or cairocffi "
2626
"is installed") from err
2727

28-
import matplotlib as mpl
2928
from .. import _api, cbook, font_manager
3029
from matplotlib.backend_bases import (
3130
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
@@ -204,9 +203,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
204203
ctx.select_font_face(*_cairo_font_args_from_font_prop(prop))
205204
ctx.set_font_size(self.points_to_pixels(prop.get_size_in_points()))
206205
opts = cairo.FontOptions()
207-
opts.set_antialias(
208-
cairo.ANTIALIAS_DEFAULT if mpl.rcParams["text.antialiased"]
209-
else cairo.ANTIALIAS_NONE)
206+
opts.set_antialias(gc.get_antialiased())
210207
ctx.set_font_options(opts)
211208
if angle:
212209
ctx.rotate(np.deg2rad(-angle))
@@ -312,6 +309,9 @@ def set_antialiased(self, b):
312309
self.ctx.set_antialias(
313310
cairo.ANTIALIAS_DEFAULT if b else cairo.ANTIALIAS_NONE)
314311

312+
def get_antialiased(self):
313+
return self.ctx.get_antialias()
314+
315315
def set_capstyle(self, cs):
316316
self.ctx.set_line_cap(_api.check_getitem(self._capd, capstyle=cs))
317317
self._capstyle = cs

lib/matplotlib/tests/test_text.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import matplotlib.transforms as mtransforms
1515
from matplotlib.testing.decorators import check_figures_equal, image_comparison
1616
from matplotlib.testing._markers import needs_usetex
17-
from matplotlib.text import Text
17+
from matplotlib.text import Text, Annotation
1818

1919

2020
@image_comparison(['font_styles'])
@@ -902,3 +902,63 @@ def test_annotate_offset_fontsize():
902902
points_coords, fontsize_coords = [ann.get_window_extent() for ann in anns]
903903
fig.canvas.draw()
904904
assert str(points_coords) == str(fontsize_coords)
905+
906+
907+
def test_set_antialiased():
908+
txt = Text(.5, .5, "foo\nbar")
909+
assert txt._antialiased == mpl.rcParams['text.antialiased']
910+
911+
txt.set_antialiased(True)
912+
assert txt._antialiased is True
913+
914+
txt.set_antialiased(False)
915+
assert txt._antialiased is False
916+
917+
918+
def test_get_antialiased():
919+
920+
txt2 = Text(.5, .5, "foo\nbar", antialiased=True)
921+
assert txt2._antialiased is True
922+
assert txt2.get_antialiased() == txt2._antialiased
923+
924+
txt3 = Text(.5, .5, "foo\nbar", antialiased=False)
925+
assert txt3._antialiased is False
926+
assert txt3.get_antialiased() == txt3._antialiased
927+
928+
txt4 = Text(.5, .5, "foo\nbar")
929+
assert txt4.get_antialiased() == mpl.rcParams['text.antialiased']
930+
931+
932+
def test_annotation_antialiased():
933+
annot = Annotation("foo\nbar", (.5, .5), antialiased=True)
934+
assert annot._antialiased is True
935+
assert annot.get_antialiased() == annot._antialiased
936+
937+
annot2 = Annotation("foo\nbar", (.5, .5), antialiased=False)
938+
assert annot2._antialiased is False
939+
assert annot2.get_antialiased() == annot2._antialiased
940+
941+
annot3 = Annotation("foo\nbar", (.5, .5), antialiased=False)
942+
annot3.set_antialiased(True)
943+
assert annot3.get_antialiased() is True
944+
assert annot3._antialiased is True
945+
946+
annot4 = Annotation("foo\nbar", (.5, .5))
947+
assert annot4._antialiased == mpl.rcParams['text.antialiased']
948+
949+
950+
@check_figures_equal()
951+
def test_text_antialiased_off_default_vs_manual(fig_test, fig_ref):
952+
fig_test.text(0.5, 0.5, '6 inches x 2 inches',
953+
antialiased=False)
954+
955+
mpl.rcParams['text.antialiased'] = False
956+
fig_ref.text(0.5, 0.5, '6 inches x 2 inches')
957+
958+
959+
@check_figures_equal()
960+
def test_text_antialiased_on_default_vs_manual(fig_test, fig_ref):
961+
fig_test.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True)
962+
963+
mpl.rcParams['text.antialiased'] = True
964+
fig_ref.text(0.5, 0.5, '6 inches x 2 inches')

lib/matplotlib/text.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ def __init__(self,
115115
wrap=False,
116116
transform_rotates_text=False,
117117
parse_math=None, # defaults to rcParams['text.parse_math']
118+
antialiased=None, # defaults to rcParams['text.antialiased']
118119
**kwargs
119120
):
120121
"""
@@ -135,6 +136,7 @@ def __init__(self,
135136
super().__init__()
136137
self._x, self._y = x, y
137138
self._text = ''
139+
self._antialiased = mpl.rcParams['text.antialiased']
138140
self._reset_visual_defaults(
139141
text=text,
140142
color=color,
@@ -149,6 +151,7 @@ def __init__(self,
149151
transform_rotates_text=transform_rotates_text,
150152
linespacing=linespacing,
151153
rotation_mode=rotation_mode,
154+
antialiased=antialiased
152155
)
153156
self.update(kwargs)
154157

@@ -167,6 +170,7 @@ def _reset_visual_defaults(
167170
transform_rotates_text=False,
168171
linespacing=None,
169172
rotation_mode=None,
173+
antialiased=None
170174
):
171175
self.set_text(text)
172176
self.set_color(
@@ -187,6 +191,8 @@ def _reset_visual_defaults(
187191
linespacing = 1.2 # Maybe use rcParam later.
188192
self.set_linespacing(linespacing)
189193
self.set_rotation_mode(rotation_mode)
194+
if antialiased is not None:
195+
self.set_antialiased(antialiased)
190196

191197
def update(self, kwargs):
192198
# docstring inherited
@@ -309,6 +315,27 @@ def get_rotation_mode(self):
309315
"""Return the text rotation mode."""
310316
return self._rotation_mode
311317

318+
def set_antialiased(self, antialiased):
319+
"""
320+
Set whether to use antialiased rendering.
321+
322+
Parameters
323+
----------
324+
antialiased : bool
325+
326+
Notes
327+
-----
328+
Antialiasing will be determined by :rc:`text.antialiased`
329+
and the parameter *antialiased* will have no effect if the text contains
330+
math expressions.
331+
"""
332+
self._antialiased = antialiased
333+
self.stale = True
334+
335+
def get_antialiased(self):
336+
"""Return whether antialiased rendering is used."""
337+
return self._antialiased
338+
312339
def update_from(self, other):
313340
# docstring inherited
314341
super().update_from(other)
@@ -322,6 +349,7 @@ def update_from(self, other):
322349
self._transform_rotates_text = other._transform_rotates_text
323350
self._picker = other._picker
324351
self._linespacing = other._linespacing
352+
self._antialiased = other._antialiased
325353
self.stale = True
326354

327355
def _get_layout(self, renderer):
@@ -737,6 +765,7 @@ def draw(self, renderer):
737765
gc.set_foreground(self.get_color())
738766
gc.set_alpha(self.get_alpha())
739767
gc.set_url(self._url)
768+
gc.set_antialiased(self._antialiased)
740769
self._set_gc_clip(gc)
741770

742771
angle = self.get_rotation()

lib/matplotlib/text.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class Text(Artist):
3636
wrap: bool = ...,
3737
transform_rotates_text: bool = ...,
3838
parse_math: bool | None = ...,
39+
antialiased: bool | None = ...,
3940
**kwargs
4041
) -> None: ...
4142
def update(self, kwargs: dict[str, Any]) -> None: ...
@@ -99,6 +100,8 @@ class Text(Artist):
99100
def set_parse_math(self, parse_math: bool) -> None: ...
100101
def get_parse_math(self) -> bool: ...
101102
def set_fontname(self, fontname: str | Iterable[str]): ...
103+
def get_antialiased(self) -> bool: ...
104+
def set_antialiased(self, antialiased: bool): ...
102105

103106
class OffsetFrom:
104107
def __init__(

0 commit comments

Comments
 (0)