9

How do I set the distance (padding) between the arrow and the text in matplotlib's annotate function? Sometimes the text ends up being too close to the arrow and I would like to move them a little further apart.

Basic example:

import matplotlib.pyplot as plt

plt.annotate('Here it is!',xy=(-1,-1),xytext=(0,0),
             arrowprops=dict(arrowstyle='->',lw=1.5))

plt.xlim(-10,10)
plt.ylim(-10,10)

plt.show()

enter image description here

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
DanHickstein
  • 6,588
  • 13
  • 54
  • 90

3 Answers3

7

For fancy arrows you can play with the bbox properties:

fig, ax = plt.subplots(1, 3, figsize=(7, 3))
pad_val = [-5, 0, 5]
for a,p in zip(ax, pad_val):
    a.annotate('Here it is!\npad={}'.format(p),xy=(-1,-1),xytext=(1,1),
                arrowprops=dict(arrowstyle='-|>', fc="k", ec="k", lw=1.5),
                bbox=dict(pad=p, facecolor="none", edgecolor="none"))
    a.set_xlim(-10,10)
    a.set_ylim(-10,10)

set pad between arrow and text in matplotlib annotate

Here the drawback is that you can't add a color behind the annotation (facecolor="none" is mandatory), or the arrow will always stick to the border of the frame and it might be ugly.

HTH

jrjc
  • 21,103
  • 9
  • 64
  • 78
  • 1
    This seems to work great! (Not sure why you got downvoted...). For those who don't want to actually see the bounding box, you can pass `facecolor='none', edgecolor='none'` in the bbox dict. I changed this to the accepted answer, since it works with the example code that I originally posted, which uses the FancyArrow. – DanHickstein Mar 27 '17 at 19:54
  • @DanHickstein Good point for the `'none'`, the `fc=None` did not work. I'll edit accordingly. – jrjc Mar 28 '17 at 08:49
2

You can use the shrink keyword argument in your arrowprops dictionary, but unfortunately the FancyArrowPatch object doesn't support it, so you'd have to remove the arrowstyle='->'.

The value given with shrink is a percentage that the tip/base will move away from the xy and xytext coordinates.

import matplotlib.pyplot as plt

plt.annotate('Here it is!',xy=(-1,-1),xytext=(0,0),
             arrowprops=dict(lw=1.5, shrink=0.15))

plt.xlim(-10,10)
plt.ylim(-10,10)

plt.show()
Ffisegydd
  • 51,807
  • 15
  • 147
  • 125
  • Thanks, this is what I was looking for! But no work-around for the fancy arrow? I much prefer the '->' style of arrow. – DanHickstein Apr 28 '14 at 15:39
  • 1
    I don't believe so. You get an `AttributeError: 'FancyArrowPatch' object has no attribute 'set_shrink'` unfortunately. – Ffisegydd Apr 28 '14 at 15:43
  • @DanHickstein See my answer for a work around for the fancy arrows – jrjc Mar 27 '17 at 16:27
2

To have full control of the distance, you must combine jrjc and Ffisegydd answers.

The pad property of the Bbox defines the distance between the text and its containing box. The shrink property of the arrow is the distance between the arrow extremity and the box, not the text itself.

Also, to use shrink with FancyArrowPatch you must defined it separately: shrinkA for the origin (extremity of the arrow close to the text) and shrinkB for the destination. From a demo in Matplotlib's website:

 ax.annotate("",
             xy=(x1, y1), xycoords='data',
             xytext=(x2, y2), textcoords='data',
             arrowprops=dict(arrowstyle="->", color="0.5",
                             shrinkA=5, shrinkB=5,
                             patchA=None, patchB=None,
                             connectionstyle=connectionstyle,
                             ),
             )

So the full answer is both:

plt.annotate('Example text',
             xy=(-1,-1), xytext=(0,0),
             arrowprops=dict(arrowstyle='->', shrinkA=0.15),
             bbox=dict(pad=0),
    )

Examples:

Influence of Bbox pad and arrow shrink parameters on distance of arrow to text

wagnifico
  • 632
  • 3
  • 13
  • This is actually the clearest explanation IMHO! Now, is there any way to control where the arrow connects with the box? It is not at the xytext coordinates, but seems to be at the center of the bbox. If it is too much for here, I can start a new question. – Adriaan Feb 17 '23 at 11:02
  • I just did: https://stackoverflow.com/q/75484393/2606407 – Adriaan Feb 17 '23 at 12:38
  • 1
    Just answered your question, hope it works for you. – wagnifico Feb 20 '23 at 17:00