matplotlib-scientific-plotting について
matplotlib-scientific-plottingは、PythonのMatplotlibで科学的な可視化を作成するスキルです。図を作成する研究者や開発者向けに、描画、レイアウト、スタイル、3Dグラフ、書き出しを扱います。
主な機能
- 01pyplotとオブジェクト指向の描画API
- 02科学グラフと複数パネルのレイアウト
- 03図のスタイルとカラーマップの調整
- 043Dの曲面、散布図、ワイヤーフレーム
- 05出版向け形式への書き出し
活用シーン
- 01論文用の複数パネル図を作成
- 02統計グラフで複数グループを比較
- 03データを3Dで可視化
- 04投稿用に図をPDFやSVGで保存
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill matplotlib-scientific-plottingインストール後、Claude Code で/matplotlib-scientific-plottingを入力して読み込まれたか確認します。
詳細
matplotlib
概要
Matplotlib は、静的、アニメーション、インタラクティブなプロットを作成するための、Python の基盤となる可視化ライブラリです。MATLAB 風の pyplot インターフェースと、Figure、Axes、Artist を完全に制御できるオブジェクト指向 API の両方を提供します。出版品質の科学図表の作成に欠かせません。
使用する場面
- フォント、目盛り、色、間隔など、あらゆる要素を細かく制御して出版品質のプロットを作成する
- 論文向けに、複雑なサブプロットレイアウトを使った複数パネルの図を作成する
- 折れ線、散布図、棒グラフ、ヒストグラム、ヒートマップ、箱ひげ図、バイオリンプロット、等高線図など、標準的な科学プロットを作成する
- 学術誌への投稿向けに、図をベクター形式(PDF、SVG)でエクスポートする
- 3D のサーフェス、散布図、ワイヤーフレームプロットを作成する
- アクセシビリティに配慮した(色覚多様性に対応した)カラーマップや配色をカスタマイズする
- プロットを NumPy 配列や pandas DataFrame と連携する
- 分布や回帰などの手軽な統計可視化には、代わりに
seabornを使用する - ホバーやズームに対応したインタラクティブな Web ベースのプロットには、代わりに
plotlyを使用する
前提条件
- Python パッケージ:
matplotlib、numpy - 任意:
pandas(DataFrame のプロット用)、seaborn(スタイルプリセット用) - 環境:スクリプト、Jupyter ノートブック(
%matplotlib inline)、GUI アプリで動作します
pip install matplotlib numpy
クイックスタート
import matplotlib.pyplot as plt
import numpy as np
# Publication-ready figure template: set size, plot, label, save as PDF
fig, ax = plt.subplots(figsize=(6, 4)) # single-column journal width ≈ 6 cm → set here in inches
x = np.linspace(0, 2 * np.pi, 200)
ax.plot(x, np.sin(x), color="steelblue", lw=1.5, label="sin(x)")
ax.plot(x, np.cos(x), color="coral", lw=1.5, label="cos(x)", linestyle="--")
ax.set_xlabel("x (radians)")
ax.set_ylabel("Amplitude")
ax.set_title("Sine and Cosine Waves")
ax.legend(frameon=False)
ax.spines[["top", "right"]].set_visible(False) # clean axis style
plt.tight_layout()
plt.savefig("quickstart.pdf", bbox_inches="tight", dpi=300)
print("Saved quickstart.pdf")
コア API
モジュール 1:Figure と Axes の作成
基本となるオブジェクト:Figure(キャンバス)と Axes(プロット領域)。
import matplotlib.pyplot as plt
import numpy as np
# Single plot (recommended: OO interface)
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 2 * np.pi, 100)
ax.plot(x, np.sin(x), label="sin(x)")
ax.plot(x, np.cos(x), label="cos(x)")
ax.set_xlabel("x"); ax.set_ylabel("y")
ax.set_title("Trigonometric Functions")
ax.legend(); ax.grid(True, alpha=0.3)
plt.savefig("basic_plot.png", dpi=300, bbox_inches="tight")
print("Saved basic_plot.png")
# Multi-panel subplots
fig, axes = plt.subplots(2, 2, figsize=(10, 8), constrained_layout=True)
axes[0, 0].plot(x, np.sin(x)); axes[0, 0].set_title("sin(x)")
axes[0, 1].scatter(x[::5], np.cos(x[::5])); axes[0, 1].set_title("cos(x)")
axes[1, 0].bar(["A", "B", "C"], [3, 7, 5]); axes[1, 0].set_title("Bar")
axes[1, 1].hist(np.random.randn(500), bins=30); axes[1, 1].set_title("Histogram")
plt.savefig("subplots.png", dpi=300, bbox_inches="tight")
print("Saved subplots.png with 4 panels")
モジュール 2:プロットの種類
標準的な科学グラフの種類。
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 3, figsize=(15, 9), constrained_layout=True)
# Line plot — trends over time
x = np.linspace(0, 10, 50)
axes[0, 0].plot(x, np.exp(-x/3) * np.sin(x), "b-", linewidth=2)
axes[0, 0].set_title("Line Plot")
# Scatter plot — correlations
np.random.seed(42)
axes[0, 1].scatter(np.random.randn(100), np.random.randn(100), alpha=0.6, c=np.random.rand(100), cmap="viridis")
axes[0, 1].set_title("Scatter Plot")
# Bar chart — categorical comparisons
categories = ["Gene A", "Gene B", "Gene C", "Gene D"]
axes[0, 2].bar(categories, [4.2, 7.1, 3.5, 6.8], color="steelblue", edgecolor="black")
axes[0, 2].set_title("Bar Chart")
# Histogram — distributions
axes[1, 0].hist(np.random.randn(1000), bins=40, edgecolor="black", alpha=0.7)
axes[1, 0].set_title("Histogram")
# Box plot — statistical distributions
data = [np.random.randn(50) + i for i in range(4)]
axes[1, 1].boxplot(data, labels=["Ctrl", "Drug A", "Drug B", "Drug C"])
axes[1, 1].set_title("Box Plot")
# Heatmap — matrix data
matrix = np.random.rand(8, 8)
im = axes[1, 2].imshow(matrix, cmap="coolwarm", aspect="auto")
plt.colorbar(im, ax=axes[1, 2])
axes[1, 2].set_title("Heatmap")
plt.savefig("plot_types.png", dpi=300, bbox_inches="tight")
print("Saved 6 plot types to plot_types.png")
モジュール 3:スタイルとカスタマイズ
色、フォント、スタイル、注釈。
import matplotlib.pyplot as plt
import numpy as np
# Use style sheets
plt.style.use("seaborn-v0_8-whitegrid")
# Custom rcParams for publication
plt.rcParams.update({
"font.size": 12, "axes.labelsize": 14,
"axes.titlesize": 16, "xtick.labelsize": 10,
"ytick.labelsize": 10, "legend.fontsize": 11,
})
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 5, 100)
ax.plot(x, np.exp(-x), "r--", linewidth=2, label="Exponential decay")
ax.fill_between(x, np.exp(-x) - 0.1, np.exp(-x) + 0.1, alpha=0.2, color="red")
# Annotations
ax.annotate("Half-life", xy=(0.693, 0.5), xytext=(2, 0.7),
arrowprops=dict(arrowstyle="->", color="black"),
fontsize=12, fontweight="bold")
ax.set_xlabel("Time (s)"); ax.set_ylabel("Signal")
ax.legend()
plt.savefig("styled_plot.png", dpi=300, bbox_inches="tight")
print("Saved styled_plot.png")
モジュール 4:高度なレイアウト
モザイクレイアウト、GridSpec、インセット。
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np
# Mosaic layout — named axes
fig, axes = plt.subplot_mosaic(
[["main", "right"], ["main", "bottom_right"]],
figsize=(10, 7), constrained_layout=True,
gridspec_kw={"width_ratios": [2, 1]}
)
x = np.linspace(0, 10, 200)
axes["main"].plot(x, np.sin(x) * np.exp(-x/5), "b-", linewidth=2)
axes["main"].set_title("Main Panel")
axes["right"].hist(np.random.randn(300), bins=20, orientation="horizontal")
axes["right"].set_title("Distribution")
axes["bottom_right"].bar(["A", "B"], [3, 5])
axes["bottom_right"].set_title("Summary")
plt.savefig("mosaic_layout.png", dpi=300, bbox_inches="tight")
print("Saved mosaic_layout.png")
モジュール 5:3D 可視化
サーフェス、散布図、ワイヤーフレームプロット。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection="3d")
# Surface plot
u = np.linspace(0, 2 * np.pi, 50)
v = np.linspace(0, np.pi, 50)
X = np.outer(np.cos(u), np.sin(v))
Y = np.outer(np.sin(u), np.sin(v))
Z = np.outer(np.ones_like(u), np.cos(v))
ax.plot_surface(X, Y, Z, cmap="viridis", alpha=0.8)
ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_zlabel("Z")
ax.set_title("3D Surface Plot")
plt.savefig("surface_3d.png", dpi=300, bbox_inches="tight")
print("Saved surface_3d.png")
モジュール 6:エクスポートと保存
出版向けの設定で、さまざまな形式に出力します。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot([1, 2, 3], [1, 4, 9], "ko-")
ax.set_title("Export Example")
# High-res PNG for presentations
fig.savefig("figure.png", dpi=300, bbox_inches="tight", facecolor="white")
# Vector PDF for journal submission
fig.savefig("figure.pdf", bbox_inches="tight")
# SVG for web
fig.savefig("figure.svg", bbox_inches="tight")
# Transparent background
fig.savefig("figure_transparent.png", dpi=300, bbox_inches="tight", transparent=True)
plt.close(fig) # Free memory
print("Exported to PNG, PDF, SVG, and transparent PNG")
一般的なワークフロー
ワークフロー 1:出版向けの複数パネル図
目標:論文向けに、異なる種類のプロットを組み合わせた 4 パネルの図を作成します。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
fig, axes = plt.subplots(2, 2, figsize=(10, 8), constrained_layout=True)
# Panel A: Time series
t = np.linspace(0, 24, 100)
axes[0, 0].plot(t, 50 + 10 * np.sin(t * np.pi / 12), "b-", linewidth=2)
axes[0, 0].set_xlabel("Time (h)"); axes[0, 0].set_ylabel("Expression")
axes[0, 0].set_title("A", loc="left", fontweight="bold")
# Panel B: Volcano plot
fc = np.random.randn(500)
pval = -np.log10(np.random.uniform(0.0001, 1, 500))
colors = ["red" if abs(f) > 1 and p > 2 else "grey" for f, p in zip(fc, pval)]
axes[0, 1].scatter(fc, pval, c=colors, s=10, alpha=0.7)
axes[0, 1].axhline(2, ls="--", color="black", alpha=0.5)
axes[0, 1].set_xlabel("log₂ FC"); axes[0, 1].set_ylabel("-log₁₀ p-value")
axes[0, 1].set_title("B", loc="left", fontweight="bold")
# Panel C: Bar chart with error bars
means = [3.2, 5.1, 4.7, 6.3]
sems = [0.4, 0.6, 0.3, 0.5]
axes[1, 0].bar(["Ctrl", "Drug A", "Drug B", "Combo"], means, yerr=sems,
capsize=5, color="steelblue", edgecolor="black")
axes[1, 0].set_ylabel("Response"); axes[1, 0].set_title("C", loc="left", fontweight="bold")
# Panel D: Heatmap
data = np.random.randn(6, 4)
im = axes[1, 1].imshow(data, cmap="RdBu_r", aspect="auto")
plt.colorbar(im, ax=axes[1, 1])
axes[1, 1].set_title("D", loc="left", fontweight="bold")
fig.savefig("publication_figure.pdf", bbox_inches="tight")
print("Saved publication_figure.pdf (4 panels)")
ワークフロー 2:統計的な比較プロット
目標:個々のデータ点と有意差の注釈を含む棒グラフを作成します。
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
groups = {"Control": np.random.normal(5, 1.2, 20),
"Treatment A": np.random.normal(7, 1.5, 20),
"Treatment B": np.random.normal(6, 1.0, 20)}
fig, ax = plt.subplots(figsize=(6, 5))
positions = range(len(groups))
for i, (name, data) in enumerate(groups.items()):
ax.bar(i, np.mean(data), yerr=np.std(data)/np.sqrt(len(data)),
capsize=5, color=["#4C72B0", "#DD8452", "#55A868"][i],
edgecolor="black", alpha=0.8, width=0.6)
# Overlay individual data points
ax.scatter(np.full_like(data, i) + np.random.uniform(-0.15, 0.15, len(data)),
data, color="black", s=15, alpha=0.5, zorder=5)
ax.set_xticks(positions); ax.set_xticklabels(groups.keys())
ax.set_ylabel("Measurement")
# Add significance bracket
y_max = max(max(d) for d in groups.values()) + 1
ax.plot([0, 0, 1, 1], [y_max, y_max + 0.2, y_max + 0.2, y_max], "k-", linewidth=1)
ax.text(0.5, y_max + 0.3, "**", ha="center", fontsize=14)
fig.savefig("comparison_plot.png", dpi=300, bbox_inches="tight")
print("Saved comparison_plot.png")
主要なパラメーター
| パラメーター | モジュール | デフォルト | 範囲 / オプション | 効果 |
|---|---|---|---|---|
figsize | Figure の作成 | (6.4, 4.8) | インチ単位の (w, h) | Figure の寸法 |
dpi | savefig | 100 | 72~600 | 解像度:印刷用は 300、Web 用は 150 |
bbox_inches | savefig | None | "tight"、None | Figure 周囲の余白を切り取る |
constrained_layout | subplots | False | True/False | 重なりを防ぐために間隔を自動調整する |
cmap | ヒートマップ/散布図 | "viridis" | "viridis"、"coolwarm"、"RdBu_r" など | データのマッピングに使用するカラーマップ |
alpha | すべてのプロットの種類 | 1.0 | 0.0~1.0 | 透明度(0=透明、1=不透明) |
linewidth | 折れ線プロット | 1.5 | 0.5~5.0 | 線の太さ(ポイント単位) |
s | 散布図 | 20 | 1~500 | マーカーのサイズ(ポイント²) |
bins | ヒストグラム | 10 | 5~100 または配列 | ヒストグラムのビン数 |
projection | add_subplot | None | "3d"、"polar" | Axes の投影タイプ |
ベストプラクティス
-
常に OO インターフェース(
fig, ax = plt.subplots())を本番コードで使用してください。plt.plot()は、手早い対話的な試行にのみ使用してください。 -
constrained_layout=Trueを使用して、ラベルやタイトルの重なりを防いでください:fig, ax = plt.subplots(figsize=(8, 5), constrained_layout=True) -
アクセシビリティに配慮したカラーマップを選んでください:
viridis、cividis、plasma(知覚的に均一で、色覚多様性にも対応)を使用してください。jetやrainbowは避けてください。 -
保存後に Figure を閉じて、ループ内でのメモリリークを防いでください:
plt.close(fig) # After savefig -
適切な DPI を設定してください:印刷・学術誌用は 300、Web・スライド用は 150、画面表示のみの場合は 72 にしてください。
-
大規模なデータセットには
rasterized=Trueを使用して、PDF/SVG のファイルサイズを小さくしてください:ax.scatter(x, y, rasterized=True) # Vector labels + rasterized data -
パネルのラベルを統一してください:複数パネルの図では、各サブプロットの左上に太字の文字(A、B、C、D)を使用してください。
よく使うレシピ
レシピ:カスタムカラーパレット
使用する場面:論文内の複数の図で色を統一したい場合。
import matplotlib.pyplot as plt
# Define a custom palette
palette = {"control": "#4C72B0", "treatment": "#DD8452", "combo": "#55A868"}
fig, ax = plt.subplots()
for group, color in palette.items():
ax.bar(group, [5, 7, 6][list(palette.keys()).index(group)], color=color)
plt.savefig("custom_palette.png", dpi=300, bbox_inches="tight")
レシピ:2つの Y 軸
使用する場面:異なるスケールの2つの変数を同じ図にプロットする場合。
import matplotlib.pyplot as plt
import numpy as np
fig, ax1 = plt.subplots(figsize=(8, 5))
x = np.arange(10)
ax1.bar(x, np.random.randint(10, 100, 10), alpha=0.7, color="steelblue", label="Count")
ax1.set_ylabel("Count", color="steelblue")
ax2 = ax1.twinx()
ax2.plot(x, np.cumsum(np.random.rand(10)), "r-o", linewidth=2, label="Cumulative")
ax2.set_ylabel("Cumulative", color="red")
fig.legend(loc="upper left", bbox_to_anchor=(0.15, 0.95))
plt.savefig("twin_axes.png", dpi=300, bbox_inches="tight")
レシピ:拡大インセットプロット
使用する場面:大きなプロットの一部を拡大して表示する場合。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(8, 5))
x = np.linspace(0, 10, 500)
y = np.sin(x) * np.exp(-x / 5)
ax.plot(x, y, "b-", linewidth=2)
# Inset
axins = ax.inset_axes([0.5, 0.5, 0.4, 0.4])
axins.plot(x, y, "b-", linewidth=2)
axins.set_xlim(1, 3); axins.set_ylim(0.2, 0.8)
ax.indicate_inset_zoom(axins, edgecolor="black")
plt.savefig("inset_zoom.png", dpi=300, bbox_inches="tight")
トラブルシューティング
| 問題 | 原因 | 解決方法 |
|---|---|---|
| ラベルやタイトルが重なる | レイアウト管理がない | plt.subplots() に constrained_layout=True を追加します |
UserWarning: tight_layout | constrained_layout と互換性がない | constrained_layout または tight_layout() のどちらか一方だけを使用し、両方は使用しないでください |
| Jupyter で図がぼやける | デフォルトの DPI が低い | %config InlineBackend.figure_format = 'retina' を設定します |
| ループ内でメモリ使用量が増える | 図が閉じられていない | 各 savefig() の後に plt.close(fig) を追加します |
| フォントが見つからないという警告 | システムフォントが不足している | plt.rcParams["font.sans-serif"] = ["DejaVu Sans"] を使用します |
| PDF/SVG ファイルのサイズが大きい | ベクター形式に多数のデータポイントが含まれている | サイズの大きいアーティストに rasterized=True を使用します |
| 3D プロットの回転が止まる | インタラクティブバックエンドの問題 | Jupyter では %matplotlib widget を、スクリプトでは plt.show() を使用します |
| カラーバーのサイズが合わない | デフォルトのサイズが Axes と一致しない | fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04) を使用します |
参考資料
- matplotlib のドキュメント — 公式ドキュメント
- matplotlib ギャラリー — プロットの種類別の例
- matplotlib チートシート — クイックリファレンス(PDF)
- Hunter, J.D. (2007). Matplotlib: A 2D graphics environment. Computing in Science & Engineering 9(3):90-95.