From f11c92ca08207a17a6594ef231beedaccbdfe01c Mon Sep 17 00:00:00 2001 From: stevezhang1999 Date: Wed, 7 Jun 2023 23:42:14 +0800 Subject: [PATCH 1/5] antialias for agg --- lib/matplotlib/_mathtext.py | 4 ++-- lib/matplotlib/backends/backend_agg.py | 2 +- lib/matplotlib/mathtext.py | 8 ++++---- lib/matplotlib/mathtext.pyi | 3 ++- lib/matplotlib/tests/test_text.py | 16 ++++++++++++++++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 09f5c618794e..f336b9aec5f5 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -99,7 +99,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], @@ -124,7 +124,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 22907b00d9a3..f8750e173c26 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -189,7 +189,7 @@ 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, 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..a5fb9db63bd9 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -58,7 +58,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 +74,10 @@ 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) + 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 +100,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 a2e6e0e056b8..ab2e73616223 100644 --- a/lib/matplotlib/mathtext.pyi +++ b/lib/matplotlib/mathtext.pyi @@ -13,7 +13,8 @@ from matplotlib.typing import ColorType class MathTextParser: def __init__(self, output: Literal["path", "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}$") From 1f6d78fc68502a56594bb731d8b8febd734db441 Mon Sep 17 00:00:00 2001 From: stevezhang1999 Date: Sat, 22 Jul 2023 11:33:48 -0400 Subject: [PATCH 2/5] handle None for antialiasing when not specified --- lib/matplotlib/mathtext.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index a5fb9db63bd9..77d8ed39ca81 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 @@ -74,6 +75,8 @@ def parse(self, s, dpi=72, prop=None, antialiased=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 + if antialiased is None: + antialiased = mpl.rcParams['text.antialiased'] return self._parse_cached(s, dpi, prop, antialiased) @functools.lru_cache(50) From 53250146791f3bbbb52d5a5f3f043aa9f9d321c9 Mon Sep 17 00:00:00 2001 From: stevezhang1999 Date: Sat, 22 Jul 2023 16:08:25 -0400 Subject: [PATCH 3/5] update mathtext.pyi --- lib/matplotlib/mathtext.pyi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/mathtext.pyi b/lib/matplotlib/mathtext.pyi index 7a6aed016102..81a42444e42a 100644 --- a/lib/matplotlib/mathtext.pyi +++ b/lib/matplotlib/mathtext.pyi @@ -13,7 +13,13 @@ 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, From 4edd250d752b3bff883b8b2e1b52ae58f0ec2668 Mon Sep 17 00:00:00 2001 From: stevezhang1999 Date: Sat, 22 Jul 2023 16:42:22 -0400 Subject: [PATCH 4/5] update what's new for text antialiasing - support mathtext --- doc/users/next_whats_new/antialiasing_text_annotation.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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:: From 20082716ed50b8dcf0ca357e9778d9809700472f Mon Sep 17 00:00:00 2001 From: stevezhang1999 Date: Sun, 30 Jul 2023 10:00:14 -0400 Subject: [PATCH 5/5] make antialiased a keyword argument in parse(), mathtext.py --- lib/matplotlib/backends/backend_agg.py | 3 ++- lib/matplotlib/mathtext.py | 2 +- lib/matplotlib/mathtext.pyi | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index dc28171997c5..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, gc.get_antialiased()) + 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 77d8ed39ca81..7f639d2c0987 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -59,7 +59,7 @@ def __init__(self, output): {"path": "vector", "agg": "raster", "macosx": "raster"}, output=output.lower()) - def parse(self, s, dpi=72, prop=None, antialiased=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" diff --git a/lib/matplotlib/mathtext.pyi b/lib/matplotlib/mathtext.pyi index 81a42444e42a..15ceb74a2dda 100644 --- a/lib/matplotlib/mathtext.pyi +++ b/lib/matplotlib/mathtext.pyi @@ -18,6 +18,7 @@ class MathTextParser: s: str, dpi: float = ..., prop: FontProperties | None = ..., + *, antialiased: bool | None = ... ): ...