GO言語のgo-echartsパッケージを使ってヒートマップを出力する方法

# はじめに

go-echarts

https://github.com/go-echarts/go-echarts


を使ってチャートを出力するシリーズの２つ目の記事です。

１つ目は、

https://qiita.com/twsnmp/items/c0bb1b6b8dd18132dfb6

です。

今回は、曜日と時間帯ごとのデータの量を色で表現するヒートマップを出力する方法です。数値が多いところを赤く表示し少ないところを青系にするようなチャートです。


# ヒートマップの出力


ヒートマップは、

```go
package main

import (
	"os"

	"github.com/go-echarts/go-echarts/v2/charts"
	"github.com/go-echarts/go-echarts/v2/opts"
)

var (
	hmData = [][3]int{
		{0, 0, 5}, {0, 1, 1}, {0, 2, 0}, {0, 3, 0}, {0, 4, 0}, {0, 5, 0},
		{0, 6, 0}, {0, 7, 0}, {0, 8, 0}, {0, 9, 0}, {0, 10, 0}, {0, 11, 2},
		{0, 12, 4}, {0, 13, 1}, {0, 14, 1}, {0, 15, 3}, {0, 16, 4}, {0, 17, 6},
		{0, 18, 4}, {0, 19, 4}, {0, 20, 3}, {0, 21, 3}, {0, 22, 2}, {0, 23, 5},
		{1, 0, 7}, {1, 1, 0}, {1, 2, 0}, {1, 3, 0}, {1, 4, 0}, {1, 5, 0},
		{1, 6, 0}, {1, 7, 0}, {1, 8, 0}, {1, 9, 0}, {1, 10, 5}, {1, 11, 2},
		{1, 12, 2}, {1, 13, 6}, {1, 14, 9}, {1, 15, 11}, {1, 16, 6}, {1, 17, 7},
		{1, 18, 8}, {1, 19, 12}, {1, 20, 5}, {1, 21, 5}, {1, 22, 7}, {1, 23, 2},
		{2, 0, 1}, {2, 1, 1}, {2, 2, 0}, {2, 3, 0}, {2, 4, 0}, {2, 5, 0}, {2, 6, 0},
		{2, 7, 0}, {2, 8, 0}, {2, 9, 0}, {2, 10, 3}, {2, 11, 2}, {2, 12, 1}, {2, 13, 9},
		{2, 14, 8}, {2, 15, 10}, {2, 16, 6}, {2, 17, 5}, {2, 18, 5}, {2, 19, 5},
		{2, 20, 7}, {2, 21, 4}, {2, 22, 2}, {2, 23, 4}, {3, 0, 7}, {3, 1, 3},
		{3, 2, 0}, {3, 3, 0}, {3, 4, 0}, {3, 5, 0}, {3, 6, 0}, {3, 7, 0},
		{3, 8, 1}, {3, 9, 0}, {3, 10, 5}, {3, 11, 4}, {3, 12, 7}, {3, 13, 14},
		{3, 14, 13}, {3, 15, 12}, {3, 16, 9}, {3, 17, 5}, {3, 18, 5}, {3, 19, 10},
		{3, 20, 6}, {3, 21, 4}, {3, 22, 4}, {3, 23, 1}, {4, 0, 1}, {4, 1, 3},
		{4, 2, 0}, {4, 3, 0}, {4, 4, 0}, {4, 5, 1}, {4, 6, 0}, {4, 7, 0},
		{4, 8, 0}, {4, 9, 2}, {4, 10, 4}, {4, 11, 4}, {4, 12, 2}, {4, 13, 4},
		{4, 14, 4}, {4, 15, 14}, {4, 16, 12}, {4, 17, 1}, {4, 18, 8}, {4, 19, 5},
		{4, 20, 3}, {4, 21, 7}, {4, 22, 3}, {4, 23, 0}, {5, 0, 2}, {5, 1, 1},
		{5, 2, 0}, {5, 3, 3}, {5, 4, 0}, {5, 5, 0}, {5, 6, 0}, {5, 7, 0}, {5, 8, 2},
		{5, 9, 0}, {5, 10, 4}, {5, 11, 1}, {5, 12, 5}, {5, 13, 10}, {5, 14, 5},
		{5, 15, 7}, {5, 16, 11}, {5, 17, 6}, {5, 18, 0}, {5, 19, 5}, {5, 20, 3},
		{5, 21, 4}, {5, 22, 2}, {5, 23, 0}, {6, 0, 1}, {6, 1, 0}, {6, 2, 0},
		{6, 3, 0}, {6, 4, 0}, {6, 5, 0}, {6, 6, 0}, {6, 7, 0}, {6, 8, 0},
		{6, 9, 0}, {6, 10, 1}, {6, 11, 0}, {6, 12, 2}, {6, 13, 1}, {6, 14, 3},
		{6, 15, 4}, {6, 16, 0}, {6, 17, 0}, {6, 18, 0}, {6, 19, 0}, {6, 20, 1},
		{6, 21, 2}, {6, 22, 2}, {6, 23, 6},
	}

	weekDays = [...]string{"Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"}

	dayHrs = [...]string{
		"12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a",
		"12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p",
	}
)

func genHeatMapData() []opts.HeatMapData {
	items := make([]opts.HeatMapData, 0)
	for i := 0; i < len(hmData); i++ {
		if hmData[i][2] == 0 {
			items = append(items, opts.HeatMapData{Value: [3]interface{}{hmData[i][1], hmData[i][0], "-"}})
		} else {
			items = append(items, opts.HeatMapData{Value: [3]interface{}{hmData[i][1], hmData[i][0], hmData[i][2]}})
		}
	}
	return items
}

func main() {
	hm := charts.NewHeatMap()
	hm.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{
			Title: "basic heatmap example",
		}),
		charts.WithXAxisOpts(opts.XAxis{
			Type:      "category",
			Data:      dayHrs,
			SplitArea: &opts.SplitArea{Show: opts.Bool(true)},
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Type:      "category",
			Data:      weekDays,
			SplitArea: &opts.SplitArea{Show: opts.Bool(true)},
		}),
		charts.WithVisualMapOpts(opts.VisualMap{
			Calculable: opts.Bool(true),
			Min:        0,
			Max:        10,
			InRange: &opts.VisualMapInRange{
				Color: []string{"#50a3ba", "#eac736", "#d94e5d"},
			},
		}),
	)

	hm.AddSeries("heatmap", genHeatMapData())

	f, _ := os.Create("heatmap.html")
	hm.Render(f)
}

```

 のようなプログラムで出力できます。結果は

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874862/59dffdd3-f1b2-9d2f-2492-73adfd6ff5ed.png)

