matplotlibでグラフを描く方法

matplotlib (Python のライブラリ)を使って、グラフを作成する方法を解説します

完成形のグラフ

使用するデータ

題材は、気温、日照時間、寡照時間の推移を使用します(気象庁データベース引用)

名称の定義

グラフの各箇所の名称を定義しておきます

グラフ(デフォルト)を表示する


import matplotlib.pyplot as plt

fig=plt.figure()
ax1=fig.add_subplot()

plt.show()

print(plt.rcParams["font.family"])
print(plt.rcParams["figure.dpi"])
print(plt.rcParams["figure.figsize"])
print(plt.ylim())
print(plt.xlim())

コードの解説

行2

import matplotlib.pyplot as plt

matplotilib の pyplot をインポートする

行4

fig=plt.figure()

グラフの表示領域の下地を宣言

行5

ax1=fig.add_subplot()

グラフに軸を追加する

行7

plt.show()

グラフを表示する

行9

plt.rcParams["font.family"]

フォントファミリーを取得

行10

plt.rcParams["figure.dpi"]

解像度dpiを取得

dpi は、ピクセル数 / インチ

行11

plt.rcParams["figure.figsize"]

グラフのサイズ(横、縦) 単位は、インチ

行12

plt.ylim()

Y軸の幅(最小値、最大値)

行13

plt.xlim()

X軸の幅(最小値、最大値)

デフォルトでは、次のように表示されます

printで出力した結果です

主なデフォルトの値

グラフのサイズ(縦、横):640px、480px

フォントファミリ:sans-serif

x軸の幅(最小値、最大値):0.0、1.0

y軸の幅(最小値、最大値):0.0、1.0

 

エクセルのデータを追加


import matplotlib.pyplot as plt
import pandas as pd

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()

fig=plt.figure()
ax1=fig.add_subplot()
ax1.plot(day,ondo)

plt.show()

 

コードの解説 (追加分)

行3

import pandas as pd

pandas をインポートする

行5

df = pd.read_excel(‘data.xlsx’)

エクセルファイルのデータをDataFrame型に変換

行6-7

day=df[‘日付’].to_list()

DataFrameの一部をリスト型に変換

行11

ax1.plot(day, ondo)

軸に折れ線グラフを追加する

エクセル内のデータ形式が日付の場合、そのデータをpandasで読み込むと、pandas.timestamp型となります

pandas.timestamp型の表示形式は、デフォルトで、”{年}-{月}” となります

timestamp型とは、日付と時刻の両方のデータを格納するデータ型です

日付の表示形式を変更


import matplotlib.pyplot as plt
import pandas as pd

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

fig=plt.figure()
ax1=fig.add_subplot()
ax1.plot(day,ondo)

plt.show()

コードの解説 (追加分)

行9-10

for i in range(len(day)): {処理内容}

配列内の要素に対して、同じ処理を繰り返す

day[i]=str(day[i].year) + '年' + str(day[i].month) + '月'

{pandas.timestamp型} → str型に変換

2023-04-01 00:00:00 → 2023年4月に表示を変換

{pandas.timestamp型} .year / month

「 年 」/ 「 月 」の値を取得します int型で出力されます

str()

{pandas.timestamp型} .year /monthは、int型で出力されます

後で他のstr型と連結できるように、str型に変換します

年、月 (日本語フォント)が、文字化けしています

これは、フォントファミリがまだ非日本語フォントのままだからです

目盛値の表示が重なってしまっています

フォントとグラフの幅を設定


import matplotlib.pyplot as plt
import pandas as pd

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()
ax1.plot(day,ondo)

plt.show()

コードの解説 (追加分)

行12

plt.rcParams["font.family"]="MS Gothic"

フォントファミリーを、”MS Gothic” に変更

行15

fig.set_figwidth(12)

グラフの幅を12インチに変更します

解像度dpi=100のため、1200pxになります

デフォルトでは、

・軸のラベル、グラフのマーカーがない

・グラフの色は、青

です

また、x軸の目盛値の間隔が狭いです

グラフの各種設定


import matplotlib.pyplot as plt
import pandas as pd

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)

plt.show()

コードの解説 (追加分)

行18

ax1.set_ylabel("平均温度(度)",labelpad=5)

軸のラベルを設定します

labelpad=5

軸とラベルとの間隔を設定します

行19

ax1.plot(day,ondo,color='darkorange',marker='o')

グラフの色とマーカーを設定します

color : グラフの色

marker : マーカーの形状

参考サイト : 設定可能な色 / マーカーの形状

行20

ax1.tick_params(axis="x",labelrotation=5)

x軸の目盛値の傾きを設定

axis : 軸の設定

labelrotation : 角度の設定

もう一つ軸を追加


import matplotlib.pyplot as plt
import pandas as pd

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)

