好问题!这是一个很好的挑战,需要结合多种因素才能实现。
首先,我们需要发明一个变换,它将返回预定义值的设备坐标加上基于给定点的偏移量。例如,如果我们知道我们希望条形位于 x_pt、y_pt,那么变换应该表示(以伪代码):
def transform(x, y):
return x_pt_in_device + x, y_pt_in_device + y
完成此操作后,我们可以使用此变换在固定数据点周围绘制一个 20 像素的框。但是,您只想在 y 方向上绘制固定像素高度的框,但在 x 方向上您想要标准数据缩放。
因此,我们需要创建一个可以独立变换 x 和 y 坐标的混合变换。执行您所要求的操作的整个代码:
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.transforms as mtrans
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.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
plt.scatter([3.1, 3.2, 3.4, 5], [2, 2, 2, 6])
ax = plt.gca()
fixed_pt_trans = FixedPointOffsetTransform(ax.transData, (0, 2))
xdata_yfixed = mtrans.blended_transform_factory(ax.transData, fixed_pt_trans)
x = [3.075, 3.425] # x range of box (in data coords)
height = 20 # of box in device coords (pixels)
path = mpath.Path([[x[0], -height], [x[1], -height],
[x[1], height], [x[0], height],
[x[0], -height]])
patch = mpatches.PathPatch(path, transform=xdata_yfixed,
facecolor='red', edgecolor='black',
alpha=0.4, zorder=0)
ax.add_patch(patch)
plt.show()