この記事は Angular Advent Calendar 2018 の 5 日目の記事です。
はじめに
IoT や機械学習などデータに触れる機会が多くなったいま、データ収集が積極的に行われています。
当然データを収集するだけでは宝の持ち腐れになってしまいます。
そのデータから
- どの部分を抽出して
- どのように加工して
- どこをどう利用するのか
- どんな知見を得るのか
それによって、持っているデータの価値は大きく変わります。
さらに、得られたデータや知見をどう見せるかという伝え方にも価値があります。
ここではデータをうまく表現する助けとなるように、Angular と Chart.js を使ってデータを可視化する方法を紹介します。
こんな方へ
- 全体のフレームワークは Angular で、データの可視化ツールを使いたい
- Angular はチュートリアル程度はわかる
- なにかしらのデータを試しに可視化してみたい
あることないこと
書いてあること
- Angular から Chart.js を利用する方法
- 棒グラフを表示する方法
- チャートのクリック・イベントをハンドルする方法
- クリックされたデータの詳細をハンドラから知る方法
下記リンクのページができあがります。
https://charts-sample-2699e.firebaseapp.com/
書いてないこと
- Node.js のインストール方法
- Angular CLI のインストール方法
- Angular の文法および書き方
環境
- Node.js: 10.13.0
- Angular CLI: 7.0.3
用語
Chart.js Documentation に習って、グラフではなく チャート
と書いています。
但し、Bar Chart については 棒グラフ
と書いています。
準備
まずは、チャートを表示するための下準備をします。
新しいプロジェクトを作成します。
使用するスタイルシート・フォーマットを聞かれますが、ここでは本質にかかわらないので何でも構いません。
$ ng new charts-sample --routing
ng2-charts
と @types/chart.js
を追加します。
$ cd charts-sample
$ yarn add ng2-charts
$ yarn add @types/chart.js --dev
src/app/app.modules.ts
で ChatsModule
を imports
に記述しておきます。
import { ChatsModule } from 'ng2-chats'
@NgModule({
imports: [
...
ChartsModule
],
...
})
チャート表示用のコンポーネントを作成します。
今回は棒グラフを表示しますのでコンポーネントの名前を bar-chart
とします。
$ ng generate component bar-chart
src/app/app-routing.module.ts
で BarChartComponent
へのルーティング設定をします。
import { BarChartComponent } from './bar-chart/bar-chart.component'
const routes: Routes = [
{ path: '**', component: BarChartComponent }
]
チャートの表示
さて、ここからが Angular での Chart.js を使う記述です。
まずは、テンプレートです。
src/app/bar-chart/bar-chart.component.html
には canvas
タグを使って各属性を次のように記述しておきます。
baseChart
以外の下記値はそれぞれ変数を設定して値が代入されるようにしています。
- chartType
- options
- labels
- legend
- datasets
<div>
<div style="display: block">
<canvas baseChart
[chartType]="chartType"
[options]="chartOptions"
[labels]="chartLabels"
[legend]="chartLegend"
[datasets]="chartData" >
</div>
</div>
src/app/bar-chart/bar-chart.component.ts
では、先ほどテンプレートで設定した変数を定義します。
棒グラフを表示するので chatType
の値は bar
にします。
(他には、折れ線グラフ line
、円グラフ pie
などがあります)
chartOptions
は今回指定していません。
chartLabels
には月を列挙しています。
これらの値が x 軸のラベルになります。
chartLegend
を true
にしておくと、チャートの上に凡例が表示されます。
chartData
には、表示させたい data
と label
をひとつのデータセットとして列挙します。
今回は、東京および京都の降水量データ 1 を使います。
export class BarChartComponent implements OnInit {
chartType = 'bar'
chartOptions = { }
chartLabels = [
'January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December' ]
chartLegend = true
chartData = [
{ data: [52.3, 56.1, 117.5, 124.5, 137.8, 167.7, 153.5, 168.2, 209.9, 197.8, 92.5, 51.0], label: 'Tokyo' },
{ data: [50.3, 68.3, 113.3, 115.7, 160.8, 214.0, 220.4, 132.1, 176.2, 120.9, 71.3, 48.0], label: 'Kyoto' }
]
constructor() { }
ngOnInit() { }
}
実行結果
ビルドしてブラウザで表示すると、下のようなチャートが表示されます。
各データセットにはそれぞれ色が付いていて、棒はアニメーションされ、マウスをホバーするとツールチップでデータの詳細が表示されます。
上部に表示されている凡例からデータセットをクリックすることで、選択したデータセットの表示/非表示を切り替えることができます。
クリック・イベント
ここまでで簡単なチャートの表示ができました。
次は、棒グラフがクリックされたときのイベント・ハンドラを定義する方法です。
クリック・イベントを扱えると、ユーザーのマウス操作でさまざまな表示切り替えができるようになります。
まず、先ほどのテンプレートに (chartClick)="chartClicked($event)"
という記述を加えます。
これでチャート上でクリック・イベントが起こったときに chartClicked($event)
が呼ばれます。
<div>
<div style="display: block">
<canvas baseChart
[chartType]="barChartType"
[options]="barChartOptions"
[labels]="barChartLabels"
[legend]="barChartLegend"
[datasets]="barChartData"
(chartClick)="chartClicked($event)" >
</div>
</div>
クリックされた棒のデータを表示するために、変数を定義しておきます。
clickedLabel = ''
clickedDatasetLabel = ''
clickedValue = 0
constructor() { }
テンプレートで、定義した変数が表示されるようにしておきます。
<div>
...
<div>
<table>
<tr>
<td>Label</td>
<td>{{clickedLabel}}</td>
</tr>
<tr>
<td>Dataset Label</td>
<td>{{clickedDatasetLabel}}</td>
</tr>
<tr>
<td>Value</td>
<td>{{clickedValue}}</td>
</tr>
</table>
</div>
</div>
クリック・イベントが起こると chartClicked
にはイベント・データが渡ってきます。
そこから model
、index
、datasetIndex
を取り出します。
model
にはクリックされた棒のモデル定義が入っており、x 軸のラベルやデータセットのラベルが含まれています。
index
はクリックされた棒のデータのインデックスです。
datasetIndex
はクリックされた棒のデータセットのインデックスです。今回の例では Tokyo データセットが 0、Kyoto データセットが 1 になります。
これらを使って、クリックされた棒のラベル、データセットのラベル、データの値を取得することができます。
// Event Handler
public chartClicked(e: any): void {
if (e.active.length > 0) {
const chart = e.active[0]._chart
const element = chart.getElementAtEvent(event)[0]
const model = element._model
const index = element._index
const datasetIndex = element._datasetIndex
this.clickedLabel = model.label
this.clickedDatasetLabel = model.datasetLabel
this.clickedValue = chart.config.data.datasets[datasetIndex].data[index]
}
}
実行結果
ビルドしてブラウザで表示すると、下のようなチャートが表示されます。
ひとつの棒をクリックすると、左下の表にクリックした棒の x 軸のラベル、データセットのラベル、およびデータ値が表示されます。
まとめ
Angular から可視化ツールである Chart.js を使って、棒グラフを表示する手順を紹介しました。
これを参考にすることで、他の chartType
でも Chart.js Charts を参照することで簡単に扱えるはずです。
棒グラフの棒をクリックしたときに発生するクリック・イベントをハンドルして、各種値を取得する方法を紹介しました。
ユーザーの操作によって、ページやチャートを変化させることができます。
こちらで動きを確認できます。
https://charts-sample-2699e.firebaseapp.com/
明日の 6 日目は @miyatomo さんです。
おまけ (JSON データ)
データを JSON ファイルから読み込みたいときには、tsconfig.json
で下記の設定をしておきます。
こうすることで、JSON ファイルをモジュールのように直接インポートすることができます。
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
例えば、下記のように記述すれば直接インポートすることができます。
import datajson from '../../data/opendata01.json'
おまけ (ホバー・イベント)
マウス・ホバーのイベントは、クリック・イベント同様にテンプレートに (chartHover)="chartHovered($event)"
のように記述することでハンドラが呼ばれます。
しかし、不具合があるようで現在 (2018/12/4) はうまく動かずハンドラが呼ばれません 2。
<div>
<div style="display: block">
<canvas baseChart
[chartType]="chartType"
[options]="chartOptions"
[labels]="chartLabels"
[legend]="chartLegend"
[datasets]="chartData"
(chartHover)="chartHovered($event)" >
</div>
</div>
テンプレートではなく chartOptions
に、onHover
を持つオブジェクトを hover
として定義します。
こう書くことでホバー・イベントで onHover
ハンドラが呼ばれます。
export class BarChartComponent implements OnInit {
chartType = 'bar'
chartOptions = {
hover: {
onHover: (event, active) => {
if (active && active.length) {
// Your code is here.
}
}
}
}
リファレンス
Chart.js
Chart.js Documentation
ng2-charts
Angular & Chart.js (with ng2-charts)
-
使用した降水量データ:東京都 東京 の気候、京都府 京都 の気候 ↩