D3.jsはSVGを使って高度なビジュアル化を行うライブラリです。
グラフに限らず、様々なチャートやビジュアルの表現ができますが、複雑な仕組みを覚えなければなりません。他のグラフライブラリなどではCSVデータを適用するだけというものもありますが、D3.jsはそこまで簡単ではありません。
今回はD3.jsで折れ線グラフ(Line Chart)を描画してみる | Will Style Inc.|神戸にあるウェブ制作会社を参考に、なるべく段階を区切ってD3.jsの使い方を解説します。
インストール
インストールはMonaca IDEのJS/CSSライブラリの管理でD3を検索するか、index.htmlに次の記述を行います。
1 2 |
<script src="https://d3js.org/d3.v5.min.js"></script> |
HTML側での準備
HTMLは body
タグ内に次の記述を行います。グラフの大きさはスタイルシートで調整してください。
1 2 3 4 5 6 7 8 9 10 11 |
<div id="chart--wrapper"></div> <style> #chart--wrapper { height: 300px; } #chart--wrapper svg { width: 100%; height: 100%; } </style> |
今回はCSVのパース用ライブラリと、JavaScriptを記述するファイルを追加しています。
1 2 3 4 5 |
<!-- CSV解析ライブラリ --> <script src="https://unpkg.com/papaparse@5.2.0/papaparse.min.js"></script> <!-- アプリケーション用コード --> <script src="js/app.js"></script> |
JavaScriptについて
www/js/app.js
の内容について解説します。
今回は塗りつぶしまで行ってみます。段階としては次のように分かれます。
D3.js用のDOM取得、については大して説明はいらないでしょう。D3.jsではjQueryのような形でDOMコンテンツを取得したり、作成できます。ここでは先ほどbodyタグ内に記述した #chart--wrapper
の取得と、その中に svg タグを記述しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// コンテンツが読み終わったら実行 document.addEventListener('DOMContentLoaded', async (e) => { // D3.js用のDOM取得 const contents = d3.select('#chart--wrapper'); const svg = contents.append("svg"); // 1. データを取得 const data = await getData(); // 2. データを整形する const dataset = filterData(data.data); // 3. グラフの枠を準備する const scale = setupGraph(contents, svg, dataset); // 4. 折れ線グラフを描画 const color = d3.rgb("#a785cc"); drawLine(svg, dataset, scale, color); // 5. 塗りつぶし drawFill(svg, dataset, scale, color); }); |
1. データを取得
次は、データの取得を行う getData 関数についての解説です。
今回は機械学習によく使われるAAPL.CSVを使っています。このファイルは様々な場所で見かけますが、GitHubからダウンロードもできます。これを www/data/aapl.csv
として保存します。
このデータを取得し、CSV解析ライブラリでテキストデータから配列に変換します。このステップは外部のWeb APIなどからデータを取得する場合には不要でしょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
async function getData() { return new Promise((res, rej) => { Papa.parse('./data/aapl.csv', { download: true, header: true, delimiter: ',', complete: res, error: rej }); }) } |
このデータの概要は以下のようになっています。日付が Date カラムに入っており、Open/Close/High/Lowというデータがあります。

2. データを整形する
次にデータを整形します。
日付は YYYY-MM-DD
という形式になっていますので d3.timeParse
を使って変換します。さらに値もCSVで解析したままでは文字列なので parseFloat
を使って数値にします。そしてデータの中に日付が入っていない不正なものも含まれていたので、filterを使って除外しています。
1 2 3 4 5 6 7 8 9 10 11 |
function filterData(data) { const timeparser = d3.timeParse("%Y-%m-%d"); return data.map(d => { return { date: timeparser(d.Date), value: parseFloat(d.Open) }; }) .filter(d => d.date != null); // 不要なデータを除外 } |
この下準備でD3.jsで使えるデータになります。
3. グラフの枠を準備する
D3.jsではデータを渡せば後は勝手に表示してくれるという訳ではありません。まずSVGを用意したのと同様に、グラフを描画する枠を準備します。これはもちろんX軸、Y軸の二つがあります。各コードの内容はコメントを参考にしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
function setupGraph(contents, svg, dataset) { const padding = 30; // グラフの幅(X軸) const width = contents.node().clientWidth - padding; // グラフの高さ(Y軸) const height = contents.node().clientHeight - padding; // gはグループです。SVGで他の要素をグループ化する際に利用するタグです // グループをXとY、両方に追加します。 x = svg .append("g") .attr("class", "axis axis-x") y = svg .append("g") .attr("class", "axis axis-y") // X軸に関する設定です const xScale = d3 // 時間ベースの軸であることを定義します .scaleTime() // 最低値、最大値の設定です .domain([ d3.min(dataset.map(d => d.date)), // 日付の配列を渡せば、d3.minで最小値を出してくれます d3.max(dataset.map(d => d.date)) // 日付の配列を渡せば、d3.maxで最大値を出してくれます ]) // 大きさを指定します .range([padding, width]); // Y軸に関する設定です const yScale = d3 // 数値ベースの軸であることを定義します .scaleLinear() // 最低値、最大値の設定です .domain([ 0, d3.max(dataset.map(d => d.value)) // 値の配列を渡せば、d3.maxで最大値を出してくれます ]) // 大きさを指定します .range([height, padding]); // 表示する際のフォーマットです(YYYY/MMという表示です) const format = d3.timeFormat("%Y/%m"); // X軸の値の個数です const xTicks = 6; // X軸の記述設定です const axisx = d3 .axisBottom(xScale) .ticks(xTicks) .tickFormat(format); // Y軸の記述設定です const axisy = d3.axisLeft(yScale); // SVGに描画します x .attr("transform", "translate(" + 0 + "," + (height) + ")") .call(axisx); y .attr("transform", "translate(" + padding + "," + 0 + ")") .call(axisy); // xScale/yScaleはこの後も使うので返却します return {x: xScale, y: yScale}; } |
この結果として、グラフの枠だけが表示されます。

4. 折れ線グラフを描画
グラフの枠はできあがったので、値を折れ線グラフとして描画していきます。ここは先ほどのグラフ枠の生成に比べるとシンプルです。こちらもコードはコメントを参考にしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function drawLine(svg, dataset, scale, color) { // pathはSVGで図形を描画する汎用的な要素です const path = svg.append("path"); // 折れ線を生成します const line = d3 .line() .x(d => scale.x(d.date)) .y(d => scale.y(d.value)); // SVG上に描画します。colorは引数で受け取っている、色の指定です path .datum(dataset) .attr("fill", "none") .attr("stroke", color) .attr("d", line); } |
これで折れ線グラフが描画できました。

5. 塗りつぶし
最後にグラデーションを使った塗りつぶしを行ってみます。これは、上が線と同じ色、下は白とグラデーションで表示する方法です。見ると分かりますが、上半分はSVGに関する記述になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
function drawFill(svg, dataset, scale, color) { // SVGのpathを用意 const lineArea = svg.append("path"); // SVGのグループも用意 const g = svg.append("g"); // defsはSVGの描画オブジェクトを定義し、再利用できるようにします // 今回であればlinearGradient(塗りをサポートした要素)がそうです const linearGradient = svg .append("defs") .append("linearGradient") // attrはjQueryのように要素を追加します .attr("id", "linear-gradient") .attr("gradientTransform", "rotate(90)"); // 上の色を定義します // stopはSVGのグラデーションを決める要素です linearGradient .append("stop") .attr("offset", "40%") .attr("stop-color",color.brighter(0.5)); // 下の色を定義します linearGradient .append("stop") .attr("offset", "60%") .attr("stop-color",color.brighter(1.7)); // ここからD3.jsの記述です // 線を描く際には line でしたが、今回は area で塗りつぶしを指定します const area = d3 .area() .x(d => scale.x(d.date)) .y1(d => scale.y(d.value)) .y0(scale.y(0)) // curveCatmullRomは曲線を描くためのアルゴリズムです .curve(d3.curveCatmullRom.alpha(0.4)); // SVGに描画します lineArea .datum(dataset) .attr("d",area) .style("fill", "url(#linear-gradient)"); } |
このようにすると、グラフにグラデーションをかけられます。

まとめ
D3.jsを使いこなす上で大事なのはSVGを把握することです。D3.jsによってSVGが幾分使いやすくなっていますが、それでも基本的なSVGを分かっていないとどう使っていいかも分からないでしょう。そしてSVGのセットアップができたら、D3.jsのオブジェクトを作成し、SVGとD3.jsオブジェクトをミックスして描画するといった形です。
基本的にSVGなので、JavaScriptとの親和性は高く、マウスオーバーでツールチップを出したり(スマートフォンでは難しそうですが)、アニメーションを追加することもできます。使いこなせば、かなり高度なグラフィックス表現に使えますので、ぜひトライしてみてください。