Lean Baseball

No Engineering, No Baseball.

nuxt-coreuiでデータサイエンスの可視化ダッシュボードを自作してみる

このエントリーは、Vue.js #3 Advent Calendar 2018アドベントカレンダー初日の記事です.

開幕投手をつとめます、@shinyorkeと申します.

この記事では、「データサイエンスもいいけど自前で可視化ダッシュボード作ると面白いぞ!」っていうテーマで、

で実際作った時の勘どころやノウハウを紹介します.

TL;DR

  • データサイエンスに必要なダッシュボードを作りたくなったらnuxt-core-uiを使おうぜ!
  • nuxt-core-uiのグラフの動的更新はvue-chartjsのmixins.reactivePropで、API(データ)の呼び出しは普通にaxiosでやろう
  • オレオレ分析基盤は作ると楽しい

完成イメージ

データ(DBとか、何でもいい)をグラフで可視化する、Redash(の簡易版)っぽいダッシュボードの雛形をnuxt-core-ui(Nuxt.js + CoreUI)でやってみます.

f:id:shinyorke:20181129084441p:plain
nuxt-coreuiでのダッシュボード例

なお、こちらは今年のPyCon JP 2018で発表したモノでもあります.

おしながき

Who am I?(お前誰よ)

  • @shinyorke(しんよーく、と読みます)
  • 野球データ解析・分析のベンチャー「ネクストベース」の野球エンジニア兼CTO
  • バックエンドにインフラ、データサイエンスにフロントと何でもやってるが基本Pythonの人

なお、Vue.js(含むNuxt.js)歴は半年とちょっとです(今年から触り始めた)*1が、縁あってこんなエントリーを書かせてもらったりもしてます.

shinyorke.hatenablog.com

登場人物の紹介

このエントリーで登場するモノです.

なお、

  • Vue.jsおよびNuxt.jsはSPA(Single Page Application)を作るものだよ
  • Vue.jsおよびNuxt.jsで開発できる環境は揃ってるよ(そろってない人は、ここと、ここを見てね&やってね)
  • Vue.jsおよびNuxt.jsでグラフを書くならvue-chartjsやぞ

を前提条件としてこの先の話を進めます(要はvue-cliが使えればなんとでもなります).

CoreUI

まず、これはVue.jsに限った話ではないのですが、フロントエンドでWebの管理画面を作るテンプレートとして、CoreUIという便利なテンプレートがあります.

🆓 Free Bootstrap Admin Template · CoreUI

何ができるかは、ライブデモをご覧頂いたほうが早いと思いますが、大雑把に言うと

  • 画面遷移ができる状態のテンプレが手に入る、しかもレスポンシブ(Bootstrapがベースとなっている)
  • ダッシュボードに必要なコンポーネントがほぼ全て入ってる(グラフ、カードなど)
  • (後述の通り)いろんなjavascript frameworkの実装がある

ちゃんと使って作ればRedashのフロントエンドに親しいものは実装できるかと思います.

なお、無料版とプロ版があり、プロ版の方がコンポーネントが揃っていたりサポートもあるみたいですが、今回は無料版でのお話です.

nuxt-coreui(この記事のメイン)

前述の通り、CoreUIは様々な実装があり、

  • 通常版(framework使ってない)
  • Angular
  • React.js
  • Vue.js

これらが用意されています.

ちょっとJavaScriptに慣れている人だったり、「俺はVue.jsより○○(ReactとかAngular)何じゃ!」って方はそれぞれのVer.を使えば良いかなと思います.

そんなCoreUIのVue.js版をNuxt.js化したやつがこのエントリーで紹介するnuxt-coreuiというものです.

GitHub - muhibbudins/nuxt-coreui: 💫 NuxtJS + CoreUI Project — Unofficial Nuxt + CoreUI project, free to use boilerplate for every need.

nuxt-coreuiをはじめる

はじめ方はメチャクチャ簡単です(Vue.jsで開発したことある人にはおなじみの光景).

README.mdとおりにやれば動きます.

インストール

vue-cliが使えている人はこれで終わります.

$ vue init muhibbudins/nuxt-coreui hello_nuxt_coreui
$ cd hello_nuxt_coreui
$ npm install

ひとまず動かす

npmもしくはyarnで動きます(これもおなじみの光景)

$ npm run dev

デフォルトではPort 3000が開くので、ブラウザでhttp://localhost:3000とかしてあげれば、ライブデモとほぼ同等の内容が動くと思います.

あとはお好きなエディタでページやコンポーネントの中身を変えたり、新しいページを作ったりして中身の理解をしてみましょう.

ダッシュボードを作るための下ごしらえ

優秀なテンプレから実用的なダッシュボード(に限らず、Webサイト全般)を作るためには、

  • CoreUIのテンプレから不要なページを追い出す
  • assets類を変更する・捨てる
  • ページ構成に従い画面遷移を変更する

