Python 如何对Matplotlib面片应用持久坐标变换?
matplotlib坐标系(在Jupyter笔记本中用于交互式动画)让我有点困惑。如果您创建一个面片,比如说一个圆,然后使用set_transform()对其进行平移,我发现该变换不是持久的,这意味着如果使用相同的(x,y)移位再次应用该变换,则圆将不会移动,因为在变换后圆的位置似乎不会更新,因此,后续变换将应用于相同的原始面片位置。我的问题是,如何应用一个转换,不仅在应用补丁后移动它,而且更新补丁位置?。假设我要应用一系列的平移,那么圆应该四处移动,而不是从原始位置来回摆动。下面是一个示例代码:Python 如何对Matplotlib面片应用持久坐标变换?,python,matplotlib,Python,Matplotlib,matplotlib坐标系(在Jupyter笔记本中用于交互式动画)让我有点困惑。如果您创建一个面片,比如说一个圆,然后使用set_transform()对其进行平移,我发现该变换不是持久的,这意味着如果使用相同的(x,y)移位再次应用该变换,则圆将不会移动,因为在变换后圆的位置似乎不会更新,因此,后续变换将应用于相同的原始面片位置。我的问题是,如何应用一个转换,不仅在应用补丁后移动它,而且更新补丁位置?。假设我要应用一系列的平移,那么圆应该四处移动,而不是从原始位置来回摆动。下面是一个示例代码
%import matplotlib
%matplotlib notebook
fig = plt.figure()
ax = fig.add_subplot(111, xlim=(-10, 10), ylim=(-10, 10))
c = ax.add_patch(plt.Circle((x, y), radius=0.5)
c.set_transform(ax.transData + mpl.transforms.Affine2D().translate(-5,-5))
c.set_transform(ax.transData + mpl.transforms.Affine2D().translate(10,10))
如果运行此命令,您将看到注释掉第一个平移不会影响圆的最终位置。我本以为圆心的最终位置是(5,5)而不是(10,10)。这意味着变换实际上不会更新面片(圆)位置;它只是在图形/轴中进行转换
问题2:我发现另一件让人困惑的事情是,上面代码生成的圆的半径似乎是要求的0.5,但是在应用(10,10)的平移后,它在图中的平移要小得多!!好像在应用转换位移之前,转换位移会被某些因素缩小!!对此我没有任何解释,它只是表明我不理解matplotlib坐标系和变换
另一方面,plot()生成的对象是Line2D对象,可以通过set_data()方法进行转换,该方法更新对象的位置,如下所示(假设fig和上面代码段中的ax对象):
我不知道如何对matplotlib修补程序执行相同的操作?将数据坐标转换为显示坐标
将变换添加到一起时,将从左向右应用变换。所以
ax.transData + mpl.transforms.Affine2D().translate(-5,-5)
首先将数据转换为显示坐标,然后按偏移量转换
显示坐标(像素)中的(-5,-5)
相比之下
mpl.transforms.Affine2D().translate(-5,-5) + ax.transData
将首先在数据坐标中移动(-5,-5),然后将数据坐标转换为显示坐标
由于转换可以通过加法组合,因此要更新转换,请使用
transform = transform + mpl.transforms.Affine2D().translate(...)
比如说,
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot(111, xlim=(-10, 10), ylim=(-10, 10))
x, y = 0, 0
c = ax.add_patch(plt.Circle((x, y), radius=5))
transform = mpl.transforms.Affine2D().translate(-5,-5)
transform += mpl.transforms.Affine2D().translate(10,10)
c.set_transform(transform+ax.transData)
ax.set_aspect('equal')
plt.show()
圆心位于(5,5)
,因为(x,y)+(-5,-5)+(10,10)=(5,5)
或者,您可以计算(或跟踪)偏移序列,并根据需要生成变换,而不是组合变换。有关此方法的示例,请参见
还要注意的是,在呈现补丁之前(例如通过调用
plt.show()
)不会应用变换。这解释了为什么对c.set\u transform
的多个调用与对c.set\u transform
的单个调用具有相同的效果。只有最后一个变换应用于面片
补丁程序c
将单个转换存储在私有属性中,您可以使用c.get\u transform
访问该属性:
In [10]: c.get_transform()
Out[15]:
CompositeGenericTransform(Affine2D(array([[ 5., 0., 0.],
[ 0., 5., 0.],
[ 0., 0., 1.]])), CompositeGenericTransform(TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())), CompositeGenericTransform(BboxTransformFrom(TransformedBbox(Bbox([[-10.0, -10.0], [10.0, 10.0]]), TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())))), BboxTransformTo(TransformedBbox(Bbox([[0.125, 0.09999999999999998], [0.9, 0.9]]), BboxTransformTo(TransformedBbox(Bbox([[0.0, 0.0], [6.4, 4.8]]), Affine2D(array([[ 100., 0., 0.],
[ 0., 100., 0.],
[ 0., 0., 1.]])))))))))
c.set\u transform
将该私有属性重新指定给新的转换。但是在执行plt.show()
或其他一些渲染调用(如plt.savefig
)之前,不会应用任何变换。阅读了吗?对于问题1的第一部分,set\u transform
不会附加变换。它重置整个矩阵。这意味着c.set_transform(ax.transData+mpl.transforms.Affine2D().translate(10,10))
之前的任何内容都将被有效忽略。是的,这是任何想要操作转换的人的必读资料。谢谢。我会读你链接的那一页。这里对我来说最重要的细节是显示与数据(如果我可以这样称呼的话)坐标。但是,如果您确认这些变换仅应用于渲染面片,它们实际上不会更新面片的“位置”或坐标。正确。渲染时应用单个变换(当前变换,由c.get_transform()
返回的变换)。
In [10]: c.get_transform()
Out[15]:
CompositeGenericTransform(Affine2D(array([[ 5., 0., 0.],
[ 0., 5., 0.],
[ 0., 0., 1.]])), CompositeGenericTransform(TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())), CompositeGenericTransform(BboxTransformFrom(TransformedBbox(Bbox([[-10.0, -10.0], [10.0, 10.0]]), TransformWrapper(BlendedAffine2D(IdentityTransform(),IdentityTransform())))), BboxTransformTo(TransformedBbox(Bbox([[0.125, 0.09999999999999998], [0.9, 0.9]]), BboxTransformTo(TransformedBbox(Bbox([[0.0, 0.0], [6.4, 4.8]]), Affine2D(array([[ 100., 0., 0.],
[ 0., 100., 0.],
[ 0., 0., 1.]])))))))))