Python matplotlib日期时间xlabel问题

Python matplotlib日期时间xlabel问题,python,datetime,matplotlib,plot,Python,Datetime,Matplotlib,Plot,我在matplotlib中的日期x轴自动标记中看到一些奇怪的行为。当我发出命令时: from datetime import datetime as dt plot( [ dt(2013, 1, 1), dt(2013, 5, 17)], [ 1 , 1 ], linestyle='None', marker='.') 我得到了非常合理的标签图表: 但如果我将结束日期增加1天: plot( [ dt(2013, 1, 1), dt(2013, 5, 18)], [ 1 , 1 ], line

我在matplotlib中的日期x轴自动标记中看到一些奇怪的行为。当我发出命令时:

from datetime import datetime as dt
plot( [ dt(2013, 1, 1), dt(2013, 5, 17)], [ 1 , 1 ], linestyle='None', marker='.')
我得到了非常合理的标签图表:

但如果我将结束日期增加1天:

plot( [ dt(2013, 1, 1), dt(2013, 5, 18)], [ 1 , 1 ], linestyle='None', marker='.')
我明白了:

我在几个不同的日历日期范围内(2012年)复制了这一点,每次触发错误所需的神奇天数约为140天(在本例中为136/137天)。有人知道这是怎么回事吗?这是一个已知的bug吗?如果是,是否有解决方法

注意:在上面的命令中,我在--pylab模式下使用IPython来创建绘图,但是我第一次直接使用matplotlib时遇到了这个问题,并且它在脚本形式下是可复制的(即,我不认为这是IPython问题)。此外,我在matplotlib 1.1.0和1.2.X中都观察到了这一点

更新:

看起来有一个窗口,如果你向前推得足够远,标签会再次正常工作。对于上面的示例,从5月18日到5月31日,标签仍处于混乱状态,但在6月1日,标签再次开始正常打印。所以

(labels are garbled)
plot( [ dt(2013, 1, 1), dt(2013, 5, 31)], [ 1 , 1 ], linestyle='None', marker='.')

(labels are fine)
plot( [ dt(2013, 1, 1), dt(2013, 6, 1)], [ 1 , 1 ], linestyle='None', marker='.')

它确实感觉像一只虫子;我会把它带到matplotlib邮件列表,看看那里的人能对它说些什么

我可以提供以下一种解决方法:

from datetime import datetime as dt
from matplotlib import pylab as pl

fig = pl.figure()
axes = fig.add_subplot(111)
axes.plot( [ dt(2013, 1, 1), dt(2013, 5, 18)], [ 1 , 1 ], linestyle='None', marker='.')
ticks = axes.get_xticks()
n = len(ticks)//6
axes.set_xticks(ticks[::n])
fig.savefig('dateticks.png')
为OO方法道歉(这不是您所做的),但这使得将滴答声与情节联系起来更容易。
数字
6
正是我想要沿x轴的标签数量,然后我通过计算
n
减少matplotlib得到的实际刻度数,这是由
AutoDateLocator
中的错误引起的。似乎尚未向问题跟踪者报告此错误。
这看起来很奇怪,只是因为画了太多的标签和记号

使用带有日期的数据打印时,默认情况下,matplotlib使用
matplotlib.dates.AutoDateLocator
作为主定位器。即,
AutoDateLocator
用于确定勾号间隔和勾号位置

假设数据序列由
[datetime(2013,1,1),datetime(2013,5,18)]给出

时间差为4个月17天。月增量为4,日增量为4*31+17=141

根据:

类matplotlib.dates.AutoDateLocator(tz=None,minticks=5,maxticks=None,interval\u multiples=False)

minticks是所需的最小滴答数,用于选择滴答的类型(每年、每月等)

maxticks是所需的最大滴答数,它控制滴答之间的任何间隔(每隔滴答一次、每3次等)。对于真正细粒度的控制,这可以是一个字典,将单个rrule频率常数(每年、每月等)映射到它们自己的最大滴答数。这可用于保持与类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是合理的。您可以通过以下操作自定义此词典:

因为月增量是4,小于5,日增量是141,不小于5。滴答声的类型将为每日。
解析勾号类型后,
AutoDateLocator
将使用间隔字典和maxticks字典确定勾号间隔

maxticks
None
时,
AutoDateLocator
使用默认的maxticks字典。 文档向我们显示了默认的间隔字典,但没有告诉我们默认的maxticks字典是什么样子。
我们可以在地图上找到它

141太大了。所有的每日间隔都会产生过多的滴答声<代码>其他
子句将被执行,勾选间隔将被设置为1。
这意味着将绘制140多个标签和记号。我们可以期待一个丑陋的x轴

如果数据序列由
[日期时间(2013,1,1),日期时间(2013,5,17)]
给出,则只需短一天。日增量为140。 然后,
AutoDateLocator
将选择14作为刻度间隔,并且只打印10个标签。 因此,您的第一个图形看起来很好

实际上,我不明白,如果不能满足
maxticks
约束,为什么matplotlib选择将间隔设置为1。 如果间隔为1,则只会导致更多的滴答声。我喜欢使用最长的间隔

结论:
给定范围大于或等于4个月零18天,小于5个月的任何日期序列,
AutoDateLocator
将选择1作为刻度间隔。 使用默认主定位器(即,
AutoDateLocator
)打印此类日期序列时,您将在x轴或y轴上看到一些丑陋的行为

解决方案:
最简单的解决方案是将每日最大滴答数增加到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()
    alldays = DayLocator()              # minor ticks on the days
    alldays.MAXTICKS = 2000

您需要将locator.MAXTICKS重置为更大的数字以避免错误:超过locator.MAXTICKS*2(2000)

例如:

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()
    alldays = DayLocator()              # minor ticks on the days
    alldays.MAXTICKS = 2000

太好了,谢谢你的解释!您是否向matplotlib邮件列表报告了此问题(以及您的解决方案)?如果没有,我会这样做,并确保为您的分析提供支持。@jeremiahbuddha:我没有报告它。为了记录在案,我非常确定我在matplotlib的上一版本(v1.4.1)中修复了这个问题。
    alldays = DayLocator()              # minor ticks on the days
    alldays.MAXTICKS = 2000