ノードダイアグラム：Yellowfin と FusionCharts の活用

Yellowfin と FusionCharts を用いてノードダイアグラムを作成してみようと思います。FusionCharts の dragnodes タイプのチャートを用いることで、組織図のような階層構造データや、ネットワーク図のような平面的なデータなどを含め、ノードどうしの結びつきを可視化することができます。今回は、階層構造のデータを使った手順を紹介したいと思います。

## 1. 事前準備

#### 1-1. データの準備まで
[前回記事](https://qiita.com/ExtremeCarvFJ/items/ad453a6110cec093bdb9)  を参考に、『1-3. データの準備』 までの作業を実施します。なお、以下の手順と同じデータを使いたい方は、[こちら]( https://github.com/ChasingHH/ShareFiles/blob/Share/nodes.csv)にサンプルデータを共有しています。

#### 1-2. ビューの作成
以下の通りに軸 (Dimensions) と集計値 (Metrics) を設定します。
&nbsp; &nbsp; &nbsp;軸 : type, id, label, shape, color
&nbsp; &nbsp; &nbsp;集計値 : height, width, x, y, from, to, arrowatstart, arrowatend, alpha

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

#### 2-1. [データ] ステップ
ビューに設定した軸と集計値を全てテーブルに配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/b092578a-3b7b-902e-466d-fda11630b0e8.png)

#### 2-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/4f9bb919-c9f0-97bf-d611-4f6d60f89ee1.png)

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

processNode = function(dataset) {
    var ds_node = [];
    for (i=0;i<dataset.from.length;i++){
        if(dataset.type[i].formatted_data === "node"){
            ds_node.push({
                id: dataset.id[i].raw_data,
                label:dataset.label[i].raw_data,
                x:dataset.x[i].raw_data,
                y:dataset.y[i].raw_data,
                shape:dataset.shape[i].raw_data,
                width:dataset.width[i].raw_data,
                height:dataset.height[i].raw_data,
                color:dataset.color[i].raw_data,
            });
        }
    }
    return ds_node;
},

processArrow = function(dataset) {
    var ds_arrow = [];
    for (ii=0;ii<dataset.from.length;ii++){
        if(dataset.type[ii].formatted_data === "arrow"){
            ds_arrow.push({
                from: dataset.from[ii].raw_data,
                to: dataset.to[ii].raw_data,
                color: dataset.color[ii].raw_data,
                arrowatstart: dataset.arrowatstart[ii].raw_data,
                arrowatend: dataset.arrowatend[ii].raw_data,
                alpha: dataset.alpha[ii].raw_data,
            });
        }
    }
    return ds_arrow;
},

doDrawing = function(ds_node, ds_arrow, $chartDrawDiv) {
    console.log(JSON.stringify(ds_node));
    console.log(JSON.stringify(ds_arrow));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                caption: "公式ホームぺージの構成",
                subcaption: "ノードを動かしてみよう",
                theme: "fusion",
                valuefontcolor: "#ffffff",
                yaxismaxvalue: "500",
                yaxisminvalue: "0",
                divlinealpha: "10"
            },
            dataset: [
                {
                    data: ds_node
                }
            ],
            connectors: [
                {
                    stdthickness: "1.5",
                    connector: ds_arrow
                }
            ]
        };
        
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "dragnode",
                renderAt: $chartDrawDiv[0],
                width: 500,
                height: 500,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};

