调整大小后是否使文本在数据坐标系中旋转?

nop*_*e11 4 python matplotlib

我正在尝试在matplotlib中旋转文本。不幸的是,旋转似乎是在显示坐标系中,而不是在数据坐标系中。那是:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_axes([0.15, 0.1, 0.8, 0.8])
t = np.arange(0.0, 1.0, 0.01)
line, = ax.plot(t, t, color='blue', lw=2)
ax.text (0.51,0.51,"test label", rotation=45)
plt.show()
Run Code Online (Sandbox Code Playgroud)

将给出一条在数据坐标系中为45度的线,但附带的文本在显示坐标系中为45度。我想使文本和数据即使在调整大小时也要对齐。我在这里看到可以变换旋转的方法,但是只有在不调整图的大小的情况下,此方法才能起作用。我尝试编写ax.text (0.51,0.51,"test label", transform=ax.transData, rotation=45),但无论如何它似乎是默认的,并且对旋转没有帮助

有没有办法在数据坐标系中进行旋转?

编辑:

我有兴趣在绘制图形后能够调整其大小-这是因为我通常会先绘制一些图形,然后在保存图形之前先进行处理

Imp*_*est 5

您可以使用以下类沿行创建文本。它取两个点(ppa)作为输入,而不是一个角度。这两个点之间的连接定义了数据坐标中的角度。如果pa未给出,则使用p和之间的连接线xy(文本坐标)。
然后,角度会自动更新,以使文本始终沿直线定向。这甚至适用于对数刻度。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.text as mtext
import matplotlib.transforms as mtransforms


class RotationAwareAnnotation(mtext.Annotation):
    def __init__(self, s, xy, p, pa=None, ax=None, **kwargs):
        self.ax = ax or plt.gca()
        self.p = p
        if not pa:
            self.pa = xy
        self.calc_angle_data()
        kwargs.update(rotation_mode=kwargs.get("rotation_mode", "anchor"))
        mtext.Annotation.__init__(self, s, xy, **kwargs)
        self.set_transform(mtransforms.IdentityTransform())
        if 'clip_on' in kwargs:
            self.set_clip_path(self.ax.patch)
        self.ax._add_text(self)

    def calc_angle_data(self):
        ang = np.arctan2(self.p[1]-self.pa[1], self.p[0]-self.pa[0])
        self.angle_data = np.rad2deg(ang)

    def _get_rotation(self):
        return self.ax.transData.transform_angles(np.array((self.angle_data,)), 
                            np.array([self.pa[0], self.pa[1]]).reshape((1, 2)))[0]

    def _set_rotation(self, rotation):
        pass

    _rotation = property(_get_rotation, _set_rotation)
Run Code Online (Sandbox Code Playgroud)

用法示例:

fig, ax = plt.subplots()
t = np.arange(0.0, 1.0, 0.01)
line, = ax.plot(t, t, color='blue', lw=2)

ra = RotationAwareAnnotation("test label", xy=(.5,.5), p=(.6,.6), ax=ax,
                             xytext=(2,-1), textcoords="offset points", va="top")

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

边缘盒的替代品

在某些情况下,在沿垂直线或x和y单位高度不同的文本上,上述操作可能会失败(此处为示例)。在这种情况下,以下更适合。它以屏幕坐标为单位计算角度,而不是依靠角度变换。

class RotationAwareAnnotation2(mtext.Annotation):
    def __init__(self, s, xy, p, pa=None, ax=None, **kwargs):
        self.ax = ax or plt.gca()
        self.p = p
        if not pa:
            self.pa = xy
        kwargs.update(rotation_mode=kwargs.get("rotation_mode", "anchor"))
        mtext.Annotation.__init__(self, s, xy, **kwargs)
        self.set_transform(mtransforms.IdentityTransform())
        if 'clip_on' in kwargs:
            self.set_clip_path(self.ax.patch)
        self.ax._add_text(self)

    def calc_angle(self):
        p = self.ax.transData.transform_point(self.p)
        pa = self.ax.transData.transform_point(self.pa)
        ang = np.arctan2(p[1]-pa[1], p[0]-pa[0])
        return np.rad2deg(ang)

    def _get_rotation(self):
        return self.calc_angle()

    def _set_rotation(self, rotation):
        pass

    _rotation = property(_get_rotation, _set_rotation)
Run Code Online (Sandbox Code Playgroud)

在通常情况下,两者都会产生相同的输出。我不确定第二堂课是否有任何弊端,所以我将两者都留在这里,选择您认为更合适的那个。