Matplotlib 日付と時刻の書式#

公開日

Matplotlibの軸ラベルに日付や時刻を指定するときの書式について解説します。 書式の設定方法は大きく分けて以下の2つがあります。

  • Figure.autofmt_xdate()による自動調整

  • Formatter, Locatorによる手動調整

この記事では、以下の通りライブラリをインポートしていることを前提とします。

from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd

datetimepandasは時刻データを作成するためにインポートします。

デフォルトの時刻表示#

Matplotlibの軸に日付・時刻を設定すると、デフォルトでは以下のようにラベルが重なる場合があります。 なお、ここではPython標準ライブラリのdatetime.datetimeの日付を横軸としています。

x = [datetime(2025, 1, 1), datetime(2025, 1, 2), datetime(2025, 1, 3)]
y = [1, 3, 2]

fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
../_images/746b464ce6912bd623f18c9c9b3cf7964a45dc5b8e0382d85b91677855ddd1bd.png

autofmt_xdateによる自動調整#

Figure.autofmt_xdate()を実行すると、簡易的に日付・時刻のラベルを回転・位置調整して重ならないようにできます。 以下の例では、Figureクラスのオブジェクトfigautofmt_xdate()を実行しています。

fig, ax = plt.subplots()
ax.plot(x, y)
fig.autofmt_xdate()
plt.show()
../_images/93b37ed4ac9352757fff9ae40d8b3a198792791734633a6bfeb96440ba504729.png

