From b59d8a32999594f4aef9db647969d84aa7d55eed Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sat, 26 Oct 2019 23:22:46 +0800 Subject: [PATCH 1/7] Resolve 'text ignores rotational part of transformation' bug (#698) Considering the text rotation don't get transformed may by a desired behavior (such as text for annotation to some data point). Here made it as an option to control whether or not the text rotation get transformed. --- lib/matplotlib/text.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 3b30a4cfb502..012064f12d6b 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -136,6 +136,7 @@ def __init__(self, rotation_mode=None, usetex=None, # defaults to rcParams['text.usetex'] wrap=False, + rotation_transformed=False, **kwargs ): """ @@ -157,6 +158,7 @@ def __init__(self, self.set_horizontalalignment(horizontalalignment) self._multialignment = multialignment self._rotation = rotation + self._rotation_transformed = rotation_transformed self._bbox_patch = None # a FancyBboxPatch instance self._renderer = None if linespacing is None: @@ -228,7 +230,16 @@ def _get_multialignment(self): def get_rotation(self): """Return the text angle in degrees between 0 and 360.""" - return get_rotation(self._rotation) # string_or_number -> number + if self.get_rotation_transformed(): + angle = get_rotation(self._rotation) + x, y = self.get_unitless_position() + return self.get_transform().transform_angles([angle, ], [[x, y]]) + else: + return get_rotation(self._rotation) # string_or_number -> number + + def get_rotation_transformed(self): + """Return if the text rotation get transformed or not.""" + return self._rotation_transformed def set_rotation_mode(self, m): """ @@ -259,6 +270,7 @@ def update_from(self, other): self._fontproperties = other._fontproperties.copy() self._usetex = other._usetex self._rotation = other._rotation + self._rotation_transformed = other._rotation_transformed self._picker = other._picker self._linespacing = other._linespacing self.stale = True @@ -843,6 +855,7 @@ def get_prop_tup(self, renderer=None): self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, self._rotation_mode, + self._rotation_transformed, self.figure.dpi, weakref.ref(renderer), self._linespacing ) @@ -1132,6 +1145,17 @@ def set_rotation(self, s): self._rotation = s self.stale = True + def set_rotation_transformed(self, t): + """ + Set if the text rotation get transformed or not. + + Parameters + ---------- + t : bool + """ + self._rotation_transformed = t + self.stale = True + def set_verticalalignment(self, align): """ Set the vertical alignment. From fd0546160e643ec72c7441e7b65c2c3fde003add Mon Sep 17 00:00:00 2001 From: Max Chen Date: Tue, 12 Nov 2019 01:08:45 +0800 Subject: [PATCH 2/7] improve arg name, docstring, add test --- lib/matplotlib/tests/test_text.py | 14 ++++++++++++-- lib/matplotlib/text.py | 24 +++++++++++++----------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 70855e6d879f..84daa88991c8 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -3,16 +3,17 @@ import warnings import numpy as np -from numpy.testing import assert_almost_equal import pytest +from numpy.testing import assert_almost_equal import matplotlib as mpl from matplotlib.backend_bases import MouseEvent import matplotlib.patches as mpatches import matplotlib.pyplot as plt +import matplotlib.transforms as mtransforms +from matplotlib.backend_bases import MouseEvent from matplotlib.testing.decorators import check_figures_equal, image_comparison - needs_usetex = pytest.mark.skipif( not mpl.checkdep_usetex(True), reason="This test needs a TeX installation") @@ -689,3 +690,12 @@ def test_fontproperties_kwarg_precedence(): text2 = plt.ylabel("counts", size=40.0, fontproperties='Times New Roman') assert text1.get_size() == 40.0 assert text2.get_size() == 40.0 + + +def test_transform_rotates_text(): + ax = plt.gca() + transform = mtransforms.Affine2D().rotate_deg(30) + text = ax.text(0, 0, 'test', transform=transform, + transform_rotates_text=True) + result = text.get_rotation()[0] + assert_almost_equal(result, 30) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 012064f12d6b..edd38898b02d 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -136,7 +136,7 @@ def __init__(self, rotation_mode=None, usetex=None, # defaults to rcParams['text.usetex'] wrap=False, - rotation_transformed=False, + transform_rotates_text=False, **kwargs ): """ @@ -158,7 +158,7 @@ def __init__(self, self.set_horizontalalignment(horizontalalignment) self._multialignment = multialignment self._rotation = rotation - self._rotation_transformed = rotation_transformed + self._transform_rotates_text = transform_rotates_text self._bbox_patch = None # a FancyBboxPatch instance self._renderer = None if linespacing is None: @@ -230,16 +230,18 @@ def _get_multialignment(self): def get_rotation(self): """Return the text angle in degrees between 0 and 360.""" - if self.get_rotation_transformed(): + if self.get_transform_rotates_text(): angle = get_rotation(self._rotation) x, y = self.get_unitless_position() return self.get_transform().transform_angles([angle, ], [[x, y]]) else: return get_rotation(self._rotation) # string_or_number -> number - def get_rotation_transformed(self): - """Return if the text rotation get transformed or not.""" - return self._rotation_transformed + def get_transform_rotates_text(self): + """ + Return whether rotations of the transform affect the text direction. + """ + return self._transform_rotates_text def set_rotation_mode(self, m): """ @@ -270,7 +272,7 @@ def update_from(self, other): self._fontproperties = other._fontproperties.copy() self._usetex = other._usetex self._rotation = other._rotation - self._rotation_transformed = other._rotation_transformed + self._transform_rotates_text = other._transform_rotates_text self._picker = other._picker self._linespacing = other._linespacing self.stale = True @@ -855,7 +857,7 @@ def get_prop_tup(self, renderer=None): self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, self._rotation_mode, - self._rotation_transformed, + self._transform_rotates_text, self.figure.dpi, weakref.ref(renderer), self._linespacing ) @@ -1145,15 +1147,15 @@ def set_rotation(self, s): self._rotation = s self.stale = True - def set_rotation_transformed(self, t): + def set_transform_rotates_text(self, t): """ - Set if the text rotation get transformed or not. + Whether rotations of the transform affect the text direction. Parameters ---------- t : bool """ - self._rotation_transformed = t + self._transform_rotates_text = t self.stale = True def set_verticalalignment(self, align): From 7efc6fd5f0ac851a495ffd9af817b54f4babeca4 Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sun, 22 Dec 2019 23:58:05 +0800 Subject: [PATCH 3/7] add a whatsnew note --- .../2019-12-22_transform-rotates-text-direction.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst diff --git a/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst b/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst new file mode 100644 index 000000000000..e6d516625f97 --- /dev/null +++ b/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst @@ -0,0 +1,7 @@ +:orphan: + +Transform can rotates text direction +------------------------------------ +The new `.Text` parameter ``transform_rotates_text`` now allows to enable +rotations of the transform affect the text direction. + From fa1f951798491a38977fb30cb0762e3f02f9b37a Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sat, 6 Jun 2020 22:13:09 +0800 Subject: [PATCH 4/7] fix GH #17005 --- .../text_rotation_relative_to_line.py | 8 ++++---- lib/matplotlib/tests/test_text.py | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py index 23b0522a2956..806c0cacb541 100644 --- a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py +++ b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py @@ -10,8 +10,8 @@ to something on the plot. In this case, the correct angle won't be the angle of that object in the plot coordinate system, but the angle that that object APPEARS in the screen coordinate system. This angle -is found by transforming the angle from the plot to the screen -coordinate system, as shown in the example below. +can be provided by the helper parameter `transform_rotates_text`, as +shown in the example below. """ import matplotlib.pyplot as plt @@ -31,12 +31,12 @@ # Rotate angle angle = 45 -trans_angle = ax.transData.transform_angles([45], l2.reshape((1, 2)))[0] # Plot text th1 = ax.text(*l1, 'text not rotated correctly', fontsize=16, rotation=angle, rotation_mode='anchor') th2 = ax.text(*l2, 'text rotated correctly', fontsize=16, - rotation=trans_angle, rotation_mode='anchor') + rotation=angle, rotation_mode='anchor', + transform_rotates_text=True) plt.show() diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 84daa88991c8..5d76d0c8785b 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -3,15 +3,14 @@ import warnings import numpy as np -import pytest from numpy.testing import assert_almost_equal +import pytest import matplotlib as mpl from matplotlib.backend_bases import MouseEvent import matplotlib.patches as mpatches import matplotlib.pyplot as plt import matplotlib.transforms as mtransforms -from matplotlib.backend_bases import MouseEvent from matplotlib.testing.decorators import check_figures_equal, image_comparison needs_usetex = pytest.mark.skipif( From 0669fa9184ed7d62b0001376db881fe3d027660e Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sat, 6 Jun 2020 22:54:23 +0800 Subject: [PATCH 5/7] fix arg role in doc --- .../text_rotation_relative_to_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py index 806c0cacb541..311be3aacd01 100644 --- a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py +++ b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py @@ -10,7 +10,7 @@ to something on the plot. In this case, the correct angle won't be the angle of that object in the plot coordinate system, but the angle that that object APPEARS in the screen coordinate system. This angle -can be provided by the helper parameter `transform_rotates_text`, as +can be provided by the helper parameter *transform_rotates_text*, as shown in the example below. """ From 68cfd75b2110821f3d35b03f5edcec498396a559 Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sat, 20 Jun 2020 00:03:21 +0800 Subject: [PATCH 6/7] change return type --- lib/matplotlib/tests/test_text.py | 2 +- lib/matplotlib/text.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 5d76d0c8785b..28a09911df1d 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -696,5 +696,5 @@ def test_transform_rotates_text(): transform = mtransforms.Affine2D().rotate_deg(30) text = ax.text(0, 0, 'test', transform=transform, transform_rotates_text=True) - result = text.get_rotation()[0] + result = text.get_rotation() assert_almost_equal(result, 30) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index edd38898b02d..e3147e262bf4 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -233,7 +233,9 @@ def get_rotation(self): if self.get_transform_rotates_text(): angle = get_rotation(self._rotation) x, y = self.get_unitless_position() - return self.get_transform().transform_angles([angle, ], [[x, y]]) + angles = [angle, ] + pts = [[x, y]] + return self.get_transform().transform_angles(angles, pts).item(0) else: return get_rotation(self._rotation) # string_or_number -> number From 46c279174ed6c218eafd28bae204d56bf431a418 Mon Sep 17 00:00:00 2001 From: Max Chen Date: Sun, 9 Aug 2020 17:06:27 +0800 Subject: [PATCH 7/7] apply suggested changes in docs --- .../2019-12-22_transform-rotates-text-direction.rst | 6 +++--- .../text_rotation_relative_to_line.py | 4 ++-- lib/matplotlib/tests/test_text.py | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst b/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst index e6d516625f97..babeee0a262c 100644 --- a/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst +++ b/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst @@ -1,7 +1,7 @@ :orphan: -Transform can rotates text direction ------------------------------------- -The new `.Text` parameter ``transform_rotates_text`` now allows to enable +Transform can rotate text direction +----------------------------------- +The new `.Text` parameter ``transform_rotates_text`` now sets whether rotations of the transform affect the text direction. diff --git a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py index 311be3aacd01..4672f5c5772d 100644 --- a/examples/text_labels_and_annotations/text_rotation_relative_to_line.py +++ b/examples/text_labels_and_annotations/text_rotation_relative_to_line.py @@ -10,8 +10,8 @@ to something on the plot. In this case, the correct angle won't be the angle of that object in the plot coordinate system, but the angle that that object APPEARS in the screen coordinate system. This angle -can be provided by the helper parameter *transform_rotates_text*, as -shown in the example below. +can be determined automatically by setting the parameter +*transform_rotates_text*, as shown in the example below. """ import matplotlib.pyplot as plt diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 28a09911df1d..c79cf4c1422a 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -13,6 +13,7 @@ import matplotlib.transforms as mtransforms from matplotlib.testing.decorators import check_figures_equal, image_comparison + needs_usetex = pytest.mark.skipif( not mpl.checkdep_usetex(True), reason="This test needs a TeX installation")