以前の記事で、グループ化した棒グラフが簡単に作成できる関数とクラスを紹介しました。
その時は、X軸に文字列ラベルを指定するようになっていましたが、今回は datetime型の日付が指定できるよう変更したものを紹介します。
コピー&ペーストして張り付けていただければ、すぐに使えるようになっていますので、X軸に日付を指定したい場合は、是非お役立て下さい。
グループ化した棒グラフ(X軸日付対応)の描画サンプル
X軸に設定する値が文字列から 日付(datetime 型)に変わった以外は、前回のグループ化棒グラフと同じです。

グループ化した棒グラフ(x軸日付対応)関数
「グループ化した棒グラフ関数」の仕様は次の通りです。
grouped_bar(x軸の値,y軸の値,フォーマット,x軸の角度,数値の表示/非表示)
| 引数 | 内容 | 具体例 |
|---|---|---|
| x軸の値 | X軸の値をdatetime型のリスト形式で指定 | [datetime(2021,7,1)datetime(2021,7,2),datetime(2021,7,3)] |
| y軸の値 | 各棒グラフごとに「ラベル」と「値のリスト」を タプルでまとめ、リストに登録したもの | ( 'chart1' , [4,1,7,6,3] ) |
| フォーマット | X軸に表示する日付けのフォーマット | '%Y/%m/%d' |
| X軸の角度 | X軸に表示する日付の角度 | 45 |
| 数値の表示/非表示 | Trueで棒の上部に値を表示、Falseで非表示 | True 、False |
下記サンプルは、X軸に2020年10月1日から5日間のdatetime データを生成してセットする内容になっています。
y = []
y.append(('chart1',[4,1,7,6,3]))
y.append(('chart2',[5,5,2,8,1]))
y.append(('chart3',[3,4,8,4,3]))
y.append(('chart4',[2,5,6,2,8]))
y.append(('chart5',[7,3,3,3,2]))
x = [datetime.datetime(2020,10,1) + datetime.timedelta(days=i) for i in range(5)]
grouped_bar(x,y,'%m/%d',45,True)
下記が実際の関数のソースコードです。
そのままコピー&ペーストして、適当にカスタマイズしてお使いください。
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
def grouped_bar(x_datetime,y,format,rotation=0,isvalue=False,groupwidth=0.8,barwidth=0.9,location='best'):
'''
グループ化した棒グラフの描画
Parameters
----------------------------
isvalue:bool
グラフ上部への値の表示/非表示
groupwidth:float
1つのグループの幅 を 0~1で指定。
barwidth:float
グループ内の棒グラフ1つ当たりの幅を0~1で指定。
location:int,str
凡例の表示場所
'''
fig = plt.figure()
ax = fig.add_subplot()
x = mdates.date2num(x_datetime)
barcnt = len(y)
size = groupwidth / barcnt
xx = groupwidth/ 2
# 棒グラフの描画
for i in range(barcnt):
pos = [size / 2 + x[n] - xx + size * i for n in range(len(x))]
rect = plt.bar(mdates.num2date(pos), y[i][1], width=size * barwidth, label=y[i][0], align="center")
# グラフに値を表示
if isvalue == True:
for tx, ty in zip(pos, y[i][1]):
plt.text(tx, ty, ty, ha='center', va='bottom')
# 凡例
ax.legend (loc=location)
#グラフ表示エリアの下左右マージン設定
plt.subplots_adjust(bottom=0.15)
# X軸のラベルを表示
ax.xaxis.set_major_formatter(mdates.DateFormatter(format))
ax.xaxis.set_major_locator(mdates.DayLocator())
ax.set_xlim(x_datetime[0] - datetime.timedelta(days=0.5),x_datetime[-1] + datetime.timedelta(days=0.5))
ax.tick_params(axis='x', rotation=rotation)
plt.show()
グループ化した棒グラフ(X軸日付対応)クラス
こちらもX軸に日付(datetime型)を指定する以外は全く同じです。
専用のメソッドを使ってX軸のラベルとY軸の値を登録し、最後に showメソッドを呼ぶことで描画されます。

