はじめに
Matplotlibはデフォルト設定のまま使うと、フォントサイズが小さかったり、線が細すぎたり、論文やプレゼンテーションに直接使うには不十分なグラフが出力されます。設定を調整することで、そのまま論文に載せられる品質のグラフを作成できます。
この記事では、論文品質のグラフを作成するための実践的なTipsを紹介します。
rcParamsによるグローバル設定
plt.rcParamsを使うと、スクリプト全体のデフォルトスタイルを一括で変更できます。以下のテンプレートを使えば、毎回個別に設定する必要がなくなります。
import matplotlib.pyplot as plt
plt.rcParams.update({
'font.size': 12,
'axes.labelsize': 14,
'axes.titlesize': 14,
'xtick.labelsize': 11,
'ytick.labelsize': 11,
'legend.fontsize': 11,
'figure.figsize': (6, 4),
'figure.dpi': 150,
'lines.linewidth': 1.5,
'axes.linewidth': 0.8,
'axes.grid': True,
'grid.alpha': 0.3,
})
各パラメータの説明
font.size: 基本フォントサイズ。ここを基準に他のサイズも調整されますaxes.labelsize,axes.titlesize: 軸ラベルとタイトルのサイズ。本文より少し大きくすると読みやすくなりますfigure.figsize: デフォルトの図サイズ(インチ単位)。論文のカラム幅に合わせて調整しますfigure.dpi: 解像度。150以上にしておくとノートブック上でも鮮明に表示されますaxes.grid,grid.alpha: 薄いグリッド線を表示してデータの読み取りを助けます

