diff --git a/doc/users/next_whats_new/antialiasing_text_annotation.rst b/doc/users/next_whats_new/antialiasing_text_annotation.rst index 7e6489e9803f..c771f6a1e19f 100644 --- a/doc/users/next_whats_new/antialiasing_text_annotation.rst +++ b/doc/users/next_whats_new/antialiasing_text_annotation.rst @@ -12,8 +12,7 @@ Examples: plt.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True) ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), antialiased=False) -If the text contains math expression, then antialiasing will be set by :rc:`text.antialiased`, and *antialiased* will have no effect -This applies to the whole text. +If the text contains math expression, *antialiased* applies to the whole text. Examples: .. code-block:: diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index d86385e94589..fabcc01c30f5 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -100,7 +100,7 @@ def to_vector(self): for x1, y1, x2, y2 in self.rects] return VectorParse(w, h + d, d, gs, rs) - def to_raster(self): + def to_raster(self, antialiased=None): # Metrics y's and mathtext y's are oriented in opposite directions, # hence the switch between ymin and ymax. xmin = min([*[ox + info.metrics.xmin for ox, oy, info in self.glyphs], @@ -125,7 +125,7 @@ def to_raster(self): for ox, oy, info in shifted.glyphs: info.font.draw_glyph_to_bitmap( image, ox, oy - info.metrics.iceberg, info.glyph, - antialiased=mpl.rcParams['text.antialiased']) + antialiased=antialiased) for x1, y1, x2, y2 in shifted.rects: height = max(int(y2 - y1) - 1, 0) if height == 0: diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index da87d82af7f5..f6ce61db5a5c 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -175,7 +175,8 @@ def draw_path(self, gc, path, transform, rgbFace=None): def draw_mathtext(self, gc, x, y, s, prop, angle): """Draw mathtext using :mod:`matplotlib.mathtext`.""" ox, oy, width, height, descent, font_image = \ - self.mathtext_parser.parse(s, self.dpi, prop) + self.mathtext_parser.parse(s, self.dpi, prop, + antialiased=gc.get_antialiased()) xd = descent * sin(radians(angle)) yd = descent * cos(radians(angle)) diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index e538d451f8dd..7f639d2c0987 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -18,6 +18,7 @@ import functools import logging +import matplotlib as mpl from matplotlib import _api, _mathtext from matplotlib.ft2font import LOAD_NO_HINTING from matplotlib.font_manager import FontProperties @@ -58,7 +59,7 @@ def __init__(self, output): {"path": "vector", "agg": "raster", "macosx": "raster"}, output=output.lower()) - def parse(self, s, dpi=72, prop=None): + def parse(self, s, dpi=72, prop=None, *, antialiased=None): """ Parse the given math expression *s* at the given *dpi*. If *prop* is provided, it is a `.FontProperties` object specifying the "default" @@ -74,10 +75,12 @@ def parse(self, s, dpi=72, prop=None): # is mutable; key the cache using an internal copy (see # text._get_text_metrics_with_cache for a similar case). prop = prop.copy() if prop is not None else None - return self._parse_cached(s, dpi, prop) + if antialiased is None: + antialiased = mpl.rcParams['text.antialiased'] + return self._parse_cached(s, dpi, prop, antialiased) @functools.lru_cache(50) - def _parse_cached(self, s, dpi, prop): + def _parse_cached(self, s, dpi, prop, antialiased): from matplotlib.backends import backend_agg if prop is None: @@ -100,7 +103,7 @@ def _parse_cached(self, s, dpi, prop): if self._output_type == "vector": return output.to_vector() elif self._output_type == "raster": - return output.to_raster() + return output.to_raster(antialiased=antialiased) def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None, diff --git a/lib/matplotlib/mathtext.pyi b/lib/matplotlib/mathtext.pyi index 7a6aed016102..15ceb74a2dda 100644 --- a/lib/matplotlib/mathtext.pyi +++ b/lib/matplotlib/mathtext.pyi @@ -13,7 +13,14 @@ from matplotlib.typing import ColorType class MathTextParser: def __init__(self, output: Literal["path", "agg", "raster", "macosx"]) -> None: ... - def parse(self, s: str, dpi: float = ..., prop: FontProperties | None = ...): ... + def parse( + self, + s: str, + dpi: float = ..., + prop: FontProperties | None = ..., + *, + antialiased: bool | None = ... + ): ... def math_to_image( s: str, diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 4215927f05fe..f5791f7cee99 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -962,3 +962,19 @@ def test_text_antialiased_on_default_vs_manual(fig_test, fig_ref): mpl.rcParams['text.antialiased'] = True fig_ref.text(0.5, 0.5, '6 inches x 2 inches') + + +@check_figures_equal() +def test_text_math_antialiased_on_default_vs_manual(fig_test, fig_ref): + fig_test.text(0.5, 0.5, r"OutsideMath $I\'m \sqrt{2}$", antialiased=True) + + mpl.rcParams['text.antialiased'] = True + fig_ref.text(0.5, 0.5, r"OutsideMath $I\'m \sqrt{2}$") + + +@check_figures_equal() +def test_text_math_antialiased_off_default_vs_manual(fig_test, fig_ref): + fig_test.text(0.5, 0.5, r"OutsideMath $I\'m \sqrt{2}$", antialiased=False) + + mpl.rcParams['text.antialiased'] = False + fig_ref.text(0.5, 0.5, r"OutsideMath $I\'m \sqrt{2}$")