Matplotlib 显示额外的 x 标签集与常规 x 标签重叠

Matplotlib shows extra set of x labels overlapping regular x labels

我在使用 matplotlib 时遇到了这个问题,我无法隐藏自动生成的、不需要的 xlabels,这些 xlabels 似乎是凭空冒出来的。

这是我的代码(在这个重现问题的最小示例中减少了实际代码):

import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd

data = pd.read_csv("TestData.csv")

# Convert string to pd.Timestamp
data["datetime"] = data["datetime"].transform(lambda d:
                              dt.datetime.strptime(d, '%Y-%m-%d %H:%M:%S'))
data.set_index("datetime")

# start and end dates of data in CSV
max_date = data["datetime"].max()
min_date = data["datetime"].min()

# make figure
fig = plt.figure(figsize=[24, 12], dpi=300)

ax = data.plot.line(x="datetime",
                    y="totalAIAD",
                    color="xkcd:aquamarine")

delta = max_date - min_date  # total span of time for the report

time_unit = pd.to_timedelta(5, unit='m')  # 5 minute ticks
floor_unit = 'T'

# floor for cleaner ticks
date = min_date.floor(floor_unit)
xticks = []

while date + time_unit <= max_date:
    date = date + time_unit  # create date ticks for x axis

    xticks.append(date)

ax.axes.set_xticks(xticks)

str_xticks = []
for xtick in xticks:
    str_xticks.append(xtick.strftime('%H:%M:%S'))

ax.axes.set_xticklabels(str_xticks, rotation=45, ha='right')

#plt.suptitle("Stream Processor and Anomaly Detector Execution times")
#plt.title("From " + min_date.strftime('%Y-%m-%d %H:%M:%S') + " to "
#          + max_date.strftime('%Y-%m-%d %H:%M:%S'))

plt.xlabel(
    "Time",
    fontdict={
        'family': 'monospace',
        'color': 'xkcd:black',
        'weight': 'normal',
        'size': 14,
    },
    labelpad=6
)
plt.ylabel(
    "Delays (ms)",
    fontdict={
        'family': 'monospace',
        'color': 'xkcd:black',
        'weight': 'normal',
        'size': 14,
    },
    labelpad=6
)

[t.set_color('red') for t in ax.xaxis.get_ticklines()]
[t.set_color('red') for t in ax.xaxis.get_ticklabels()]

# vertical range for values (0 to configured MAX_Y)
plt.ylim((0, 50))

plt.grid(True, axis='y', alpha=0.5)

plt.axhline(y=10, color='r', linestyle='-')

plt.show()
plt.close(fig)

这需要 TestData.csv: https://www.toptal.com/developers/hastebin/uqepujujav.apache

它产生以下输出:

如您所见,只有我在代码中设置的 xtick 标签是红色的。不需要的(11:30、11:45 和 12:15)不受颜色影响。它们也不受我移除它们的所有尝试的影响。 (我尝试了 ax.set_xticks([])ax.set_xticklabels([])plt.xticks([])ax.xaxis.set_major_locator(ticker.NullLocator()))。

有什么想法吗?我失去了摆脱这些标签的希望。

通过使用 pandas 绘制日期作为 x-axis,自动设置 AutoDateLocatorAutoDateFormatter。这些设置自己的刻度,独立于 set_xticks(并且在缩放时也会计算新的刻度)。另见 matplotlib's date tick tutorial

如示例中所示, pandas plotting doesn't work easy with customized date formatting。您可以直接通过 matplotlib 绘图。这是代码的可能改编:

import matplotlib.pyplot as plt
from matplotlib.dates import MinuteLocator, ConciseDateFormatter
import pandas as pd
import datetime as dt

data = pd.read_csv('TestData.csv', parse_dates=True)
data["datetime"] = data["datetime"].transform(lambda d: dt.datetime.strptime(d, '%Y-%m-%d %H:%M:%S'))
data.set_index("datetime")

fig, ax = plt.subplots(figsize=[24, 12], dpi=300)
ax.plot("datetime", "totalAIAD", data=data, color="xkcd:aquamarine")

locator = MinuteLocator(interval=5)
formatter = ConciseDateFormatter(locator)
formatter.formats = ['%y',  # ticks are mostly years
                     '%b',  # ticks are mostly months
                     '%d',  # ticks are mostly days
                     '%H:%M',  # hrs
                     '%H:%M:%S',  # min
                     '%S.%f', ]  # secs
formatter.zero_formats = [''] * len(formatter.formats)
formatter.offset_formats = [''] * len(formatter.formats) # this would write out the current date at the lower right
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)

ax.set_xlabel("Time", fontdict={'family': 'monospace', 'color': 'xkcd:black', 'weight': 'normal', 'size': 14},
              labelpad=6)
ax.set_ylabel("Delays (ms)", fontdict={'family': 'monospace', 'color': 'xkcd:black', 'weight': 'normal', 'size': 14},
              labelpad=6)

[t.set_color('red') for t in ax.xaxis.get_ticklines()]
[t.set_color('red') for t in ax.xaxis.get_ticklabels()]

ax.set_ylim((0, 50))
ax.margins(x=0)
ax.grid(True, axis='y', alpha=0.5)
ax.axhline(y=10, color='r', linestyle='-')
fig.autofmt_xdate() # automatically makes the x-labels rotate
plt.tight_layout()
plt.show()