1

I'm trying to build matplotlib charts whose x-axis is a dateIndex from a pandas dataframe. Trying to mimic some examples from matplotlib, I've been unsuccessful. The xaxis ticks and labels never appear.

I thought maybe matplotlib wasn't properly digesting the pandas index, so I converted it to ordinal with the matplotlib date2num helper function, but that gave the same result.

# https://matplotlib.org/api/dates_api.html
# https://matplotlib.org/examples/api/date_demo.html

import datetime as dt

import matplotlib.dates as mdates
import matplotlib.cbook as cbook

import matplotlib.dates as mpd


years = mdates.YearLocator()   # every year
months = mdates.MonthLocator()  # every month
yearsFmt = mdates.DateFormatter('%Y')


majorLocator = years
majorFormatter = yearsFmt #FormatStrFormatter('%d')
minorLocator = months


y1 = np.arange(100)*0.14+1
y2 = -(np.arange(100)*0.04)+12

"""neither of these indices works"""
x = pd.date_range(start='4/1/2012', periods=len(y1))
#x = map(mpd.date2num, pd.date_range(start='4/1/2012', periods=len(y1)))

fig, ax = plt.subplots()
ax.plot(x,y1)
ax.plot(x,y2)

ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)
ax.xaxis.set_minor_locator(months)

datemin = x[0]   
datemax = x[-1]  
ax.set_xlim(datemin, datemax)
fig.autofmt_xdate()
plt.show()

enter image description here

2 Answers 2

3

The problem is the following. pd.date_range(start='4/1/2012', periods=len(y1)) creates dates from the first of April 2012 to the 9th of July 2012.
Now you set the major locator to be a YearLocator. This means, that you want to have a tick for each year on the axis. However, all dates are within the same year 2012. So there is no major tick to be shown within the plot range.

The suggestion would be to use a MonthLocator instead, such that the first of each month is ticked. Also if would make sense to use a formatter, which actually shows the months, e.g. '%b %Y'. You may use a DayLocator for the minor ticks, if you want, to show the small tickmarks for each day.

ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.xaxis.set_minor_locator(mdates.DayLocator())

Complete example:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

y1 = np.arange(100)*0.14+1
y2 = -(np.arange(100)*0.04)+12

x = pd.date_range(start='4/1/2012', periods=len(y1))

fig, ax = plt.subplots()
ax.plot(x,y1)
ax.plot(x,y2)

ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
ax.xaxis.set_minor_locator(mdates.DayLocator())

fig.autofmt_xdate()
plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

2

You could use pd.DataFrame.plot to handle most of that

df = pd.DataFrame(dict(
    y1=y1, y2=y2
), index=x)

df.plot()

enter image description here

1 Comment

thanks this is a good point. The biggest concern I have with abstracting behind pd.plot() is that it adds one more layer of control to matplotlib. I already find it often confusing wrangling matplotlib because there are various ways to treat it (as a state machine, as an object), and i tend to have those approaches commingle and cause confusion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.