Matplotlib
で時系列データをプロットすると、自動で軸が時間軸になります。
しかし、残念ながらデフォルト設定では、目盛り値が適切に表示できない場合が多々あります。
そこで、この記事では時系列データの軸設定について、次の内容を解説していきます。
- 時系列データの軸目盛の自動調整方法
- 表示期間の指定方法
Formatter
,Locator
を使用した任意の目盛り設定方法
このあたりを抑えれば、時間軸目盛りがある程度自由にできるようになってきます。
- 時系列データの軸目盛り
- 時系列目盛りの設定方法の基本
- デフォルトのFormatterとLocator
- 目盛りの表示形式の設定(Formatter)
- 目盛りの表示位置の設定(Locator)
- オススメ|matplotlibとデータ分析の勉強方法
時系列データの軸目盛り
Matplotlib
で時系列データをプロットしても、目盛り値が適切に表示できない場合が多々あります。
まずは、サンプルの時系列データを用意して、デフォルト設定でプロットしてみます。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
data = np.random.rand(36)
df = pd.DataFrame({"Val":data}, index=pd.Index(pd.date_range("2020/1/1", periods=36, freq='MS'), name="Date"))
# Val
# Date
# 2020-01-01 0.428362
# 2020-02-01 0.917356
# …省略…
# 2022-12-01 0.535586
このサンプルデータをMatplotlib
でグラフ化してみます。
fig, ax = plt.subplots(figsize=(6, 2)) # 軸を見たいだけなので、グラフをサイズを縮小
ax.plot(df.index, df["Val"])
次のようにx軸の時間軸目盛りが重なってしまい、よく見えません。
設定を変更して、時間軸を見やすく、自分の思った通りに設定したいですよね。
- 【注意】時系列データの軸設定をする場合には、
plt.subplots()
でオブジェクト指向のプロットをすることをおすすめします。
オブジェクト指向のプロット方法については、次の記事を参考にしてください。
時系列目盛りの設定方法の基本
まずは、時間軸に関する基本設定方法を次の順番で紹介します。
- 表示期間の指定
- 時系列目盛りの自動調整機能
Formatter
,Locaor
を使用した任意の時間軸設定
簡単な設定変更から、応用的な設定変更へと順番に紹介していきます。
時系列目盛りの自動調整機能
目盛りを見えるようにするだけの場合は、時系列目盛りの自動調整機能で十分な場合もあります。
目盛りを自動で調整する場合は、Figure
オブジェクトの.autofmt_xdate()
を使用します。
fig.autofmt_xdate()
次のように、目盛りの水平位置、文字の向き(回転角度)を次のように自動で調整してくれます。
- 文字の向き:30°
- 水平位置:右寄せ
引数で、目盛り値の回転や水平配置を調整することもできます。
設定内容 | 引数 | 適用 |
---|---|---|
目盛りの向き(回転角度) | rotation=数値 |
デフォルト:30 |
目盛りの水平位置 | ha="位置を表す文字列" |
● "right" :右寄せ(デフォルト)● "center" :中央寄せ● "left" :左寄せ |
サンプルデータで実行例を確認してみましょう。
fig, ax = plt.subplots(figsize=(6, 2.5)) # 軸を見たいだけなので、グラフをサイズを縮小
fig.autofmt_xdate()
ax.plot(df.index, df["Val"])
fig.autofmt_xdate()
を実行するだけで、時間軸目盛りが一気に見やすくなっていますね。
引数で目盛り値を90°回転, 水平位置を中央に変更した例も確認しておきましょう。
fig, ax = plt.subplots(figsize=(6, 2.5))
ax.plot(df.index, df["Val"])
fig.autofmt_xdate(rotation=90, ha="center")
次のように軸目盛が90°回転されます。
ちなみに、fig.autofmt_xdate()
を使用せず、上記の目盛り表示を設定すると、次のようになります。
# 目盛り値の回転
ax.xaxis.set_tick_params(rotation=90)
# 目盛り値の水平配置調整
for label in ax.get_xticklabels():
label.set_ha("center")
あまり見慣れないメソッドを複数使わないといけないので、fig.autofmt_xdate()
を覚えた方が良さそうですね。
- 【参考】
Figure
オブジェクトのその他の便利なメソッドは、次の記事で紹介しています。
表示期間の指定
表示期間は、ax.set_xlim()
で指定します。
ax.set_xlim([開始日時, 終了日時])
開始日時、終了日時のみを指定する場合は、引数で指定することも可能です。
- 開始日時のみ:
ax.set_xlim(xmin=開始日時)
orleft=開始日時
- 終了日時のみ:
ax.set_xlim(xmax=終了日時)
orright=開始日時
開始・終了日時は、datetime
に準ずるタイプで指定します。
使用するタイミングでインポート済みのライブラリから使用すると良いと思います。
ライブラリの種類 | 型名 | 生成方法の例 |
---|---|---|
datetime |
datetime |
datetime.datetime(2020, 1, 1) |
NumPy |
datetime64 |
np.datetime64("2020-01-01") |
pandas |
Timestamp |
pd.to_datetime("2020-01-01") |
どれを使用しても、結果は同じなので、まとめて実行例を見てみましょう。
# datetimeの場合
import datetime
span = [datetime.datetime(2020, 4, 1), datetime.datetime(2021, 4, 1)]
# span => [datetime.datetime(2020, 4, 1, 0, 0), datetime.datetime(2021, 4, 1, 0, 0)]
# np.datetime64の場合
import numpy as np
span = [np.datetime64("2020-01-01"), np.datetime64("2021-01-01")]
# span => [numpy.datetime64('2020-01-01'), numpy.datetime64('2021-01-01')]
# pd.to_datetimeの場合
import pandas as pd
span = pd.to_datetime(["2020-01-01", "2021-01-01"])
# span => DatetimeIndex(['2020-01-01', '2021-01-01'], dtype='datetime64[ns]', freq=None)
fig, ax = plt.subplots(figsize=(6, 2.5))
fig.autofmt_xdate()
ax.plot(df.index, df["Val"])
ax.set_xlim(span)
次のように、表示期間が変更されています。
上記のサンプルでもわかるように、pd.to_datetime()
だけは日付文字列のリストを受け取れます。
そのため、関数名を書くのが一回で済むので、datetime
, np.datetime64
よりも使い勝手が良いです。
- 【参考】
pandas
の時系列操作については、次の記事で解説しています。
FormatterとLocaterの基本
時間軸目盛を自由に設定するためには、Formatter
とLocator
の2つのオブジェクトを使用する必要があります。
Formatter
とLocator
の設定先イメージは次のようになっています。
Formatter
とLocator
の使い方の流れは次の通りです。
matplotlib.dates
のimport
(mdates
という名前で読み込むことが多い)Locator
とFormatter
をそれぞれ用意ax.set_major_locator()
,ax.set_major_formatter()
メソッドで適用
スクリプトにすると次のようになります。
# mdateのインポート
import matplotlib.dates as mdates
# Locator, Formatterの基本的な使用方法
# Locatorの設定
locator = mdates.使用するLocator()
ax.xaxis.set_major_locator(locator)
# Formatterの設定
formatter = mdates.使用するFormatter()
ax.xaxis.set_major_formatter(formatter)
一見難しそうですが、Formatter
, Locator
の設定方法を理解すると、比較的簡単です。
以下で、Formatter
, Locator
の設定方法を紹介します。
デフォルトのFormatterとLocator
Formatter
, Locator
の基本を理解するために、デフォルトのFormatter
, Locator
が何なのか見てみましょう。
デフォルトでは、それぞれAutoDateLocator
, AutoDateLocator
というオブジェクトが使用されます。
ax.xaxis.get_major_locator()
# <matplotlib.dates.AutoDateLocator at 0x2056e045220>
ax.xaxis.get_major_formatter()
# <matplotlib.dates.AutoDateFormatter at 0x2056dfe1e50>
Auto
という名前の通り、表示する期間に応じて、目盛りの数、目盛りの表示形式が自動で調整されます。
サンプルデータで表示期間を変更して、表示形式の変化を確認してみます。
# 機関の異なるグラフの作成
fig, ax = plt.subplots(1,2, figsize=(12,4))
fig.autofmt_xdate()
# 2年分のデータ可視化
ax[0].plot(df.index, df["Val"])
# 2ヶ月分のデータ可視化
ax[1].plot(df.index, df["Val"])
ax[1].set_xlim(pd.to_datetime(["2020-01-01", "2020-02-28"]))
次のように期間に応じて、日付の表示有無が自動で変更されます。
自動で調整してくれるので便利ですが、毎回年月日を出力すると少し見ずらい場合もありますね。
- 【参考】
fig, axes = plt.subplots()
のオブジェクト指向プロットは、次の記事で解説しています。
目盛りの表示形式の設定(Formatter)
時系列目盛りのフォーマットを任意に指定する場合は、DateFormatter
でフォーマットを指定します。
DateFormatter
の使い方の流れは次の通りです。
matplotlib.dates
のimport
(mdates
という名前で読み込むことが多い)- フォーマットを指定した
DateFormatter
を用意 ax.set_major_formatter()
メソッドで適用
スクリプトにすると次のようになります。
import matplotlib.dates as mdates # mdateのインポート
formatter = mdates.DateFormatter("formatを指定する文字列") # Formatterオブジェクト生成
ax.xaxis.set_major_formatter(formatter) # axにフォーマットを適用
以下で、次の内容を紹介します。
- フォーマット指定子まとめ
- 【コピペ用】フォーマットテンプレ
- シンプルな自動フォーマット
フォーマット指定子をおさえると、Formatter
は比較的簡単に設定できます。
フォーマット指定子まとめ
pythonのdatetime
ライブラリと同じフォーマット指定子が使用できます。
重要な指定子としては、次のようなものがあります。
単位 | 指定子 | 内容 | 例) 2021-03-09 15:10:30の表示例 |
---|---|---|---|
年 | %Y |
4ケタの年 | 2021 |
%y |
世紀部分を除いた2ケタの年 | 21 | |
月 | %m |
2ケタの月 | 03 |
%B |
英語の月名 | April | |
%b |
英語の月名(省略版) | Apr | |
日にち | %d |
2ケタの日にち | 09 |
曜日 | %A |
英語の曜日 | Tuesday |
%a |
英語の曜日(省略版) | Tue | |
時間 | %H |
24時間形式の時間 | 15 |
%I |
12時間形式の時間 | 03 | |
%p |
AM or PM | PM | |
分 | %M |
60分形式の分 | 10 |
秒 | %S |
60秒形式の秒 | 30 |
フォーマット指定子は、次のように文字列の中に組み込んで使用します。
%Y-%m-%d
→2021-04-12
のようにフォーマットされる
その他、必要な場合にはdatetime
ライブラリのマニュアルも確認してみてください。
【コピペ用】フォーマットテンプレ
'2021-03-09 15:10:30'
を例に、コピペ用のフォーマットの例を挙げておきます。
表示例 | フォーマット |
---|---|
2021/03/09 | %Y/%m/%d |
2021年03月09日 | %Y月%m年%d日 |
03/09(Tuesday) | %m/%d(%A) |
03/09 15:10 | %m/%d %H:%M |
03/09 03:10(PM) | %m/%d %I:%M(%p) |
15:10:30 | %H:%M:%S |
matplotlib
でのフォーマット適用例を確認してみます。
import matplotlib.dates as mdates
# 日本語表示用の設定
plt.rcParams['font.family'] = "MS Gothic"
fig, axes = plt.subplots(1,3, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
ax.xaxis.set_major_locator( mdates.AutoDateLocator(minticks=3, maxticks=4) )
ax.set_xlim(pd.to_datetime(["2020/3/1", "2020/3/15"]))
# axes[0]の目盛りフォーマット指定:2020-03-01形式
axes[0].set_title("%Y-%m-%d")
formatter = mdates.DateFormatter("%Y-%m-%d")
axes[0].xaxis.set_major_formatter(formatter)
# axes[1]の目盛りフォーマット指定:2020-03-01形式
axes[1].set_title("%m-%d (%a)")
formatter = mdates.DateFormatter("%m-%d (%a)")
axes[1].xaxis.set_major_formatter(formatter)
# axes[2]の目盛りフォーマット指定:03月01日形式
axes[2].set_title("%m月%d日")
formatter = mdates.DateFormatter("%m月%d日")
axes[2].xaxis.set_major_formatter(formatter)
次のように目盛りのフォーマットが変更されています。
フォーマット指定子さえ理解できれば、Formatter
は簡単に設定できますね。
- 【参考】日本語を使用する際は、特殊な設定が必要になります。次の記事を参考にしてください
シンプルなフォーマット
特殊なFormatter
として、自動でシンプルな表示形式を設定できるConciseDateFormatter
を紹介します。
formatter = mdates.ConciseDateFormatter(locator)
設定は最小限な方が良いので、ConciseDateFormatter
で十分なら、この設定だけで済ませたいですね。
こちらもデフォルトのAutoDateFormatter
同様、期間に応じて目盛りの表示形式が自動で調整されています。
fig, axes = plt.subplots(1,2, figsize=(12,4))
for ax in axes:
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax.plot(df.index, df["Val"])
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
# axes[0]は、サンプルデータ全期間のグラフ
axes[0].set_title("Long term")
# axes[1]は、サンプルデータ2か月分のグラフ
axes[1].set_title("Short term")
axes[1].set_xlim(pd.to_datetime(["2020-01-01", "2020-02-28"]))
AutoDateFormatter
よりシンプルになっています。
期間に応じて、日付の表示有無が自動で変更されていますね。
目盛りの表示位置の設定(Locator)
時系列目盛りの表示位置を任意に指定する場合は、各種Locator
で指定します。
Locator
の使い方の流れは次の通りです。
matplotlib.dates
のimport
(mdates
という名前で読み込むことが多い)- 表示期間に応じた
Locator
を用意 ax.set_major_locator()
メソッドで適用
スクリプトにすると次のようになります。
import matplotlib.dates as mdates # mdateのインポート
locator = mdates.DateLocator(表示内容を指定する引数) # Locatorオブジェクト生成
ax.xaxis.set_major_locator(locator) # axにロケータ―を適用
以下で、次の内容を紹介します。
- 主要
Locator
まとめ - 目盛り数の調整方法
- 各種
Locator
の詳細設定方法
主要Locetorまとめ
主なロケータは次の通りです。
Locatorの時間単位 | オブジェクト | コメント |
---|---|---|
自動調整ロケータ | AutoDateLocator |
デフォルトのLocator 時間軸に応じて目盛り数を自動調整 |
年 | YearLocator |
1年ごと, 2年ごとなど |
月 | MonthLocator |
1月ごと, 2月ごとなど |
曜日 | WeekdayLocator |
毎月曜日, 隔週の日曜日など |
日にち | DayLocator |
1日ごと, 2日ごとなど |
時間 | HourLocator |
1時間ごと, 2時間ごとなど |
分 | MinuteLocator |
1分ごと, 2分ごとなど |
秒 | SecondLocator |
1秒ごと, 2秒ごとなど |
表示するグラフの時間軸に応じて、適切なLocator
を選択しましょう。
目盛りの数を調整
デフォルトのAutoDateLocator()
を使用して、目盛りの数を調整する方法を紹介します。
少ない設定で済めばそれに越したことはないので、この方法も覚えておくと便利です。
AutoDateLocator()
を生成する際に、引数minticks, maxticks
で最小数、最大数を設定してしまいます。
locator = mdates.AutoDateLocator(minticks=目盛りの最小数, maxticks=目盛りの最大数)
目盛り数を減らした例を見てみましょう。
fig, axes = plt.subplots(1,2, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
# デフォルト
axes[0].set_title("Default (AutoDateFormatter)")
# 目盛り数調整
axes[1].set_title("minticks=3, maxticks=5")
locator = mdates.AutoDateLocator(minticks=3, maxticks=5)
axes[1].xaxis.set_major_locator(locator)
Formatter
はデフォルトのままなので、目盛りの幅に応じて自動で表示形式も調整してくれます。
これだけで、目盛りの設定が十分なことも多いと思います。
これでも対応しきれいない場合は、各種Locator
で個別に設定しましょう。
年単位の目盛り
年単位の目盛り位置を調整する場合は、YearLocator
を使用します。
YearLocator
の主要引数は次の通りです。
設定内容 | 引数名 | 適用 |
---|---|---|
表示間隔 | base |
デフォルト:base=1 → 1年ごとに目盛り表示 |
目盛りの表示月 | month |
デフォルト:month=1 |
目盛りの表示日 | day |
デフォルト:day=1 |
デフォルトだと、1年ごとに1月1日に目盛りが表示されます。
サンプルコードで挙動を確認してみましょう。
fig, axes = plt.subplots(1,2, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
formatter = mdates.DateFormatter("%Y/%m/%d")
ax.xaxis.set_major_formatter(formatter)
# デフォルト(毎年1月1日に表示)
axes[0].set_title("Default (base=1, month=1, day=1)")
locator = mdates.YearLocator()
axes[0].xaxis.set_major_locator(locator)
# 隔年で4/1に表示表示
axes[1].set_title("base=2, month=4, day=1")
locator = mdates.YearLocator(base=2, month=4, day=1)
axes[1].xaxis.set_major_locator(locator)
月日もわかりやすいように、Formatter
で日付も表示させています。
月単位の目盛り
月単位の目盛り位置を調整する場合は、MonthLocator
を使用します。
MonthLocator
の主要変数は次の通りです。
設定内容 | 引数名 | 適用 |
---|---|---|
目盛りの表示月 | bymonth |
● デフォルト:None → 1-12月まで全て表示● 月 または[月のリスト] で指定可能 |
目盛りの表示日 | bymonthday |
● デフォルト:day=1 ● day=-1 で前月の月末することが可能 |
目盛りの表示間隔 | interval |
● デフォルト:interval=1 → 1ヶ月毎に目盛り表示interval=2 にすると2ヵ月ごとに表示 |
デフォルトだと、毎月1日に目盛りが表示されます。
サンプルコードで挙動を確認してみましょう。
#MonthLocator適用例
fig, axes = plt.subplots(1,3, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
formatter = mdates.DateFormatter("%Y/%m/%d")
ax.xaxis.set_major_formatter(formatter)
ax.set_xlim(pd.to_datetime(["2020-01-01", "2020-04-15"]))
# デフォルト(毎月1日に表示)
axes[0].set_title("Default")
locator = mdates.MonthLocator()
axes[0].xaxis.set_major_locator(locator)
# 隔月の15日に表示
axes[1].set_title("Every two month @15th")
locator = mdates.MonthLocator(bymonthday=15, interval=2)
axes[1].xaxis.set_major_locator(locator)
# 月末に目盛り表示
axes[2].set_title("End of month (bymonthday=-1)")
locator = mdates.MonthLocator(bymonthday=-1)
axes[2].xaxis.set_major_locator(locator)
それぞれ次のように目盛りの位置が調整されています。
曜日単位の目盛り
曜日単位の目盛り位置を調整する場合は、WeekdayLocator
を使用します。
WeekdayLocator
の主要変数は次の通りです。
設定内容 | 引数名 | 適用 |
---|---|---|
目盛りの表示曜日 | byweekday |
● デフォルト:1 → 火曜日に目盛り表示● 0, 1, 2, …, 6 がそれぞれ月, 火, 水, …, に対応● matplotlib の曜日を指定する定数(MO , TU , …, SU )も使用可能● byweekday=(MO, WE, FR) のように複数指定も可能 |
目盛りの表示間隔 | interval |
● デフォルト:interval=1 → 毎週指定曜日に目盛り表示● interval=2 にすると2週間ごとに表示 |
曜日を指定する定数は、次のように次のようにimport
して使用します。
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU
サンプルコードで挙動を確認してみましょう。
#WeekdayLocator適用例
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU
fig, axes = plt.subplots(1,3, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
formatter = mdates.DateFormatter("%m/%d(%a)")
ax.xaxis.set_major_formatter(formatter)
ax.set_xlim(pd.to_datetime(["2020/1/1", "2020/1/31"]))
# デフォルト(毎週火曜日に表示)
axes[0].set_title("Default (byweekday=TU)")
locator = mdates.WeekdayLocator()
axes[0].xaxis.set_major_locator(locator)
# 隔週の月曜日に表示
axes[1].set_title("byweekday=(MO), interval=2")
locator = mdates.WeekdayLocator(byweekday=(MO), interval=2)
axes[1].xaxis.set_major_locator(locator)
# 月曜日と金曜日に表示
axes[2].set_xlim(pd.to_datetime(["2020/1/1", "2020/1/14"]))
axes[2].set_title("byweekday=(MO, FR)")
locator = mdates.WeekdayLocator(byweekday=(MO, FR))
axes[2].xaxis.set_major_locator(locator)
それぞれ次のように目盛りの位置が調整されています。
日にち単位の目盛り
日にち単位の目盛り位置を調整する場合は、DayLocator
を使用します。
DayLocator
の主要変数は次の通りです。
設定内容 | 引数名 | 適用 |
---|---|---|
目盛りの表示曜日 | bymonthday |
● デフォルト:None, 毎日目盛りを表示 ● bymonthday=(日にちのリスト) で目盛りを表示する日にちを指定ex) bymonthday=([1, 15]) → 1日と15日に表示 |
目盛りの表示間隔 | interval |
● デフォルト:interval=1 → 毎日を表示 ● interval=2にすると2日ごとに表示 |
サンプルコードで挙動を確認してみましょう。
#DayLocator適用例
fig, axes = plt.subplots(1,3, figsize=(12,2))
fig.autofmt_xdate()
for ax in axes:
ax.plot(df.index, df["Val"])
formatter = mdates.DateFormatter("%m/%d")
ax.xaxis.set_major_formatter(formatter)
ax.set_xlim(pd.to_datetime(["2020/1/1", "2020/1/7"]))
# デフォルト(毎日に表示)
axes[0].set_title("Default (everyday)")
locator = mdates.DayLocator()
axes[0].xaxis.set_major_locator(locator)
# 1, 4, 7日に表示
axes[1].set_title("1st, 4th ,7th day")
locator = mdates.DayLocator(bymonthday=[1,4,7])
axes[1].xaxis.set_major_locator(locator)
# 2日ごとに表示
axes[2].set_title("Every two day")
locator = mdates.DayLocator(interval=2)
axes[2].xaxis.set_major_locator(locator)
それぞれ次のように目盛りの位置が調整されています。
オススメ|matplotlibとデータ分析の勉強方法
今回は、Matplotlib
の時系列データの軸設定について基本的なものを解説しました。
Matplotlib
は奥の深いモジュールですが、なかなかわかりにくい部分もあります…。
そこで、グラフの作成方法、種類変更、凡例、タイトルの設定など網羅的にわかりやすく整理した記事を作りました。ぜひ参考にしてみてください。
また、データ分析初心者の方にはこちらの記事もおススメです。
私がこれまで勉強してきた経験をもとに考えたおススメの勉強本の紹介記事です。
何から始めて、どうやってレベルアップしていけばいいのか、初心者の方にぜひおススメしたい本を紹介しました。