Claude CodeでD3.jsのチャートを作り、描画をブラウザで確かめる
D3.jsの棒グラフをClaude Codeに書かせ、Chrome連携でSVGの描画とコンソールのエラーを読ませて直す反復を、scale・axis・data joinの骨格と指示文の例でまとめます。
D3.jsのチャートをClaude Codeに書かせるとき、コードが生成できたかどうかは完了の条件になりません。D3は数値をSVGの属性に変換するライブラリなので、間違いは実行時の属性値に出ます。ブラウザで描かれた結果を、Claudeが自分の目で見られる形にしておくのが要点です。
この記事では、棒グラフを題材に、scale・axis・data joinの骨格をClaudeに書かせる指示、Chrome連携で描画とコンソールを読ませる手順、壊れ方の実例、そして反復をCLAUDE.mdに固定する書き方を扱います。
D3のチャートは「描けた」をどこで判定するか
D3のコードは、型エラーやビルドエラーでは失敗しません。スケールに存在しないキーを渡すと、属性が黙って消えます。selection.attrがundefinedを受け取ると属性を削除するためで、画面には何も出ず、例外も出ません。
この種の失敗は、描画後のDOMを読むか、画面を見て初めて分かります。Claude Codeには、それを任せられる道具があります。Chrome連携を有効にすると、Claudeは新しいタブで開いたページのコンソールエラーとDOMの状態を直接読み、原因のコードを直せます。ローカルで動いているWebアプリを開いて操作させる使い方も、Chrome連携の基本の使い方です。
Chrome連携を前提にした反復は、D3のように「実行してみないと崩れ方が分からない」ライブラリと相性が良い構成です。本記事の流れは次の4段です。
D3チャートの反復
- 1
骨格を書かせる
scale・axis・data joinを、データの形とグラフの大きさを指定して書かせます。
- 2
ローカルサーバーで開かせる
生成したHTMLをlocalhostで配信し、Chromeのタブで開かせます。
- 3
描画とコンソールを読ませる
SVGの要素数、属性値、コンソールのエラーを確認させます。
- 4
直して再読み込みする
原因を特定して直し、同じ確認をもう一度回します。
Chrome連携の前提 — 使えない構成を先に潰す
Chrome連携は、Claude CodeとChromeの拡張機能(Claude in Chrome)を組み合わせて動きます。準備の条件は次のとおりです。
- Google ChromeかMicrosoft Edge、またはBrave・Arc・Vivaldi・Operaなど別のChromium系ブラウザ
- Claude in Chrome拡張のバージョン1.0.36以降
- 直接契約のAnthropicプラン(Pro、Max、Team、Enterprise)
/loginでのサインイン
使えない構成もあります。APIキーやclaude setup-tokenで発行した長期トークンで認証している場合、--chromeを付けてもChrome連携はオフのままです。Amazon BedrockやGoogle Cloud、Microsoft Foundryのようなサードパーティ経由でしかClaudeに接続していない場合も使えません。WSL(Windows Subsystem for Linux)でも未対応です。
準備ができたら、CLIでは--chromeを付けて起動します。
claude --chrome初回は導入のダイアログが出るので、Enterで進めます。接続状態は、セッション内で/chromeを実行すると確認できます。ステータスパネルに「Status: Enabled」と「Extension: Installed」が出ていれば接続済みです。毎回フラグを付けたくない場合は、/chromeで「Enabled by default」を選びます。ただしブラウザ用のツールと説明が常にコンテキストへ載るので、コンテキストの消費が増えます。D3のチャートを描くときだけ使うなら、フラグ付きの起動が無難です。
サイトごとの権限は、Chrome拡張側の設定を引き継ぎます。Claudeが操作できるサイトを絞りたいときは、拡張の設定で調整します。ローカルのチャート確認だけなら、localhost以外を許可する必要はありません。
最初にClaudeへ渡す指示 — 題材と完了条件を一緒に書く
骨格を書かせる指示には、題材のデータ、グラフの形、そして「何を見たら完了か」を含めます。完了条件を書かないと、Claudeは生成しただけで終わりにしがちです。
index.html に、D3.js v7 で月別の売上の棒グラフを作ってください。
- D3は https://cdn.jsdelivr.net/npm/d3@7/+esm から ES モジュールで読み込む
- データは [{month: "Jul", value: 120}, ...] の配列。4か月分
- x軸は scaleBand、y軸は scaleLinear で0始まり。軸は axisBottom と axisLeft
- 棒は selectAll("rect").data(data).join("rect") で描く
- 完了条件: python3 -m http.server 8000 で配信し、Chromeで
localhost:8000 を開いて、rect が4本あり、各 rect の
x・y・width・height が数値であること、コンソールにエラーが
ないことを確認してから報告するD3のバージョンと書き方を指定しているのは、書き方の流儀を揃えるためです。selection.joinは、enter・exit・append・remove・orderをまとめて置き換える書き方で、D3のドキュメントでは明示的なenter・exitの連鎖に代わる手軽な方法として説明されています。
scale・axis・data joinの骨格
Claudeが書く棒グラフの骨格は、概ね次の形になります。D3の公式の入門ページにある余白変数(marginTopなど)とスケール・軸の組み立てを土台に、棒の部分を足した例です。
<!DOCTYPE html>
<div id="container"></div>
<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
const data = [
{month: "Jul", value: 120}, {month: "Aug", value: 180},
{month: "Sep", value: 150}, {month: "Oct", value: 210},
];
const width = 640, height = 400;
const marginTop = 20, marginRight = 20, marginBottom = 30, marginLeft = 40;
const x = d3.scaleBand()
.domain(data.map(d => d.month))
.range([marginLeft, width - marginRight])
.padding(0.2);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)]).nice()
.range([height - marginBottom, marginTop]);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
svg.append("g").attr("fill", "steelblue")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", d => x(d.month))
.attr("y", d => y(d.value))
.attr("width", x.bandwidth())
.attr("height", d => y(0) - y(d.value));
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
container.append(svg.node());
// 描画後の自己点検: 属性が数値でない rect があればコンソールに出す
for (const r of svg.selectAll("rect").nodes()) {
for (const a of ["x", "y", "width", "height"]) {
if (!Number.isFinite(+r.getAttribute(a))) {
console.error(`rect の ${a} が数値ではありません:`, r.getAttribute(a));
}
}
}
</script>読みどころは3つあります。
- yの
rangeが逆順: SVGは上が0なので、[height - marginBottom, marginTop]と下から上へ並べます。順序を間違えると、棒が天井から垂れ下がる絵になります - 棒の高さは
y(0) - y(d.value): 値の大きさを、基準線までのピクセル距離として計算します - 末尾の自己点検: 属性が数値でない
rectをコンソールに出します。Claudeはコンソールを読めるので、「見た目が変」という曖昧な症状を、検索できるメッセージに変えておく仕掛けです
CDNから読むESM版は、D3の入門ページが推奨している読み込み方です。オフラインで動かす場合は、UMD版をダウンロードしてローカルから読む方法もあります。npmで導入するならnpm install d3で、import * as d3 from "d3"の形で読み込めます。
描画結果をClaudeに確かめさせる
HTMLができたら、配信から確認までを1つの指示で回させます。
python3 -m http.server 8000Claude Codeのセッション内では、次のように頼みます。Chrome連携の使用例にあるローカルアプリの確認と、コンソールの読み取りを合わせた形です。
localhost:8000 を開いて、次を確認して。
1. svg の中の rect が何本あるか、それぞれの x・y・width・height
2. 軸の目盛りのラベル(x軸とy軸)
3. コンソールにエラーが出ていないか。出ていれば内容を教えて
問題があれば index.html を直して、再読み込みして同じ確認をして。コンソールについては、「全部出して」ではなく、見てほしいパターンや種別を伝えるのが公式の推奨です。ログは冗長になりやすく、無関係な警告が文脈を圧迫するためです。自己点検のメッセージに固有の文言を入れておくと、「rect のを含む行だけ読んで」と頼めます。
見た目そのものを残したい場合は、スクリーンショットをファイルに保存させる頼み方があります。
localhost:8000 のスクリーンショットを撮ってディスクに保存して保存先のパスはClaudeが報告します。修正の前後でスクリーンショットを撮らせておくと、棒の高さや軸の位置が変わったことを後から見比べられます。操作の流れを見せたい場合は、GIFの記録も頼めます。ただしGIFは画面に見えているもの全部を撮るので、ログイン済みのページを映したときは共有前に中身を確かめます。
壊したときに何が見えるか — 属性が消える実例
D3の失敗は、思ったより静かに起きます。実際に確かめた結果を示します。上のコードを、D3 7.9.0とjsdom 24(Node.js 20上のDOM実装)で実行しました。ブラウザではなくjsdomなので、描画そのものではなくDOMの属性値を読んでいます。
正しいデータでは、4本のrectの属性は次のようになりました(小数は丸めています)。
| 月 | x | y | width | height |
|---|---|---|---|---|
| Jul | x67.6 | y179.1 | width110.5 | height190.9 |
| Aug | x205.7 | y83.6 | width110.5 | height286.4 |
| Sep | x343.8 | y131.4 | width110.5 | height238.6 |
| Oct | x481.9 | y35.9 | width110.5 | height334.1 |
次に、データのキー名を間違えた状態を作りました。y(d.value)のところを、存在しないd.countに変えたものです。
| 月 | x | y | width | height |
|---|---|---|---|---|
| Jul〜Oct(4本とも) | x数値 | y属性なし | width110.5 | heightNaN |
y属性は空になり、heightはNaNになりました。y(undefined)がundefinedを返し、attrが属性を取り除き、y(0) - undefinedがNaNになるためです。ブラウザで開くと、棒は1本も表示されません。軸の目盛りは正しく出るので、「軸はあるのに棒だけ無い」という症状になります。
この症状は、コードを眺めるだけでは見つけにくい部類です。DOMを読めばrectの属性が欠けていると分かり、自己点検を仕込んでおけばコンソールに文言が出ます。Claudeに「rectは4本あるのに高さがNaN」と観察させれば、原因をd.countとd.valueの食い違いに絞り込めます。
同じ型の落とし穴は、バンドスケールにもあります。scaleBandは、定義域に無い値を渡されるとundefinedを返します。月名の綴りがデータと軸で食い違うと、その棒だけxが消えます。
落とし穴
一部の棒だけ消えるのは、キーが定義域に無いから
scaleBandに渡すキーがdomainに含まれないと、スケールはundefinedを返します。表記ゆれ(SeptとSepなど)や、domainの作り忘れが原因です。Claudeに「rectの数とデータの件数が一致するか」を毎回数えさせると早く見つかります。
反復をCLAUDE.mdに固定する
毎回指示文に確認項目を書くより、CLAUDE.mdに置いておくほうが安定します。D3のチャートを頻繁に触るリポジトリなら、次のような断片が使えます。
## D3.js チャート規約
- D3 は v7 の ES モジュール版(jsdelivr)を使う。selection.join を使い、
enter().append() の連鎖は書かない
- チャートを変更したら、python3 -m http.server 8000 で配信し、
Chrome 連携で localhost:8000 を開いて以下を確認してから完了とする
- 描画された rect/circle/path の数がデータの件数と一致する
- 位置・サイズの属性に NaN や未設定がない
- コンソールにエラーがない
- 確認の結果は、数と属性値を添えて報告する(「問題ありません」だけで終えない)
- チャートの末尾には、属性が数値でない要素を console.error する点検を残す「数と属性値を添えて報告する」の一文が効きます。Claudeに「確認しました」とだけ言わせると、実際には見ていなくても同じ文面になります。rectの本数や属性値を書かせれば、見たかどうかが読み取れます。
つまずいたとき
Chrome連携側で起きやすい問題と、公式の切り分けの要点です。
- 拡張機能が検出されない:
chrome://extensionsで拡張が有効かを確かめ、Chromeが起動しているかを見ます。/chromeの「Reconnect extension」で再接続し、それでも駄目なら、Claude CodeとChromeの両方を再起動します。初回に設定ファイルを入れるため、Chromeの再起動が要ることもあります - ブラウザが反応しなくなる:
alertなどのJavaScriptダイアログが出ていると、ブラウザのイベントが止まります。ダイアログを手で閉じてから、続けるようClaudeに伝えます。チャートのコードにalertを入れないのが一番の予防です - 長いセッションで接続が切れる: 拡張のservice workerが待機状態になると接続が切れます。
/chromeから「Reconnect extension」を選びます - プロジェクトの設定でChromeを有効にしても無視される: プロジェクトの
.claude/settings.jsonにCLAUDE_CODE_ENABLE_CFCを書いても、Claude Codeは適用しません。チェックアウトしたリポジトリがブラウザへ勝手につながらないようにするためです。--chromeか/chromeで自分で有効にします - ログインやCAPTCHAの画面: Claudeはそこで止まり、手動での対応を求めます。チャート単体の確認では出ませんが、認証付きのダッシュボードにD3を組み込んでいる場合は起こります
ブラウザの操作をClaude in Chrome以外で行いたい場合は、Stagehandをつなぐ方法がStagehand MCPの手順にあります。Claude Code Desktopなら内蔵ブラウザで外部サイトを操作する方法も選べます。
Reactで使うときの分担
Reactの中でD3を使う場合は、D3の入門ページに書かれた分担が参考になります。d3-scale・d3-array・d3-interpolate・d3-formatのようにDOMに触れないモジュールは、Reactでもそのまま使えます。つまり、スケールの計算はD3に任せ、SVG要素の生成はJSXに任せる構成です。
この構成では、Claudeに渡す確認項目は変わりません。描画後のDOMにrectが期待どおりの数だけあり、属性が数値であることを、Chromeで読ませます。コード側の責任が分かれても、検証はDOMの結果に対して行います。
チャートの配色や形式の選定まで任せたい場合
ここまでの流れは、すでに形が決まったチャートを正しく描かせる話でした。グラフの種類の選び方や配色の検証まで任せたいときは、datavizスキルの使い方が補います。配色の検証をスクリプトで回す仕組みがあります。
また、描画結果をブラウザで読ませる反復は、WebAssemblyの成果物をヘッドレスブラウザで検証する流れとも共通します。RustのWebAssemblyを作る手順では、同じ考え方をテストコマンドとStop hookで固定しています。
まとめ
D3のチャートは、生成できたことよりも、ブラウザで描かれた結果で判定します。rectの本数、位置と大きさの属性、コンソールのエラーを、完了条件として指示とCLAUDE.mdに書いておくと、Claudeは直して再確認するところまで自走します。
壊れ方が静かなぶん、自己点検をチャートの末尾に1か所置いておく価値があります。属性が数値でない要素をコンソールに出すだけで、「棒だけ無い」という症状が検索できるメッセージに変わります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。