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')一時的に適用したい場合 (withの内側のみ)sns.set_context('talk', font_scale=0.8)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がある場合に全体タイトルを付ける
tight_layoutを使う場合
fig.suptitle('title')fig.tight_layout(rect=[0,0,1,0.95])
figとax
- figのサイズを指定 (単位はインチ)
pixelで指定したい場合 (dpiは予め適当なfig作ってfig.get_dpi()で調べておく)
fig, ax = plt.subplots(figsize=(8,6))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の中にカスタムサイズのaxを作る (左下を(0,0), 右上を(1,1)として、[left, bottom, width, height] の順)
ax = ax.inset_axes([0.25, 0.25, 0.5, 0.5])
描画範囲
- 描画範囲を指定
ax.set_xlim((0, 100)) - 余白を入れる (データの範囲に対する割合。xlim, ylim指定があると無視される)
ax.margins(0.05)
目盛り
- 目盛りの表示間隔や値を変更
単に間引きたい場合
ax.set_xticks([1,3]) ax.set_xticklabels([10,30])sns.clustermapで全ての目盛りを表示したい場合xticks = ax.get_xticks() xlabels = ax.get_xticklabels() ax.set_xticks(xticks[::5]) ax.set_xticklabels(xlabels[::5])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))import matplotlib.dates as mdates ax.xaxis.set_major_formatter(mdates.DateFormatter('%b\n%Y'))
軸の名前
- 軸の名前を付ける
ax.set_xlabel('x') - 軸の名前の文字の大きさを変える
ax.set_xlabel(..., fontsize=20) - 軸の名前の位置を移動
ax.yaxis.set_label_position('right')
辺 (枠線)
- 辺を消す
または、以下の方法 (初期設定で上と右を消す、左と下はオプションでTrue指定)
ax.spines['top'].set_visible(False)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)})
ヒートマップ
- 基本
上は以下と等価 (matshowはimshowをorigin='upper', interpolation='nearest', aspect='equal'で呼ぶwrapper関数)
ax.matshow(np.random.randn(200,100), aspect='auto')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') - y軸を逆向きにする
ax.invert_yaxis() - sns.heatmapで整数値データに色を付ける (n_colorは色の数)
cmap=sns.color_palette('tab10', n_color) sns.heatmap([[0,1,2],[2,3,4]], cmap=cmap)
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))