```
##### プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。
今回は、ホームページの構成を示すダイアグラムを作成してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/232542df-10d5-8c4d-06b5-632a287cfc6d.png)

ノードをドラッグアンドドロップで移動させることで、配置を変更することも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/7cffcf60-fcc4-a5ce-5a4e-cad996b18d34.png)

## 3. コードの内容
チャートの動作概要が分かったところで、コードの中身を見てみましょう。

##### generateChart
```JavaScript:generateChart
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedNode = processNode(options.dataset.data);
    var processedArrow = processArrow(options.dataset.data);
    doDrawing(processedNode, processedArrow, $chartDrawDiv);
},
```

JavaScript グラフの処理において、最初に呼び出されるのが generateChart = function(options) です。
[データ] ステップでテーブルに追加した情報が options に格納されて、メソッドに受け渡されます。
`var $chartDrawDiv = $(options.divSelector)` でグラフを出力する div を選択します。
`var processedNode = processNode(options.dataset.data);`
`var processedArrow = processArrow(options.dataset.data);`
`doDrawing(processedNode, processedArrow, $chartDrawDiv);`
上記3行で、別の関数を呼び出して、データ処理とグラフ描画処理を行っています。呼び出し先の関数での処理内容は後続の個所で説明をします。

##### processNode
```JavaScript:processNode
processNode = function(dataset) {
    var ds_node = [];
    for (i=0;i<dataset.from.length;i++){
        if(dataset.type[i].formatted_data === "node"){
            ds_node.push({
                id: dataset.id[i].raw_data,
                label:dataset.label[i].raw_data,
                x:dataset.x[i].raw_data,
                y:dataset.y[i].raw_data,
                shape:dataset.shape[i].raw_data,
                width:dataset.width[i].raw_data,
                height:dataset.height[i].raw_data,
                color:dataset.color[i].raw_data,
            });
        }
    }
    return ds_node;
},
```

Yellowfin のデータセットを JSON の配列に変換して ds_node にオブジェクトとして格納しています。
今回のサンプルデータであれば、以下のような JSON の書式になります。画面は [グラフ] ステップでディベロッパーツールのコンソールから確認したものです。コードの中に `console.log(JSON.stringify(ds_node))` を記述しておくと、データオブジェクトの中身をコンソールで確認することができます。今回の場合は、doDrawing の先頭に記述しています。デバッグに便利なので、活用してみてください。

ds_node データセットの中身は、ノードを描画するための情報です。
id で各ノードに一意の情報を割り振っています。後述の手順では、この id 情報を用いて、ノードどうしを線で結びます。x, y でノードの配置場所を指定します。label, shape, height, width, color はノードの見た目を決めるための情報です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/04e74ad7-8d6a-b6c3-3c2e-c0f200cf4f38.png)

##### processArrow

```JavaScript:processArrow
processArrow = function(dataset) {
    var ds_arrow = [];
    for (ii=0;ii<dataset.from.length;ii++){
        if(dataset.type[ii].formatted_data === "arrow"){
            ds_arrow.push({
                from: dataset.from[ii].raw_data,
                to: dataset.to[ii].raw_data,
                color: dataset.color[ii].raw_data,
                arrowatstart: dataset.arrowatstart[ii].raw_data,
                arrowatend: dataset.arrowatend[ii].raw_data,
                alpha: dataset.alpha[ii].raw_data,
            });
        }
    }
    return ds_arrow;
},
```

Yellowfin のデータセットを JSON の配列に変換して ds_arrow にオブジェクトとして格納しています。ds_arrow データセットの中身は、矢印を描画するための情報で、ノードの id を from, to で指定して、矢印の起点と終点を決めています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/013c0a20-655e-179b-7314-6877413de392.png)

```JavaScript:doDrawing
doDrawing = function(ds_node, ds_arrow, $chartDrawDiv) {
    console.log(JSON.stringify(ds_node));
    console.log(JSON.stringify(ds_arrow));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                caption: "公式ホームぺージの構成",
                subcaption: "ノードを動かしてみよう",
                theme: "fusion",
                valuefontcolor: "#ffffff",
                yaxismaxvalue: "500",
                yaxisminvalue: "0",
                divlinealpha: "10"
            },
            dataset: [
                {
                    data: ds_node
                }
            ],
            connectors: [
                {
                    stdthickness: "1.5",
                    connector: ds_arrow
                }
            ]
        };
        
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "dragnode",
                renderAt: $chartDrawDiv[0],
                width: 500,
                height: 500,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};
```

`require[]` の中で、JavaScriptライブラリーを格納したディレクトリーを相対パスで記述します。

`dataSource` `chart` の中で、チャートのタイトルや軸などに関する設定を施しています。
`dataset:` `data: ds_node` で ds_node データセットを FushionCharts に受け渡しています。
同様に、`connectors:` `connector: ds_arrow` で ds_arrow データセットを FushionCharts に受け渡しています。

`FusionCharts.ready` でチャートを描画します。
`type: "dragnode,` でチャートの種類を指定します。
`renderAt: $chartDrawDiv[0]` でチャートを描画する div を指定します。`$chartDrawDiv` はコードの先頭で宣言した変数です。
`width` と `height` はダッシュボードの大きさなどに合わせてピクセル単位で指定します。FusionCharts のサンプルを見ると、%で指定していますが、Yellowfin で扱う場合は、ピクセルで指定した方がきれいに表示されます。

## 4. 応用
同じタイプのチャートを活用して、地下鉄マップやネットワーク図を描画することも可能です。詳細は [FusionCharts の公式サイト]( https://www.fusioncharts.com/charts/drag-node-charts)でご確認ください。 

## 5. 最後に
いかがでしたか、色々な用途に活用できそうなチャートですね。
是非、皆さんの想像力を生かして、素敵なチャートを描いてみてください。
では、良いデータ分析を! See you then, cheers!!