matplotlib datetime xlabel问题

jer*_*dha 9 python plot datetime matplotlib

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

from datetime import datetime as dt
plot( [ dt(2013, 1, 1), dt(2013, 5, 17)], [ 1 , 1 ], linestyle='None', marker='.')
Run Code Online (Sandbox Code Playgroud)

我得到了非常合理的标签图表:

在此输入图像描述

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

plot( [ dt(2013, 1, 1), dt(2013, 5, 18)], [ 1 , 1 ], linestyle='None', marker='.')
Run Code Online (Sandbox Code Playgroud)

我明白了:

在此输入图像描述

我在几个不同的日历日期范围转载此(2012年),每一次的幻数跳闸的bug所需的天是约140(在这种情况下一百三十七分之一百三十六).谁知道这里发生了什么?这是一个已知的错误,如果有,是否有解决方法?

一些注意事项:在上面的命令中,我在-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='.')
Run Code Online (Sandbox Code Playgroud)

nym*_*ymk 7

它被一个错误所引发AutoDateLocator.似乎尚未向问题跟踪器报告此错误.
它看起来很奇怪,因为已经绘制了太多的标签和刻度.

使用日期数据绘图时,默认情况下,matplotlib matplotlib.dates.AutoDateLocator用作主要定位器.即,AutoDateLocator用于确定刻度间隔和刻度位置.

假设,数据序列由下式给出[datetime(2013, 1, 1), datetime(2013, 5, 18)].
时间差为4个月和17天.月份增量为4,日期增量为4*31 + 17 = 141.

根据matplotlib文档:

class matplotlib.dates.AutoDateLocator(tz = None,minticks = 5,maxticks = None,interval_multiples = False)

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

maxticks是所需的最大滴答数,它控制滴答之间的任何间隔(每隔一个滴答,每隔3滴等).对于非常细粒度的控制,这可以是将各个rrule频率常数(YEARLY,MONTHLY等)映射到它们自己的最大tick数的字典.这可以用于保持适合在类中选择的格式的刻度数:AutoDateFormatter.未在此词典中指定的任何频率都将被赋予默认值.

AutoDateLocator有一个区间字典,用于映射tick的频率(来自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]
      }
Run Code Online (Sandbox Code Playgroud)

该间隔用于指定适合滴答频率的倍数.例如,每7天对于每日蜱是合理的,但是对于分钟/秒,15或30是有意义的.您可以通过以下操作自定义此词典:

由于月份delta为4,小于5,而日期delta为141,不小于5.滴答的类型为每日.
在解析滴答类型后,AutoDateLocator将使用区间字典和maxticks字典来确定滴答间隔.

如果maxticksNone,AutoDateLocator使用其默认maxticks字典.文档向我们展示了默认的区间字典,并没有告诉我们默认的maxticks字典是什么样的.
我们可以在dates.py中找到它.

self.maxticks = {YEARLY : 16, MONTHLY : 12, DAILY : 11, HOURLY : 16,
            MINUTELY : 11, SECONDLY : 11}
Run Code Online (Sandbox Code Playgroud)

确定滴答间隔的算法

# 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
Run Code Online (Sandbox Code Playgroud)

滴答的类型DAILY现在.所以,freqDAILYnum是141,这一天三角洲.上面的代码相当于

for interval in [1, 2, 3, 7, 14]:
    if 141 <= interval * (11 - 1):
        break
else:
    interval = 1
Run Code Online (Sandbox Code Playgroud)

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作为滴答间隔.当使用默认主要定位器绘制此类日期序列时,您会在x轴或y轴上看到一些丑陋的行为,即AutoDateLocator.

解决方案:
最简单的解决方案是将每日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()
Run Code Online (Sandbox Code Playgroud)