Search code examples
pythonpandasmatplotlibtimeserieschart

Detailed date in cursor pos on pyplot charts


Let's say there's a time series that I want to plot in matplotlib:

dates = pd.date_range(start='2011-01-01', end='2012-01-01')
s = pd.Series(np.random.rand(1, len(dates))[0], index=dates)

The GUI backends in matplotlib have this nice feature that they show the cursor coordinates in the window. When I plot pandas series using its plot() method like this:

fig = plt.figure()
s.plot()
fig.show()

the cursor's x coords are shown in full yyyy-mm-dd at the bottom of the window as you can see on pic 1.

Series s plotted with s.plot()

However when I plot the same series s with pyplot:

fig = plt.figure()
plt.plot(s.index, s.values)
fig.show()

full dates are only shown when I zoom in and in the default view I can only see Mon-yyyy (see pic 2) and I would see just the year if the series were longer.

Series s plotted with plt.plot()

In my project there are functions for drawing complex, multi-series graphs from time series data using plt.plot(), so when I view the results in GUI I only see the full dates in the close-ups. I'm using ipython3 v. 4.0 and I'm mostly working with the MacOSX backend, but I tried TK, Qt and GTK backends on Linux with no difference in the behavior.

So far I've got 2 ideas on how to get the full dates displayed in GUI at any zoom level:

  1. rewrite plt.plot() to pd.Series.plot()
  2. use canvas event handler to get the x-coord from the cursor pos and print it somewhere

However before I attempt any of the above I need to know for sure if there is a better quicker way to get the full dates printed in the graph window. I guess there is, because pandas is using it, but I couldn't find it in pyplot docs or examples or elsewhere online and it's none of these 2 calls:

ax.xaxis_date()
fig.autofmt_xdate()

Somebody please advise.


Solution

  • Hooks for formatting the info are Axes.format_coord or Axes.fmt_xdata. Standard formatters are defined in matplotlib.dates (plus some additions from pandas). A basic solution could be:

    import matplotlib.dates
    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    
    dates = pd.date_range(start='2011-01-01', end='2012-01-01')
    series = pd.Series(np.random.rand(len(dates)), index=dates)
    
    plt.plot(series.index, series.values)
    plt.gca().fmt_xdata = matplotlib.dates.DateFormatter('%Y-%m-%d')
    plt.show()