Search code examples
pythonmatplotlibdatetimedatetime-formatxticks

How to set the xticks for the end of the month


I have a list of dates that fall on the end of each month, and I would like for the gridlines and labels of my plot to coincide with these dates. Currently I can only get the chart to plot at the beginning of the month. Is there a way to force Matplotlib to use the end of month values in its charting?

import matplotlib.pyplot as plt 
from datetime import datetime
from matplotlib.dates import MonthLocator
from matplotlib.dates import DateFormatter
  
dts = [datetime(2020, 11, 30), datetime(2020, 12, 31),
           datetime(2021, 1, 31), datetime(2021, 2, 28),
           datetime(2021, 3, 31), datetime(2021, 4, 30),
           datetime(2021, 5, 31), datetime(2021, 6, 30),
           datetime(2021, 7, 31), datetime(2021, 8, 31),
           datetime(2021, 9, 30), datetime(2021, 10, 31),
           datetime(2021, 11, 30), datetime(2021, 12, 31),
           datetime(2022, 1, 31), datetime(2022, 2, 28),]
vals = [2000, 2500, 3000, 4000, 4500, 4000, 3000, 2500, 4000, 4500, 3000, 
             2500, 6000, 4000, 3000, 5000]
    
figsize=(3, 6)
fig, ax = plt.subplots(figsize=figsize)
    
ax.xaxis.set_major_locator(MonthLocator((3, 6, 9, 12)))
fmt = DateFormatter("%Y-%m")
ax.xaxis.set_major_formatter(fmt)

ax.plot(dts, vals, color = 'blue')
ax.grid(True)
plt.show()

Solution

  • One option is just to manually or dynamically set_ticks() with:

    ax.set_xticks([datetime(2020, 12, 31), datetime(2021, 3, 31), datetime(2021, 6, 30), datetime(2021, 9, 30), datetime(2021, 12, 31)])
    

    OR Better:

    ax.set_xticks(dts[1::3]) # this uses every third element starting with second element
    

    Full code:

    import matplotlib.pyplot as plt 
    from datetime import datetime
    from matplotlib.dates import MonthLocator
    from matplotlib.dates import DateFormatter
    
    fig, ax = plt.subplots(figsize=(12, 6))
    
    fmt = DateFormatter("%Y-%m-%d")
    ax.xaxis.set_major_formatter(fmt)
    ax.set_xticks([datetime(2020, 12, 31), datetime(2021, 3, 31), datetime(2021, 6, 30), datetime(2021, 9, 30), datetime(2021, 12, 31)])
    ax.set_xticks(dts[1::3])
    
    ax.plot(dts, vals, color = 'blue')
    ax.grid(True)
    plt.show()
    

    enter image description here