一覧へ

Pythonでバイオデータを可視化する

Kaplan-Meier生存曲線、volcano plot、遺伝子発現heatmapをPython matplotlibで描く方法。

中級
|
120
|
検証済み (2026-06)
matplotlibKaplan-Meiervolcano plotheatmap生存分析DEG
進捗0/12 (0%)

Pythonでバイオデータを可視化する

このトピックを終えたら

matplotlibでバイオ研究でよく使う3つのグラフ(生存曲線、volcano plot、heatmap)を描けるようになります。


matplotlib基礎:最初のグラフ

matplotlibはPythonの代表的な可視化ライブラリです。plt.plot()1行でグラフが描けます。

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
# 細胞成長曲線(指数成長)
hours = np.array([0, 2, 4, 6, 8, 10, 12, 24])
cell_count = np.array([1000, 1200, 1800, 3200, 6000, 11000, 22000, 500000])
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(hours, cell_count, "o-", color="#2E86AB", linewidth=2, markersize=6)
ax.set_xlabel("Time (hours)", fontsize=12)
ax.set_ylabel("Cell Count", fontsize=12)
ax.set_title("Cell Growth Curve", fontsize=14, fontweight="bold")
ax.set_yscale("log")
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig("growth_curve.png", dpi=150)
plt.close(fig)
assert len(hours) == 8
assert cell_count[-1] == 500000
print("growth_curve.png 保存完了")

棒グラフ:複数遺伝子のGC Content比較

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def calculate_gc(seq: str) -> float:
seq = seq.upper()
return (seq.count("G") + seq.count("C")) / len(seq) * 100
genes = {
"BRCA1": "ATGGATTTATCTGCTCTTCGCGTTGAAGAAGTACAAAATGTC",
"TP53": "ATGGAGGAGCCGCAGTCAGATCCTAGCGTGAGTTTGCTGTGA",
"EGFR": "ATGCGACCCTCCGGGACGGCCGGGGCAGCGCTCCTGGCGCTG",
"MYC": "ATGCCCCTCAACGTTAGCTTCACCAACAGGAACTATGACCTCG",
"KRAS": "ATGACTGAATATAAACTTGTGGTAGTTGGAGCTGGTGGCGTAG",
}
names = list(genes.keys())
gc_values = [calculate_gc(seq) for seq in genes.values()]
colors = ["#E74C3C" if gc > 60 else "#2E86AB" for gc in gc_values]
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(names, gc_values, color=colors, edgecolor="white", linewidth=0.5)
ax.axhline(y=60, color="#E74C3C", linestyle="--", alpha=0.5, label="GC > 60% threshold")
ax.set_ylabel("GC Content (%)", fontsize=12)
ax.set_title("GC Content by Gene", fontsize=14, fontweight="bold")
ax.legend()
ax.set_ylim(0, 100)
fig.tight_layout()
fig.savefig("gc_bar_chart.png", dpi=150)
plt.close(fig)
assert len(gc_values) == 5
assert all(0 <= gc <= 100 for gc in gc_values)
print(f"GC値: {[f'{gc:.1f}%' for gc in gc_values]}")

Kaplan-Meier生存曲線

生存分析は臨床試験で最も重要な可視化です。2つのグループ(治療群 vs 対照群)の生存率を比較します。

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
# 仮想臨床データを生成
n_patients = 50
treatment_times = np.sort(np.random.exponential(scale=24, size=n_patients))
control_times = np.sort(np.random.exponential(scale=16, size=n_patients))
def kaplan_meier(times, max_time=48):
times = times[times <= max_time]
n = len(times)
km_times = [0]
km_survival = [1.0]
at_risk = n
for t in sorted(set(times)):
events = np.sum(times == t)
survival = km_survival[-1] * (1 - events / at_risk)
km_times.append(t)
km_survival.append(survival)
at_risk -= events
return np.array(km_times), np.array(km_survival)
t_times, t_surv = kaplan_meier(treatment_times)
c_times, c_surv = kaplan_meier(control_times)
fig, ax = plt.subplots(figsize=(8, 5))
ax.step(t_times, t_surv, where="post", color="#2E86AB", linewidth=2, label="Treatment (n=50)")
ax.step(c_times, c_surv, where="post", color="#E74C3C", linewidth=2, label="Control (n=50)")
ax.fill_between(t_times, t_surv, step="post", alpha=0.1, color="#2E86AB")
ax.fill_between(c_times, c_surv, step="post", alpha=0.1, color="#E74C3C")
ax.set_xlabel("Time (months)", fontsize=12)
ax.set_ylabel("Survival Probability", fontsize=12)
ax.set_title("Kaplan-Meier Survival Curve", fontsize=14, fontweight="bold")
ax.legend(fontsize=11, loc="lower left")
ax.set_xlim(0, 48)
ax.set_ylim(0, 1.05)
ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig("kaplan_meier.png", dpi=150)
plt.close(fig)
assert t_surv[0] == 1.0
assert c_surv[0] == 1.0
assert len(t_times) > 1
print("kaplan_meier.png 保存完了")

