#author("2019-09-01T12:14:26+00:00","","")
#mynavi(Python覚え書き)
#setlinebreak(on);

* 目次 [#o6e637f2]
#contents
- 参考
-- https://matplotlib.org/
-- [[Matplotlib が PC で追加のフォントをインストールしなくても日本語を表示できるようになった:https://qiita.com/yniji/items/2f0fbe0a52e3e067c23c]]
-- [[早く知っておきたかったmatplotlibの基礎知識、あるいは見た目の調整が捗るArtistの話:https://qiita.com/skotaro/items/08dc0b8c5704c94eafb9]]

- 関連
-- [[Python]]
-- [[Python覚え書き]]
-- [[numpy入門]]
-- [[pandas入門]]
-- [[Jupyter Notebook]]

* 概要 [#ubd317a3]
#html(<div style="padding-left:10px">)
Pythonのグラフ描画ライブラリ Matplotlib の覚え書き。
#html(</div>)

* インストール [#na833a68]
#html(<div style="padding-left:10px">)

#myterm2(){{
pip install matplotlib
}}

#html(</div>)

* 使い方 [#r8b777f2]
#html(<div style="padding-left:10px">)

** タイトルを設定する [#s0ebe6a4]
#html(<div style="padding-left:10px">)
#TODO
** 日本語を描画する場合 [#z3d884bf]
#html(<div style="padding-left: 10px;">)

日本語が文字化けする場合、フォント一覧から日本語表示可能なフォントを選んで font.family に設定する。

#mycode2(){{
import matplotlib
import re
[f.name for f in matplotlib.font_manager.fontManager.ttflist if re.match('.*Gothic.*', f.name)]
}}

確認結果
#mycode3(){{
['Apple SD Gothic Neo',
 'Franklin Gothic Medium',
 'Franklin Gothic Book',
 'Hiragino Maru Gothic Pro',
 'AppleGothic',
 'MS PGothic',
 'MS Gothic',
 'HGMaruGothicMPRO',
 'Franklin Gothic Medium',
 'HGGothicE',
 'Noto Sans Gothic',
 'Franklin Gothic Book']
}}

フィントを設定
#mycode2(){{
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Hiragino Maru Gothic Pro'
}}
// plt.rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'Noto Sans CJK JP']

日本語表示可能なフォントがない場合は、以下のURLよりIPAフォントの「4書体パック」をダウンロード 及び 解凍。
https://ipafont.ipa.go.jp/old/ipafont/download.html

解凍してできた ttf を以下のディレクトリに配置する。
#mycode2(){{
import os
import matplotlib
print(os.path.join(matplotlib.get_data_path(), "fonts"))
}}

あとは上記と同じ用に rcParams でフォントを設定するだけ。
設定するフォント名は、先程ダウンロードしたファイルの README に書いてある。

Readme_IPAfont00303.txt
#mycode2(){{
 :
IPA Font (IPA Fonts 4 fonts package)   IPAfont00303.zip
|--Readme   Readme_IPAfont00303.txt
|--IPA Font License Agreement v1.0   IPA_Font_License_Agreement_v1.0.txt
|--IPAGothic   ipag.ttf
|--IPAPGothic   ipagp.ttf
|--IPAMincho   ipam.ttf
|--IPAPMincho   ipamp.ttf
 :
}}

うまく表示されない場合はキャッシュを削除して jupyter notebook を再起動。

キャッシュディレクトリの確認
#mycode2(){{
matplotlib.get_cachedir()
}}

キャッシュの削除
#myterm2(){{
mv ~/.matplotlib ~/.matplotlib_BAK
mv ~/.cache/matplotlib ~/.cache/matplotlib_BAK      # こっちもかも
}}

#html(</div>)