のようになります。


ヒートマップを出力する時のポイントは、

### X軸、Y軸の設定

タイプをcategoryにしてデータに配列を設定します。

```go
	weekDays = [...]string{"Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"}

	dayHrs = [...]string{
		"12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a", "10a", "11a",
		"12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p",
	}

|
		charts.WithXAxisOpts(opts.XAxis{
			Type:      "category",
			Data:      dayHrs,
			SplitArea: &opts.SplitArea{Show: opts.Bool(true)},
		}),
		charts.WithYAxisOpts(opts.YAxis{
			Type:      "category",
			Data:      weekDays,
			SplitArea: &opts.SplitArea{Show: opts.Bool(true)},
		}),

```

### データ

データは、

> X座標、Y座標、数値

の３つの数値の配列です。

```go
hmData = [][3]int{
		{0, 0, 5}

items = append(items, opts.HeatMapData{Value: [3]interface{}{hmData[i][1], hmData[i][0], hmData[i][2]}})

```

座標(0,0)の原点は、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874862/1a713522-9471-3eb3-382e-167ad1f98201.png)

の位置です。Y軸は上へ、X軸は、右へいくほど大きくなります。


# 応用

このヒートマップは

https://note.com/twsnmp/n/nd90978e728c0

のソフトの中で曜日と時間帯や日付と時間帯のログの件数を表現するために使っています。

X軸とY軸を変更すれば、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874862/d9f08973-d791-8ada-3aa2-fa874ed5434e.png)

のような表現もできます。