実データを流し込んだら、見せ物を道具に作り替えたくなった。nebula.js × Qlik でスーパーストアの赤字を探す

前回の記事(で、これクリックできるの?→できました。nebula.jsの自作チャートにQlikの「選択・連想・ドリルダウン」を通してみた)で、自作チャートに Qlik の「選択・連想・ドリルダウン」を通しました。クリックさえ Qlik に返せば、あとは連想エンジンが全部やってくれる。見た目は Web、頭脳は Qlik。

ただ、ここまでのデータはカテゴリ8つ × 12か月のトイデータでした。かわいいデータで動いても、「で、実務では?」と言われたら何も言い返せません。

なので今回は実データを流し込みます。最終的にはこうなります。

目次

1. まずは今までのチャートに、実データをそのまま流し込む

使ったのは、Tableau のサンプルでおなじみの「スーパーストア」の日本版です。1万明細・4年分で、製品・地域・顧客・売上・利益・割引率が入っています。利益が赤字の明細が2割以上あるのが、分析しがいのあるところです。

(Qlik Cloud にアップロードしてロードスクリプトで読むだけですが、CSV が Shift-JIS なので codepage is 932 を付けないと途中で読み込みが止まる、という罠だけ踏みました。)

これを、前編・後編で作ってきた rich-table(1つの拡張で十数パターンに描き分けるやつ)にそのまま流し込みます。

見た目は前編のまま、中身だけ実データになりました。せっかくなので、実データならではの対応をいくつか入れています。

ドリルが2軸になった

製品(カテゴリ → サブカテゴリ → 製品名)と、時間(年 → 四半期 → 月)の2本の階層を持たせました。行をクリックすると製品側、列の見出しをクリックすると時間側が降ります。パンくずも2本です。

仕組みは後編と同じで、次元を2つとも qGrouping: 'H' の階層グループにしただけです。

利益を見るパターンを追加

売上だけでなく利益が入ったので、利益ヒートマップ(赤字は赤、黒字は緑)と、0 を中心に左右に振れる利益のダイバージングバー、割引率 × 利益率の散布図を足しました。どれも「家具」に降りた状態です。

家具の中で「テーブル」だけが真っ赤です。しかも4年連続で赤字で、2019年がいちばん深い(-1,379,183)。これがヒートマップだと一目で分かります。

ここで1つだけ気をつけたのが、率はそのまま足せないことです。利益率や平均割引率をそのままメジャーにすると、ドリルで階層が変わったときに正しく集計し直せません。なのでメジャーは Sum(Profit) や Sum(Sales*Discount) のような「足せる素の値」で持って、率は描画するときに割り算しています。

2. でも、これで毎日仕事をするのはつらい

実データで動いた。赤字も見つかった。……んですが、これを毎朝開いて仕事をするかというと、ちょっと違います。

rich-table は「1つの表を十数通りに描き分ける」ための見せ物です。上から下まで、描いているのは全部同じ数字。見せ方の引き出しとしては楽しいけれど、

  • 全体の KPI、推移、地域、顧客を一度に見渡せない
  • 見たい数字を探してスクロールし続けることになる
  • 「テーブルが赤字」は分かっても、「なぜ?」を別の角度から確かめに行けない

実務で欲しいのは、1画面で全体が見えて、気になったところをクリックして掘れる、普通のダッシュボードです。なので、作り替えました。

3. ダッシュボードに作り替えた

改めて、完成品です。

KPI:まず全体を5つの数字で

売上 2.27億円、利益 2,739万円、利益率 12.1%、平均割引率 8.3%、赤字率 23.2%。

数字の大きさと色だけで「どこを見るべきか」が分かるようにしています。赤字率だけは最初から赤。ここが今回の主役です。

推移:売上と利益を2軸で

売上(左軸)と利益(右軸)の月次推移です。売上と利益は桁が違うので2軸にしています。

サブカテゴリ × 割引率と利益率

左はサブカテゴリ別の売上で、赤字のサブカテゴリだけ赤い棒になっています。右は横軸が割引率、縦軸が利益率の散布図で、円の大きさが売上です。

右下、つまり「割引しているのに利益が出ていない」位置に、赤い円がぽつんと1つあります。さっきの「テーブル」です。

地図とヒートマップ

地域別の売上を日本地図で塗り分けました。都道府県のポリゴンを地域の売上で塗っているだけなので、SVG の path に色を付けているだけです。右はサブカテゴリ × 地域のヒートマップ。

顧客区分と上位顧客

顧客区分の構成比と、売上トップ10の顧客です。上位顧客は売上だけでなく利益と利益率も並べているので、「売上は多いけど利益が薄いお客さん」がすぐ分かります。

