4

I'm using matplotlib to plot some data that I wish to annotate with arrows (distance markers). These arrows should be offset by several points so as not to overlap with the plotted data:

import matplotlib.pyplot as plt
import matplotlib.transforms as transforms

fig, ax = plt.subplots()

x = [0, 1]
y = [0, 0]

# Plot horizontal line
ax.plot(x, y)

dy = 5/72

offset = transforms.ScaledTranslation(0, dy, ax.get_figure().dpi_scale_trans)
verttrans = ax.transData+offset

# Plot horizontal line 5 points above (works!)
ax.plot(x, y, transform = verttrans)

# Draw arrow 5 points above line (doesn't work--not vertically translated)
ax.annotate("", (0,0), (1,0),
            size = 10,
            transform=verttrans,
            arrowprops = dict(arrowstyle = '<|-|>'))

plt.show()

Is there any way to make lines drawn by ax.annotate() be offset by X points? I wish to use absolute coordinates (e.g., points or inches) instead of data coordinates because the axis limits are prone to changing.

Thanks!

sircolinton
  • 6,536
  • 3
  • 21
  • 19

2 Answers2

3

The following code does what I desired. It uses ax.transData and figure.get_dpi():

import matplotlib.pyplot as plt
import matplotlib.transforms as transforms

fig, ax = plt.subplots()


x = [0, 1]
y = [0, 0]


ax.plot(x, y)


dy = 5/72

i = 1  # 0 for dx

tmp = ax.transData.transform([(0,0), (1,1)])
tmp = tmp[1,i] - tmp[0,i]  # 1 unit in display coords
tmp = 1/tmp  # 1 pixel in display coords
tmp = tmp*dy*ax.get_figure().get_dpi()  # shift pixels in display coords

ax.plot(x, y)

ax.annotate("", [0,tmp], [1,tmp],
            size = 10,
            arrowprops = dict(arrowstyle = '<|-|>'))

plt.show()
sircolinton
  • 6,536
  • 3
  • 21
  • 19
2

What's your expected output? If you're just looking to move the arrow you're drawing vertically, the API for annotate is

annotate(s, xy, xytext=None, ...)

so you can draw something like

ax.annotate("", (0,0.01), (1,0.01),
    size = 10,
    arrowprops = dict(arrowstyle = '<|-|>'))

which is moved up by 0.01 in data coordinates in the y direction. You can also specify coordinates as a fraction of the total figure size in annotate (see doc). Is that what you wanted?

Alex Z
  • 1,449
  • 4
  • 20
  • 29
  • Hi Alex, thanks for your answer. My aim is to avoid using data coordinates for the offset and to specify the offset in absolute units (inches or points) instead. This is because the axis limits are prone to changing, but this shouldn't change how the distance markers are plotted. (Similarly, I wish to avoid using a fraction of the image size, since the image size may change too.) – sircolinton May 23 '14 at 23:31