マリメッコチャートを活用して 2 軸から比率を分析：Yellowfin と FusionCharts の連携

## 1. はじめに
１ つのチャート上で、2 つの側面からの比率をまとめて可視化するためには、マリメッコチャートがとても便利です。
例えば、横軸に地域、縦軸に事業部別の販売比率をそれぞれ配置すれば、地域別と事業部別の販売比率を一目で確認することができます。直感的に分かりやすく数値のバランスを伝えることができるため、プレゼンテーション資料なんかでも良く使われるチャートです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/888a8d0a-cf16-fe76-7d2f-7dbc802aea65.png)
Yellowfin の規定機能でツリーマップがあり、類似の表現をすることは可能ですが、やはりマリメッコチャートでないと表現できないものもあります。私も様々な場面でマリメッコを活用しています。

## 2. データの準備
架空の売上データを[こちら](https://github.com/ChasingHH/ShareFiles/blob/Share/marimekko.csv)に共有しています。自分でも後述の手順でチャートを作成してみたい方は、是非ご活用ください。直接データベースに取り込む以外にも、[Yellowfin トランスフォーメーションフロー]( https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2293853)を活用することも可能です。

## 3. ビューの作成
以下の情報を参考に[ビュー](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294284)を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/78ee667b-234a-c9d0-177a-35f5671ffb5b.png)

## 3. グラフの作成
準備が整ったら、グラフの作成に手順を進めます。新規でレポートを作成し、以下の手順に従ってグラフを作成します。

#### 3-1. [データ] ステップ
ビューに設定した軸と集計値を全てテーブルに配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/3bee44db-9ad0-fdf0-81fb-c68f8d6b4232.png)

#### 3-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/5a518524-6106-95a3-5eae-c1c7d4854c88.png)

##### JavaScriptタブ
雛形を全て削除し、以下のコードに置き換えます。コードの処理の内容は後ほど説明します。
```javascript:JS
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedDataLabel = processDataLabel(options.dataset.data);
    var processedDataValue1 = processDataValue1(options.dataset.data);
    var processedDataValue2 = processDataValue2(options.dataset.data);
    var processedDataValue3 = processDataValue3(options.dataset.data);
    var processedDataValue4 = processDataValue4(options.dataset.data);
    doDrawing(processedDataLabel, processedDataValue1, processedDataValue2, processedDataValue3, processedDataValue4, $chartDrawDiv);
},

processDataLabel = function(dataset) {
    var ds_label = [];
    for (i=0;i<dataset.area.length;i++){
        ds_label.push({
            label: dataset.area[i].raw_data,
            widthpercent: dataset.share[i].raw_data
        });
    }
    return ds_label;
},

processDataValue1 = function(dataset) {
    var ds_value1 = [];
    for (j=0;j<dataset.energy.length;j++){
        ds_value1.push({
            value: dataset.energy[j].raw_data,
        });
    }
    return ds_value1;
},

processDataValue2 = function(dataset) {
    var ds_value2 = [];
    for (k=0;k<dataset.finance.length;k++){
        ds_value2.push({
            value: dataset.finance[k].raw_data,
        });
    }
    return ds_value2;
},

processDataValue3 = function(dataset) {
    var ds_value3 = [];
    for (l=0;l<dataset.electronic.length;l++){
        ds_value3.push({
            value: dataset.electronic[l].raw_data,
        });
    }
    return ds_value3;
},

processDataValue4 = function(dataset) {
    var ds_value4 = [];
    for (m=0;m<dataset.entertainment.length;m++){
        ds_value4.push({
            value: dataset.entertainment[m].raw_data,
        });
    }
    return ds_value4;
},

doDrawing = function(ds_label, ds_value1, ds_value2, ds_value3, ds_value4, $chartDrawDiv) {
    console.log(JSON.stringify(ds_label));
    console.log(JSON.stringify(ds_value1));
    console.log(JSON.stringify(ds_value2));
    console.log(JSON.stringify(ds_value3));
    console.log(JSON.stringify(ds_value4));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                caption: "地域・事業部別シェア",
                numbersuffix: "%",
                showsum: "0",
                usepercentdistribution: "1",
                showxaxispercentvalues: "1",
                showvalues: "1"
            },
            categories:[{category: ds_label}],
            dataset:[
                {
                    seriesname: "エネルギー",
                    color: "#149868",
                    ratio:"100",
                    data: ds_value1
                },
                {
                    seriesname: "ファイナンス",
                    color: "#E7BC4F",
                    ratio:"100",
                    data: ds_value2
                },
                {
                    seriesname: "電子機器",
                    color: "#CE9B1C",
                    ratio:"100",
                    data: ds_value3
                },
                {
                    seriesname: "娯楽",
                    color: "#D9D9D9",
                    ratio:"100",
                    data: ds_value4
                }
            ]
        };
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "marimekko",
                renderAt: $chartDrawDiv[0],
                width: 850,
                height: 500,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};
```
##### プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。グローバルに事業を展開する企業の架空の売上データで、マリメッコチャートを作成してみました。横軸に地域ごとの売上比率、縦軸に各地域内での事業部毎の売上比率を示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/80e1ce0f-66d4-2f0f-f801-53af685f3ce0.png)