Volcano Plot:差次発現遺伝子の可視化

Volcano plotはRNA-seqデータで有意に発現が変化した遺伝子を一目で示します。X軸は変化量(log2 fold change)、Y軸は統計的有意性(-log10 p-value)です。

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
n_genes = 500
log2fc = np.random.normal(0, 1.5, n_genes)
pvalues = 10 ** (-np.abs(log2fc) * np.random.uniform(0.5, 3, n_genes))
fc_threshold = 1.0
p_threshold = 0.05
colors = []
for fc, p in zip(log2fc, pvalues):
if p < p_threshold and fc > fc_threshold:
colors.append("#E74C3C") # 上方制御
elif p < p_threshold and fc < -fc_threshold:
colors.append("#2E86AB") # 下方制御
else:
colors.append("#CCCCCC") # 非有意
neg_log_p = -np.log10(pvalues)
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(log2fc, neg_log_p, c=colors, s=10, alpha=0.7, edgecolors="none")
ax.axhline(-np.log10(p_threshold), color="gray", linestyle="--", alpha=0.5)
ax.axvline(fc_threshold, color="gray", linestyle="--", alpha=0.5)
ax.axvline(-fc_threshold, color="gray", linestyle="--", alpha=0.5)
n_up = sum(1 for c in colors if c == "#E74C3C")
n_down = sum(1 for c in colors if c == "#2E86AB")
ax.set_xlabel("log₂ Fold Change", fontsize=12)
ax.set_ylabel("-log₁₀ p-value", fontsize=12)
ax.set_title(f"Volcano Plot (↑{n_up} ↓{n_down} DEGs)", fontsize=14, fontweight="bold")
ax.grid(True, alpha=0.2)
fig.tight_layout()
fig.savefig("volcano_plot.png", dpi=150)
plt.close(fig)
assert n_up > 0
assert n_down > 0
print(f"上方制御: {n_up}個、下方制御: {n_down}個")

Heatmap:遺伝子発現パターン

Heatmapは複数サンプルの遺伝子発現量を色で比較します。

python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
gene_names = ["BRCA1", "TP53", "EGFR", "MYC", "KRAS", "PTEN", "RB1", "APC"]
sample_names = ["Normal_1", "Normal_2", "Tumor_1", "Tumor_2", "Tumor_3"]
expression = np.random.randn(len(gene_names), len(sample_names))
expression[:, 2:] += np.random.uniform(0.5, 2.0, (len(gene_names), 3))
fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(expression, cmap="RdBu_r", aspect="auto", vmin=-3, vmax=3)
ax.set_xticks(range(len(sample_names)))
ax.set_xticklabels(sample_names, rotation=45, ha="right", fontsize=10)
ax.set_yticks(range(len(gene_names)))
ax.set_yticklabels(gene_names, fontsize=10)
ax.set_title("Gene Expression Heatmap", fontsize=14, fontweight="bold")
fig.colorbar(im, ax=ax, label="Z-score", shrink=0.8)
fig.tight_layout()
fig.savefig("heatmap.png", dpi=150)
plt.close(fig)
assert expression.shape == (8, 5)
print(f"Heatmap: {expression.shape[0]} genes × {expression.shape[1]} samples")

やってみよう(Faded Example)

空欄を埋めて散布図を完成させてください。

穴埋め問題python
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [2.1, 3.9, 6.2, 7.8, 10.1]
fig, ax = plt.subplots()
ax.(x, y, color="blue")
ax.set_xlabel("Concentration")
ax.set_ylabel("")
fig.savefig("scatter.png")
plt.close(fig)

よくあるエラーと解決法

Q: グラフが表示されずUserWarning: Matplotlib is currently using agg

サーバー環境(Colab、SSHなど)ではmatplotlib.use("Agg")をplt import前に呼び出し、plt.show()の代わりにfig.savefig()でファイルに保存します。

Q: 日本語タイトルが文字化けします

plt.rcParams['font.family'] = 'IPAGothic'を追加してください。Colabでは!apt-get install -y fonts-ipafont後にランタイムを再起動する必要があります。

Q: ラベルが切れて見えません

fig.tight_layout()savefig()の前に呼び出してください。ほとんどの切り欠け問題が解決します。


次の記事では、機械学習で遺伝子発現データを分類する方法を学びます。

💬 質問・コメント

0件のコメント

ログインせずに投稿できます。ゲスト投稿は投稿者自身で編集・削除できません。

0/2000

読み込み中...