matplotlib中的转换

时间:2015-08-23 22:43:27

标签: python matplotlib transform

我正在尝试在特定位置(在数据坐标中)绘制具有固定大小(在设备坐标中)的对象(线/补丁)。此行为类似于标记和注释箭头的提示,两者在缩放和平移下都是(大小)不变的。

为什么以下示例不能按预期工作?

预期输出是两条交叉线,形成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()

1 个答案:

答案 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

enter image description here