Figure.autofmt_xdate()には、パラメータを渡してラベルの表示方法を細かく指定できます。主なパラメータは以下の通りです。

  • rotation (float): x軸ラベルの回転角度(単位:[度]。デフォルト値: 30

  • ha ('left', 'center', 'right'のいずれか): 横方向の位置を指定(デフォルト値: 'right'

  • which ('major', 'minor', 'both'のいずれか): 主目盛り(major)・補助目盛り(minor)のどちらを調節するか指定(デフォルト値: 'major'

rotation=45, ha="center"とした実行結果を以下に示します。ラベルの角度は45度となり、目盛りとラベルの中心位置が一致しています

fig, ax = plt.subplots()
ax.plot(x, y)
fig.autofmt_xdate(rotation=45, ha="center")
plt.show()
../_images/174473236d3efe7bc6832fa9085f96519999b8cb1deb59ce4f45a1e4f46e38f7.png

Formatter, Locatorによる手動調整#

表示形式はFormatter, 日付・時刻の間隔はLocatorでそれぞれ細かく設定できます。 以下に簡単な例を示します。

fig, ax = plt.subplots()
ax.plot(x, y)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y/%m/%d'))
ax.xaxis.set_major_locator(mdates.DayLocator())
ax.xaxis.set_minor_locator(mdates.HourLocator(byhour=(0, 6, 12, 18)))
plt.show()
../_images/c95ea6f0c22cb8067c39d205c000fa6d5ee83f4aad2c23b60bafab5917021949.png

上の例では、グラフの横軸を以下の通り設定しています。

  • 主目盛り (major tick) の表示形式: %Y/%m/%d(年/月/日)

  • 主目盛りの間隔: 1日

  • 補助目盛り (minor tick) の間隔: 6時間

Formatterによる表示形式#

以下のメソッドにDateFormatter()を渡すことにより、日付・時刻の表示形式を指定できます(axAxesオブジェクトです)。

  • ax.xaxis.set_major_formatter(): 主目盛り (major tick)

  • ax.xaxis.set_minor_formatter(): 補助目盛り (minor tick)

以下のようにDateFormatter()matplotlib.datesモジュールをインポートして使用できます。

import matplotlib.dates as mdates

mdates.DateFormatter()

また、DateFormatter()には以下のオプションを渡すことができます。

  • fmt (str): 日付・時刻の表示形式

  • tz: (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

  • usetex: (bool): Trueの場合、TeXの数式と同じ形式で表示する(デフォルト値: False

fmtに指定できる主な表示形式は以下の表の通りです。

時間の単位

表示形式

備考

4桁の西暦

%Y

2025

下2桁の西暦

%y

25

%m

01, 12

%d

01, 31

時(24時間制)

%H

00, 23

%M

00, 59

%S

00, 59

マイクロ秒(6桁の0埋め)

%f

000000, 001000

時:分:秒

%X

01:23:45

%H:%M:%Sと等価

タイムゾーン

%Z

UTC, JST

その他に指定可能な表示形式については、以下のページを参照ください。

datetime — Basic date and time types — Python documentation

主目盛りを「月/日 時:分」、補助目盛りを「時:分」とした例を以下に示します。 DayLocatorHourLocatorについては次の節で説明します。

x = pd.date_range("2025-01-01 00:00:00", periods=10, freq="6h")
y = [1, 3, 2, 4, 2] * 2

fig, ax = plt.subplots()
ax.plot(x, y)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d\n%H:%M'))
ax.xaxis.set_minor_formatter(mdates.DateFormatter('%H:%M'))
ax.xaxis.set_major_locator(mdates.DayLocator())
ax.xaxis.set_minor_locator(mdates.HourLocator(byhour=(0, 12)))
ax.grid()
plt.show()
../_images/a507214af2c32799344d97080ac05ccb510e0245e0dee50a31b46ba3611efca2.png

Locatorによる間隔の調整#

以下のメソッドにLocatorを渡すことにより、日付・時刻の間隔を指定できます(axAxesオブジェクトです)。

  • ax.xaxis.set_major_locator(): 主目盛り (major tick)

  • ax.xaxis.set_minor_locator(): 補助目盛り (minor tick)

Locatorには主に以下の種類があります。

単位

Locator

(自動)

AutoDateLocator

YearLocator

MonthLocator

DayLocator

曜日

WeekdayLocator

時間

HourLocator

MinuteLocator

SecondLocator

マイクロ秒

MicroSecondLocator

デフォルトではAutoDateLocatorが設定されています。 また、以下のように各Locatorはmatplotlib.datesモジュールをインポートして使用できます。

import matplotlib.dates as mdates

mdates.YearLocator()

年 YearLocator#

年単位の目盛りを設定する場合、YearLocator()を使用します。以下に例を示します。

yearly_x = pd.date_range("2025-01-01 00:00:00", periods=4, freq="1YS")
y2 = [1, 3, 2, 4]

fig, ax = plt.subplots()
ax.plot(yearly_x, y2)
ax.xaxis.set_major_locator(mdates.YearLocator())
plt.show()
../_images/feb8b1c9c5eccbdbe4bd76b091927a5ca8c4d8baa48971a3bd5483ddcd707b93.png

デフォルトでは、1年周期で1月1日の位置に目盛りが表示されます。 また、YearLocator()には以下のオプションを渡すことができます。

  • base (int): 何年ごとに目盛りを表示するか。デフォルト値は1(1年ごと)

  • month (int): 目盛りを表示する月(デフォルト値: 1

  • day (int): 目盛りを表示する日(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

month=7, day=31とすると、7月31日の位置に目盛りが表示されます。 また、base=2とすると、以下のように2年間隔で目盛りが表示されます。

fig, ax = plt.subplots()
ax.plot(yearly_x, y2)
ax.xaxis.set_major_locator(mdates.YearLocator(base=2))
plt.show()
../_images/e5aaacc64605ad93f80aeb3a5c8762c1aaf286be36993cb81a390b1612c68fb0.png

月 MonthLocator#

月単位の目盛りを設定する場合、MonthLocator()を使用します。 デフォルトでは、1か月周期で1日の位置に目盛りが表示されます。

MonthLocator()には以下のオプションを渡すことができます。

  • bymonth (int, list[int]): 目盛りを表示する月。デフォルト値はrange(1, 13)(1か月ごと)

  • bymonthday (int): 目盛りを表示する日(デフォルト値: 1

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

bymonthday=15とすると、15日の位置に目盛りが表示されます。 また、interval=2とすると、以下のように2か月間隔で目盛りが表示されます。

monthly_x = pd.date_range("2025-01-01 00:00:00", periods=4, freq="1MS")
y2 = [1, 3, 2, 4]

fig, ax = plt.subplots()
ax.plot(monthly_x, y2)
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
plt.show()
../_images/2f200f8788c324fa349c1d0d9cd561a5e9db1ae5b9c7aad482e19998b2f5caa4.png

日 DayLocator#

日単位の目盛りを設定する場合、DayLocator()を使用します。 デフォルトでは、1日周期で目盛りが表示されます。

DayLocator()には以下のオプションを渡すことができます。

  • bymonthday (int, list[int]): 目盛りを表示する日。デフォルト値はrange(1, 32)(1日ごと)

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

bymonthday=[1, 15]とすると、1日と15日の位置に目盛りが表示されます。 また、interval=2とすると、以下のように2日間隔で目盛りが表示されます。

daily_x = pd.date_range("2025-01-01 00:00:00", periods=4, freq="1D")
y2 = [1, 3, 2, 4]

fig, ax = plt.subplots()
ax.plot(daily_x, y2)
ax.xaxis.set_major_locator(mdates.DayLocator(interval=2))
plt.show()
../_images/68fb3a2a0d94fe8acf9d6b542fee9add9e2d990bd3e151468179ce8e5bacf9d6.png

曜日 WeekdayLocator#

曜日単位の目盛りを設定する場合、WeekdayLocator()を使用します。 デフォルトでは火曜日の位置に目盛りが表示されます。

WeekdayLocator()には以下のオプションを渡すことができます。

  • byweekday (int, list[int]): 目盛りを表示する曜日。デフォルト値は1(火曜日)

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

byweekday引数では、曜日を整数で指定することが可能です。 曜日と整数は月曜: 0, 火曜: 1, 水曜: 2, ..., 日曜: 6のように対応しています。 また、mdates.MOのように指定することも可能です。 月曜から順にMO, TU, WE, TH, FR, SA, SUです。

byweekday=[0, 3]とすると、以下のように月曜と木曜の位置に目盛りが表示されます。 byweekday=[mdates.MO, mdates.TH]としても同じ結果となります。

weekday_x = pd.date_range(start="2025-01-01", periods=15, freq="1D")
y3 = [1, 3, 2, 4, 2] * 3

fig, ax = plt.subplots()
ax.plot(weekday_x, y3)
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=[0, 3]))
# ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=[mdates.MO, mdates.TH])) # 同じ結果
plt.show()
../_images/37b7de542685ad7819913d497ac732d63827f9c0487a99524f3ca1c9b3dc2f6b.png

時間 HourLocator#

時間単位の目盛りを設定する場合、HourLocator()を使用します。 デフォルトでは1時間ごとに目盛りが表示されます。

HourLocator()には以下のオプションを渡すことができます。

  • byhour (int, list[int]): 目盛りを表示する時間。デフォルト値はrange(24)(1時間ごと)

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

分 MinuteLocator#

分単位の目盛りを設定する場合、MinuteLocator()を使用します。 デフォルトでは1分ごとに目盛りが表示されます。

MinuteLocator()には以下のオプションを渡すことができます。

  • byminute (int, list[int]): 目盛りを表示する時間。デフォルト値はrange(60)(1分ごと)

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

秒 SecondLocator#

秒単位の目盛りを設定する場合、SecondLocator()を使用します。 デフォルトでは1秒ごとに目盛りが表示されます。

SecondLocator()には以下のオプションを渡すことができます。

  • bysecond (int, list[int]): 目盛りを表示する時間。デフォルト値はrange(60)(1秒ごと)

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

マイクロ秒 MicrosecondLocator#

マイクロ秒単位の目盛りを設定する場合、MicrosecondLocator()を使用します。 デフォルトでは1マイクロ秒ごとに目盛りが表示されます。

MicrosecondLocator()には以下のオプションを渡すことができます。

  • interval (int): 目盛りを表示する間隔(デフォルト値: 1

  • tz (str, tzinfo): タイムゾーン(デフォルト値: 'UTC'

MicrosecondLocator()を使用する場合、注意点があります。 Matplotlibのデフォルト設定では、時刻データを1970年1月1日午前0時0分0秒を起点としたUNIX時間で扱っています。 この起点の時刻から離れた時間(2020年代など)では、浮動小数の誤差によってマイクロ秒のオーダでは精度が低下します。 そのため、以下のように目盛りの間隔が一定になりません。

microsecond_x = pd.date_range(start="2025-01-01 00:00:00", periods=5, freq="1us")
# 'us'はマイクロ秒
y3 = [1, 3, 2, 4, 2]

fig, ax = plt.subplots()
ax.plot(microsecond_x, y3)
ax.xaxis.set_major_locator(mdates.MicrosecondLocator())
fig.autofmt_xdate()
ax.grid()
plt.show()
../_images/9052750a028294801bcfe17ca435e858935ebb37abd833b418aa22286226fa5f.png

誤差を減らして目盛りの間隔を一定にするためには、起点の時刻をプロットしたい時刻に近いものに変更する必要があります。 起点の時刻を変更するには、以下のようにmdates.set_epoch()メソッドを使用します。

mdates.set_epoch("2025-01-01 00:00:00")

なお、このメソッドはMatplotlibで時刻データを扱う前に実行する必要があります。 時刻データを扱った後にmdates.set_epoch()を実行すると、以下のエラーが表示されます。

RuntimeError: set_epoch must be called before dates plotted.

そのため、Matplotlibをインポートした直後にmdates.set_epoch()を実行した方が良いと思います。