目次
matplotlib
matplotlibはpythonでグラフを描画できるパッケージである.
matplotlib.pyplotモジュールを利用するのが一般的.この場合はimport matplotlib.pyplot as plt
でimportする.
- 私の推奨は Fiture を使うもの。
from matplotlib.figure import Figure
pyplotモジュールを直接操作して手続き的に図を作成していく方法もあるが, 内部にあるFigureクラスを用いてオブジェクト指向的に操作する方法もある. ネット上の解説では手続き的に作成していく方法が多いが, ここではオブジェクト指向でやっていく.
オブジェクト指向操作概要
pyplotモジュールには figure() 関数があり,
これにより新規の matplotlib.figure.Figure クラスのインスタンスが得られる.
Figureクラスは作成するグラフの紙面のようなもの.Figureを分割して中に複数の図を入れることもできる.
Figureクラスは add_subplot() メソッドを持ち,
これによって matplotlib.axes._subplots.AxesSubplot クラスのインスタンスが得られる.
AxesSubplotクラスはpyplotモジュールの持つ関数を普通に使える
(全てが使えるわけではない 例 .xlabel() → .set_xlabel() )
のでpyplotの代わりとして使っていくのが良いだろう.
オブジェクト指向でやっていくならFigureインスタンスにAxesSubplotを用意して使う.
まとめ
- pltモジュール
- Figureクラス : savefig()メソッドで画像として保存.add_subplot()メソッドでAxesSubplotインスタンスの呼び出し.
- AxesSubplotクラス : pltモジュールと同じ関数がメソッドとして使える.
追記
Jupyter で正しくオブジェクト指向をやっていくなら plt 自体 import してはいけない。
matplotlib.figure の Figure をimport してやっていくのが良い。
plt をimport しなかったら plt.close() できない気がするが大丈夫か?
→ 大丈夫なのかも
Colab のときは最初から matplotlib inline されているから問題ないが、
jupyter のときは matplotlib inline を手動でやっていく必要がある。
add_subplot()
Figure.add_subplot(arg1,arg2,arg3) でSubplotを作成するときの
引数について解説する.
引数は前から順に
- (arg1) 行の個数
- (arg2) 列の個数
- (arg3) 場所
を表す. 場所は1から始まり,1行1列,1行2列,…の順番に数えていく.(下図参照)
| 列 | |||
|---|---|---|---|
| 行 | 1 | 2 | 3 |
| 4 | 5 | 6 | |
例
fig = plt.figure() sbplt = fig.add_subplot() sbplt.scatter(x=X[:,0],y=X[:,1],c=colors) fig.savefig(output_path) # または sbplt.figure.savefig(output_path) plt.close() # 20枚以上使う場合は必ずcloseが必要.
fig, sbplts = plt.subplots(rows,cols) # rows,cols が共に1のとき sbplts がlistじゃなくなるので注意 sbplts[i].scatter(x=X[:,0],y=X[:,1],c=colors) fig.savefig(output_path) # または sbplt.figure.savefig(output_path) plt.close() # 20枚以上使う場合は必ずcloseが必要.
ndarray に書き出す
import io with io.BytesIO() as buff: fig.savefig(buff, format='png', dpi=dpi) figarray = cv2.decode( np.frombuffer(buff.getvalue(),dtype=np.uint8), 1)
3次元グラフを書く
対応表
| pylot手続きインターフェース | オブジェクト指向インターフェース | 意味 |
|---|---|---|
plt.figure( figsize=(8.0,8.0) ) | Figure( figsize=(8.0,8.0) ) | 図のサイズを決める.(横,縦) 100倍. |
plt.plot() | sbplt.plot() | 折れ線グラフの描画 |
sbplt.scatter() | 散布図 | |
sbplt.hist() | ヒストグラム | |
sbplt.imshow() | ヒートマップ | |
sbplt.pie() | 円グラフ | |
| 箱ひげ図 boxplot | ||
plt.title('hoge') | sbplt.set_title('hoge') | グラフタイトル |
plt.xlabel() | sbplt.set_xlabel() | x軸の名前 |
plt.ylabel() | sbplt.set_ylabel() | y軸の名前 |
plt.xlim(left, right) | sbplt.set_xlim(left, right) | x軸の値の範囲 |
plt.ylim(bottom, top) | sbplt.set_ylim(bottom, top) | y軸の値の範囲 |
plt.xticks([]) | sbplt.set_xticks([],minor=False) | x軸の目盛りを設定 |
plt.yticks([]) | sbplt.set_yticks([],minor=False) | y軸の目盛りを設定 |
plt.xticks(fontsize=10) | sbplt.ticks_params(axis=“x”, labelsize=10) | x軸の目盛りのfontsizeを設定 |
plt.legend( bbox_to_anchor=(1,1), loc='upper right') | sbplt.legend( bbox_to_anchor=(1,1), loc='upper right') | 凡例を付ける.plot時に label= で設定. |
sbplt.vlines() | ||
sbplt.hlines() | ||
plt.subplots_adjust() | fig.subplots_adjust() | 余白の調整 |
fig.savefig('hoge.pdf') | 図の保存 | |
凡例(legend)の配置
bbox_to_anchor | 凡例の外接矩形のどこを基準点とするか.左下を (0,0) 右上を (1,1) とする配置.(x軸,y軸) |
loc | 置く場所.同様に左下を (0,0) 右上を (1,1) とする配置.文字だと upper, lowerなど |
余白の調整(subplots_adjust)
subplots_adjust() のキーワード引数解説。
left, right, bottom, top はすべて座標.幅のことではない。
wspace, hspace は幅のこと
| 変数 | 意味 | 初期値 |
|---|---|---|
left | 左 | 0.125 |
bottom | 下 | 0.1 |
top | 上 | 0.9 |
right | 右 | 0.9 |
wspace | 図同士の間(幅) | 0.2 |
hspace | 図同士の間(高さ) | 0.2 |
その他
- 目盛りがオフセット表記(=
x+2013みたいな表記)になってしまうのを防ぐ
sbplt.get_yaxis().get_major_formatter().set_useOffset(False) - 目盛りを3桁区切りにする
sbplt.yaxis.set_major_formatter(
ticker.FuncFormatter(lambda x, loc: '{:,}'.format(int(x))))matplotlib.ticker
- 縦線を引く
sbplt.vlines([880], 0, 262635, 'blue', linestyles='dashed') - 横線を引く
sbplt.hlines([262635], 0, 1000, 'blue', linestyles='dashed')- 線のスタイルについては https://python.atelierkobato.com/linestyle/ 参考
- “solid”, “dashed”, “dashdot”, “dotted”
- 線の太さは linewidth
- 片対数グラフ
sbplt.set_yscale('log')
折れ線グラフ
sbplt.plot(xdata, ydata)
ヒストグラム
簡単コード
fig = plt.figure() sbplt = fig.add_subplot() sbplt.hist(hoge) fig.savefig( Path('hoge.pdf') ) plt.close()
histのパラメータ
| bins | 棒の個数 |
二次元ヒストグラム
ヒートマップのこと
ヒートマップ
seaborn は使わなくて良い
https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
matplotlib only でのサンプル
sbplt.imshow を使う。
- sample.py
import matplotlib.pyplot as plt import numpy as np data = np.array([[0,0,2,2], [0,0,2,2], [2,2,2,3], [2,2,3,3]]) fig = plt.figure() sbplt = fig.add_subplot() sbplt.imshow( data ,cmap='jet') sbplt.set_xticks([]) sbplt.set_yticks([]) H,W = data.shape for i in range(H): for j in range(W): _ = sbplt.text(j, i, int(data[i,j]), ha="center", va="center", color="w") fig.savefig('/tmp/hoge.pdf')
グリッド線の描画
メジャー目盛りとは別にマイナー目盛りを設定する。
マイナー目盛りに線を描画するだけ。
H,W = tensor.shape sbplt.set_xticks( np.arange(-0.5, H, 1), minor=True) sbplt.set_yticks( np.arange(-0.5, W, 1), minor=True) sbplt.grid(which='minor', color='w', linestyle='-', linewidth=2)
seaborn でのサンプル
- sample.py
import matplotlib.pyplot as plt import seaborn hoge # ndarray (H,W) fig = plt.figure() sbplt = fig.add_subplot() sbplt = seaborn.heatmap(hoge, vmin=0.0,vmax=1.0, annot=True, fmt='1.3f', ax=sbplt) sbplt.figure.savefig('hoge.pdf')
散布図・棒グラフ・円グラフ
.scatter.bar.pieax.pie(data, colors=colors, startangle=90, counterclock=False)
カラーマップの自作
- カラーマップの自作 =
LinearSegmentedColormap.from_list() - 凡例カラーバーの作成 =
plt.cm.ScalarMappable()
from matplotlib.colors import LinearSegmentedColormap processed # list of ndarray, len=256 processed[0] # ndarray, shape (3,) RGB range [0.0, 1.0] my_cmap = LinearSegmentedColormap.from_list( 'my_name', processed ) my_norm = plt.Normalize(vmin=myvmin,vmax=myvmax) # https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.colors.Normalize.html my_smap = plt.cm.ScalarMappable(cmap=my_cmap, norm=my_norm) # 描画 ## heatmapの描画 ## return <class 'matplotlib.collections.PolyCollection'> _polycollection = sbplt.pcolor(grid_data, vmin=myvmin,vmax=myvmax, edgecolors='gray', cmap=my_cmap) # https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.pcolor.html?highlight=pcolor#matplotlib.axes.Axes.pcolor # 描画設定 ## 正方形に ## return None _ = sbplt.set_aspect("equal") ## x軸の数値を描画しない ## return list of <class 'matplotlib.text.Text'> _ = sbplt.set_xticklabels([]) ## y軸の数値を描画しない ## return list of <class 'matplotlib.text.Text'> _ = sbplt.set_yticklabels([]) ## カラーマップを可視化 # Axes増える ## return <class 'matplotlib.colorbar.Colorbar'> _ = sbplt.figure.colorbar(my_smap) # https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.figure.Figure.html?highlight=colorbar#matplotlib.figure.Figure.colorbar
memo : SakuData/config/cvpr/figure/maskgen_fig.py
文字の描画
軸目盛の削除
目盛りの文字を削除するのには
ax.get_xaxis().set_ticks([])
を使う。
必要に応じて .annotate() を使うのが良い。
描画
ax.annotate('your text', xy=(0.5, 0.5), # 座標 xycoords='axes fraction', # 座標の考え方 ha='right', # 座標アンカー位置をテキストボックスのどこにするか、横 va='bottom', # 座標アンカー位置をテキストボックスのどこにするか、縦 fontsize=9, # テキストのフォントサイズ rotation=40, # テキストボックスの回転角度(度) rotation_mode='anchor' # テキストボックス回転の中心 annotation_clip=False # ax の箱外にいるときに描画されない設定を消す )
- xycoords
axes fraction: ax を 横=0~1, 縦=0~1 とみなしたときの座標data: ax のデータの座標系での位置figure fraction: fig を 横=0~1, 縦=0~1 とみなしたときの座標
グリッドベースレイアウト
-
- gridspec, grid_spec
spec = fig.add_gridspec() ax = spec[:, :]
gridH = 12 gridW = 8 # 0 1 2 3 4 5 6 7 8 # 0 |^^^^^| |^^^^^^^^^^^^| |^^^^| | |^^^^| # 1 | | | | | | | | | # 2 | | | | |vvvv| | | | # 3 |vvvvv| | | |^^^^| | |vvvv| # 4 |^^^^^| | | | | | |^^^^| # 5 | | | | |vvvv| | | | # 6 | | | | |^^^^| | | | # 7 |vvvvv| | | | | | |vvvv| # 8 |^^^^^| | | |vvvv| |^^^^^^| # 9 | | | | |^^^^| | | # 10 | | | | | | | | # 11 |vvvvv| |vvvvvvvvvvvv| |vvvv| |vvvvvv| w_img = 1 # セグメンテーション画像の幅 w_lin = 0.78 # セグメンテーション画像とヒストグラムの隙間 w_his = 5 # ヒストグラムの幅 w_ma1 = 0.05 # ヒストグラムとサンプリング画像の隙間 w_fet = 0.7 # サンプリング画像の幅 w_ma2 = 0.1 # サンプリング画像と出力画像の隙間 w_ma3 = 0.2 # グラフ左と出力画像左の隙間 w_gra = 1 # グラフ幅 width_ratios = [w_img, w_lin, w_his, w_ma1, w_fet, w_ma2, w_ma3, w_gra]
消す系
図の枠線
ax.spines['left'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.spines['bottom'].set_visible(False)
図の目盛り
ax.set_xticks([]) ax.set_yticks([])
図の背景
ax.patch.set_facecolor('none') fig.patch.set_facecolor('none')
日本語フォント
Ubuntu でのフォントディレクトリ
/usr/share/fonts
メイリオ(meiryo)を使いたい場合 は Windows から引っこ抜いてくるのが良さそう。
C:\\Windows\Fontsにある.ttcファイルは使えそう。- WSL で言うところの
/mnt/c/Windows/Fonts - メイリオは以下二つ
/mnt/c/Windows/Fonts/meiryo.ttc/mnt/c/Windows/Fonts/meiryob.ttc
mkdir /usr/share/fonts/meiryo
フォントの設定やフォントをアウトライン化して出力する設定
from matplotlib import rcParams rcParams['font.family'] = 'sans-serif' rcParams['font.sans-serif'] = ['Noto Sans CJK JP'] rcParams['svg.fonttype'] = 'path'
フォントの確認
import matplotlib.font_manager as fm fonts = set([fm.FontProperties(fname=font).get_name() for font in fm.findSystemFonts()])
