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..babeee0a262c --- /dev/null +++ b/doc/users/next_whats_new/2019-12-22_transform-rotates-text-direction.rst @@ -0,0 +1,7 @@ +:orphan: + +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 23b0522a2956..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 -is found by transforming the angle from the plot to the screen -coordinate system, 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 @@ -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 70855e6d879f..c79cf4c1422a 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -10,6 +10,7 @@ from matplotlib.backend_bases import MouseEvent import matplotlib.patches as mpatches import matplotlib.pyplot as plt +import matplotlib.transforms as mtransforms from matplotlib.testing.decorators import check_figures_equal, image_comparison @@ -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() + assert_almost_equal(result, 30) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 3b30a4cfb502..e3147e262bf4 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, + transform_rotates_text=False, **kwargs ): """ @@ -157,6 +158,7 @@ def __init__(self, self.set_horizontalalignment(horizontalalignment) self._multialignment = multialignment self._rotation = rotation + self._transform_rotates_text = transform_rotates_text self._bbox_patch = None # a FancyBboxPatch instance self._renderer = None if linespacing is None: @@ -228,7 +230,20 @@ 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_transform_rotates_text(): + angle = get_rotation(self._rotation) + x, y = self.get_unitless_position() + 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 + + 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): """ @@ -259,6 +274,7 @@ def update_from(self, other): self._fontproperties = other._fontproperties.copy() self._usetex = other._usetex self._rotation = other._rotation + self._transform_rotates_text = other._transform_rotates_text self._picker = other._picker self._linespacing = other._linespacing self.stale = True @@ -843,6 +859,7 @@ def get_prop_tup(self, renderer=None): self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, self._rotation_mode, + self._transform_rotates_text, self.figure.dpi, weakref.ref(renderer), self._linespacing ) @@ -1132,6 +1149,17 @@ def set_rotation(self, s): self._rotation = s self.stale = True + def set_transform_rotates_text(self, t): + """ + Whether rotations of the transform affect the text direction. + + Parameters + ---------- + t : bool + """ + self._transform_rotates_text = t + self.stale = True + def set_verticalalignment(self, align): """ Set the vertical alignment.