GolangとGoogle Chartで時系列感情分析グラフを作成
はじめに
最近、転生したらスライムだった件を全話見終わりました。本当に癒されるアニメですね。Amazon Prime Videoでおすすめのアニメやドラマ、映画、小説などがあれば教えてください。娯楽に飢えています。
今回は、Golangで取り込んだCSVファイルをGoogle Chartで時系列に表示し、感情値を分析する方法を紹介します。これは、先日コメントでリクエストされた内容です(ぽんすけさん、いつもコメントありがとうございます!)。
今回やること
Golangで取り込んだCSVファイルをGoogle Chartで時系列に表示します。
せっかく表示するならと、感情値を時系列に出力したものが見たいとコメントでリクエストがありましたのでそちらを実装してみようと思います。 (ぽんすけさん、いつもコメントありがとうございます。励みになります。)
今回は余裕だなと思ってはじめましたが、Google Chartの所でハマりました。とても勉強になりました。
やっぱビジュアル的に見やすいのはいいですね。ひと目で分かるのがいいです。
CSVファイルは、前回記事Twitterの過去ツイートからベストポジティブツイートを見つけよう(golang)で作成したものを使います。
前回記事の出力のままでは、余計な情報も有ります。
- 冒頭のデータテーブル
- ファイルの中盤に区切りとして導入した「——————————」より下を全部削除 以上2点だけ修正して利用してください。
実行コード
事前準備
go get "github.com/jszwec/csvutil"
csvutilを使います。
main.go
コード全文
package main
import (
"fmt"
"html/template"
"io/ioutil"
"net/http"
"sort"
"github.com/jszwec/csvutil"
)
var templates = template.Must(template.ParseFiles("index.html"))
type Twitter struct {
Create string `csv:"create"`
Tweet string `csv:"tweet"`
Sum float64 `csv:"sum"`
Average float64 `csv:"average"`
}
type TweetdataList []Twitter
var Tweetdatas TweetdataList
func (e TweetdataList) Len() int {
return len(e)
}
func (e TweetdataList) Less(i, j int) bool {
return e[i].Create < e[j].Create
}
func (e TweetdataList) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}
func readCSV() TweetdataList {
fp, err := ioutil.ReadFile("graph.csv")
if err != nil {
panic(err)
}
_ = csvutil.Unmarshal(fp, &Tweetdatas)
sort.Sort(TweetdataList(Tweetdatas))
return Tweetdatas
}
func viewCharthandler(w http.ResponseWriter, r *http.Request) {
err := templates.ExecuteTemplate(w, "index.html", Tweetdatas)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func StartWebServer() error {
http.HandleFunc("/chart/", viewCharthandler)
return http.ListenAndServe(fmt.Sprintf(":%d", 8080), nil)
}
func main() {
_ = readCSV()
StartWebServer()
}
CSVファイルデータの構造体格納
type Twitter struct {
Create string `csv:"create"`
Tweet string `csv:"tweet"`
Sum float64 `csv:"sum"`
Average float64 `csv:"average"`
}
type TweetdataList []Twitter
var Tweetdatas TweetdataList
func readCSV() TweetdataList {
fp, err := ioutil.ReadFile("graph.csv")
if err != nil {
panic(err)
}
_ = csvutil.Unmarshal(fp, &Tweetdatas)
sort.Sort(TweetdataList(Tweetdatas))
return Tweetdatas
}
readCSVのReadFile()でCSVファイルを取り込みます。 csvutil.Unmarshalを使うことで、データの中身を構造体に詰め込むことができます。
データ構造の中身をSortする
前回記事では、感情値で並び替えを行っていたのですが、時系列に並べかえます。 当然、もともと時系列で並べて出力して於けば不要な処理ですが、再実行するのも時間がかかるため今回はSortで対応します。
func (e TweetdataList) Len() int {
return len(e)
}
func (e TweetdataList) Less(i, j int) bool {
return e[i].Create < e[j].Create
}
func (e TweetdataList) Swap(i, j int) {
e[i], e[j] = e[j], e[i]
}
Golangに準備されているSortパッケージを活用します。 SortパッケージではInterfaceだけ用意されているため、こうして実体となる関数を定義して使います。 構造体の中身で並び替えを行いたい場合、上記のように記載します。 今回は、日時で並べ替えを行いたいため、 .Createで比較演算した値を返り値として使用します。
呼び出し元はこのような書き方です。
sort.Sort(TweetdataList(Tweetdatas))
これでOKです。
Google Chartへデータ渡しを行う方法
func viewCharthandler(w http.ResponseWriter, r *http.Request) {
err := templates.ExecuteTemplate(w, "index.html", Tweetdatas)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func StartWebServer() error {
http.HandleFunc("/chart/", viewCharthandler)
return http.ListenAndServe(fmt.Sprintf(":%d", 8080), nil)
}
ExecuteTemplate()で読み出すベースとなるhtmlファイルと、渡すデータを指定します。 Tweetdatasを今回は渡しています。 これはツイートデータと日時、感情値が格納された構造体配列です。
index.html
Golangからデータを受け取る部分を書いていきます。 Google ChartのサンプルにあるLine Chartのコードをベースに書いていきます。 修正箇所は、var data ..の箇所です。
コード全文
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['line']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
{{ range. }}
['{{.Create}}',0, {{.Sum}}, {{.Average}}],
{{ end}}
], true);
var options = {
chart: {
title: 'aaa',
subtitle: 'a'
},
width: 1920,
height: 1080,
axes: {
x: {
0: {side: 'top'}
}
}
};
var chart = new google.charts.Line(document.getElementById('line_top_x'));
chart.draw(data, google.charts.Line.convertOptions(options));
}
</script>
</head>
<body>
<div id="line_top_x"></div>
</body>
</html>
データ受信部
Sampleコードをこのように変えていきます。 修正箇所は特に作り込みもないのでこの部分だけです。
var data = google.visualization.arrayToDataTable([
{{ range. }}
['{{.Create}}',0, {{.Sum}}, {{.Average}}],
{{ end}}
], true);
var options = {
chart: {
title: 'aaa',
subtitle: 'a'
},
width: 1920,
height: 1080,
axes: {
x: {
0: {side: 'top'}
}
}
};
{{range.}}
{{end}}
いわゆるForループみたいなもので、配列を末尾まで取得することができます。 {{.構造体名}}を指定し中身を取り出していきます。 Tweetデータは今回グラフ描画時には不要となるため0埋めで実装しています。
実行結果
ツイート数が多く一括で取得しようとすると処理ができた部分から順次出力されるようです。 まずは、合計値から出力されている様子を示します。
PCスペックにもよりますが大体アニメ一本分ぐらい待機していると、感情の平均値が出力されます。 黒っぽく見えますがindex.htmlを変更すれば色は変えることができます。
ちなみに日付に合わせてクリックすると、日時と感情値の合計値が取得できます。
ツイートデータが多いため全て描画を待っていると時間がかかると思います。 ツイート数を減らすとか、画面描画のタイミングを100ツイート取り込む度になど変えるなどが改善点としては思いつきます。
まとめ
この記事では、Google Chartを使ってグラフを表示する方法と、Golangからデータを渡してグラフ化する方法を学びました。Google Chartは様々なグラフが用意されており、データ収集を行うプログラムを使って結果を表示するのに適しています。特に、Golangで少し手の込んだグラフを表示したい場合に適した選択肢です。
ただし、感情値の算出方法に問題があるかもしれません。これは今後の改善ポイントです。今後も改善を重ねていきたいと思います。
明後日は息子の出産日です。楽しみにしています!早く会いたいものです。