Matplotlib の日付目盛りフォーマッタ

Beginner

This tutorial is from open-source community. Access the source code

はじめに

~.dates.ConciseDateFormatter は、Matplotlib を使用して日付の目盛りをフォーマットする際の便利なツールです。この実験では、このフォーマッタを使用して目盛りラベルに選択される文字列を改善し、それらの目盛りラベルに使用される文字列をできるだけ少なくする方法を学びます。

VM のヒント

VM の起動が完了したら、左上隅をクリックして ノートブック タブに切り替え、Jupyter Notebook を使用して練習します。

場合によっては、Jupyter Notebook が読み込み完了するまで数秒待つ必要があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。

学習中に問題に遭遇した場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。そうすれば、迅速に問題を解決します。

デフォルトのフォーマッタ

まずは、デフォルトのフォーマッタとその冗長な出力を見てみましょう。時間の経過に伴うデータをプロットし、デフォルトのフォーマッタが日付と時刻をどのように表示するかを見ます。

import datetime
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates

## create time data
base = datetime.datetime(2005, 2, 1)
dates = [base + datetime.timedelta(hours=(2 * i)) for i in range(732)]
N = len(dates)
np.random.seed(19680801)
y = np.cumsum(np.random.randn(N))

## plot data
fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(6, 6))
lims = [(np.datetime64('2005-02'), np.datetime64('2005-04')),
        (np.datetime64('2005-02-03'), np.datetime64('2005-02-15')),
        (np.datetime64('2005-02-03 11:00'), np.datetime64('2005-02-04 13:20'))]
for nn, ax in enumerate(axs):
    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
    ## rotate labels...
    for label in ax.get_xticklabels():
        label.set_rotation(40)
        label.set_horizontalalignment('right')
axs[0].set_title('Default Date Formatter')
plt.show()

デフォルトのフォーマッタ

まずは、デフォルトのフォーマッタとその冗長な出力を見てみましょう。時間の経過に伴うデータをプロットし、デフォルトのフォーマッタが日付と時刻をどのように表示するかを見ます。

import datetime
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates

## 時間データを作成する
base = datetime.datetime(2005, 2, 1)
dates = [base + datetime.timedelta(hours=(2 * i)) for i in range(732)]
N = len(dates)
np.random.seed(19680801)
y = np.cumsum(np.random.randn(N))

## データをプロットする
fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(6, 6))
lims = [(np.datetime64('2005-02'), np.datetime64('2005-04')),
        (np.datetime64('2005-02-03'), np.datetime64('2005-02-15')),
        (np.datetime64('2005-02-03 11:00'), np.datetime64('2005-02-04 13:20'))]
for nn, ax in enumerate(axs):
    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
    ## ラベルを回転させる...
    for label in ax.get_xticklabels():
        label.set_rotation(40)
        label.set_horizontalalignment('right')
axs[0].set_title('Default Date Formatter')
plt.show()

簡略化された日付フォーマッタ

次に、~.dates.ConciseDateFormatter とその出力を調べます。簡略化された日付フォーマッタを使用して新しいプロットを作成し、デフォルトのフォーマッタとどのように異なるかを見ます。

fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(6, 6))
for nn, ax in enumerate(axs):
    locator = mdates.AutoDateLocator(minticks=3, maxticks=7)
    formatter = mdates.ConciseDateFormatter(locator)
    ax.xaxis.set_major_locator(locator)
    ax.xaxis.set_major_formatter(formatter)

    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
axs[0].set_title('Concise Date Formatter')
plt.show()

コンバータの登録

日付を持つ軸へのすべての呼び出しがこのコンバータを使用して行われる場合、おそらく最も便利なのは、単位レジストリを使用することです。単位レジストリにコンバータを登録し、簡略化された日付フォーマッタを使用してデータをプロットします。

import datetime
import matplotlib.units as munits

converter = mdates.ConciseDateConverter()
munits.registry[np.datetime64] = converter
munits.registry[datetime.date] = converter
munits.registry[datetime.datetime] = converter

fig, axs = plt.subplots(3, 1, figsize=(6, 6), layout='constrained')
for nn, ax in enumerate(axs):
    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
axs[0].set_title('Concise Date Formatter')
plt.show()

日付フォーマットのローカライゼーション

デフォルトのフォーマットが望ましくない場合、日付フォーマットをローカライズすることができます。これは、3 つの文字列のリストのいずれかを操作することで行われます。ISO の「年 月 日」ではなく、ラベルを「日 月 年」に変更します。

fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(6, 6))

for nn, ax in enumerate(axs):
    locator = mdates.AutoDateLocator()
    formatter = mdates.ConciseDateFormatter(locator)
    formatter.formats = ['%y',  ## 目盛りは主に年
                         '%b',       ## 目盛りは主に月
                         '%d',       ## 目盛りは主に日
                         '%H:%M',    ## 時
                         '%H:%M',    ## 分
                         '%S.%f', ]  ## 秒
    ## これらは主に上のレベルと同じです...
    formatter.zero_formats = [''] + formatter.formats[:-1]
    #...ただし、目盛りが主に時間の場合を除き、
    ## 月 - 日が欲しい場合があります:
    formatter.zero_formats[3] = '%d-%b'

    formatter.offset_formats = ['',
                                '%Y',
                                '%b %Y',
                                '%d %b %Y',
                                '%d %b %Y',
                                '%d %b %Y %H:%M', ]
    ax.xaxis.set_major_locator(locator)
    ax.xaxis.set_major_formatter(formatter)

    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
axs[0].set_title('Concise Date Formatter')
plt.show()

ローカライゼーション付きのコンバータの登録

キーワード引数を ~.dates.ConciseDateConverter に渡し、使用するデータ型を単位レジストリに登録することで、ローカライゼーション付きのコンバータを登録することもできます。

import datetime

formats = ['%y',          ## 目盛りは主に年
           '%b',     ## 目盛りは主に月
           '%d',     ## 目盛りは主に日
           '%H:%M',  ## 時
           '%H:%M',  ## 分
           '%S.%f', ]  ## 秒
## これらは同じでも良いですが、1 つレベルオフセットさせます...
zero_formats = [''] + formats[:-1]
#...ただし、目盛りが主に時間の場合を除き、月 - 日が欲しいです
zero_formats[3] = '%d-%b'
offset_formats = ['',
                  '%Y',
                  '%b %Y',
                  '%d %b %Y',
                  '%d %b %Y',
                  '%d %b %Y %H:%M', ]

converter = mdates.ConciseDateConverter(
    formats=formats, zero_formats=zero_formats, offset_formats=offset_formats)

munits.registry[np.datetime64] = converter
munits.registry[datetime.date] = converter
munits.registry[datetime.datetime] = converter

fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(6, 6))
for nn, ax in enumerate(axs):
    ax.plot(dates, y)
    ax.set_xlim(lims[nn])
axs[0].set_title('Concise Date Formatter registered non-default')
plt.show()

まとめ

この実験では、Matplotlib を使用して日付の目盛りをフォーマットする際に、~.dates.ConciseDateFormatter をどのように使用するかを学びました。また、日付フォーマットをローカライズし、コンバータを登録して処理をより便利にする方法も学びました。