yuuho.wiki

カオスの欠片を集めて知恵の泉を作る

ユーザ用ツール

サイト用ツール


tips:python:matplotlib:start

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.figureFigure を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')
  • 片対数グラフ sbplt.set_yscale('log')

折れ線グラフ

ヒストグラム

簡単コード

fig = plt.figure()
sbplt = fig.add_subplot()
sbplt.hist(hoge)
 
fig.savefig( Path('hoge.pdf') )
plt.close()

histのパラメータ

bins 棒の個数

二次元ヒストグラム

ヒートマップのこと

ヒートマップ

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
  • .pie
    • ax.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 とみなしたときの座標

グリッドベースレイアウト

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()])
tips/python/matplotlib/start.txt · 最終更新: 2025/08/28 12:55 by yuuho