2

When doing an image which puts lots of focus on some arrows, I noticed that the arrows didn't reach the full length between the specified points.

For example:

import matplotlib.pyplot as plt
import matplotlib as mpl

fig, ax = plt.subplots()
fig.set_size_inches(5, 5)

w = 0.001
h = 1000

ax.set_xlim(0, w)
ax.set_ylim(0, h)

ax.add_artist(mpl.patches.FancyArrowPatch(
    (w*1/3, h*0.0),
    (w*1/3, h*1.0),
    edgecolor='black',
    facecolor='red',
    arrowstyle=mpl.patches.ArrowStyle.CurveFilledAB(head_length=10, head_width=10)
))
ax.add_artist(mpl.patches.FancyArrowPatch(
    (w*2/3, h*0.0),
    (w*2/3, h*1.0),
    edgecolor='black',
    facecolor='red',
    arrowstyle=mpl.patches.ArrowStyle.Simple(head_length=10, head_width=10, tail_width=1)
))
plt.savefig(
    'main.svg',
    format='svg',
    bbox_inches='tight',
    dpi=100,
)

produces:

enter image description here

and here is a screenshot of a browser zoom of the arrows showing that they don't touch the black line above:

enter image description here

How to make them touch exactly without that white space?

Tested on matplotlib==3.2.2.

Related questions:

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985

1 Answers1

2

shrinkA=0 and shrinkB=0

This is the first main direct reason why arrows don't touch.

Those values default to 2, presumably because arrows were originally mostly used in annotations where some space is desired.

If I set them to zero:

FancyArrowPatch(
    shrinkA=0,
    shrinkB=0,

then the arrows touch as shown at:

enter image description here

A is for the start, and B is for the end of the arrow.

The effect of linewidth

Another thing to keep in mind however is that the linewidth can also affect if the arrow touches something or not.

For example, if I add an exaggerated linewidth=10 to the original code:

FancyArrowPatch(
    shrinkA=0,
    shrinkB=0,
    linewidth=10,

then the result is:

enter image description here

so we note how:

  • the tracing of the edges is always rounded, and therefore the arrows stop being pointy and become rounded with large line widths
  • Simple and CurveFilledAB have different drawing algorithms: the one for Simple makes the arrow overrun the target, and CurveFilledAB makes it under run
  • the linewidth above was so fat that it hid the red inner color

For the case of Simple, if you don't need a different border color, you can get back the pointy arrow with linewidth=0, and control the main arrow line width with tail_width.

This does not work for CurveFilledAB however: the drawing algorithm for that style is to use the border alone for the main arrow line, so I'm not sure how to separately control the main line width of a double headed arrow without getting the rounded corners, except for drawing two simple arrows which is uglier: matplotlib simple and two head arrows Seems like something that could be patched by adding a new SimpleAB class.

The result of:

FancyArrowPatch(
    shrinkA=0,
    shrinkB=0,
    linewidth=0,

is:

enter image description here

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985