ax2=ax1.twinx()

p1=ax2.bar(day,kasho)
p1=ax2.bar(day.nisho)

plt.show()

コードの解説 (追加分)

行8-9

nisho=df['日照時間'].to_list()

DataFrameの一部をリスト型に変換します

行24

ax2=ax1.twinx()=df['日照時間'].to_list()

軸を追加する

行26-27

p1=ax2.bar(day,kasho)

軸に棒グラフを追加する

実行結果

エラー発生してしまいます

.bar の 引数は、float型に対応しています

kashoの要素のデータ型が、datetime.time型のままとなっています


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)

ax2=ax1.twinx()

p1=ax2.bar(day,kasho)
p1=ax2.bar(day.nisho)

plt.show()

コードの解説 (追加分)

行5-6

def float_time(pd_ts):
return pd_ts.hour + pd_ts.minute / 60

float_timeという関数を宣言

{pandas.timestamp型} .hour : 「 時 」を取得 

int型で出力される

{pandas.timestamp型} .hour : 「 分 」を取得 

int型で出力される

数値の単位を、「 時 」にあわせるため、「 分 」の値を、60で除する

int型 ÷ int型 → float型となる

int型 + float型 → float型となる

日照時間、寡照時間の棒グラフが重なってしまっています

積み上げグラフにする


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)

ax2=ax1.twinx()

p1=ax2.bar(day,kasho)
p1=ax2.bar(day.nisho,bottom=kasho)

plt.show()

コードの解説 (追加分)

行36

p2=ax.bar(day,nisho,bottom=kasho)

積み上げ棒グラフに設定します

bottomに、他方の棒グラフを設定します

折れ線グラフと棒グラフが重なってしまっています

目盛値の最小値 / 最大値の設定


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

ax2=ax1.twinx()
ax2.set_ylim(0,80)

p1=ax2.bar(day,kasho)
p1=ax2.bar(day.nisho,bottom=kasho)

plt.show()

コードの解説 (追加分)

行32,35

ax1.set_ylim(-15,35)

y軸の最小値と最大値を設定します

折れ線グラフと棒グラフが同じ色

y軸(右側)にラベルがない

という状況です

グラフの各種設定


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

plt.show()

コードの解説 (追加分)

行36

ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

軸のラベルを設定します

labelpad : 軸とラベルとの距離を設定

行38-39

p1=ax2.bar(day,kasho,color='lightgrey')

グラフの色を設定します

color : グラフの色

参考サイト : 設定可能な色

グラフにまだテキストが表示されていない状態です

グラフにテキストを追加


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

for i,value in enumerate(ondo):
  ax1.text(day[i],ondo[i],value)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

ax2.bar_label(p1)
ax2.bar_label(p2)

plt.show()

コードの解説 (追加分)

行34-35

for i,value in enumerate(ondo):
ax1.text(day[i],ondo[i],value)

折れ線グラフにテキストを追加します

for i,value in enumerate(ondo):

配列から、添字と値を取得します

ax1.text(day[i], ondo[i], value)

折れ線グラフにテキストを追加します

第1引数 : x軸の値

第2引数 : y軸の値

第3引数 : 表示するテキスト

行44-45

ax2.bar_label(p1)

棒グラフにテキストを追加します

折れ線グラフとテキストが重なっています

棒グラフのテキストがfloat型となっています


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

for i,value in enumerate(ondo):
  ax1.text(day[i],ondo[i]-3,value)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

labels1=[]
labels2=[]

for tmp in df['寡照時間']:
  labels1.append(tmp.strftime('%H:%M'))

for tmp in df['日照時間']:
  labels2.append(tmp.strftime('%H:%M'))

ax2.bar_label(p1,labels=labels1)
ax2.bar_label(p2,labels=labels2)

plt.show()

コードの解説 (追加分)

行35

ax1.text(day[i],ondo[i]-3,value)

テキストの位置を設定する

第2引数に、「 -3 」を追記することで、 テキストの位置を下側へ設定する

行44-45

labels1=[]

配列を宣言する

行47,50

for tmp in df['寡照時間']:

DataFrame内の一部の要素を取得する

行48,51

labels1.append(tmp.strftime('%H:%M'))

配列にデータを追加する

tmp.strftime('%H:%M')

{pandas.timestamp型}から、「 時 」と 「 分 」を取得する

str型で出力される

折れ線グラフとテキストが、一部重なっています

棒グラフのテキストの位置が棒グラフの位置から離れています


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

posi=0
for i,value in enumerate(ondo):
  if i==5:
      posi=2
  elif i==6 or i==7:
      posi=-4
  else:
      posi=-3
  ax1.text(day[i],ondo[i]+posi,value)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

labels1=[]
labels2=[]

