它是由 AutoDateLocator 中的错误引起的。似乎此错误尚未报告给问题跟踪器。
它看起来很奇怪,只是因为绘制了太多的标签和刻度。
当使用带有日期的数据进行绘图时,默认情况下,matplotlib 使用 matplotlib.dates.AutoDateLocator 作为主要定位符。即AutoDateLocator用于确定tick间隔和tick位置。
假设,数据序列由[datetime(2013, 1, 1), datetime(2013, 5, 18)]给出。
时间增量为 4 个月零 17 天。月 delta 为 4,日 delta 为 4*31+17=141。
根据matplotlib docs:
类 matplotlib.dates.AutoDateLocator(tz=None, minticks=5, maxticks=None, interval_multiples=False)
minticks 是所需的最小刻度数,用于选择刻度类型(每年、每月等)。
maxticks 是所需的最大刻度数,它控制刻度之间的任何间隔(每隔一个刻度,每 3 个刻度等)。对于真正细粒度的控制,这可以是一个字典,将单个规则频率常数(每年、每月等)映射到它们自己的最大刻度数。这可用于保持刻度数适合于在 class:AutoDateFormatter 中选择的格式。任何未在本词典中指定的频率都会被赋予一个默认值。
AutoDateLocator 有一个间隔字典,用于映射滴答的频率(来自 dateutil.rrule 的常量)和允许该滴答的倍数。默认如下所示:
self.intervald = {
YEARLY : [1, 2, 4, 5, 10],
MONTHLY : [1, 2, 3, 4, 6],
DAILY : [1, 2, 3, 7, 14],
HOURLY : [1, 2, 3, 4, 6, 12],
MINUTELY: [1, 5, 10, 15, 30],
SECONDLY: [1, 5, 10, 15, 30]
}
间隔用于指定适合滴答频率的倍数。例如,对于每日刻度,每 7 天是合理的,但对于分钟/秒,15 或 30 是有意义的。您可以通过以下方式自定义此词典:
由于月份 delta 为 4,小于 5,而日 delta 为 141,不小于 5。tick 的类型将是每天。
在解析了tick的类型后,AutoDateLocator会使用interval字典和maxticks字典来确定tick的间隔。
当maxticks 为None 时,AutoDateLocator 使用其默认的 maxticks 字典。
文档向我们展示了默认的区间字典,并没有告诉我们默认的 maxticks 字典是什么样的。
我们可以在dates.py找到它。
self.maxticks = {YEARLY : 16, MONTHLY : 12, DAILY : 11, HOURLY : 16,
MINUTELY : 11, SECONDLY : 11}
The algorithm to determine the tick interval是
# Find the first available interval that doesn't give too many ticks
for interval in self.intervald[freq]:
if num <= interval * (self.maxticks[freq] - 1):
break
else:
# We went through the whole loop without breaking, default to 1
interval = 1
现在的类型是DAILY。所以freq 是DAILY 和num 是141,日增量。上面的代码相当于
for interval in [1, 2, 3, 7, 14]:
if 141 <= interval * (11 - 1):
break
else:
interval = 1
141 太大。所有的每日间隔都会给出太多的滴答声。 else 子句将被执行,并且刻度间隔将设置为 1。
这意味着将绘制 140 多个标签和刻度。我们可以期待一个丑陋的 x 轴。
如果数据序列由[datetime(2013, 1, 1), datetime(2013, 5, 17)] 给出,则仅短一天。日差为 140。
然后AutoDateLocator 将选择 14 作为刻度间隔,并且只会绘制 10 个标签。
因此,您的第一个图表看起来不错。
其实我不明白如果maxticks约束不能满足,matplotlib为什么选择将区间设置为1。
如果间隔为 1,它只会导致更多的滴答声。我更喜欢使用最长的间隔。
结论:
给定范围大于或等于 4 个月 18 天且小于 5 个月的任何日期序列,AutoDateLocator 将选择 1 作为刻度间隔。
当使用默认的主要定位器(即AutoDateLocator)绘制此类日期序列时,您会在 x 轴或 y 轴上看到一些丑陋的行为。
解决方案:
最简单的解决方案是将每日 maxticks 增加到 12。
例如:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import DAILY
from datetime import datetime
ax = plt.subplot(111)
plt.plot_date([datetime(2013, 1, 1), datetime(2013, 5, 31)],
[datetime(2013, 1, 1), datetime(2013, 5, 10)])
loc = ax.xaxis.get_major_locator()
loc.maxticks[DAILY] = 12
plt.show()