pythonmatplotlibplot

Set arrow size based on figure units instead of axis data units?


In matplotlib, is there a way to specify arrow head sizes in figure units rather than in data units?

The use case is: I am making a multi-panel figure in which each panel has a different axis size (e.g., one goes from 0 to 1 on the X-axis, and the next goes from 0 to 10). I'd like the arrows to appear the same in each panel. I'd also like the arrows to appear the same independent of direction.

For axes with an aspect ratio not equal to 1, the width of the tail (and therefore the size of the head) varies with direction.

The closest I've come is, after drawing on the canvas:

dx = ax.get_xlim()[1] - ax.get_xlim()[0]
for arrow in ax.patches:
arrow.set_data(width=dx/50)

but this does not work; it results in images like this:

Graphic


Solution

  • Just use ax.annotate() instead of ax.arrow():

    enter image description hereenter image description here

    import matplotlib.pyplot as plt
    import numpy as np
    
    xlim, ylim = (-.3, .8), (0, 5.8)
    arrow_start, arrow_end = np.asarray([.1, 3]), np.asarray([.5, 5])
    
    fig = plt.figure(figsize=(3, 2))
    
    ax = plt.gca()
    ax.set_title('using ax.arrow()')
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
    ax.arrow(*arrow_start, *(arrow_end - arrow_start), width=1/50)
    
    fig = plt.figure(figsize=(3, 2))
    
    ax = plt.gca()
    ax.set_title('using ax.annotate()')
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
    ax.annotate('', arrow_end, arrow_start, arrowprops=dict(width=5, headwidth=10, headlength=5))