Search code examples
pythondatetimematplotlibxticks

Matplotlib- make x-ticks the first time of the month on contourf plot


The issue

I have a filled contour plot and some time series data with time on the x-axis and height on the y-axis. I made a datetime list and can substitute that in for the x-axis ticks in place of the default list of numbers that usually gets used as x-ticks instead. That's fine and all, but I'd like the xticks to be plotted on the first of each month instead of every 30 days. I know there's a MonthLocator function in mpl.dates, but I can't figure out how it to use it correctly. All the examples I'm finding use line plots, not contourf, and the axes work differently between both.

Working example

#Modules

import numpy             as     np
import datetime          as     dt
import matplotlib.pyplot as     plt
from   matplotlib        import ticker
%matplotlib inline

#Data
data = np.random.randint(0,50,(10,61))
print(data.shape)
(10, 61)
#Dates
dates = []
base = dt.datetime(2000,1,1,1)
for i in range(len(data[1])):
    date      = base + dt.timedelta(days=i)
    dates.append(str(date.strftime("%-m/%-d/%-Y")))
print(dates[0], dates[-1])
('1/1/2000', '3/1/2000')
#Levels
levels = np.arange(1,len(data[1])+1)
clevels = np.arange(0,50,5)

#Figure
fig, ax = plt.subplots(figsize=(10, 5))
im      = ax.contourf(data,levels,levels=clevels,cmap='RdBu_r',extend='both')

#Axis customization
ax.set_xticklabels(dates)
plt.xticks(np.arange(len(dates))[::30],dates[::30])
ax.set_ylabel("Level")
cbar = plt.colorbar(im,values=clevels,pad=0.01)

enter image description here

The question

How do I make the x-ticks plot the first day of each month instead of at a set interval?


Solution

  • You can set the x-axis major locator to use a matplotlib.dates.MonthLocator, but you have to supply the X and Y parameters to matplotlib.pyplot.contourf and the X array must be populated by datetime, i.e.

    import numpy as np
    from datetime import datetime, timedelta
    import matplotlib.pyplot as plt
    from matplotlib import ticker
    from matplotlib.dates import MonthLocator, DateFormatter
    
    data = np.random.randint(0, 50, (10, 61))
    dates = [datetime.strptime('01-01-2000', '%m-%d-%Y') + timedelta(d) for d 
             in range(len(data[0]))]
    clevels = np.arange(0, 50, 5)
    
    fig, ax = plt.subplots(figsize=(10, 5))
    im  = ax.contourf(dates, range(data.shape[0]), data, levels=clevels, 
                          cmap='RdBu_r', extend='both')
    
    ax.set_ylabel("Level")
    ax.xaxis.set_major_locator(MonthLocator())
    ax.xaxis.set_major_formatter(DateFormatter("%m/%d/%Y"))
    cbar = plt.colorbar(im, values=clevels, pad=0.01)
    plt.show()
    

    This will then automatically place the major ticks at a specified date of each month (it defaults to the first of each month):

    enter image description here