** X/Y軸のメモリ幅を設定する [#q4d3681f]
#html(<div style="padding-left:10px">)
#TODO
** 線グラフの描画 [#zacf5ffd]
#html(<div style="padding-left: 10px;">)

https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html
#mycode2(){{
import matplotlib.pyplot as plt
import numpy as np

#plt.rcParams['font.family'] = 'Hiragino Maru Gothic Pro'

x = np.arange(10)
y = x**2
plt.plot(x, y, c="green")
plt.xlim(-1, 11)
plt.ylim(-10, 100)
plt.xlabel("X軸")
plt.ylabel("Y軸")
plt.show()
}}

#html(</div>)

** X/Y軸のメモリラベルを設定する [#odb94ce9]
#html(<div style="padding-left:10px">)
** 散布図の描画 [#qde44fee]
#html(<div style="padding-left: 10px;">)

https://matplotlib.org/api/_as_gen/matplotlib.pyplot.scatter.html

#mycode2(){{
import matplotlib.pyplot as plt
import numpy as np

np.random.seed()
x = np.random.uniform(1, 100, 20)
y = x + np.random.uniform(-10, 10, x.shape[0])
plt.scatter(x, y, c="red", marker="x")
plt.ylim(-20,120)
plt.xlim(-20,120)
plt.show()
}}

#html(</div>)

** ヒストグラムの描画 [#k14c4a4d]
#html(<div style="padding-left: 10px;">)

https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html

#mycode2(){{
import matplotlib.pyplot as plt

x = np.array([42, 32, 44, 43, 36, 14, 22, 35, 45])
plt.hist(x, range=[0, 50], bins=10)
plt.grid(True)
plt.show()
}}

*** ヒストグラムの正規化 [#u0d1dcdb]
#html(<div style="padding-left: 10px;">)

%%normed=1%%  density=True を指定するとヒストグラムが正規化される。(binの面積の合計は1.0となる)
// μ = 0, σ2 = 1  である標準正規分布(1次元)のグラフを描いてみる。

#mycode2(){{
bins_num = 10  # 階級の数
data_num = 1000
normal_data = np.random.normal(0, 1.0, data_num)

plt.hist(normal_data, bins=bins_num, density=True)
plt.grid(True)
plt.show()
}}

//# y軸のメモリを再計算()
//ax.yaxis.set_ticklabels(["{:0.2f}".format(i / (sum(hist_values) / data_num)) for i in ax.yaxis.get_ticklocs()])

目盛りを密度(パーセンテージ)で描画したい場合は、weight を調整するか、目盛りを再計算する。

#mycode2(){{
hist_weight = np.zeros(len(normal_data)) + 1 / len(normal_data) * 100
plt.hist(normal_data, bins=bins_num, weights=hist_weight)
}}

#html(</div>)


#html(</div>)

** 目盛りの設定 [#q7ebc060]
#html(<div style="padding-left: 10px;">)

xticks または yticks で目盛りラベルを設定する事ができる。
※figureの場合は set_xticks または set_yticks。

#mycode2(){{
bins_num = 10
data_num = 1000
normal_data = np.random.normal(0, 1.0, data_num)

plt.hist(normal_data, bins=bins_num, density=True)
plt.yticks([0.1, 0.2, 0.3, 0.4, 0.5, 0.6])  # Y軸メモリを設定
plt.grid(True)
plt.show()
}}

#html(</div>)

** グリッドの描画 [#od6e450a]
#html(<div style="padding-left: 10px;">)

#mycode2(){{
plt.grid(True)
}}

#html(</div>)

** グラフを重ねる [#if40bf38]
#html(<div style="padding-left: 10px;">)

複数回 plot する事で、複数のグラフを描画する事ができる。
また、plot 時に label を指定しつつ、plt.legend を呼ぶことで凡例を表示する事ができる。
#mycode2(){{
data1 = np.random.normal(0, 1.0, 100)
data2 = np.random.normal(0, 1.0, 100)

plt.plot(data1, label="data1")
plt.plot(data2, label="data2")
plt.legend()
plt.grid(True)
plt.show()
}}
#html(</div>)

