Grafanaで箱ひげ図（Boxplot）を描くーその２

## 元データ
PostgreSQLでデータを作成
```
CREATE TABLE "成績" (
"学生番号"  varchar(255) not null,
"英語"      decimal(3,0),
"数学"      decimal(3,0),
"国語"      decimal(3,0),
PRIMARY KEY("学生番号")
);

INSERT INTO "成績" VALUES ('A01', 20, 20, 50);
INSERT INTO "成績" VALUES ('A02', 30, 25, 51);
INSERT INTO "成績" VALUES ('A03', 40, 30, 52);
INSERT INTO "成績" VALUES ('A04', 50, 35, 53);
INSERT INTO "成績" VALUES ('A05', 45, 40, 54);
INSERT INTO "成績" VALUES ('A06', 60, 45, 55);
INSERT INTO "成績" VALUES ('A07', 20, 50, 56);
INSERT INTO "成績" VALUES ('A08', 10, 55, 57);
INSERT INTO "成績" VALUES ('A09', 10, 60, 58);
INSERT INTO "成績" VALUES ('A10', 10, 65, 59);
INSERT INTO "成績" VALUES ('A11', 10, 70, 60);
```
## Grafanaエディタ画面の左側、クエリーの設定
いたって普通の設定です。データソース選んで、テーブル選んで、カラムを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/29ce8dec-78be-5b61-400a-b6b2cb34c573.png)

## Grafanaエディタ画面の右側、Visual Editorの設定
Dataset Itemsに成績の科目のみ選びます。学生番号は選びません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/f696b4d2-3d7c-c23d-4c78-fe60cdb75354.png)

## コード
感触としてはdatasetだけのコードが違うApache EChartsコードです。
Bussiness Chartsのサンプルコードでは以下の記述が多いですが、これだとdatasetは描画する直接の座標値データになるため、transformを入れた工夫が必要です。
```
return {
  dataset: context.editor.dataset,
  series: context.editor.series,
  xAxis: {
...
```
context.editor.dataset.sourceの１行目にはラベルが入っているので今回は邪魔なので別の変数に移動させて、X軸のラベル描画の際にその変数を用います。formatterのfunctionのparamsには値が0,1,2と入ってくるので配列のインデックス指定に使います。
```
// 最初の１行はラベル名、sourceから取り除く
mylabels = context.editor.dataset.source.shift();
//const mylabels = ['英語', '数学', '国語'];
```
```
  xAxis: {
    type: 'category',
    axisLabel: {
      formatter: function (params) {
        return mylabels[params];
      }
    }
  },
```
箱ひげ図の値データは１行の行データに変換する必要があるので行と列の変換を行います。
以下のコードはJavaScriptの行列交換のコード
```
// 行列交換
const transpose = a => a[0].map((_, c) => a.map(r => r[c]));
showdata = transpose(context.editor.dataset.source);
```

データはtransformオプションで箱ひげ図の元データとして計算させて描画させるデータへ変換させます。
```
    {
      // datasetindex is 1 
      fromDatasetIndex: 0,
      transform: {
        type: 'boxplot',
      },
    },
```   
最終的なコードは以下の通り
```
// 最初の１行はラベル名、sourceから取り除く
mylabels = context.editor.dataset.source.shift();
//const mylabels = ['英語', '数学', '国語'];

// 行列交換
const transpose = a => a[0].map((_, c) => a.map(r => r[c]));
showdata = transpose(context.editor.dataset.source);

return {
  dataset: [
    {
      // datasetindex is 0 
      source: showdata,
    },
    {
      // datasetindex is 1 
      fromDatasetIndex: 0,
      transform: {
        type: 'boxplot',
      },
    },
  ],
  grid: {
    left: '10%',
    right: '10%',
    bottom: '15%'
  },
  series: {
    type: 'boxplot',
    datasetIndex: 1
  },
  xAxis: {
    type: 'category',
    axisLabel: {
      formatter: function (params) {
        return mylabels[params];
      }
    }
  },
  yAxis: {
    type: 'value',
    name: '点数',
    splitArea: {
      show: true
    }
  },
}
``` 

## 最初試したコード
クエリーから表示する前は以下のような感じでデータを直接コードに書きながらグラフが正しく表示されるか確認していました。
```
return {
  grid: {
    left: '10%',
    right: '10%',
    bottom: '15%'
  },
  dataset: [
    {
      // datasetindex=0
      source: [
        [74, 90, 107, 93, 85, 95, 98, 98, 88, 100, 98, 93, 65, 76],
        [24, 36, 44, 58, 60, 85, 88, 90, 84, 83, 79, 81, 88, 88],
        [88, 88, 86, 72, 72, 62, 86, 97, 95, 88, 91, 85, 87, 84],
        [81, 81, 82, 80, 77, 76, 74, 75, 76, 91, 92, 89, 86, 88],
      ]
    },
    {
      // datasetindex=1
      fromDatasetIndex: 0,
      transform: {
        type: 'boxplot',
        config: {
          itemNameFormatter: function (params) {
            if (params.value == 0) return '数学';
            if (params.value == 1) return '英語';
            if (params.value == 2) return '国語';
            if (params.value == 3) return '地理';
          }
        }
      },
    },
  ],
  series: {
    type: 'boxplot',
    datasetIndex: 1
  },
  xAxis: {
    type: 'category',
  },
  yAxis: {
    type: 'value',
    name: '点数',
    splitArea: {
      show: true
    }
  },
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/b737b3cc-8673-2d2b-0e13-cbe20b39201e.png)

## ２系列、色を変える場合
こんな感じだと思います。Business ChartsのVisual Editorは１つのdatasetだけなので、複数のdatasetを使う場合はクエリーからVisual Editorへのデータセットをどうやって複数に分けるか考える必要があると思います。
```
const mylabels = ['英語', '数学', '国語'];

return {
  dataset: [
    {
      // dataset index = 0
      source: [
        [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
        [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
        [30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
      ]
    },
    {
      // dataset index = 1
      source: [
        [40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50],
        [50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60],
        [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70],
      ]
    },
    {
      // dataset index = 2
      fromDatasetIndex: 0,
      transform: {
        type: 'boxplot',
      },
    },
    {
      // dataset index = 3
      fromDatasetIndex: 1,
      transform: { type: 'boxplot' },
    },
  ],
  grid: {
    left: '10%',
    right: '10%',
    bottom: '15%'
  },
  series: [
    {
      type: 'boxplot',
      name: 'boxplot1',
      itemStyle: {
        color: 'blue'
      },
      datasetIndex: 2
    },
    {
      type: 'boxplot',
      name: 'boxplot2',
      itemStyle: {
        color: 'white'
      },
      datasetIndex: 3
    },
  ],
  xAxis: {
    type: 'category',
    axisLabel: {
      formatter: function (params) {
        return mylabels[params];
      }
    }
    // datasetを使うと、ここでdataは使えない
    // data: ['英語', '数学', '社会']
  },
  yAxis: {
    type: 'value',
    name: '点数',
    splitArea: {
      show: true
    }
  },
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242268/8f82d597-9f28-0603-cc17-86622599f088.png)

[Grafanaで箱ひげ図（Boxplot）を描く－その１](https://qiita.com/solarisintel/items/5f9e56cb35ca4377ec46)