10

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) です。ここで何が起こっているか知っている人はいますか?これは既知のバグですか? もしそうなら、回避策はありますか?

いくつかのメモ: 上記のコマンドでは、IPython を --pylab モードで使用してプロットを作成していますが、最初にこの問題に遭遇したのは、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='.')
4

3 に答える 3

8

のバグが原因でしたAutoDateLocator。このバグはまだイシュー トラッカーに報告されていないようです。
あまりにも多くのラベルと目盛りがプロットされているため、奇妙に見えます。

日付を含むデータをプロットする場合、デフォルトでは、matplotlib はmatplotlib.dates.AutoDateLocatorメジャー ロケーターとして使用します。つまり、AutoDateLocatorティック間隔とティック位置を決定するために使用されます。

データ シーケンスが で与えられるとし[datetime(2013, 1, 1), datetime(2013, 5, 18)]ます。
タイム デルタは 4 か月と 17 日です。月の差分は 4 で、日の差分は 4*31+17=141 です。

matplotlib docsによると:

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

minticks は必要なティックの最小数で、ティックのタイプ (年次、月次など) を選択するために使用されます。

maxticks は、必要なティックの最大数であり、ティック間の任意の間隔 (1 回おき、3 回おきなど) を制御します。本当にきめの細かい制御のために、これは個々の rrule 頻度定数 (YEARLY、MONTHLY など) を独自の最大ティック数にマッピングするディクショナリにすることができます。これを使用して、クラス: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がの場合NoneAutoDateLocatorデフォルトの maxticks ディクショナリを使用します。ドキュメントには、デフォルトのインターバル ディクショナリが示されていますが、デフォルトの maxticks ディクショナリがどのように見えるかは示されていません。dates.py
で見つけることができます。

self.maxticks = {YEARLY : 16, MONTHLY : 12, DAILY : 11, HOURLY : 16,
            MINUTELY : 11, SECONDLY : 11}

ティック間隔を決定するアルゴリズムは次のとおりです。

# 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今です。141日のデルタもそうですfreq。上記のコードは次と同等になりますDAILYnum

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)]1 日だけ短くなります。日のデルタは 140 です。次にAutoDateLocator、ティック間隔として 14 を選択し、10 個のラベルのみがプロットされます。したがって、最初のグラフは問題なく表示されます。

maxticks実際、制約が満たされない場合、matplotlib が間隔を 1 に設定する理由がわかりません。間隔が 1 の場合にのみ、ティック数がはるかに多くなります。私は最長の間隔を使用することを好みます。

結論:
範囲が 4 か月 18 日以上 5 か月未満の日付シーケンスを指定するとAutoDateLocator、ティック間隔として 1 が選択されます。このような日付シーケンスをデフォルトの主要なロケーター、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()
于 2013-03-06T14:53:41.947 に答える
2

バグのように感じます。私はそれを matplotlib メーリング リストに持って行き、そこで人々がそれについて何を言うことができるかを確認します。

私が提供できる1つの回避策は次のとおりです。

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 軸に沿って必要なラベルの数にすぎません。次に、計算された によって、matplotlib が思いついた実際の目盛りの数を減らしますn

于 2013-03-05T10:00:39.410 に答える
0

エラーを回避するには、locator.MAXTICKS をより大きな数値にリセットする必要があります: Locator.MAXTICKS * 2 (2000) を超えています

例えば:

    alldays = DayLocator()              # minor ticks on the days
    alldays.MAXTICKS = 2000
于 2014-10-15T12:01:13.670 に答える