LoginSignup
5
9

matplotlib tips

Last updated at Posted at 2023-02-04

Pythonのmatplotlibの自分用の備忘録 (2017/03/08作成) をQiitaに持ってきました。一応アップする前に見直しましたが、情報が古いままの箇所もあると思いますので注意して下さい。また、全機能を網羅するつもりはなく、個人的にハマった箇所を中心に書いただけです。

参考ページ

基本の流れ

  • 必要なパッケージを入れる
    import matplotlib.pyplot as plt
    import seaborn as sns
    
  • figとaxの生成 (複数の図をまとめて1つの図にする場合があるので、全体をfig、個々の図をaxと呼んで区別している)
    fig, ax = plt.subplots()
    
    上は以下と等価
    fig = plt.figure()
    ax  = fig.add_subplot()
    
  • メインの図の描画
    ax.plot(...)
    
  • 細かい調整
    ax.set_xlabel('x')
    
  • 表示
    fig.show()
    
  • ファイルへ出力
    fig.savefig('tmp.png')
    

図の種類

matplotlibの図

  • 折れ線グラフ
    ax.plot(...)
    
  • 散布図
    ax.scatter(...)
    
  • 棒グラフ
    ax.bar(...)
    
  • 箱ひげ図
    ax.boxplot(...)
    
  • ヒストグラム
    ax.hist(...)
    
  • ヒートマップ
    ax.matshow(...)
    
    または
    ax.imshow(...)
    
  • 円グラフ
    ax.pie(...)
    

seabornの図

  • 折れ線グラフ
    sns.pointplot(...)
    
  • 散布図
    sns.scatterplot(...)
    
  • 棒グラフ (連続変数の場合)
    sns.barplot(...)
    
  • 棒グラフ (カテゴリカル変数の場合)
    sns.countplot(...)
    
  • 箱ひげ図
    sns.boxplot(...)
    
  • 蜂群図
    sns.swarmplot(...)
    
  • バイオリン図
    sns.violinplot(...)
    
  • ヒストグラムとカーネル密度推定 (古いバージョン)
    sns.distplot(...)
    
  • ヒストグラムとカーネル密度推定 (新しいバージョン)
    sns.displot(...)
    sns.histplot(...)
    sns.kdeplot(...)
    
  • ヒートマップ
    sns.heatmap(...)
    
  • ヒートマップ (樹形図付き)
    sns.clustermap(...)
    

全体的なスタイル

  • 全体的な文字サイズと線の太さを変える (paper < notebook (default) < talk < poster)
    sns.set_context('talk')
    
    文字サイズを調整したい場合
    sns.set_context('talk', font_scale=0.8)
    
    一時的に適用したい場合 (withの内側のみ)
    with sns.plotting_context('talk'):
      # 略
    
  • rcParamsを個別に変更する
    with plt.rc_context({'lines.linewidth':5}):
    
    または
    with sns.plotting_context(..., rc={'lines.linewidth':5}):
    
  • 描画スタイルを変える (darkgrid, whitegrid, dark, white, ticks)
    with sns.axes_style('whitegrid'):
    
  • 使う色の種類を変える
    with sns.color_palette('colorblind'):
    

タイトル

  • タイトルを付ける
    ax.set_title('title')
    
  • タイトルの文字を大きくする
    ax.set_title(..., fontsize=20)
    
  • タイトルと図の間を広げる
    ax.set_title(..., pad=10)
    
  • 複数のaxがある場合に全体タイトルを付ける
    fig.suptitle('title')
    
    tight_layoutを使う場合
    fig.tight_layout(rect=[0,0,1,0.95])
    