といった泥臭い仕事作業が必要です.

全部上げるとキリが無いので、私個人が最もハマった

  • グラフとページの連携
  • 複数のAPI呼び出しを束ねた上での処理

について解説します.

グラフのデータをPage側からの同期で変更する

元リポジトリの棒グラフのサンプル(BarExample.vue)のコードを見ると、

オリジナルの棒グラフ

<script>
import { Bar } from 'vue-chartjs'

export default {
  extends: Bar,
  mounted () {
    // Overwriting base render method with actual data.
    this.renderChart({
      labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      datasets: [
        {
          label: 'GitHub Commits',
          backgroundColor: '#f87979',
          data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11]
        }
      ]
    })
  }
}
</script>

(サンプルという名前の通り)、labelsとdatasetsが直接記載されていて困っちゃいます、現実のアプリではこんな書き方をするわけがありません.

ので、公式の手順に従い、こんな感じでリアクティブに変更可能な書き方にしました.

リアクティブ後の棒グラフ

グラフライブラリの方

<script>
  import {Bar, mixins} from 'vue-chartjs'

  export default {
    extends: Bar,
    mixins: [mixins.reactiveProp],
    props: {
      chartData: Object,
      options: Object
    },
    mounted() {
      this.renderChart(this.chartData, this.options)
    }
  }
</script>

呼び出し方はこんな感じ.

chartDatasetsおよび、chartOptionsにそれぞれdatasetsとoptionを渡します(中身はmethods内とかで一生懸命作る).

        <b-card header-tag="header">
          <div slot="header">
            BarGraph Sample
          </div>
          <div class="chart-wrapper">
            <bar-graph :chartData="chartDatasets" :options="chartOptions"/>
          </div>
        </b-card>

RESTful API呼び出し(axiosを入れる・使う)

このブログのちょっと前のエントリーですが、こちらですこーし触れました.

shinyorke.hatenablog.com

大雑把に言うと、

  • axiosを使って呼び出しをシンプルにする
  • 複数APIを束ねて呼ぶときはasync / awaitをうまーく重ねて使う
<script>
  import axios from 'axios'

  const HTTP_HEADER = {headers: {'Content-Type': 'application/json'}}

  export default {
    name: "hourse",
    data() {
      return {
        // 省略
      }
    },
    methods: {
      search: async function (url) {
        const response = await axios.get(url, HTTP_HEADER)
        if (response.status !== 200) {
          console.error('エラー時の処理')
          process.exit()
        }
        const body = response.data
        this.getStatsJapan(body.stats_japan)
        this.getStatsOther(body.stats_other)
      },
      getStatsJapan: async function (url) {
        const response = await axios.get(url, HTTP_HEADER)
        if (response.status !== 200) {
          console.error('エラー時の処理')
          process.exit()
        }
        const body = response.data
        // TODO データを埋め込む
      },
      getStatsOther: async function (url) {
        const response = await axios.get(url, HTTP_HEADER)
        if (response.status !== 200) {
          console.error('エラー時の処理')
          process.exit()
        }
        const body = response.data
        // TODO データを埋め込む
      }
      // TODO 続く
   }
</script>

先程のグラフデータのdatasets/optionもこの流れで作れるので是非試してみてください!

まとめ

実際に作った分析ダッシュボードは前述の通り、PyCon JP 2018で発表させてもらいました.

発表のメインはnuxt-coreuiではなくてPython(Django、Luigiほか)でしたが笑.

実際作った・使った感想としては、

  • 社内のオレオレ分析ダッシュボードとして十分使えるクオリティ、キビキビ・ヌルヌル動いて体験的にも良い.*2
  • 追加開発・保守運用もメンバーがVue.js知ってる・使える前提でイケそう.*3
  • 基本のグラフ(棒とか折れ線とか)以外のやつもなんとかしたい、d3.jsとか組み込めないものか.*4

ということで、社内で作ってる別のVue.jsアプリと加えて社内基盤として整理できたらなと思っています.

というわけで、nuxt-coreuiいいぞ!の紹介はここまで、明日はpenton310さんよろしくお願いします!

*1:触り始めたキッカケは2月からJOINした弊社で、だいぶVue.jsが気に入ったので今はSPA開発をVue.js/Nuxt.jsでやってます(フロントエンドエンジニア募集中だよ)

*2:ベンチマークはとってませんが、ローカルでもサクサク動く、待ち時間も少ないといい感じです.Djangoでキャッシュ、DB側でインデックス張りまくりと他のノウハウを駆使しての結果ですが笑

*3:社内のSPAは基本Vue.jsと決めてるのでこの辺障害・障壁はなさそう.

*4:表現力必要な可視化とかどうしよう問題は常にある.