## 4. コードの内容
動作概要が分かったところで、コードの中身を見てみましょう。
##### generateChart
```JavaScript:generateChart
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedDataLabel = processDataLabel(options.dataset.data);
    var processedDataValue1 = processDataValue1(options.dataset.data);
    var processedDataValue2 = processDataValue2(options.dataset.data);
    var processedDataValue3 = processDataValue3(options.dataset.data);
    var processedDataValue4 = processDataValue4(options.dataset.data);
    doDrawing(processedDataLabel, processedDataValue1, processedDataValue2, processedDataValue3, processedDataValue4, $chartDrawDiv);
},
```

JavaScript グラフの処理において、最初に呼び出されるのが generateChart = function(options) です。
[データ] ステップでテーブルに追加した情報が、options に格納されて、メソッドに受け渡されます。
`var $chartDrawDiv = $(options.divSelector)` でグラフを出力する div を選択します。
 `var processedDataLabel = processDataLabel(options.dataset.data);`
 `var processedDataValue1 = processDataValue1(options.dataset.data);`
 `var processedDataValue2 = processDataValue2(options.dataset.data);`
 `var processedDataValue3 = processDataValue3(options.dataset.data);`
 `var processedDataValue4 = processDataValue4(options.dataset.data);`
 `doDrawing(processedDataLabel, processedDataValue1, processedDataValue2, processedDataValue3, processedDataValue4, $chartDrawDiv);processedMilestone = processMilestone(options.dataset.data);`

上記 6 行で、別の関数を呼び出して、データ処理とグラフ描画処理を行っています。呼び出し先の関数での処理内容は後続の個所で説明をします。

##### processDataLabel
```JavaScript:processDataLabel
processDataLabel = function(dataset) {
    var ds_label = [];
    for (i=0;i<dataset.area.length;i++){
        ds_label.push({
            label: dataset.area[i].raw_data,
            widthpercent: dataset.share[i].raw_data
        });
    }
    return ds_label;
},
```

Yellowfin のデータセットを JSON の配列に変換して ds_label にオブジェクトとして格納しています。
今回のサンプルデータであれば、以下のような JSON の書式になります。横軸のラベルと比率を決めています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/ac7332a2-4e78-98e5-37ab-a0b025043481.png)

画面は [グラフ] ステップでディベロッパーツールのコンソールから確認したものです。コードの中に `console.log(JSON.stringify(ds_label))` を記述しておくと、データオブジェクトの中身をコンソールで確認することができます。今回の場合は、doDrawing の先頭に記述しています。デバッグに便利なので、活用してみてください。

以下の手順では、上記と同じ要領で、マリメッコチャートを描くために必要なデータを各関数の中データセットで取り込んでいく流れになります。

##### processDataValue1
エネルギー (energy) 関連事業部の売上比率に関わるデータをオブジェクトに格納します。
```JavaScript: processDataValue1
processDataValue1 = function(dataset) {
    var ds_value1 = [];
    for (j=0;j<dataset.energy.length;j++){
        ds_value1.push({
            value: dataset.energy[j].raw_data,
        });
    }
    return ds_value1;
},
```

##### processDataValue2
ファイナンス (finance) 関連事業部の売上比率に関わるデータをオブジェクトに格納します。

