data-visualization について
matplotlib と seaborn で分析用チャートを作成するスキルです。データ分析やモデル結果の提示に向け、ヘッドレス描画、PNG 出力、会話内表示の手順を定めています。
主な機能
- 01棒・折れ線・散布図・ヒートマップ
- 02ヒストグラムと箱ひげ図
- 03複数パネルの分析サマリー
- 04チャートの保存と会話内表示
活用シーン
- 01cuDF 分析結果のプロット
- 02cuML モデル結果の可視化
- 03統計結果の図表による提示
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ langchain-ai/ deepagents --skill data-visualizationインストール後、Claude Code で/data-visualizationを入力して読み込まれたか確認します。
詳細
データ可視化スキル
ヘッドレス GPU サンドボックスで matplotlib と seaborn を使用し、出版品質の分析チャートを作成します。チャートは取得できるように /workspace/ に PNG ファイルとして保存されます。
このスキルを使用するタイミング
次の場合にこのスキルを使用します。
- cuDF の分析結果や cuML モデルの結果を可視化する場合
- チャート(棒グラフ、折れ線グラフ、散布図、ヒートマップ、ヒストグラム、箱ひげ図)を作成する場合
- 複数パネルの分析サマリーを作成する場合
- ユーザーが視覚的な出力、プロット、グラフ、チャートを求める場合
- 統計的な知見を図で提示する場合
初期化(必須)
pyplot をインポートする前に、必ず matplotlib.use('Agg') を呼び出してください。これによりヘッドレスレンダリングが有効になります。
import matplotlib
matplotlib.use('Agg') # Headless backend — MUST be before pyplot import
import matplotlib.pyplot as plt
import numpy as np
# Publication-quality defaults
plt.rcParams.update({
'figure.dpi': 100,
'savefig.dpi': 300,
'font.size': 11,
'axes.labelsize': 12,
'axes.titlesize': 14,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'figure.constrained_layout.use': True,
})
# Colorblind-safe palette (Okabe-Ito)
COLORS = ['#0173B2', '#DE8F05', '#029E73', '#D55E00', '#CC78BC',
'#CA9161', '#FBAFE4', '#949494', '#ECE133', '#56B4E9']
チャートの保存
常に次の設定で /workspace/ に保存してください。
plt.savefig('/workspace/chart_name.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
- 印刷品質にするため
dpi=300を指定します - 余分な余白を取り除くため
bbox_inches='tight'を指定します - 背景を白にするため
facecolor='white'を指定します - メモリを解放するため、保存後は必ず
plt.close()を呼び出します
チャートの表示(必須)
チャートを保存した後は、会話内にインライン表示するため、必ずそのチャートに対して read_file を呼び出してください。
read_file("/workspace/chart_name.png")
これを行わないと、ユーザーはチャートを確認できません。保存したチャートには、必ず続けて read_file を呼び出してください。
クイックリファレンス
棒グラフ(groupby の結果)
# After: result = to_pd(df.groupby("category")["value"].mean())
fig, ax = plt.subplots(figsize=(8, 5))
bars = ax.bar(result.index, result.values, color=COLORS[:len(result)],
edgecolor='black', linewidth=0.8)
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height,
f'{height:.1f}', ha='center', va='bottom', fontsize=9)
ax.set_ylabel('Mean Value', fontweight='bold')
ax.set_xlabel('Category', fontweight='bold')
ax.set_title('Average Value by Category', fontweight='bold')
ax.grid(axis='y', alpha=0.3, linestyle='--')
ax.set_axisbelow(True)
plt.savefig('/workspace/bar_chart.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
折れ線グラフ(時系列の傾向)
fig, ax = plt.subplots(figsize=(10, 5))
for i, col in enumerate(columns_to_plot):
ax.plot(df["date"], df[col], label=col, color=COLORS[i], linewidth=2,
marker='o', markersize=3, markevery=max(1, len(df)//20))
ax.set_ylabel('Values', fontweight='bold')
ax.set_xlabel('Date', fontweight='bold')
ax.set_title('Trends Over Time', fontweight='bold')
ax.legend(frameon=True, shadow=False)
ax.grid(True, alpha=0.3, linestyle='--')
ax.set_axisbelow(True)
plt.xticks(rotation=45, ha='right')
plt.savefig('/workspace/line_chart.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
散布図 — 連続値の色分け(相関)
fig, ax = plt.subplots(figsize=(8, 6))
scatter = ax.scatter(df["x"], df["y"], c=df["value"], cmap='viridis',
s=40, alpha=0.7, edgecolors='black', linewidth=0.3)
plt.colorbar(scatter, ax=ax, label='Value')
# Optional: trend line
z = np.polyfit(df["x"], df["y"], 1)
ax.plot(df["x"].sort_values(), np.poly1d(z)(df["x"].sort_values()),
"r--", linewidth=2, label=f'y={z[0]:.2f}x+{z[1]:.2f}')
ax.set_xlabel('X', fontweight='bold')
ax.set_ylabel('Y', fontweight='bold')
ax.set_title('Correlation Analysis', fontweight='bold')
ax.legend()
ax.grid(True, alpha=0.3, linestyle='--')
plt.savefig('/workspace/scatter_correlation.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
散布図 — カテゴリ別の色分け(クラスタ)
fig, ax = plt.subplots(figsize=(8, 6))
for i, label in enumerate(sorted(df["cluster"].unique())):
mask = df["cluster"] == label
ax.scatter(df.loc[mask, "x"], df.loc[mask, "y"],
c=COLORS[i], label=f'Cluster {label}', s=40, alpha=0.7)
ax.set_xlabel('X', fontweight='bold')
ax.set_ylabel('Y', fontweight='bold')
ax.set_title('Cluster Visualization', fontweight='bold')
ax.legend()
ax.grid(True, alpha=0.3, linestyle='--')
plt.savefig('/workspace/scatter_clusters.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
ヒートマップ(相関行列または混同行列)
import seaborn as sns
fig, ax = plt.subplots(figsize=(8, 7))
# corr_matrix = to_pd(df[numeric_cols].corr())
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdBu_r', center=0,
square=True, linewidths=1, vmin=-1, vmax=1,
cbar_kws={'label': 'Correlation'}, ax=ax)
ax.set_title('Correlation Matrix', fontweight='bold')
plt.savefig('/workspace/heatmap.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
KDE 付きヒストグラム
fig, ax = plt.subplots(figsize=(8, 5))
ax.hist(df["value"], bins=30, color=COLORS[0], alpha=0.7,
edgecolor='black', linewidth=0.5, density=True, label='Distribution')
# Add KDE curve
from scipy.stats import gaussian_kde
kde = gaussian_kde(df["value"].dropna())
x_range = np.linspace(df["value"].min(), df["value"].max(), 200)
ax.plot(x_range, kde(x_range), color=COLORS[1], linewidth=2, label='KDE')
ax.set_xlabel('Value', fontweight='bold')
ax.set_ylabel('Density', fontweight='bold')
ax.set_title('Value Distribution', fontweight='bold')
ax.legend()
ax.grid(axis='y', alpha=0.3, linestyle='--')
plt.savefig('/workspace/histogram.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
箱ひげ図(グループの比較)
fig, ax = plt.subplots(figsize=(8, 5))
groups = [df[df["group"] == g]["value"].values for g in group_names]
bp = ax.boxplot(groups, labels=group_names, patch_artist=True,
widths=0.6, showmeans=True,
meanprops=dict(marker='D', markerfacecolor='red', markersize=6))
for i, patch in enumerate(bp['boxes']):
patch.set_facecolor(COLORS[i % len(COLORS)])
patch.set_alpha(0.7)
ax.set_ylabel('Value', fontweight='bold')
ax.set_title('Distribution by Group', fontweight='bold')
ax.grid(axis='y', alpha=0.3, linestyle='--')
ax.set_axisbelow(True)
plt.savefig('/workspace/boxplot.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
複数パネルの分析サマリー
複数のチャートを含む単一の画像を作成する際に使用します。分析全体を提示する最も効果的な方法です。
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# Top-left: Distribution
axes[0, 0].hist(df["value"], bins=30, color=COLORS[0], alpha=0.7, edgecolor='black', linewidth=0.5)
axes[0, 0].set_title('Value Distribution', fontweight='bold')
axes[0, 0].set_xlabel('Value')
axes[0, 0].grid(axis='y', alpha=0.3, linestyle='--')
# Top-right: Scatter
axes[0, 1].scatter(df["x"], df["y"], c=COLORS[0], s=30, alpha=0.5)
axes[0, 1].set_title('X vs Y', fontweight='bold')
axes[0, 1].set_xlabel('X')
axes[0, 1].set_ylabel('Y')
axes[0, 1].grid(True, alpha=0.3, linestyle='--')
# Bottom-left: Bar chart
group_means = df.groupby("category")["value"].mean()
axes[1, 0].bar(group_means.index, group_means.values, color=COLORS[:len(group_means)])
axes[1, 0].set_title('Mean by Category', fontweight='bold')
axes[1, 0].set_xlabel('Category')
axes[1, 0].grid(axis='y', alpha=0.3, linestyle='--')
# Bottom-right: Box plot
axes[1, 1].boxplot([df[df["category"] == c]["value"].values for c in categories],
labels=categories, patch_artist=True)
axes[1, 1].set_title('Distribution by Category', fontweight='bold')
axes[1, 1].grid(axis='y', alpha=0.3, linestyle='--')
fig.suptitle('Analysis Summary', fontsize=16, fontweight='bold')
plt.savefig('/workspace/analysis_summary.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
特徴量重要度チャート(cuML モデルから)
fig, ax = plt.subplots(figsize=(8, max(4, len(feature_names) * 0.35)))
# importances = to_pd(model.feature_importances_)
sorted_idx = np.argsort(importances)
ax.barh(np.array(feature_names)[sorted_idx], importances[sorted_idx],
color=COLORS[0], edgecolor='black', linewidth=0.5)
ax.set_xlabel('Importance', fontweight='bold')
ax.set_title('Feature Importances', fontweight='bold')
ax.grid(axis='x', alpha=0.3, linestyle='--')
ax.set_axisbelow(True)
plt.savefig('/workspace/feature_importance.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
混同行列(cuML の分類から)
import seaborn as sns
fig, ax = plt.subplots(figsize=(7, 6))
# cm = confusion_matrix(to_pd(y_test), to_pd(predictions))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', square=True,
xticklabels=class_names, yticklabels=class_names,
linewidths=1, cbar_kws={'label': 'Count'}, ax=ax)
ax.set_xlabel('Predicted', fontweight='bold')
ax.set_ylabel('Actual', fontweight='bold')
ax.set_title('Confusion Matrix', fontweight='bold')
plt.savefig('/workspace/confusion_matrix.png', dpi=300, bbox_inches='tight',
facecolor='white', edgecolor='none')
plt.close()
# IMPORTANT: call read_file("/workspace/<chart>.png") to display inline
スタイルルール
- 色覚に配慮した
COLORSパレットを使用し、要素の区別を色だけに頼らないでください - 円グラフは使用しないでください(棒グラフの方が常に明瞭です)
- 3D プロットは使用しないでください(データの見え方が歪みます)
alpha=0.3, linestyle='--'のグリッド線を使用し、ax.set_axisbelow(True)を設定してください- 軸ラベルとタイトルは太字にしてください(
fontweight='bold') - すべての出力の背景を白にしてください
- 1 回の分析で使用するチャートは通常 1~4 個です。それ以上の場合は複数パネルを使用してください
出力ガイドライン
- すべてのチャートを PNG として
/workspace/に保存してください - エージェントが参照できるよう、保存後にファイルパスを出力してください
- 複数パネルのサマリーでは、2×2 レイアウトに
figsize=(14, 10)を使用してください - チャートのタイトルは簡潔でありながら内容が分かるものにしてください
- 該当する場合は、軸ラベルに単位を含めてください
コメント
Markdown 対応