Data Portalのデータビジュアライゼーション事始め


## 本記事について
本稿は以下の内容について内容の要点と所感についての記事なります。  
詳しいことを知りたい方は 下記リンクから各記事を参照してください。

- [データポータルのコミュニティ ビジュアリゼーション  |  コミュニティ由来ビジュアル表示  |  Google Developers](https://developers.google.com/datastudio/visualization/)
- [Community Visualizations: Introduction to Community Visualizations - YouTube](https://www.youtube.com/watch?v=11Ujl4y-SFA&feature=emb_logo)

## Data Portalとは
Googleが提供しているデータビジュアライゼーションツールです。  BI(Business Integration)ツールと呼ばれることもあります。
Googleが提供しているグラフも種類を多岐に渡るのですが、使っていくとかゆいところに手が届かなくなることがしばしばあります。  
Data Portalではユーザー独自のビジュアライゼーションを行うためにコミュニティビジュアライゼーションと呼ばれる機能を提供しています。 これはJSで構成された独自のビジュアライゼーションをGoogleCloudStrageにアップロードしておき、それを呼び出してレポートに含めることが出来る機能です。本稿はそのコミュニティビジュアライゼーションをどう実装するのかをまとめたものになります。

## 開発環境をつくる

公式でプロジェクトテンプレートを提供しているので活用しましょう。
テンプレートを使用すると棒グラフのコミュニティビジュアライゼーションプロジェクトが作成されます。

```shell
$ npx @google/dscc-gen viz                                                                                                                                            

npx: 315個のパッケージを13.01秒でインストールしました。
? Project name minimal-d3js-sample           // ディレクトリ名 (Vizの名前ではない)
? What is your "dev" directory? gs://[backet path]/minimal-d3js-dev           // 開発中のものを入れるディレクトリ
? What is your GCS prod directory? gs://[backet path]/minimal-d3js-prod  // 本運用しているものを入れるディレクトリ
Installing dependencies...

Created new community viz: minimal-d3js-sample

cd minimal-d3js-sample and npm run start to begin working on your viz!
```


### 初期の状態を確かめる

プロジェクトテンプレートの中には棒グラフのビジュアライズの例が入っているので動かしてみます。  

```shell
$ npm run start                                                                                                                                   [~/dev/datapotal-sample/minimal-d3js-sample][master]

> @ start /Users/shogo.matsushita/dev/datapotal-sample/minimal-d3js-sample
> dscc-scripts viz start

ℹ ｢wds｣: Project is running at http://localhost:8080/
ℹ ｢wds｣: webpack output is served from /
ℹ ｢wds｣: Content not from webpack is served from ./dist
ℹ ｢wdm｣: wait until bundle finished: /

```

実行するとブラウザが立ち上がり以下のような画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/c67f52e8-90a5-d3f5-114e-bd3bb34f941e.png)

### コードを読む
 このときのディレクトリ構成は下記の通りになります。  

```shell
$ tree -L 2            
                                                                                                                      
├── README.md
├── dist 
│   ├── index.html
│   └── vizframe.html
├── node_modules
├── package-lock.json
├── package.json
├── src
│   ├── index.css  // 見た目を整えるためのCSS
│   ├── index.js     //  呼び出すときに呼ばれる実装ファイル
│   ├── index.json // プロパティの定義
│   ├── localMessage.js  // モックデータ
│   └── manifest.json  // コミュニティビジュアライゼーションプロジェクト定義ファイル
├── webpack.config.js
└── yarn.lock
```
## 必要なファイル

 独自の視覚化を行うには下記のファイルがGoogle Cloud Platform上にアップされている必要があります。

| ファイル名              | ファイルタイプ | 目的                                                             |
|-------------------------|----------------|------------------------------------------------------------------|
| manifest.json *         | JSON           | 他のリソースの視覚化と場所に関するメタデータを提供します。 (名前変更不可)       |
| myViz.json              | JSON           | プロパティパネルのデータとスタイルの構成オプションを提供します。 |
| myViz.js                | JavaScript     | 視覚化の表示に必要なJavaScriptコードを提供します。               |
| myViz.css（オプション） | CSS            | 視覚化のスタイルを提供します。                                   |



####  index.js

一番最初に呼ばれるファイルは`manifest.json`で設定ができます。  
デフォルトではこの`index.js`が設定されています。

```javascript

const dscc = require('@google/dscc');
const viz = require('@google/dscc-scripts/viz/initialViz.js');
const local = require('./localMessage.js');

// ローカルか否か 初期では直接記載されている
// falseの場合はモックデータが入っている`localMessage.js`が呼び出される
// change this to 'true' for local development
// change this to 'false' before deploying
export const LOCAL = false;

// write viz code here
const drawViz = (data) => {
  console.log(data)
  // ここでVizのコードを呼び出し描画を行っている
  // このファイル自体は initialViz.jsを使用している
  viz.forceDirected(data);
};

// renders locally
if (LOCAL) {
  drawViz(local.message);
} else {
  dscc.subscribeToData(drawViz, {transform: dscc.objectTransform});
}

```

#### index.json

DataPortalから受け取る値の定義とその型などを定義するファイルです。
詳細は[コミュニティ由来ビジュアル表示の設定リファレンス  |  Google Developers](https://developers.google.com/datastudio/visualization/config-reference?hl=ja)を参照してください。

下記の例ではdimIDとmetricIDを定義しています。
また設定できる見た目の定義もここでおこないます。

```json

{
  "data": [
    {
      "id": "concepts",
      "label": "Concepts",
      "elements": [
        {
          "id": "dimID",
          "label": "A dimension",
          "type": "DIMENSION",
          "options": {
            "min": 1,
            "max": 1
          }
        },
        {
          "id": "metricID",
          "label": "A metric",
          "type": "METRIC",
          "options": {
            "min": 1,
            "max": 1
          }
        }
      ]
    }
  ],
  "style": [ ]
}

```

#### manifest.json

コミュニティビジュアライゼーションプロジェクトの定義を行います。このファイルは命名不変更不可です。
詳細は[コミュニティ ビジュアリゼーションのマニフェスト リファレンス  |  コミュニティ由来ビジュアル表示  |  Google Developers](https://developers.google.com/datastudio/visualization/manifest-reference?hl=ja)を参照のしてください。

```json
{
  "name": "[パッケージ名]",
  "organization": "[組織名]",
  "description": "[説明]].",
  "logoUrl": "[ロゴURL]",
  "organizationUrl": "[組織URL]",
  "supportUrl": "[ドキュメントURL]",
  "privacyPolicyUrl": "[プライバシーポリシーURL]",
  "termsOfServiceUrl": "https://url",
  "packageUrl": "https://url",
  "devMode": "DEVMODE_BOOL",
  "components": [
    {
      "name": "[Viz名]",
      "description": "[説明]",
      "iconUrl": "[アイコンURL]",
      "resource": {
        "js": "YOUR_GCS_BUCKET/[最初に呼び出されるjavascriptsファイルパス]",
        "config": "YOUR_GCS_BUCKET/[設定ファイルパス]",
        "css": "YOUR_GCS_BUCKET/[CSSファイルパス]"
      }
    }
  ]
}
```

## d3.jsでhello world.


### d3.jsを入る
まずはd3.jsを使えるようにします。

```console
$ npm install d3

+ d3.js@0.0.2-security
added 1 package and audited 686 packages in 3.953s

22 packages are looking for funding
```

### 描写を実装する

新しく`main.js`を作成して下記のコードを書きます。

```javascript
const d3 = require("d3");

export const draw = async(data) => {
  d3.select("body").append("span")
  .text("Hello, world!");

}
```

記載ができたら`index.js`で呼び出すのをgoogleのサンプルから今実装した内容に変更します。

```javascript
const dscc = require('@google/dscc');
const viz = require('./main'); // 読み込み先を変更
const local = require('./localMessage.js');

// change this to 'true' for local development
// change this to 'false' before deploying
export const LOCAL = true;

// write viz code here
const drawViz = (data) => {
// 呼び出しを変更
  viz.draw(data);
};

// renders locally
if (LOCAL) {
  drawViz(local.message);
} else {
  dscc.subscribeToData(drawViz, {transform: dscc.objectTransform});
}

```

うまく行けば次のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/01ba33d5-c76c-9527-520e-12d6779c8d92.png)



## デプロイする

次に実際にデータポータルで使えるようにデプロイします。  
Data Portal上で使うにはGoogle Cloud Strage(GCS)上で公開されている必要があります。  
もし一番最初にGCSのパスを設定できていれば次のコマンドでデプロイ出来ます。  

```console
 $ npm run build:dev       

> @ build:dev /Users/shogo.matsushita/dev/datapotal-sample/minimal-d3js-sample
> dscc-scripts viz build -d dev
```

```console
$n npm run push:dev    

> @ push:dev /Users/shogo.matsushita/dev/datapotal-sample/minimal-d3js-sample
> dscc-scripts viz push -d dev

Copying file://build/index.js [Content-Type=application/javascript]...
Copying file://build/index.css [Content-Type=text/css]...                       
Copying file://build/manifest.json [Content-Type=application/json]...           
Copying file://build/index.json [Content-Type=application/json]...              
- [4 files][  1.3 MiB/  1.3 MiB]                                                
Operation completed over 4 objects/1.3 MiB.                                      
Viz deployed to: gs://datapotal-sample/minimal-d3js-sample
```

以上のコマンドでデプロイが可能です。


## データポータル上で使う

早速デプロイしたものを使用してみます。  
新しくレポートを作成してCommunity visualizationsの追加(下記参照)を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/c6bf02a9-dbf6-0c1a-8e28-9108c6608591.png)

Community visualizationsのメニューがでたら一番下のもっと見るをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/f15a23bf-3942-dd2d-a15e-2b6dbaaced23.png)


