luffe
luffe

Reputation: 1665

Annotate Time Series plot

I have an index array (x) of dates (datetime objects) and an array of actual values (y: bond prices). Doing the following:

plot(x,y)

produces a perfectly fine time series graph with the x-axis labeled with the dates. No problem so far. But I want to add text on certain dates. For example, on 2009-10-31, I wish to display the text "Event 1" with an arrow pointing to the y value at that date.

I have read through the Matplotlib documentation on text() and annotate() to no avail.

Upvotes: 49

Views: 47642

Answers (2)

cottontail
cottontail

Reputation: 23141

Newer versions of matplotlib (e.g. 3.7.0) doesn't require explicit date2num calls anymore. Just pass a point on the plot directly as xy= to annotate().

from datetime import datetime
import matplotlib.pyplot as plt

x = [datetime(2009, 5, 1), datetime(2010, 6, 1), 
     datetime(2011, 4, 1), datetime(2012, 6, 1)]
y = [1, 3, 2, 5]

fig, ax = plt.subplots(facecolor='white')
ax.plot(x, y, linestyle='--')

ax.annotate('Test', xy=(x[1], y[1]),   # <---- directly pass the point position
            xytext=(-15, 15), textcoords='offset points', 
            arrowprops={'arrowstyle': '->'})

fig.autofmt_xdate()

img1

A more terse (but less flexible) solution is to use text() to annotate. Again, no need to perform a datetime-to-number conversion; just pass the point as is.

plt.plot(x, y, linestyle='--')
plt.text(x[1], y[1], 'Test')        # use x-y coordinate values as is
plt.xticks(plt.xticks()[0][::2]);

img2

Upvotes: 2

Joe Kington
Joe Kington

Reputation: 284602

Matplotlib uses an internal floating point format for dates.

You just need to convert your date to that format (using matplotlib.dates.date2num or matplotlib.dates.datestr2num) and then use annotate as usual.

As a somewhat excessively fancy example:

import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

x = [dt.datetime(2009, 05, 01), dt.datetime(2010, 06, 01), 
     dt.datetime(2011, 04, 01), dt.datetime(2012, 06, 01)]
y = [1, 3, 2, 5]

fig, ax = plt.subplots()
ax.plot_date(x, y, linestyle='--')

ax.annotate('Test', (mdates.date2num(x[1]), y[1]), xytext=(15, 15), 
            textcoords='offset points', arrowprops=dict(arrowstyle='-|>'))

fig.autofmt_xdate()
plt.show()

enter image description here

Upvotes: 89

Related Questions