Quantcast
Viewing latest article 5
Browse Latest Browse All 25

データ可視化への一歩目 〜Angular + Chart.js〜

この記事は Angular Advent Calendar 2018 の 5 日目の記事です。

はじめに

IoT や機械学習などデータに触れる機会が多くなったいま、データ収集が積極的に行われています。
当然データを収集するだけでは宝の持ち腐れになってしまいます。
そのデータから

  • どの部分を抽出して
  • どのように加工して
  • どこをどう利用するのか
  • どんな知見を得るのか

それによって、持っているデータの価値は大きく変わります。

さらに、得られたデータや知見をどう見せるかという伝え方にも価値があります。
ここではデータをうまく表現する助けとなるように、AngularChart.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.tsChatsModuleimports に記述しておきます。

src/app/app.modules.ts
import { ChatsModule } from 'ng2-chats'

@NgModule({
  imports: [
    ...
    ChartsModule
  ],
  ...
})

チャート表示用のコンポーネントを作成します。
今回は棒グラフを表示しますのでコンポーネントの名前を bar-chart とします。

$ ng generate component bar-chart

src/app/app-routing.module.tsBarChartComponent へのルーティングを設定をします。

src/app/app-routing.module.ts
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
src/app/bar-chart/bar-chart.component.html
<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 軸のラベルになります。

chartLegendtrue にしておくと、チャートの上に凡例が表示されます。

chartData には、表示させたい datalabel をひとつのデータセットとして列挙します。
今回は、東京および京都の降水量データ 1 を使います。

src/app/bar-chart/bar-chart.component.ts
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() { }
}

実行結果

ビルドしてブラウザで表示すると、下のようなチャートが表示されます。
Image may be NSFW.
Clik here to view.
Screen Shot 2018-12-03 at 11.20.10.png

各データセットにはそれぞれ色が付いていて、棒はアニメーションされ、マウスをホバーするとツールチップでデータの詳細が表示されます。
上部に表示されている凡例からデータセットをクリックすることで、選択したデータセットの表示/非表示を切り替えることができます。

クリック・イベント

ここまでで簡単なチャートの表示ができました。
次は、棒グラフがクリックされたときのイベント・ハンドラを定義する方法です。

クリック・イベントを扱えると、ユーザーのマウス操作でさまざまな表示切り替えができるようになります。

まず、先ほどのテンプレートに (chartClick)="chartClicked($event)" という記述を加えます。
これでチャート上でクリック・イベントが起こったときに chartClicked($event) が呼ばれます。

src/app/bar-chart/bar-chart.component.html
<div>
  <div style="display: block">
    <canvas baseChart
            [chartType]="barChartType"
            [options]="barChartOptions"
            [labels]="barChartLabels"
            [legend]="barChartLegend"
            [datasets]="barChartData"
            (chartClick)="chartClicked($event)" >
  </div>
</div>

クリックされた棒のデータを表示するために、変数を定義しておきます。

src/app/bar-chart/bar-chart.component.ts
  clickedLabel        = ''
  clickedDatasetLabel = ''
  clickedValue        = 0

  constructor() { }

テンプレートで、定義した変数が表示されるようにしておきます。

src/app/bar-chart/bar-chart.component.html
<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 にはイベント・データが渡ってきます。
そこから modelindexdatasetIndex を取り出します。
model にはクリックされた棒のモデル定義が入っており、x 軸のラベルやデータセットのラベルが含まれています。
index はクリックされた棒のデータのインデックスです。
datasetIndex はクリックされた棒のデータセットのインデックスです。今回の例では Tokyo データセットが 0、Kyoto データセットが 1 になります。

これらを使って、クリックされた棒のラベル、データセットのラベル、データの値を取得することができます。

src/app/bar-chart/bar-chart.component.ts
  // 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 軸のラベル、データセットのラベル、およびデータ値が表示されます。
Image may be NSFW.
Clik here to view.
Screen Shot 2018-12-03 at 18.26.00.png

まとめ

Angular から可視化ツールである Chart.js を使って、棒グラフを表示する手順を紹介しました。
これを参考にすることで、他の chartType でも Chart.js Charts を参照することで簡単に扱えるはずです。

棒グラフの棒をクリックしたときに発生するクリック・イベントをハンドルして、各種値を取得する方法を紹介しました。
ユーザーの操作によって、ページやチャートを変化させることができます。

こちらで動きを確認できます。
https://charts-sample-2699e.firebaseapp.com/

明日の 6 日目は @miyatomo さんです。

おまけ (JSON データ)

データを JSON ファイルから読み込みたいときには、tsconfig.json で下記の設定をしておきます。
こうすることで、JSON ファイルをモジュールのように直接インポートすることができます。

tsconfig.json
   "resolveJsonModule": true,
   "allowSyntheticDefaultImports": true

例えば、下記のように記述すれば直接インポートすることができます。

import datajson from '../../data/opendata01.json'

おまけ (ホバー・イベント)

マウス・ホバーのイベントは、クリック・イベント同様にテンプレートに (chartHover)="chartHovered($event)" のように記述することでハンドラが呼ばれます。
しかし、不具合があるようで現在 (2018/12/4) はうまく動かずハンドラが呼ばれません 2

src/app/bar-chart/bar-chart.component.html
<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 ハンドラが呼ばれます。

src/app/bar-chart/bar-chart.component.ts
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)


Viewing latest article 5
Browse Latest Browse All 25

Trending Articles