** 凡例の設定 [#he6c19ec]
#html(<div style="padding-left: 10px;">)

https://matplotlib.org/api/_as_gen/matplotlib.pyplot.legend.html

#mycode2(){{
# フォントサイズ
plt.legend(fontsize=10)

# 影付き
plt.legend(shadow=True)

# 凡例の位置を指定
plt.legend(loc='upper right')
#plt.legend(loc='lower left')

# 図に対する相対的な位置指定
plt.legend(bbox_to_anchor=(1, 1))
}}

#html(</div>)

** 線の設定 [#p609ce4d]
#html(<div style="padding-left: 10px;">)
#TODO
#html(</div>)

** グラフ画像をファイルに出力する [#dc02d118]
#html(<div style="padding-left:10px">)
** 任意の位置に線を引く [#hd97127f]
#html(<div style="padding-left: 10px;">)
#TODO
#html(</div>)

** グラフ画像のバイナリデータを取得する [#u198a1ad]
#html(<div style="padding-left:10px">)
** 任意の位置に文字を書く [#db59fdb4]
#html(<div style="padding-left: 10px;">)
#TODO
#html(</div>)

** 領域を分割して複数のグラフを描く [#ia539f4d]
#html(<div style="padding-left: 10px;">)

#mycode2(){{
from matplotlib import pyplot as plt

data = [20, 37, 41, 25, 31, 28, 32, 44, 29, 23]

# 日本語フォントを利用可能にしておく
plt.rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'Noto Sans CJK JP']

fig = plt.figure(figsize=(15, 5))

# グラフ1
ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(data, color="#ef1234")
ax1.set_title("線グラフ")

# グラフ2
ax2 = fig.add_subplot(1, 2, 2)
ax2.hist(data, bins=15)
ax2.set_title("ヒストグラム")

plt.show()
}}


#html(</div>)

#html(</div>)
// 使い方 END

* サンプル [#hf0becef]
#html(<div style="padding-left: 10px">)

サーバーのロードアベレージの時系列データをグラフ描画してみる。

サンプルデータ
&ref(sample_loadaverage.csv);

sample.py
#mycode2(){{
# coding: utf-8

import io
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import base64


def main():

  df = pd.read_csv("sample_loadaverage.csv")

  # 日本語フォントを利用可能にしておく
  plt.rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'Noto Sans CJK JP']

  fig, ax = plt.subplots() # Figureオブジェクトとそれに属する一つのAxesオブジェクトを同時に作成
  plt.title("2019-08-01", size = 10, color = "black")
  plt.suptitle("Load Average", size = 12, color = "black")
  plt.xticks(np.arange(0, 144, 6), np.arange(0, 24))
  plt.xlabel("時刻")
  plt.ylabel("ロードアベレージ")

  #plt.xlim(xmin, xmax)
  ax.set_xticks(np.arange(0, 144, 6))
  ax.set_xticklabels(np.arange(0, 24))
  ax.set_title("2019-08-05", size = 10, color = "black")
  fig.suptitle("Load Average", size = 12, color = "black")
  ax.set_xlabel("時刻")
  #ax.set_ylabel("Load average")
  ax.set_ylabel("ロードアベレージ")
  plt.plot(df["datetime"], df["load-average01"])

  ax.plot(df["datetime"], df["load-average01"])

  # そのまま描画(jupyter notebook 等の場合)
  plt.show()

  # ファイルに出力
  plt.savefig("sample_loadaverage.png")

  # 画像データを取得
  buff = io.BytesIO()
  plt.savefig(buff, format="png")
  plt.close(fig)
  plt.close()

  # 画像データをbase64エンコードしてHTMLに出力.
  with open("sample_loadaverage.html", "w") as f:
    encoded_image = base64.b64encode(buff.getvalue()).decode("utf-8")
    f.write("<!doctype html>")
    f.write("<html>")
    f.write("<meta charset='utf-8'>")
    f.write("<img src='data:image/png;base64," + encoded_image + "' />")
    f.write("</html>")

if __name__ == "__main__":
  main()
}}

** 結果 [#o8edbe1f]
&ref(sample_loadaverage.png);
&ref(sample_loadaverage.png,nolink);


#html(</div>)


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS