Jim421616
Jim421616

Reputation: 1536

Plotting a vertical double-headed arrow in matplotlib

I have the following plot, showing a linear relationship (black) and its residuals (blue). The red dotted lines show the upper and lower bounds for the residuals, and the vertical red line shows the range:

enter image description here

Here's how I've coded the bounds for the residuals:

plt.hlines(y = max(model.resid), xmin = min(x), xmax = max(x),
               color = 'r', linestyle = 'dotted')
plt.hlines(y = min(model.resid), xmin = min(x), xmax = max(x),
               color = 'r', linestyle = 'dotted')
plt.vlines(label = 'Range of residuals: %g'%(max(model.resid) - min(model.resid)),
               x = min(x), ymin = min(model.resid), ymax = max(model.resid),
               color = 'r', linestyle = 'solid')

I want the vertical line to be a double-headed arrow, so I tried using arrowprops = {'arrowstyle': '<->'} after the linestyle, but I got AttributeError: Unknown property arrowprops.

All of the questions and example I've found show how to make an arbitrarily-positioned arrow, but none of them give a nicely-proportioned head.

Is there an easy way to convert the line to a double-headed arrow?

Upvotes: 2

Views: 5042

Answers (1)

Sheldore
Sheldore

Reputation: 39052

Here is a minimal working solution to your problem. The main keyword here is arrowstyle="<->". I personally prefer to use plt.text separately to put the text independently of the arrow end point in the plot. It gives you more freedom. I had to generate random data due to absence of your data but I kept the x and y range similar to yours. You can adapt your code accordingly. Your problem was that you were assigning arrowprops which is a property of annotate to vlines.

import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111)

x = np.linspace(-0.4, 0.6, 1000)
y = np.random.normal(0, 0.033, 1000)

plt.plot(x, y, 'o')
plt.hlines(y = max(y), xmin = min(x), xmax = max(x),
               color = 'r', linestyle = 'dotted')
plt.hlines(y = min(y), xmin = min(x), xmax = max(x),
               color = 'r', linestyle = 'dotted')

ax.annotate("",
            xy=(min(x), min(y)), xycoords='data',
            xytext=(min(x), max(y)), textcoords='data',
            arrowprops=dict(arrowstyle="<->",
                            connectionstyle="arc3", color='r', lw=2),
            )

plt.text(1.2*min(x), max(y), 'Range of residuals: %g'%(max(y) - min(y)), 
         rotation = 90, fontsize = 16)
plt.xlim(1.3*min(x), 1.3*max(x))

Output

enter image description here

Upvotes: 2

Related Questions