graphic-chart について
JSON または CSV のデータから PNG の可視化を作るスキルです。Playwright を介してヘッドレス Chromium 上で Apache ECharts を描画し、設定、スタイル、描画確認、書き出しまで扱います。
主な機能
- 01棒、折れ線、面、円、散布図、レーダー、ツリーマップに対応
- 02JSON 配列、オブジェクト配列、CSV の解析
- 035 種類のスタイルプリセット
- 04Apache ECharts と Playwright による HTML 描画
- 05デバイス倍率 2 倍で PNG を出力
活用シーン
- 01構造化データから静的なチャート画像を作成
- 02指定した値やカテゴリの強調
- 03指定スタイルとサイズでのチャート出力
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ varnan-tech/ opendirectory --skill graphic-chartインストール後、Claude Code で/graphic-chartを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdevals/evals.jsonreferences/chart-library.mdstyle-presets.mdscripts/export-chart.shscreenshot-chart.mjs詳細
graphic-chart
データを可視化したグラフを PNG として生成します。Playwright 経由でヘッドレス Chromium 上に Apache ECharts v6 を使用して HTML をレンダリングし、2×の Retina 品質でスクリーンショットを撮影します。
CDN: https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js
重要なルール(生成のたびに確認してください)
areaタイプ →type: 'line'+areaStyle: {}— ECharts にtype: 'area'はありません。doughnut→type: 'pie'+radius: ['40%', '70%']— ECharts にtype: 'doughnut'はありません。- 準備完了のシグナル:
chart.setOption()より前にchart.on('finished', fn)を登録する — ECharts のバグ #14101/#17500 により、リスナーを setOption の後に登録すると、イベントが何も通知されません。finishedとrenderedの両方のイベントを必ず setOption の前に登録してください。 xAxis.type: 'category'を明示する必要があります — ECharts はデータからこれを推測しません。指定し忘れると、グラフは空白になります。- カテゴリラベルは
data.labels配列ではなく、xAxis.dataに指定します。 ECharts の構造はフラットです:{ xAxis, yAxis, series, grid, title, legend }—dataやoptionsの下にネストする構造ではありません。 - データラベルは組み込み機能です — どの系列でも
label: { show: true }を使用してください。プラグインは不要です。 - 特定の棒やポイントを強調するには、項目ごとの
itemStyleを使用します —{ value: N, itemStyle: { color: '#...' } }をdata配列に直接指定してください。Chart.js 形式のbackgroundColor配列は使用しないでください。 - ECharts の初期化には
<canvas>ではなく<div>コンテナーを使用します —echarts.init(document.getElementById('chart'))。コンテナーの div には明示的な寸法が必要です。 - オプションで
animation: falseを指定します — アニメーションを無効にして、即座にレンダリングします。準備完了のシグナルを受け取るには、setOption の前にfinishedとrenderedのイベントを引き続き登録してください。 - HTML をチャットに出力しないでください。 ファイルに保存し、概要のみを表示してください。
- タイトルには主題ではなく、示唆する内容を記載します。 「月間売上」ではなく「売上は12か月で3倍に成長」。
- 円グラフ/ドーナツグラフ:
bodyのpadding: 64px 80pxと.chart-container { max-height: 860px }を使用します — タイトルがない場合に、グラフが端まで広がるのを防ぎます。
ステップ 1:情報の確認
必須: chart_type、data
任意のパラメーターとデフォルト値:
| パラメーター | デフォルト値 | 説明 |
|---|---|---|
| chart_type | — | bar / line / area / pie / doughnut / scatter / radar / treemap |
| data | — | JSON 配列または CSV — 必須 |
| title | — | 示唆する内容を記載。10語以内 |
| subtitle | — | 文脈を説明する1文 |
| style | clean-slate | clean-slate / midnight-editorial / matt-gray / electric-burst / brutalist |
| dimensions | 1080x1080 | 幅×高さのピクセル数(出力 PNG は deviceScaleFactor により2倍) |
| x_label | — | X 軸のラベルテキスト |
| y_label | — | Y 軸のラベルテキスト |
| source | — | フッターに表示するデータソース |
| highlight | — | 強調するデータラベル(例:「Q4」、「Dec」、インデックス 3) |
chart_type または data がない場合は、次のとおりに尋ねてください:
"グラフを作成するには、次の情報が必要です:
- グラフの種類 — bar / line / area / pie / doughnut / scatter / radar / treemap
- データ — JSON 配列または CSV で指定してください(例:ラベル
['Q1','Q2','Q3','Q4','Q5']を付けた[12, 18, 22, 25, 31])任意:タイトル、スタイル(デフォルト:clean-slate)、寸法(デフォルト:1080×1080)、強調するデータポイント"
両方が指定されている場合は、ステップ 2 に進んでください。
ステップ 2:内部アーキテクチャ(ユーザーには表示しません)
1. グラフの種類を正規化します:
area→line+ 系列にareaStyle: {}を指定doughnut→pie+ 系列にradius: ['40%', '70%']を指定horizontal bar→bar+ xAxis/yAxis を入れ替え(y 軸をカテゴリ軸にする)- それ以外:そのまま使用します
2. references/chart-library.md を読み込みます — このグラフの種類の設定仕様をすべて読み込みます。
3. references/style-presets.md を読み込みます — 選択したスタイルの CSS トークンとデータパレットを読み込みます。
4. デザインの方向性を決定します:
| 決定事項 | 判断基準 |
|---|---|
| トーン | プロフェッショナル/エディトリアル/大胆/技術的 — データの対象読者に合わせます |
| データのストーリー | このグラフが示す単一の洞察(タイトルになります) |
| 強調方法 | 視覚的に強調する必要があるデータポイントとその理由 |
| 背景 | 明るい(clean-slate、matt-gray)または暗い(midnight-editorial、electric-burst、brutalist) |
5. データを解析します:
- 単純な配列
[12, 18, 22]→ series.data に設定し、ラベルは別途指定します - オブジェクトの配列
[{x: 'Jan', y: 12}]→ x のキーを xAxis.data に、y の値を series.data に設定します - CSV:ヘッダー行を xAxis.data に、値の行を series.data に設定します
- 複数系列:それぞれ
type、name、dataを持つ複数のseriesエントリを使用します - 散布図:
series.data: [[x1,y1], [x2,y2], ...]の形式を使用します
6. 寸法を解析します: "1080x1080" → W=1080、H=1080。本文 = WxH。出力 PNG = 2W × 2H。
ステップ 3:HTML の生成
生成前にすべて読み込みます:
- このグラフの種類の ECharts 設定仕様全体については
references/chart-library.md - 選択したスタイルの CSS トークンとパレットについては
references/style-presets.md
必須の HTML 構造:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
[font CDN link from style preset]
<style>
:root {
[all CSS tokens from style preset]
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: [W]px; height: [H]px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
}
body {
display: flex;
flex-direction: column;
padding: 40px 48px 32px; /* pie/doughnut: use 64px 80px */
}
/* ECharts container must have explicit size */
.chart-container {
flex: 1;
min-height: 0;
/* pie/doughnut only: max-height: 860px; */
}
.chart-header { margin-bottom: 24px; }
.chart-title {
font-family: var(--font-display);
font-size: clamp(1.1rem, 2.5vw, 1.6rem);
font-weight: 700;
color: var(--text);
line-height: 1.2;
}
.chart-subtitle {
font-family: var(--font-body);
font-size: clamp(0.75rem, 1.2vw, 0.9rem);
color: var(--text-muted);
margin-top: 6px;
line-height: 1.5;
}
.chart-footer {
margin-top: 14px;
font-family: var(--font-body);
font-size: 10px;
color: var(--text-muted);
opacity: 0.65;
}
</style>
</head>
<body>
[if title or subtitle: <div class="chart-header"><div class="chart-title">...</div>...</div>]
<div id="chart" class="chart-container"></div>
[if source: <div class="chart-footer">Source: [source]</div>]
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script>
window.__chartReady = false;
document.fonts.ready.then(() => {
const container = document.getElementById('chart');
const chart = echarts.init(container, null, { renderer: 'canvas' });
// CRITICAL: register events BEFORE setOption — ECharts bug #14101/#17500
// 'finished' may silently not fire if registered after setOption with animation:false
chart.on('finished', () => {
window.__chartReady = true;
});
// Belt-and-suspenders fallback via 'rendered'
chart.on('rendered', () => {
clearTimeout(window.__renderDebounce);
window.__renderDebounce = setTimeout(() => { window.__chartReady = true; }, 100);
});
const palette = [palette from style preset];
const option = {
animation: false, // instant render for screenshot
backgroundColor: 'transparent', // body CSS handles bg color
textStyle: {
fontFamily: '[--font-body value]',
color: '[--text-muted value]',
},
[title config if title param provided],
[legend config per chart type],
[grid config per chart type],
[xAxis config per chart type],
[yAxis config per chart type],
series: [{
[full series config from chart-library.md for this type]
[palette colors applied per chart type]
[if highlight: per-item itemStyle on the highlighted data point]
}]
};
chart.setOption(option); // setOption ALWAYS comes after event registration
});
</script>
</body>
</html>
デザイン品質のルール:
- タイトルのフォント:
fontWeight: 'bold'、fontSize: 20–24— 細いタイトルは使用しません - グリッド線:不透明度を低く(0.06~0.10)し、データより目立たないようにします
- 棒:
barMaxWidth: 60、itemStyle.borderRadius: [4,4,0,0]で角を丸めます - 折れ線:自然な曲線には
smooth: true、ポイントにはsymbolSize: 8を指定します - 円グラフ/ドーナツグラフ:組み込みのスライス上ラベルには
label.formatter: '{b}\n{d}%'を指定します - 暗いプリセット:グリッドには
rgba(255,255,255,0.07)、軸線/目盛りの色にはrgba(255,255,255,0.15)を指定します - ツールチップ:静的 PNG ではホバー操作がないため、
show: falseを指定します - タイトルが指定されていない場合:
.chart-headerを省略し、ECharts のオプションからタイトルを省きます
ステップ 4:セルフ QA(ステップ 5 の前にすべての不備を修正します)
構造:
- コンテナが
<canvas>ではなく<div>である -
document.fonts.readyの前にwindow.__chartReady = falseが宣言されている -
chart.on('finished', ...)がchart.setOption()より前に登録されている -
chart.on('rendered', ...)のデバウンスフォールバックがchart.setOption()より前に登録されている - オプションオブジェクトに
animation: falseがある - 初期化ブロック内で
chart.setOption(option)が最後の呼び出しである
種類ごとの確認:
- エリア:
type: 'line'+areaStyle: {}—type: 'area'は使用しない - ドーナツ:
type: 'pie'+radius: ['40%', '70%']—type: 'doughnut'は使用しない - 棒グラフ:
xAxis.type: 'category'が明示的に設定されている - カテゴリデータが
data.labelsではなくxAxis.dataにある - 円グラフ/ドーナツグラフ:本文の
padding: 64px 80px+.chart-container { max-height: 860px } - 強調:データ配列内で、項目ごとに
{ value: N, itemStyle: { color } }を指定している
デザイン:
- パレットの色がすべて
references/style-presets.mdから選ばれている - タイトルが単なる題材ではなく、洞察を示している
-
tooltip: { show: false }が指定されているか、省略されている(静的 PNG ではホバー操作なし) - 暗いプリセット:グリッド/軸の色に
rgba(255,255,255,...)を使用している -
sourceパラメーターが指定されている場合、フッターに出典がある - データラベルが表示されている(系列に組み込みの
label: { show: true }を指定)
ステップ 5:エクスポート
タイトル、またはグラフの種類とデータの文脈からスラッグを決定します(ケバブケース、30 文字以内):
mkdir -p chart/[slug]
HTML を保存します:chart/[slug]/chart.html
ブラウザーで簡易確認します:
open chart/[slug]/chart.html
エクスポートを実行します([skill-root] をこのスキルのディレクトリの実際のパスに置き換えます):
bash [skill-root]/scripts/export-chart.sh \
chart/[slug]/chart.html \
chart/[slug]/chart.png \
--width [W] \
--height [H]
初回実行時にスクリプトが Playwright をインストールし(Chromium を約 200MB ダウンロード)、その後 deviceScaleFactor: 2 でグラフをキャプチャします。
ステップ 6:出力の概要
## Chart: [title]
Date: [YYYY-MM-DD] | Type: [chart_type] | Style: [style]
Dimensions: [W×H]px → PNG: [2W×2H]px @2× retina
Files
Source: chart/[slug]/chart.html
Output: chart/[slug]/chart.png
Size: [X] KB
Checklist
- [ ] Title states the insight clearly
- [ ] Data labels legible at display size
- [ ] Highlight visible on correct data point
- [ ] Source attribution present in footer
プロンプトのヒント(ユーザーがガイダンスを求めたときに表示)
「説明文ではなく、JSON や CSV などの構造化データを指定してください。」
「グラフの種類を明示してください。『四半期を示すグラフ』ではなく、『第1四半期〜第4四半期を比較する棒グラフ』のように指定してください。」
「データが伝えるストーリーを指定してください。『他のすべてを上回った第4四半期を強調する』と指定すれば、注釈の文脈が明確になります。」
✅ 良い例:「折れ線グラフを作成してください。タイトル:『12か月でARRが1.2万ドルから9.5万ドルに』。データ:[12, 18, 22, 25, 31, 38, 44, 52, 61, 68, 78, 95](2024年1月〜12月)。12月を強調してください。出典:社内CRM。スタイル:electric-burst。」
❌ 悪い例:「当社の成長についてグラフを作成して」