```JavaScript: processDataValue2
processDataValue2 = function(dataset) {
    var ds_value2 = [];
    for (k=0;k<dataset.finance.length;k++){
        ds_value2.push({
            value: dataset.finance[k].raw_data,
        });
    }
    return ds_value2;
},
```
##### processDataValue3
電子機器 (electronic) 関連事業部の売上比率に関わるデータをオブジェクトに格納します。
```JavaScript: processDataValue3
processDataValue3 = function(dataset) {
    var ds_value3 = [];
    for (l=0;l<dataset.electronic.length;l++){
        ds_value3.push({
            value: dataset.electronic[l].raw_data,
        });
    }
    return ds_value3;
},

```

##### processDataValue4
娯楽 (entertainment) 関連事業部の売上比率に関わるデータをオブジェクトに格納します。
```JavaScript: processDataValue4
processDataValue4 = function(dataset) {
    var ds_value4 = [];
    for (m=0;m<dataset.entertainment.length;m++){
        ds_value4.push({
            value: dataset.entertainment[m].raw_data,
        });
    }
    return ds_value4;
},
```

##### doDrawing
```JavaScript:doDrawing
doDrawing = function(ds_label, ds_value1, ds_value2, ds_value3, ds_value4, $chartDrawDiv) {
    console.log(JSON.stringify(ds_label));
    console.log(JSON.stringify(ds_value1));
    console.log(JSON.stringify(ds_value2));
    console.log(JSON.stringify(ds_value3));
    console.log(JSON.stringify(ds_value4));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                caption: "地域・事業部別シェア",
                numbersuffix: "%",
                showsum: "0",
                usepercentdistribution: "1",
                showxaxispercentvalues: "1",
                showvalues: "1"
            },
            categories:[{category: ds_label}],
            dataset:[
                {
                    seriesname: "エネルギー",
                    color: "#149868",
                    ratio:"100",
                    data: ds_value1
                },
                {
                    seriesname: "ファイナンス",
                    color: "#E7BC4F",
                    ratio:"100",
                    data: ds_value2
                },
                {
                    seriesname: "電子機器",
                    color: "#CE9B1C",
                    ratio:"100",
                    data: ds_value3
                },
                {
                    seriesname: "娯楽",
                    color: "#D9D9D9",
                    ratio:"100",
                    data: ds_value4
                }
            ]
        };
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "marimekko",
                renderAt: $chartDrawDiv[0],
                width: 850,
                height: 500,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};
```

`require[]` の中で、JavaScriptライブラリーを格納したディレクトリーを相対パスで記述します。
`dataSource` `chart` の中で、タイトルや数値表示に関わる設定など、チャートの見た目を定義しています。
例えば`showxaxispercentvalues: "1",` は、横軸の数値ラベルの非表示を Boolean で指定しています。
`categories:[{category: ds_label}],`で、先の手順でデータセットに取り込んだオブジェクトの中身 (地域別の割合を描画するために必要なデータ) を FushionCharts に受け渡します。

`dataset:[...]`の中で、事業部別の割合を描画するために必要なデータを受け渡します。例えば、`data: ds_value1`でエネルギー関連事業、`data: ds_value2`でファイナンス関連事業といった具合に、先の手順でデータセットに取り込んだオブジェクトの中身を受け渡します。`seriesname: "エネルギー"`で凡例に示す言葉を指定し、`color: "#149868"`でデータエリアの色を明示的に指定しています。

`FusionCharts.ready` でチャートを描画します。
`type: " marimekko”,` でチャートの種類を指定します。
`renderAt: $chartDrawDiv[0]` でチャートを描画する div を指定します。`$chartDrawDiv` はコードの先頭で宣言した変数です。

## 5. 最後に
やはり、マリメッコチャートは視覚的に分かりやすく情報を伝えることに優れていますね。
ところで先日、[JSBA](https://www.jsba.or.jp/) 主催のスノーボード・インストラクター講習会に参加してきました。そこで聞いた話として、関東地区ではインストラクターの資格を持つスノーボーダーの 2 - 3 割程度しか、スノーボードスクールに所属して仕事をしていないそうです。一方、東海地区は、6 – 7 割程度がスクールに所属して仕事をしているとのこと。ほとんどの人たちは、平日仕事をしていて、土日だけの非常勤で教えているみたいですが。ちなみに私は東海所属です。詳細な数値が分かったら、地域ごとのインストラクターの数と、スクールへの所属の割合をマリメッコで描画してみようかな。
では皆様、良いデータ分析を! Cheers!!