for tmp in df['寡照時間']:
  labels1.append(tmp.strftime('%H:%M'))

for tmp in df['日照時間']:
  labels2.append(tmp.strftime('%H:%M'))

ax2.bar_label(p1,labels=labels1,label_type='center')
ax2.bar_label(p2,labels=labels2,label_type='center')

plt.show()

コードの解説 (追加分)

行34

posi=0

変数の宣言と初期化

行36-41

if i==5:
posi=2

6番目の要素に対して、位置を再設定する

添字は、0始まり

行60-61

ax2.bar_label(p1,labels=labels1,label_type=‘center’)

ラベルの位置を、棒グラフの上下中央に設定する

凡例を設定する


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

posi=0
for i,value in enumerate(ondo):
  if i==5:
      posi=2
  elif i==6 or i==7:
      posi=-4
  else:
      posi=-3
  ax1.text(day[i],ondo[i]+posi,value)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

labels1=[]
labels2=[]

for tmp in df['寡照時間']:
  labels1.append(tmp.strftime('%H:%M'))

for tmp in df['日照時間']:
  labels2.append(tmp.strftime('%H:%M'))

ax2.bar_label(p1,labels=labels1,label_type='center')
ax2.bar_label(p2,labels=labels2,label_type='center')

ax1.legend(labels=['平均温度'])
ax1.legend(labels=['寡照時間','日照時間'])

plt.show()

コードの解説 (追加分)

行63-64

ax1.legend(labels=['平均温度'])

軸の凡例を追加する

labels : 凡例に表示する文字列の設定

平均温度の凡例が隠れてしまっています

凡例の表示順序が逆になってしまっています(日照時間→寡照時間としたい)

凡例の枠が表示されています


import matplotlib.pyplot as plt
import pandas as pd

def float_time(pd_ts):
  return pd_ts.hour + pd_ts.minute / 60

df=pd.read_excel('data.xlsx')
day=df['日付'].to_list()
ondo=df['温度'].to_list()
nisho=df['日照時間'].to_list()
kasho=df['寡照時間'].to_list()

for i in range(len(day)):
  day[i]=str(day[i].year + '年' + str(day[i].month) + '月')

for i in range(len(nisho)):
  nisho[i]=float_time(nisho[i])

for i in range(len(kasho)):
  kasho[i]=float_time(kasho[i])

plt.rcParams["font.family"]="MS Gothic"

fig=plt.figure()
fig.set_figwidth(12)
ax1=fig.add_subplot()

ax1.set_ylabel("平均温度(度)",labelpad=5)
ax1.plot(day,ondo,color='darkorange',marker='o')
ax1.tick_params(axis="x",labelrotation=5)
ax1.set_ylim(-15,35)

posi=0
for i,value in enumerate(ondo):
  if i==5:
      posi=2
  elif i==6 or i==7:
      posi=-4
  else:
      posi=-3
  ax1.text(day[i],ondo[i]+posi,value)

ax2=ax1.twinx()
ax2.set_ylim(0,80)
ax2.set_ylabel("日照時間 / 寡照時間(時間)",labelpad=10)

p1=ax2.bar(day,kasho,color='lightgrey')
p1=ax2.bar(day.nisho,bottom=kasho,color='darkturquoise')

labels1=[]
labels2=[]

for tmp in df['寡照時間']:
  labels1.append(tmp.strftime('%H:%M'))

for tmp in df['日照時間']:
  labels2.append(tmp.strftime('%H:%M'))

ax2.bar_label(p1,labels=labels1,label_type='center')
ax2.bar_label(p2,labels=labels2,label_type='center')

ax1.legend(labels=['平均温度'],frameon=False)
ax1.legend(handles=[p2,p1],labels=['寡照時間','日照時間'],bbox_to_anchor=(1,0.94),frameon=False)

plt.show()

コードの解説 (追加分)

行63-64

ax1.legend(labels=['平均温度'],frameon=False)

frameon : 凡例の枠の設定

行64

ax2.legend( handles = [p2,p1], labels = [ ‘日照時間’ , ‘寡照時間’ ],
bbox_to_anchor = (1, 0.94), frameon = False)

凡例の順序と位置を設定します

handles : 凡例の順書を設定

bbox_to_anchor : 凡例の位置を設定

基準の座標 (左下) から、どれだけの位置にあるかを設定

デフォルトは、(1, 1) で右上となる

これで冒頭の完成形となります

matplotlibでグラフを作成する方法の解説はこれで終了です

2軸、折れ線グラフ、棒グラフ、テキストの追加、色の変更、マーカーの追加、凡例の追加などができるようになったと思います

汎用性のある題材としていますので、他のデータでグラフを作成するときにご活用ください

コメント

この記事が気に入ったら
いいね!しよう
最新情報をお届けします。
タイトルとURLをコピーしました