How to rotate matplotlib annotation to match a line?

This is the exact same process and basic code as given by @Adam — it’s just restructured to be (hopefully) a little more convenient.

def label_line(line, label, x, y, color="0.5", size=12):
    """Add a label to a line, at the proper angle.

    Arguments
    ---------
    line : matplotlib.lines.Line2D object,
    label : str
    x : float
        x-position to place center of text (in data coordinated
    y : float
        y-position to place center of text (in data coordinates)
    color : str
    size : float
    """
    xdata, ydata = line.get_data()
    x1 = xdata[0]
    x2 = xdata[-1]
    y1 = ydata[0]
    y2 = ydata[-1]

    ax = line.get_axes()
    text = ax.annotate(label, xy=(x, y), xytext=(-10, 0),
                       textcoords="offset points",
                       size=size, color=color,
                       horizontalalignment="left",
                       verticalalignment="bottom")

    sp1 = ax.transData.transform_point((x1, y1))
    sp2 = ax.transData.transform_point((x2, y2))

    rise = (sp2[1] - sp1[1])
    run = (sp2[0] - sp1[0])

    slope_degrees = np.degrees(np.arctan2(rise, run))
    text.set_rotation(slope_degrees)
    return text

Used like:

import numpy as np
import matplotlib.pyplot as plt

...
fig, axes = plt.subplots()
color="blue"
line, = axes.plot(xdata, ydata, '--', color=color)
...
label_line(line, "Some Label", x, y, color=color)

Edit: note that this method still needs to be called after the figure layout is finalized, otherwise things will be altered.

See: https://gist.github.com/lzkelley/0de9e8bf2a4fe96d2018f1b1bd5a0d3c

Leave a Comment