figとax

  • figのサイズを指定 (単位はインチ)
    fig, ax = plt.subplots(figsize=(8,6))
    
    pixelで指定したい場合 (dpiは予め適当なfig作ってfig.get_dpi()で調べておく)
    dpi = 80.0
    fig, ax = plt.subplots(figsize=(400/dpi, 300/dpi))
    # (中略)
    fig.savefig('tmp.png', dpi='figure')
    
  • 余白を詰める
    fig.tight_layout()
    
    または
    fig.subplots_adjust(left=0.05, top=0.95, bottom=0.05, right=0.95)
    
  • ax同士の間を調節する (hはheightで縦方向、wはwidthで横方向)
    fig.tight_layout(h_pad=0.1, w_pad=0.1)
    
    または
    fig.subplots_adjust(wspace=0.1, hspace=0.1)
    
  • 複数のaxを並べる (サイズが同じ場合)
    fig, axes = plt.subplots(nrows=2, ncols=2)
    ax1 = axes[0,0]
    
  • 複数のaxを並べる (サイズがばらばらの場合、方眼紙を作ってカスタムで配置するイメージ)
    fig = plt.figure()
    gs = fig.add_gridspec(100, 100)
    ax = fig.add_subplot(gs[:50, :50])
    
  • 複数のaxを一次元配列にする
    axes = axes.flatten()
    
  • カスタムサイズのaxを作る (左下を(0,0), 右上を(1,1)として、[left, bottom, width, height] の順)
    ax = fig.add_axes([0, 0, 1, 1])
    

描画範囲

  • 描画範囲を指定
    ax.set_xlim((0, 100))
    
  • 余白を入れる (データの範囲に対する割合。xlim, ylim指定があると無視される)
    ax.margins(0.05)
    

目盛り

  • 目盛りの表示間隔や値を変更
    ax.set_xticks([1,3])
    ax.set_xticklabels([10,30])
    
    単に間引きたい場合
    xticks = ax.get_xticks()
    xlabels = ax.get_xticklabels()
    ax.set_xticks(xticks[::5])
    ax.set_xticklabels(xlabels[::5])
    
    sns.clustermapで全ての目盛りを表示したい場合
    sns.clustermap(df, yticklabels=1)
    
  • 目盛りの文字の大きさを変える
    ax.tick_params(labelsize=20)
    
  • 目盛りの文字の向きを変える (横書きは0, 縦書きは90, 斜めも可)
    ax.set_xticklabels(..., rotation=90)
    
  • 目盛りのラベルを置換
    labels = [v.get_text().replace('-',' ') for v in ax.get_xticklabels()]
    ax.set_xticklabels(labels)
    
  • 目盛りの位置を移動
    ax.xaxis.tick_bottom()
    
    上は以下と同じ
    ax.tick_params(top=False, bottom=True)
    
  • 目盛り (軸) を0を横切る位置に移動
    ax.spines['left'].set_position('zero')
    
  • 軸の先を矢印にする (x_max, y_maxはそれぞれx軸、y軸の最大値)
    ax.plot(x_max, 0, marker='>', ms=10, color='k', clip_on=False)
    ax.plot(0, y_max, marker='^', ms=10, color='k', clip_on=False)
    
  • 目盛りを消す
    ax.set_xticks([])
    
  • 目盛りと辺を全部消す
    ax.axis('off')
    
  • 目盛りの太さを変える
    ax.tick_params(width=3)
    
  • 目盛りの長さを変える
    ax.tick_params(length=5)
    
  • 目盛りを外向きにする
    ax.tick_params(direction='out')
    
  • 目盛りと文字の間を広げる
    ax.tick_params(pad=10)
    
  • 目盛りの表記フォーマットを変更
    def fmt(x, pos):
      return '{:.2e}'.format(x)
    ax.xaxis.set_major_formatter(plt.FuncFormatter(fmt))
    

軸の名前

  • 軸の名前を付ける
    ax.set_xlabel('x')
    
  • 軸の名前の文字の大きさを変える
    ax.set_xlabel(..., fontsize=20)
    
  • 軸の名前の位置を移動
    ax.yaxis.set_label_position('right')
    

辺 (枠線)

  • 辺を消す
    ax.spines['top'].set_visible(False)
    
    または、以下の方法 (初期設定で上と右を消す、左と下はオプションでTrue指定)
    sns.despine()
    
  • 辺と目盛りを全部消す (再掲)
    ax.axis('off')
    
  • 辺を離して交わらないようにする
    ax.spines['bottom'].set_position(('outward', 10))
    
    または
    sns.despine(offset=10, trim=True)
    
  • sns.heatmapに枠線を付ける
    for spine in ax.spines.values():
      spine.set_visible(True)
      spine.set_linewidth(2)
    