そして左側にはリストボックス(顧客区分・地域・カテゴリ・顧客名)、右上には今の選択状態と「すべて解除」ボタン。このあたりは Qlik のシートと同じ使い勝手にしています。

4. 全部クリックできる

ここからが本題です。このダッシュボード、どのチャートをクリックしても全チャートが連動します。

さっきの「テーブル」をクリックしてみます。

KPI がこうなりました。

  • 売上 1,392万円
  • 利益 -318万円
  • 利益率 -22.9%
  • 平均割引率 24.7%(全体は 8.3%)
  • 赤字率 70.4%

テーブルは、全体の3倍近い割引をしていて、明細の7割が赤字でした。売っても売っても赤字、というやつです。数字自体は rich-table の計器パネルにも出ていましたが、ここでは KPI・推移・地図・散布図が1クリックで一斉に「テーブルだけの世界」に切り替わるので、「割引のしすぎで赤字」という話が画面全体から伝わってきます。

もちろん地図や顧客からも絞れます。

地図で関西地方をクリックして、左のリストで「家具」を足しました。関西 × 家具だと売上 2,110万円、利益率 15.8% と、全体(12.1%)よりむしろ優秀です。それでもサブカテゴリの棒を見ると、テーブルだけは利益率 -12.4% で赤いまま。地域を変えても赤字が消えないので、「特定の地域の問題」ではなく「テーブルという商材の値付けの問題」っぽい、というところまでクリック数回で辿り着けます。

「気になったところをクリックして、別の角度から見る」を、画面遷移なしで繰り返せる。これが Qlik の連想のいちばんおいしいところで、それが自作の見た目のまま使えます。

5. 仕組み:チャートごとにハイパーキューブを1個

rich-table は「1つのハイパーキューブを十数通りに描く」拡張でした。ダッシュボードは逆で、チャートごとにセッションオブジェクト(独立したハイパーキューブ)を作っているだけです。

for (const spec of specs) {
  const model = await app.createSessionObject({
    qInfo: { qType: 'ss-dash-chart' },
    qHyperCubeDef: spec.hc,
  });
  const draw = async () => spec.render(await model.getLayout(), el);
  // クリック → その次元の値を選択(連想で全チャートへ波及)
  el.addEventListener('click', (evt) => {
    const hit = evt.target.closest('[data-elem]');
    if (hit) model.selectHyperCubeValues('/qHyperCubeDef', 0, [Number(hit.dataset.elem)], true);
  });
  model.on('changed', draw); // 選択が変わるとエンジンが通知してくる
  await draw();
}

各チャートは「ハイパーキューブの定義」と「描画関数」のペアで、たとえば散布図の定義はこれだけです。

hc: {
  qDimensions: [{ qDef: { qFieldDefs: ['SubCategory'] } }],
  qMeasures: [
    { qDef: { qDef: '=Sum(Sales)' } },
    { qDef: { qDef: '=Sum(Profit)/Sum(Sales)' } },           // 利益率
    { qDef: { qDef: '=Sum(Sales*Discount)/Sum(Sales)' } },   // 売上加重の平均割引率
  ],
},

どこかで選択が起きると、エンジンが影響を受けるオブジェクトに changed を送ってくるので、受け取ったら getLayout() し直して描き直すだけ。チャート同士を繋ぐコードは、今回も1行もありません。

これ、構造としては Qlik のシートとまったく同じです。シートに置いたチャートも、1つ1つがハイパーキューブを持ったオブジェクトです。つまり描画だけを自分で書いた Qlik のシートを作った、と言えます。

ちなみに、stardust の組み込みチャートは1つも使っていません。enigma.js の getLayout と selectHyperCubeValues だけで描いています。見た目を100%自分で決めたかったので。

まとめ:見せ物から道具へ

  • 前編・後編のチャートに実データを流し込んでも、連想・ドリルはそのまま動いた
  • でも実務で使うなら、1画面で見渡せてクリックで掘れる「ダッシュボード」の形が要る
  • ダッシュボードは「チャートごとにハイパーキューブ1個」で作れる。構造は Qlik のシートと同じで、連動のコードは今回も0行

前編で「実務でこそ効く」と大きく出たので、今回でやっと回収できた気がします。

次回予告:やりすぎます

実用的なダッシュボードができたので、次は逆に実用性を無視して遊びます。同じデータ・同じ連想のまま、見た目だけを変えた5種類を作りました。

  • 光って脈打つネオン版
  • スクロールするとチャートが描き上がっていく、すりガラス版
  • 映画のタイトルバックみたいなシネマティック版
  • 操作不要でずっと回り続ける、大画面サイネージ版
  • スポットライトが1枚ずつ当たって解説してくれる、ガイドツアー版

中身は全部 Qlik です。たぶん、今回よりだいぶうるさいです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次