简体   繁体   中英

Matplotlib Subplot Datetime X-Axis Ticks Not Working As Intended

I'm attempting to plot many plots, here's a sample of how the data is organized:

数据帧

My intention is to build a series of subplots for either hours or days (say 7 days in a week, or 24 hours in a day) using google analytics data. My index are date-time objects.

Here's an example of how a single plot looks, when the axis is done correctly.

from datetime import datetime, date, timedelta
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import matplotlib.dates as dates

#creating our graph and declaring our locator/formatters used in axis labelling.
hours = dates.HourLocator(interval=2)
hours_ = dates.DateFormatter('%I %p')

el = datetime(year=2016, day=1, month=3, hour=0)
fig, ax = plt.subplots(ncols = 1, nrows= 1)
fig.set_size_inches(18.5, 10.5)
fig.tight_layout()
ax.set_title(el.strftime('%a, %m/%d/%y'))
ax.plot(df_total.loc[el:el+timedelta(hours=23, minutes=59),:].index, 
                             df_total.loc[el:el+timedelta(hours=23, minutes=59),:].hits, '-')
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(hours_) 
fig.show()

对图!

As you can see, the x axis looks good, working as intended with the right ticks/date labels.

However, when I try and run the same plot on a subplot series, I'm running into the following error. Here's my code:

fig, ax = plt.subplots(ncols = 3, nrows= 2)
fig.set_size_inches(18.5, 10.5)
fig.tight_layout()

nrows=2
ncols=3

count = 0

for row in range(nrows):
    for column in range(ncols):
        el = cleaned_date_range[count]
        ax[row][column].set_title(el.strftime('%a, %m/%d/%y'))
        ax[row][column].xaxis.set_major_locator(hours)
        ax[row][column].xaxis.set_major_formatter(hours_)
        ax[row][column].plot(df_total.loc[el:el+timedelta(hours=23,minutes=59),:].index, df_total.loc[el:el+timedelta(hours=23,minutes=59),:].hits)
        count += 1

        if count == 7:
            break

However, that yields the very funky plot below, with mislabelled axes:

错误的图形!

I experimented with adding an additional row to see if it was just covering up because of vertical space: 在此处输入图片说明

but was confronted with the same behavior, only the last subplot's axes appears to be working with the rest not working.

Any insight would be appreciated!

so the answer is in the following github issue raised a few years ago related to the set_major_locator() and set_major_formatter() objects:

https://github.com/matplotlib/matplotlib/issues/1086/

to quote eric:

"You are missing something, but it is something that is quite non-intuitive and easy to miss: Locators can't be shared among axes. The set_major_locator() method assigns its axis to that Locator, overwriting any axis that was previously assigned."

so the solution is to instantiate a new dates.MinuteLocator and dates.DateFormatter object for each new axes, eg:

for ax in list_of_axes:
    minutes = dates.MinuteLocator(interval=5)
    minutes_ = dates.DateFormatter('%I:%M %p')
    ax.xaxis.set_major_locator(minutes)
    ax.xaxis.set_major_formatter(minutes_)

I've experimented and it looks like you don't need to reference the dates.Locator and dates.Formatter objects after the plot so it's ok to just re-instantiate with each loop using the same name. (I could be wrong here though!)

I had the same missing subplot datetime x-axis tick marks issue. The following code, which is quite similar to the OP's, seems to work, see the attached figure. However, I'm using matplotlib 3.1.0, perhaps the issue has been addressed in this version? But I do have one observation: if I enable fig.autofmt_xdate() for the second subplot, the first subplot datetime x-axis will not display.

fig = plt.figure()
plt.rcParams['figure.figsize'] = (width, height)
plt.subplots_adjust(wspace=0.25, hspace=0.2)

ax = fig.add_subplot(2,1,1)
ax.xaxis.set_major_locator(MonthLocator(bymonthday=1))
ax.xaxis.set_major_formatter(DateFormatter('%Y-%b'))
ax.plot(df1['DATE'], df1['Movement'], '-')
plt.ylabel(r'$D$', fontsize=18)
plt.xticks(fontsize=12)
plt.yticks(fontsize=16)
plt.legend(fontsize=16, frameon=False)
fig.autofmt_xdate()

ax = fig.add_subplot(2,1,2)
ax.xaxis.set_major_locator(MonthLocator(bymonthday=1))
ax.xaxis.set_major_formatter(DateFormatter('%Y-%b'))
ax.plot(df2['DATE'], df2['Movement'], '-')
#plt.ylabel(r'$D`enter code here`$', fontsize=18)
plt.xticks(fontsize=16)
plt.yticks(fontsize=16)
plt.legend(fontsize=16, frameon=False)
#fig.autofmt_xdate()

plt.show()

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM