Vue.jsとSVGでグラフをかいてみる
2019.05.14

こんにちは、千田です。
GWはみなさん楽しめましたか?
千田は帰省したり、もうすぐ4歳になる娘の最初の反抗期が来てしまってそれと戦ってたり、
1歳の息子に携帯を水没させられたり(なんでそうなったかは察して下さい。。。)
とバタバタやってたら、あっという間に終わった感じでした。
さて、今回ですがSVGを使ってWebブラウザ上でグラフをかいてみようと思います。
javascriptを使ってグラフをかく場合、D3.jsやChart.jsなどライブラリは色々とありますが、
フレームワークとの相性が悪かったり、そこまで機能が豊富じゃなくていいんだよなーって時におすすめです。
今回やること
- 棒グラフをかく
- 散布図(分布図)をかく
- 折れ線グラフをかく
- Vue.jsと組み合わせて棒グラフをかく
グラフをかいてみる前にSVGとは?といった点についても軽く触れておきたいと思います。
SVGとは?
Scalable Vector Graphicsの略です。以下、Wikipediaより。
XMLベースの、2次元ベクターイメージ用の画像形式の1つである。ベクタ形式であるため、拡縮自在である。その他に、XMLベースの為、ウェブブラウザで(画像として、という意味ではなく、HTMLのソースビュー等と同様に、という意味で)閲覧でき、テキストエディタ等で編集できる。また、HTMLとの親和性により、ハイパーリンクを埋め込んだり、JavaScript 等と連携させることもできる。
要するにテキストエディタで画像や図がかけて、且つそれは拡大縮小が自在な画像形式だよってことですね。
では、早速かいていきます。最初は棒グラフから。
棒グラフをかく
viewboxの指定
まず、最初にviewboxのサイズを指定します。viewboxの詳しい説明はこちらのサイトに記載がありました。
<svg viewbox="0 0 400 450" width="400" height="450">
周りの罫線の指定
サイズが決まったら、とりあえずグラフの表示範囲を線で囲みます。
線を引く時は<line>タグを使用します。
<g stroke="black" stroke-width="1">
<line x1="40" y1="0" x2="40" y2="400"></line>
<line x1="40" y1="0" x2="380" y2="0"></line>
<line x1="380" y1="0" x2="380" y2="400"></line>
<line x1="40" y1="400" x2="380" y2="400"></line>
</g>
目盛り表示
グラフなので、目盛りが必要ですね。
テキストを表示する時は<text>タグを使用します。
縦の目盛り
<g>
<text x="0" y="400">0</text>
<text x="0" y="350">50</text>
<text x="0" y="300">100</text>
<text x="0" y="250">150</text>
<text x="0" y="200">200</text>
<text x="0" y="150">250</text>
<text x="0" y="100">300</text>
<text x="0" y="50">350</text>
</g>
横の目盛り
<g>
<text x="60" y="425">1月</text>
<text x="120" y="425">2月</text>
<text x="180" y="425">3月</text>
<text x="240" y="425">4月</text>
<text x="300" y="425">5月</text>
</g>
データの表示
枠ができたら表示するデータを記述します。
棒グラフは四角形(長方形)の表示になるので<rect>タグを使用します。
<g>
<rect x="60" y="350" fill="blue" width="40" height="50" />
<rect x="120" y="290" fill="red" width="40" height="110" />
<rect x="180" y="230" fill="yellow" width="40" height="170" />
<rect x="240" y="200" fill="green" width="40" height="200" />
<rect x="300" y="20" fill="black" width="40" height="380" />
</g>
棒グラフの全体のコードはこんな感じです。
<svg viewbox="0 0 400 450" width="400" height="450">
<!-- 罫線 -->
<g stroke="black" stroke-width="1">
<line x1="40" y1="0" x2="40" y2="400"></line>
<line x1="40" y1="0" x2="380" y2="0"></line>
<line x1="380" y1="0" x2="380" y2="400"></line>
<line x1="40" y1="400" x2="380" y2="400"></line>
</g>
<!-- 縦の目盛り -->
<g>
<text x="0" y="400">0</text>
<text x="0" y="350">50</text>
<text x="0" y="300">100</text>
<text x="0" y="250">150</text>
<text x="0" y="200">200</text>
<text x="0" y="150">250</text>
<text x="0" y="100">300</text>
<text x="0" y="50">350</text>
</g>
<!-- 横の目盛り -->
<g>
<text x="60" y="425">1月</text>
<text x="120" y="425">2月</text>
<text x="180" y="425">3月</text>
<text x="240" y="425">4月</text>
<text x="300" y="425">5月</text>
</g>
<!-- グラフ -->
<g>
<rect x="60" y="350" fill="blue" width="40" height="50" />
<rect x="120" y="290" fill="red" width="40" height="110" />
<rect x="180" y="230" fill="yellow" width="40" height="170" />
<rect x="240" y="200" fill="green" width="40" height="200" />
<rect x="300" y="20" fill="black" width="40" height="380" />
</g>
</svg>

散布図(分布図)をかく
では、次は散布図(分布図)を書いてみようと思います。
棒グラフでなんとなくの感覚は掴んでいただいたと思うので、ここからはちょっと手短に。
罫線や目盛り
<svg viewbox="0 0 400 450" width="400" height="400">
<!-- 罫線 -->
<g stroke="black" stroke-width="1">
<!-- 枠線 -->
<line x1="40" y1="0" x2="40" y2="350"></line>
<line x1="40" y1="0" x2="400" y2="0"></line>
<line x1="400" y1="0" x2="400" y2="350"></line>
<line x1="40" y1="350" x2="400" y2="350"></line>
<!-- 縦線 -->
<line x1="100" y1="0" x2="100" y2="350"></line>
<line x1="160" y1="0" x2="160" y2="350"></line>
<line x1="220" y1="0" x2="220" y2="350"></line>
<line x1="280" y1="0" x2="280" y2="350"></line>
<line x1="340" y1="0" x2="340" y2="350"></line>
<!-- 横線 -->
<line x1="40" y1="50" x2="400" y2="50"></line>
<line x1="40" y1="100" x2="400" y2="100"></line>
<line x1="40" y1="150" x2="400" y2="150"></line>
<line x1="40" y1="200" x2="400" y2="200"></line>
<line x1="40" y1="250" x2="400" y2="250"></line>
<line x1="40" y1="300" x2="400" y2="300"></line>
</g>
<!-- 縦の目盛り -->
<g>
<text x="0" y="350">0</text>
<text x="0" y="300">50</text>
<text x="0" y="250">100</text>
<text x="0" y="200">150</text>
<text x="0" y="150">200</text>
<text x="0" y="100">250</text>
<text x="0" y="50">300</text>
</g>
<!-- 横の目盛り -->
<g>
<text x="60" y="380">10</text>
<text x="120" y="380">20</text>
<text x="180" y="380">30</text>
<text x="240" y="380">40</text>
<text x="300" y="380">50</text>
<text x="360" y="380">60</text>
</g>
</svg>
データの表示
棒グラフと同様に四角形をかきます。正方形の場合はwidthとheightに同じ値を指定します。
<g>
<rect x="120" y="50" fill="blue" width="10" height="10" />
<rect x="180" y="230" fill="blue" width="10" height="10" />
<rect x="240" y="200" fill="blue" width="10" height="10" />
<rect x="330" y="15" fill="blue" width="10" height="10" />
<rect x="250" y="50" fill="blue" width="10" height="10" />
<rect x="350" y="123" fill="blue" width="10" height="10" />
<rect x="159" y="235" fill="blue" width="10" height="10" />
<rect x="210" y="208" fill="blue" width="10" height="10" />
<rect x="180" y="290" fill="blue" width="10" height="10" />
<rect x="280" y="230" fill="blue" width="10" height="10" />
<rect x="50" y="120" fill="blue" width="10" height="10" />
<rect x="360" y="130" fill="blue" width="10" height="10" />
<rect x="70" y="190" fill="blue" width="10" height="10" />
<rect x="150" y="250" fill="blue" width="10" height="10" />
<rect x="180" y="150" fill="blue" width="10" height="10" />
<rect x="230" y="90" fill="blue" width="10" height="10" />
<rect x="50" y="300" fill="blue" width="10" height="10" />
<rect x="80" y="310" fill="blue" width="10" height="10" />
<rect x="90" y="320" fill="blue" width="10" height="10" />
</g>
散布図の全体のコードはこんな感じです。
<svg viewbox="0 0 400 450" width="400" height="400">
<!-- 罫線 -->
<g stroke="black" stroke-width="1">
<!-- 枠線 -->
<line x1="40" y1="0" x2="40" y2="350"></line>
<line x1="40" y1="0" x2="400" y2="0"></line>
<line x1="400" y1="0" x2="400" y2="350"></line>
<line x1="40" y1="350" x2="400" y2="350"></line>
<!-- 縦線 -->
<line x1="100" y1="0" x2="100" y2="350"></line>
<line x1="160" y1="0" x2="160" y2="350"></line>
<line x1="220" y1="0" x2="220" y2="350"></line>
<line x1="280" y1="0" x2="280" y2="350"></line>
<line x1="340" y1="0" x2="340" y2="350"></line>
<!-- 横線 -->
<line x1="40" y1="50" x2="400" y2="50"></line>
<line x1="40" y1="100" x2="400" y2="100"></line>
<line x1="40" y1="150" x2="400" y2="150"></line>
<line x1="40" y1="200" x2="400" y2="200"></line>
<line x1="40" y1="250" x2="400" y2="250"></line>
<line x1="40" y1="300" x2="400" y2="300"></line>
</g>
<!-- 縦の目盛り -->
<g>
<text x="0" y="350">0</text>
<text x="0" y="300">50</text>
<text x="0" y="250">100</text>
<text x="0" y="200">150</text>
<text x="0" y="150">200</text>
<text x="0" y="100">250</text>
<text x="0" y="50">300</text>
</g>
<!-- 横の目盛り -->
<g>
<text x="60" y="380">10</text>
<text x="120" y="380">20</text>
<text x="180" y="380">30</text>
<text x="240" y="380">40</text>
<text x="300" y="380">50</text>
<text x="360" y="380">60</text>
</g>
<!-- プロット -->
<g>
<rect x="120" y="50" fill="blue" width="10" height="10" />
<rect x="180" y="230" fill="blue" width="10" height="10" />
<rect x="240" y="200" fill="blue" width="10" height="10" />
<rect x="330" y="15" fill="blue" width="10" height="10" />
<rect x="250" y="50" fill="blue" width="10" height="10" />
<rect x="350" y="123" fill="blue" width="10" height="10" />
<rect x="159" y="235" fill="blue" width="10" height="10" />
<rect x="210" y="208" fill="blue" width="10" height="10" />
<rect x="180" y="290" fill="blue" width="10" height="10" />
<rect x="280" y="230" fill="blue" width="10" height="10" />
<rect x="50" y="120" fill="blue" width="10" height="10" />
<rect x="360" y="130" fill="blue" width="10" height="10" />
<rect x="70" y="190" fill="blue" width="10" height="10" />
<rect x="150" y="250" fill="blue" width="10" height="10" />
<rect x="180" y="150" fill="blue" width="10" height="10" />
<rect x="230" y="90" fill="blue" width="10" height="10" />
<rect x="50" y="300" fill="blue" width="10" height="10" />
<rect x="80" y="310" fill="blue" width="10" height="10" />
<rect x="90" y="320" fill="blue" width="10" height="10" />
</g>
</svg>

折れ線グラフをかく
では、最後に折れ線グラフを書いてみようと思います。
折れ線グラフは散布図とちょっと似ています。
罫線や目盛り
<svg viewbox="0 0 400 450" width="400" height="400">
<!-- 罫線 -->
<g stroke="black" stroke-width="1">
<line x1="40" y1="0" x2="40" y2="350"></line>
<line x1="40" y1="0" x2="380" y2="0"></line>
<line x1="380" y1="0" x2="380" y2="350"></line>
<line x1="40" y1="350" x2="380" y2="350"></line>
</g>
<!-- 縦の目盛り -->
<g>
<text x="0" y="350">0</text>
<text x="0" y="300">50</text>
<text x="0" y="250">100</text>
<text x="0" y="200">150</text>
<text x="0" y="150">200</text>
<text x="0" y="100">250</text>
<text x="0" y="50">300</text>
</g>
<!-- 横の目盛り -->
<g>
<text x="60" y="380">1月</text>
<text x="120" y="380">2月</text>
<text x="180" y="380">3月</text>
<text x="240" y="380">4月</text>
<text x="300" y="380">5月</text>
<text x="360" y="380">6月</text>
</g>
</svg>
データの表示
折れ線グラフでは円(点)をかいて、そこで使った座標を使ってそれを線で繋ぎます。
円を書く時は<circle>タグを使用します。
<g fill="blue">
<circle cx="60" cy="150" r="5" />
<circle cx="120" cy="70" r="5" />
<circle cx="180" cy="130" r="5"/>
<circle cx="240" cy="80" r="5"/>
<circle cx="300" cy="200" r="5"/>
<circle cx="360" cy="180" r="5"/>
</g>
<g stroke="blue" stroke-width="1">
<line x1="60" y1="150" x2="120" y2="70"></line>
<line x1="120" y1="70" x2="180" y2="130"></line>
<line x1="180" y1="130" x2="240" y2="80"></line>
<line x1="240" y1="80" x2="300" y2="200"></line>
<line x1="300" y1="200" x2="360" y2="180"></line>
</g>
折れ線グラフの全体のコードはこんな感じです。
<svg viewbox="0 0 400 450" width="400" height="400">
<!-- 罫線 -->
<g stroke="black" stroke-width="1">
<line x1="40" y1="0" x2="40" y2="350"></line>
<line x1="40" y1="0" x2="380" y2="0"></line>
<line x1="380" y1="0" x2="380" y2="350"></line>
<line x1="40" y1="350" x2="380" y2="350"></line>
</g>
<!-- 縦の目盛り -->
<g>
<text x="0" y="350">0</text>
<text x="0" y="300">50</text>
<text x="0" y="250">100</text>
<text x="0" y="200">150</text>
<text x="0" y="150">200</text>
<text x="0" y="100">250</text>
<text x="0" y="50">300</text>
</g>
<!-- 横の目盛り -->
<g>
<text x="60" y="380">1月</text>
<text x="120" y="380">2月</text>
<text x="180" y="380">3月</text>
<text x="240" y="380">4月</text>
<text x="300" y="380">5月</text>
<text x="360" y="380">6月</text>
</g>
<!-- グラフ -->
<g fill="blue">
<circle cx="60" cy="150" r="5" />
<circle cx="120" cy="70" r="5" />
<circle cx="180" cy="130" r="5"/>
<circle cx="240" cy="80" r="5"/>
<circle cx="300" cy="200" r="5"/>
<circle cx="360" cy="180" r="5"/>
</g>
<g stroke="blue" stroke-width="1">
<line x1="60" y1="150" x2="120" y2="70"></line>
<line x1="120" y1="70" x2="180" y2="130"></line>
<line x1="180" y1="130" x2="240" y2="80"></line>
<line x1="240" y1="80" x2="300" y2="200"></line>
<line x1="300" y1="200" x2="360" y2="180"></line>
</g>
</svg>

【応用編】Vue.jsと組み合わせて棒グラフをかく
ここまでsvgタグを使ってグラフをかいてきましたが、応用編として実際にjavascriptと組み合わせてかいてみようと思います。
今回はVue.jsと組み合わせてかいてみます。(最近Vue.jsに触れることが多いので)
目盛りなどは先ほどかいたものをそのまま使います。
データの定義
export default {
name: 'home',
data () {
return {
dataSet: [
{ month: 1, val: 150 },
{ month: 2, val: 350 },
{ month: 3, val: 200 },
{ month: 4, val: 305 },
{ month: 5, val: 250 }
]
}
}
}
データの表示
v-for文を使って、データを表示しています。
xで60を掛け算したり、yで引き算をしているのは、描画位置の調整の為です。
<g fill="blue">
<rect v-for="data in dataSet" :key="data.month" :x="data.month * 60" :y="400 - data.val" :height="data.val" width="40"/>
</g>

まとめ
今回はライブラリを使わずにSVGタグだけで棒グラフ、散布図(分布図)、折れ線グラフをかいてみました。
ライブラリを使わなくても意外と簡単にグラフがかけることが伝わったかと思います。
千田も実際の案件でVue.jsとSVGを組み合わせて使ってみましたが、上記のように基本的なところををおさえておけばサクッとグラフをかくことができました。
それでは!
参考
↓↓↓ぜひチェックしてください
~提供中のヒューマンセンシング技術~
◆なりすまし判定技術
eKYC・顔認証のなりすまし対策を!
https://bio-check.pas-ta.io
◆まばたき検出技術
PCやスマホアプリに組み込めて高精度にまばたきを検出
https://blink.pas-ta.io
◆視距離推定技術
単一RGBカメラで、目からカメラまでの距離を推定
https://vd.pas-ta.io
◆虹彩認証技術
目の虹彩を利用した生体認証技術
https://iris.pas-ta.io
◆視線検出技術
アイトラッキングや次世代UIに
https://eyetrack.pas-ta.io
◆目検出技術
あらゆる目周りデータを高精度に取得
https://pupil.pas-ta.io