すると下部からビジュアライズのリストが出てきます。 右上にある独自のビジュアライズの追加を押します。  
そうするとコミュニティビジュアライゼーションのテストと追加が出てくるので先程デプロイしたGCSのパスを入力して送信をおします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/9919d122-4e0c-c4c8-5f75-9aaf00c82b72.png)




## レポートに追加しよう
テストと追加で追加が終わるとビジュアライゼーションとして選択できるようになります。  
選択してレポートに追加すると、無事`Hello, world!`が表示されました。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/8f5eae90-d460-a9b7-9c13-75282ffbf761.png)



## データを受け取ってみる

初期ではデータは下記のような状態で送られてきます。  

```json

{
    "tables": {
        "DEFAULT": [
            {
                "dimID": [
                    "25-54"
                ],
                "metricID": [
                    128863172
                ]
            },
            {
                "dimID": [
                    "0-14"
                ],
                "metricID": [
                    61175933
                ]
            },
            {
                "dimID": [
                    "65+"
                ],
                "metricID": [
                    51055052
                ]
            },
            {
                "dimID": [
                    "15-24"
                ],
                "metricID": [
                    43351778
                ]
            },
            {
                "dimID": [
                    "55-64"
                ],
                "metricID": [
                    42179856
                ]
            }
        ]
    },
    "fields": {
        "dimID": [
            {
                "id": "qt_nzqx6a0xvb",
                "name": "Age Group",
                "type": "TEXT",
                "concept": "DIMENSION"
            }
        ],
        "metricID": [
            {
                "id": "qt_8isx6a0xvb",
                "name": "Population",
                "type": "NUMBER",
                "concept": "METRIC"
            }
        ]
    },
    "style": {}
}
```

この場合例えばディメンション`dimID`に入ったデータを読み取ってテキストとして表示するには下記のようなプログラムになります。

```javascript
const d3 = require("d3");

export const draw = async(data) => {
  let rowData = data.tables.DEFAULT;
  console.log(JSON.stringify(data))
  let body = d3.select("body")
  for(let idx in rowData){
    body.append("span")
    .text(rowData[idx]["dimID"][0]);
  
  }
}
```
動作させると下記の用になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77203/9047d8da-73c2-c901-b32f-7ab1d058103d.png)



## 更新しよう
再度データポータルで見るためにアップロードします。
更新を有効にするにはブラウザリロードを行う必要があります。  

## 最後に

日本語でのドキュメントはほとんどありませんが、開発周辺の環境は非常に整っています。  また内容としてもjavascripで動けば何でもできるような印象を受けます。  
今回はd3.jsでしたが他の外部ライブラリ動くのではないでしょうか。  
ただ、データや処理が肥大化すると処理の時間に多大な時間が必要になるので大きくなればなるほど軽量化との闘いになりそうです。