| 機能 | メソッド名 | 引数 |
|---|---|---|
| コンストラクタ | GroupedBar ( isvalue=False, groupwith=0.8, barwidth=0.9, location='best' ) | 値を棒の上に表示, 棒グラフグループの幅, 棒グラフの幅, 凡例の表示位置 |
| X軸ラベルの登録 | set_xlabel(xlabel,format,rotation=0) | Xラベルのリスト, フォーマット, X軸の日付けの角度 |
| Y軸ラベルと データの登録 | add_bar(ylabel,values) | Y軸のラベルのリスト, Y軸の値のリスト |
| グラフの表示 | show() |
具体的な使用方法は次の通りです。
gb=GroupedBar()
gb.add_bar('chart1',[4,1,7,6,3])
gb.add_bar('chart2',[5,5,2,8,1])
gb.add_bar('chart3',[3,4,8,4,3])
#gb.add_bar('chart4',[2,5,6,2,8])
#gb.add_bar('chart5',[7,3,3,3,2])
gb.set_xlabel( [datetime.datetime(2020,10,1) + datetime.timedelta(days=i) for i in range(5)],'%m/%d',45)
gb.show()
下記が実際のクラスのソースコードになります。
そのままコピー&ペーストして、適当にカスタマイズしてお使いください。
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
class GroupedBar:
'''
グループ化した棒グラフを描画するためのヘルパークラス
'''
def __init__(self,isvalue=False,groupwidth=0.8,barwidth=0.9,location='best'):
'''
コンストラクタ
Parameters
----------------------------
isvalue:bool
グラフ上部への値の表示/非表示
groupwidth:float
1つのグループの幅 を 0~1で指定。
barwidth:float
グループ内の棒グラフ1つ当たりの幅を0~1で指定。
location:int,str
凡例の表示場所
'''
self.groupwidth = groupwidth
self.barwidth = barwidth
self.location = location
self.isvalue = isvalue
self.values = []
self.xlabel = []
self.groupwidth=0.8
self.barwidth = 0.9
self.location='best'
self.isvalue=False
self.rotation = 0
self.format = ''
def set_xlabel(self,xlabel,format,rotation=0):
'''
X軸ラベルの登録
Parameters
----------------------------
xlabel:[str]
X軸のラベルをリストで指定
'''
self.xlabel = xlabel
self.format = format
self.rotation = rotation
def add_bar(self,ylabel,values):
'''
棒グラフの登録
Parameters
----------------------------
ylabel:str
棒グラフのラベル
values:[int,float]]
y軸の値をリストで指定
'''
self.values.append((ylabel,values))
def show(self):
'''
棒グラフの描画
'''
x = mdates.date2num(self.xlabel)
barcnt = len(self.values)
diff = abs(x[0] - x[1])
size = (self.groupwidth / barcnt) * diff
xx = (self.groupwidth/ 2) * diff
fig = plt.figure()
ax = fig.add_subplot()
# 棒グラフの描画
for i in range(barcnt):
pos = [size / 2 + x[n] - xx + size * i for n in range(len(x))]
rect = plt.bar(mdates.num2date(pos), self.values[i][1], width=size * self.barwidth,
label=self.values[i][0], align="center")
# グラフに値を表示
if self.isvalue == True:
for tx, ty in zip(pos, self.values[i][1]):
plt.text(tx, ty, ty, ha='center', va='bottom')
# 凡例
plt.legend (loc=self.location)
#グラフ表示エリアの下マージン設定
plt.subplots_adjust(bottom=0.15)
# X軸のラベルを表示
ax.xaxis.set_major_formatter(mdates.DateFormatter(self.format))
ax.xaxis.set_major_locator(mdates.DayLocator())
ax.set_xlim(self.xlabel[0] - datetime.timedelta(days=0.5),self.xlabel[-1] + datetime.timedelta(days=0.5))
ax.tick_params(axis='x', rotation=self.rotation)
plt.show()
前回からの変更点
各X軸の値を中心に、複数の棒グラフ左右に振り分けるため、棒の位置や幅を計算していたのですが、X軸の値が datetime 型になったことにより、そのままでは計算できなくなりました。
そこで、X軸で渡された datetime型の値を date2num を使って一旦シリアル値に変換することで、棒の位置や幅を検索するロジックをそのまま利用できるようにしました。
x = mdates.date2num(self.xlabel)
そして、実際に棒を表示する際は、 num2date を使ってシリアル値からdatetime型に再び変換し、plt.barに渡すようにしました。
pos = [size / 2 + x[n] - xx + size * i for n in range(len(x))]
rect = plt.bar(mdates.num2date(pos), self.values[i][1], width=size * self.barwidth,
label=self.values[i][0], align="center")
また、X軸のラベルを表示する箇所では、set_major_formatterや set_major_locator を使って、指定されたフォーマットで日付が表示できるようにしています。
ax.xaxis.set_major_formatter(mdates.DateFormatter(format))
ax.xaxis.set_major_locator(mdates.DayLocator())
X軸にdatetime型を表示する場合、set_xlim を使ってX軸の表示範囲を設定しないとレイアウトが崩れる場合があります。
しかし、set_xlim を使うと棒グラフの開始と終了の一部が見切れてしまうので、実際の開始~終了より、0.5日間だけ広く取るように設定しています。
ax.set_xlim(x_datetime[0] - datetime.timedelta(days=0.5),x_datetime[-1] + datetime.timedelta(days=0.5))

最後に、X軸の角度を tick_params で設定しています。
ax.tick_params(axis='x', rotation=rotation)
もし日付ではなく時刻で表示する場合は、set_major_locatorの引数を DayLocator() からHourLocater() に、timedeltaの引数を days= から hours= に変更することで対応できると思います。
まとめ
今回は、以前紹介した「グループ化した棒グラフが簡単に描画できる関数とクラス」に対して、X軸にdatetime型の日付が指定できるようにしたものを紹介しました。
今回はX軸の単位が日付になっていますが、プログラムを少し変更すれば年や時分秒に対応することも可能です。
もし良ければお使いください。
コメント