スタイルシートとの併用
Matplotlibにはプリセットのスタイルシートもあります。rcParamsと併用する場合、スタイルシートを先に適用してから個別に上書きします。
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams.update({
'font.size': 12,
'axes.labelsize': 14,
})
日本語フォントの設定
Matplotlibはデフォルトでは日本語フォントに対応しておらず、そのままでは文字化けします。
macOSの場合
macOSではjapanize-matplotlibパッケージを使うのが最も簡単です。
pip install japanize-matplotlib
import matplotlib.pyplot as plt
import japanize_matplotlib
plt.plot([1, 2, 3], [1, 4, 9])
plt.title("日本語タイトル")
plt.xlabel("X軸ラベル")
plt.ylabel("Y軸ラベル")
plt.show()
手動でフォントを指定する方法
japanize-matplotlibを使わない場合、フォントパスを直接指定できます。
import matplotlib
from matplotlib import font_manager
# macOS
font_path = '/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc'
# Linux
# font_path = '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc'
font_manager.fontManager.addfont(font_path)
matplotlib.rc('font', family='Hiragino Sans')
Linuxの場合
Linux環境ではNotoフォントなどをインストールしてから設定します。
# フォント一覧の確認
fc-list :lang=ja
# Noto Sans CJKのインストール(Ubuntu/Debian)
sudo apt install fonts-noto-cjk
フォントキャッシュのクリアが必要な場合があります。
import matplotlib
matplotlib.font_manager._load_fontmanager(try_read_cache=False)
カラーマップの選択
jet/rainbowを避ける理由
jetやrainbowは色覚多様性のある読者にとって判読が困難です。また、明るさが均一でないため、データの大小関係が正しく伝わらない場合があります。
推奨カラーマップ
連続データには以下のカラーマップが推奨されます。
- viridis: デフォルトカラーマップ。明るさが均一で色覚多様性に配慮されています
- cividis: viridisに似ていますが、より色覚バリアフリーに特化しています
- plasma: 暖色系で、viridisとの使い分けに適しています
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
y = np.linspace(0, 10, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
cmaps = ['viridis', 'cividis', 'plasma']
for ax, cmap in zip(axes, cmaps):
im = ax.pcolormesh(X, Y, Z, cmap=cmap)
ax.set_title(cmap)
fig.colorbar(im, ax=ax)
plt.tight_layout()
plt.show()

カテゴリデータ用の定性パレット
カテゴリデータ(折れ線グラフで複数系列を区別する場合など)には定性パレットを使います。
# tab10: 最大10色、区別しやすい配色
colors = plt.cm.tab10.colors
for i in range(5):
plt.plot(x, np.sin(x + i), color=colors[i], label=f'Series {i+1}')
plt.legend()
plt.show()
Set2やDark2も論文向きの落ち着いた色合いで使いやすいパレットです。
サブプロットの配置と軸の共有
基本的なサブプロット
fig, axes = plt.subplots(2, 2, figsize=(10, 8), sharex=True, sharey=True)
for ax in axes.flat:
ax.plot(np.random.randn(50).cumsum())
fig.align_ylabels(axes[:, 0])
plt.tight_layout()
plt.show()
sharex=Trueとsharey=Trueを指定すると、各サブプロットで軸の範囲が統一されます。fig.align_ylabels()でy軸ラベルの位置も揃えられます。
gridspec_kwによる細かいレイアウト制御
サブプロット間の余白を調整したい場合はgridspec_kwを使います。
fig, axes = plt.subplots(
2, 2,
figsize=(10, 8),
gridspec_kw={'hspace': 0.05, 'wspace': 0.05},
sharex=True,
sharey=True
)
サイズの異なるサブプロット
GridSpecを使うと、サブプロットごとに異なるサイズを指定できます。
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(10, 6))
gs = GridSpec(2, 3, figure=fig)
ax_main = fig.add_subplot(gs[:, :2]) # 左側2/3を占める大きなプロット
ax_top = fig.add_subplot(gs[0, 2]) # 右上
ax_bottom = fig.add_subplot(gs[1, 2]) # 右下
ベクター出力(PDF/SVG)
ベクター形式で保存する
論文投稿にはベクター形式(PDF, SVG)が推奨されます。拡大しても画質が劣化しません。
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
# PDF出力
fig.savefig('figure.pdf', bbox_inches='tight')
# SVG出力
fig.savefig('figure.svg', bbox_inches='tight')
bbox_inches='tight'を指定すると、余白が自動的にトリミングされます。
ラスター形式を使う場面
以下のような場合はPNG(ラスター形式)の方が適しています。
- データ点が非常に多い散布図(数万点以上)
- ヒートマップやイメージプロット
- ファイルサイズを小さくしたい場合
ラスター形式で保存する場合はdpiを指定します。
fig.savefig('figure.png', dpi=300, bbox_inches='tight')
ベクターとラスターの組み合わせ
一つの図の中でベクターとラスターを混在させることもできます。rasterized=Trueを指定した要素だけがラスター化されます。
ax.scatter(x, y, rasterized=True) # 散布図だけラスター化
fig.savefig('figure.pdf', dpi=300, bbox_inches='tight')
完成例:すべてのTipsを組み合わせる
以下は、ここまで紹介したTipsをすべて組み合わせた完成例です。
import numpy as np
import matplotlib.pyplot as plt
# グローバル設定
plt.rcParams.update({
'font.size': 12,
'axes.labelsize': 14,
'axes.titlesize': 14,
'xtick.labelsize': 11,
'ytick.labelsize': 11,
'legend.fontsize': 11,
'figure.figsize': (6, 4),
'figure.dpi': 150,
'lines.linewidth': 1.5,
'axes.linewidth': 0.8,
'axes.grid': True,
'grid.alpha': 0.3,
})
# データ生成
np.random.seed(42)
x = np.linspace(0, 2 * np.pi, 100)
signals = {
'Signal A': np.sin(x) + np.random.normal(0, 0.1, 100),
'Signal B': np.cos(x) + np.random.normal(0, 0.1, 100),
'Signal C': np.sin(2 * x) + np.random.normal(0, 0.1, 100),
}
# カテゴリ用パレット
colors = plt.cm.Set2.colors
# サブプロット作成
fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
# 左: 折れ線グラフ
ax = axes[0]
for i, (label, data) in enumerate(signals.items()):
ax.plot(x, data, color=colors[i], label=label)
ax.set_xlabel('Time [s]')
ax.set_ylabel('Amplitude')
ax.set_title('Time Series Comparison')
ax.legend()
# 右: ヒートマップ
ax = axes[1]
X, Y = np.meshgrid(x, x)
Z = np.sin(X) * np.cos(Y)
im = ax.pcolormesh(X, Y, Z, cmap='cividis', rasterized=True)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('2D Heatmap')
fig.colorbar(im, ax=ax)
plt.tight_layout()
# ベクター形式で保存
fig.savefig('publication_figure.pdf', bbox_inches='tight')
fig.savefig('publication_figure.svg', bbox_inches='tight')
plt.show()

まとめ
論文品質のグラフを作成するためのポイントをまとめます。
rcParamsでグローバル設定を定義し、一貫したスタイルを維持する- 日本語フォントは
japanize-matplotlibで手軽に対応する - カラーマップは色覚多様性に配慮した
viridis系を選ぶ - サブプロットは
sharex/shareyとalign_ylabelsで整列させる - 最終出力はPDF/SVGのベクター形式で保存する
Matplotlibの基本的な使い方や3Dアニメーション(GIF)の作成方法については、MatplotlibでGIFアニメーションを作成する方法もご参照ください。