Great question! It was a good challenge, and a combination of things is required to achieve this.
First, we need to come up with a transformation that returns the device coordinates of a predetermined value plus an offset based on this point. For example, if we know that we want the string to be in x_pt, y_pt, then the transformation should represent (in pseudocode):
def transform(x, y): return x_pt_in_device + x, y_pt_in_device + y
Once we do this, we can use this transformation to draw a 20px rectangle around a fixed data point. However, you only want to draw a rectangle with a fixed pixel height in the y direction, but in the x direction you would like standard data scaling.
Therefore, we need to create a mixed transformation that can independently transform the x and y coordinates. All code to do what you ask:
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]