我正在尝试在特定位置(在数据坐标中)绘制具有固定大小(在设备坐标中)的对象(线/补丁)。此行为类似于标记和注释箭头的提示,两者在缩放和平移下都是(大小)不变的。
为什么以下示例不能按预期工作?
预期输出是两条交叉线,形成50x50点方形(设备坐标)的对角线。所述正方形的左下角应位于数据坐标中的点(1,0)处。 虽然计算出的点看起来是正确的,但第二对角线根本不可见。
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.transforms as mtrans
import matplotlib as mpl
import numpy as np
class FixedPointOffsetTransform(mtrans.Transform):
"""
Always returns the same transformed point plus
the given point in device coordinates as an offset.
"""
def __init__(self, trans, fixed_point):
mtrans.Transform.__init__(self)
self.input_dims = self.output_dims = 2
self.has_inverse = False
self.trans = trans
self.fixed_point = np.array(fixed_point).reshape(1, 2)
def transform(self, values):
fp = self.trans.transform(self.fixed_point)
values = np.array(values)
if values.ndim == 1:
return fp.flatten() + values
else:
return fp + values
fig , ax = plt.subplots(1,1)
ax.set_xlim([-1,10])
ax.set_ylim([-1,10])
# this transformation shifts the input by the given offset
# the offset is transformed with the given transformation
# and then added to the input
fixed_pt_trans = FixedPointOffsetTransform(ax.transData, (1, 0))
# these values are in device coordinates i.e. points
height = 50
width = 50
# two points in device coordinates, that are modified with the above transformation
A = fixed_pt_trans.transform((0,0))
B = fixed_pt_trans.transform((width,height))
l1 = mpl.lines.Line2D([A[0],B[0]], [A[1],B[1]])
ax.add_line(l1)
# already in device coordinates with the offset applied,
# no further transformation nessesary
l1.set_transform(None)
print(A)
print(B)
print(l1.get_transform().transform(A))
print(l1.get_transform().transform(B))
# two points in device coordinates (unmodified)
A = (width,0)
B = (0,height)
l2 = mpl.lines.Line2D([A[0],B[0]], [A[1],B[1]])
ax.add_line(l2)
# apply transformation to add offset
l2.set_transform(fixed_pt_trans)
print(l2.get_transform().transform(A))
print(l2.get_transform().transform(B))
fig.show()
答案 0 :(得分:2)
根据matplotlib API Changes文档,从matplotlib 1.2.x开始:
现在巧妙地改变了变换子类化行为。如果您的转换实现了非仿射转换,那么它应该覆盖
transform_non_affine
方法,而不是通用的transform
方法。
因此,如上所述,只需重新实现transform_non_affine
代替transform
方法,FixedPointOffsetTransform
类就可以解决问题:
class FixedPointOffsetTransform(mtrans.Transform):
"""
Always returns the same transformed point plus
the given point in device coordinates as an offset.
"""
def __init__(self, trans, fixed_point):
mtrans.Transform.__init__(self)
self.input_dims = self.output_dims = 2
self.has_inverse = False
self.trans = trans
self.fixed_point = np.array(fixed_point).reshape(1, 2)
def transform_non_affine(self, values):
fp = self.trans.transform(self.fixed_point)
values = np.array(values)
if values.ndim == 1:
return fp.flatten() + values
else:
return fp + values