凡例

  • 凡例を表示する (予め各プロットでlabelを指定)
    ax.plot(..., label='a')
    ax.plot(..., label='b')
    ax.legend()
    
  • 凡例の位置を変える (upper/center/lowerとleft/center/rightの組み合わせ)
    ax.legend(loc='upper left')
    
  • 凡例を図の外に移動する
    ax.legend(bbox_to_anchor=(1,1), loc='upper left')
    
  • 凡例の枠の太さを調整
    leg = ax.legend(...)
    leg.get_frame().set_linewidth(3)
    
  • 凡例の枠を消す
    ax.legend(frameon=False)
    
  • 凡例のマーカーの大きさを調整
    ax.legend(markerscale=10)
    
  • 凡例の周囲の余白を調整
    ax.legend(borderaxespad=0)
    
  • 凡例のマーカーと文字の間隔を調整
    ax.legend(handletextpad=0)
    
  • 凡例の行間を調整
    ax.legend(labelspacing=0)
    
  • 凡例を消す (seabornで勝手に出力されてしまう場合など)
    ax.legend_.remove()
    
  • 凡例を逆順にする
    handles, labels = ax.get_legend_handles_labels()
    leg = ax.legend(handles[::-1], labels[::-1])
    

文字や線を追加で書き込む

  • 横腺を引く / 縦線を引く
    ax.axhline(y=0)
    ax.axvline(x=0)
    
  • 部分領域を塗りつぶす
    ax.axvspan(0, 0.5, alpha=0.5)
    
  • 文字を書く (x座標、y座標、文字)
    ax.text(0, 0, 'text', ha='center', va='center')
    
  • 指定座標を左端にするか、中央にするかなどを変える (horizontal alignment, vertical alignment)
    ax.text(..., ha='left', va='center')
    
  • 文字の位置を、座標軸の値でなく[0,1]の範囲で指定する
    ax.text(..., transform=ax.transAxes)
    
  • 文字に背景色を付ける
    t = ax.text(...)
    t.set_bbox(dict(facecolor='white', alpha=0.5))
    
  • 文字に縁取りを付ける
    from matplotlib import patheffects
    ax.text(..., path_effects=[patheffects.withStroke(linewidth=3, foreground='w')])
    
  • 角が丸い四角形を描く
    from matplotlib import patches
    box = patches.FancyBboxPatch(...)
    ax.add_patch(box)
    
  • patchesオブジェクトを回転させる (楕円ならオプションで指定可能)
    t = mpl.transforms.Affine2D().rotate_deg_around(x, y, theta) + ax.transData
    box.set_transform(t)
    

箱ひげ図

  • 外れ値を非表示にする
    ax.boxplot(..., showfliers=False)
    
  • ひげの先の横棒を消す
    ax.boxplot(..., showcaps=False)
    
  • 中央の線の色を変える
    ax.boxplot(..., medianprops={'color':'white'})
    
  • 箱の色を変える (colorだと枠線の色も変わるので注意)
    ax.boxplot(..., boxprops={'fc':plt.cm.Paired(0)})
    

ヒートマップ

  • 基本
    ax.matshow(np.random.randn(200,100), aspect='auto')
    
    上は以下と等価 (matshowはimshowをorigin='upper', interpolation='nearest', aspect='equal'で呼ぶwrapper関数)
    ax.imshow(np.random.randn(200,100), aspect='auto', interpolaiton='nearest')
    
  • カラーバーを別のaxに表示
    im = ax.matshow(...)
    cb = fig.colorbar(im, cax=ax2)
    
  • カラーバーの枠の太さを変える
    cb.outline.set_linewidth(2)
    
  • カラーバーの枠を消す
    cb.outline.set_visible(False)
    
  • sns.heatmapのカラーバーの調節
    sns.heatmap(..., ax=ax)
    cax = ax.collections[0].colorbar.ax
    cax.tick_params(length=0)
    
  • sns.heatmapでNoneの色を変える
    g = sns.heatmap(df, mask=df.isnull())
    g.set_facecolor('0.8')
    

sns.clustermap

  • 基本 (予め用意したaxに入れるのでなく、これ自体がfigとaxを作るので注意)
    g = sns.clustermap(np.random.randn(200,100))
    
  • figを取得
    fig = g.fig
    
  • ヒートマップの部分のaxを取得
    ax = g.ax_heatmap
    
  • 樹形図の占める割合を変更
    sns.clustermap(..., dendrogram_ratio=(0.1,0.1))
    
5
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
9