I am trying to annotate text in plots so that they follow the curvature of the line. I have the following plot:
And this is what I want to obtain, if I fix a particular y value for the annotation, for each curve it should place the annotation along the curve at the required slope (i.e. it should follow the curvature of the curve) as shown below:
The reproducible code for the plot without annotations is:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([[53.4, 57.6, 65.6, 72.9],
[60.8, 66.5, 73.1, 83.3],
[72.8, 80.3, 87.2, 99.3],
[90.2, 99.7, 109.1, 121.9],
[113.6, 125.6, 139.8, 152]])
y = np.array([[5.7, 6.4, 7.2, 7.8],
[5.9, 6.5, 7.2, 7.9],
[6.0, 6.7, 7.3, 8.0],
[6.3, 7.0, 7.6, 8.2],
[6.7, 7.5, 8.2, 8.7]])
plt.figure(figsize=(5.15, 5.15))
plt.subplot(111)
for i in range(len(x)):
plt.plot(x[i, :] ,y[i, :])
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
How to place such texts in Python with matplotlib?
You can get the gradient in degrees and use that in matplotlib.text.Text with the rotate argument
rotn = np.degrees(np.arctan2(y[:,1:]-y[:,:-1], x[:,1:]-x[:,:-1]))
EDIT: so it's a bit messier than I suggested as the plot area is scaled to match data and has margins etc. but you get the idea
...
plt.figure(figsize=(7.15, 5.15)) #NB I've changed the x size to check it didn't distort
plt.subplot(111)
for i in range(len(x)):
plt.plot(x[i, :] ,y[i, :])
rng = plt.axis()
x_scale = 7.15 * 0.78 / (rng[1] - rng[0])
y_scale = 5.15 * 0.80 / (rng[3] - rng[2])
rotn = np.degrees(np.arctan2((y[:,1:]-y[:,:-1]) * y_scale,
x[:,1:]-x[:,:-1]) * x_scale)
labls = ['first', 'second', 'third', 'fourth', 'fifth']
for i in range(len(x)):
plt.annotate(labls[i], xy=(x[i,2], y[i,2]), rotation=rotn[i,2])
plt.xlabel('X')
RE-EDIT noticed that the scaling was wrong but just happened to work by coincidence! Also the xy values of labels are a little approximate because of scaling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With