Go 言語でもグラフを描きたい!
いや,決まったデータに対して棒グラフとか折れ線グラフとか簡単に描けないかなぁ,と思っただけなんスけどね。 ぶっちゃけ「グラフを描く」だけなら,それこそ gnuplot で必要十分なんだけど,今回もお遊びということで。
とはいえ自前でコードを書くのはアレなので,なにか手頃なパッケージはないかなぁ,とググってみたら Gonum ってのがいいらしい。 Gonum は
とある通り,本来は数値計算パッケージなのだが, plot
パッケージを使って簡単なグラフを描くこともできるらしい。
どんなグラフが描けるかについては以下が参考になる。
試しに何か描いてみる。
棒グラフを描いてみる
まずは普通に棒グラフを描いてみよう。 ちょっと長いが,こんな感じのコードでどうだろう。
package main
import (
"fmt"
"math"
"os"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
)
type CaseData struct {
Date string
NewCases int
}
var Dataset = []CaseData{
{"2020-04-18", 628},
{"2020-04-19", 566},
{"2020-04-20", 390},
{"2020-04-21", 368},
{"2020-04-22", 377},
{"2020-04-23", 423},
{"2020-04-24", 469},
}
func main() {
//import data
labelX := []string{}
dataY := plotter.Values{}
for _, d := range Dataset {
labelX = append(labelX, d.Date)
dataY = append(dataY, (float64)(d.NewCases))
}
//new plot
p, err := plot.New()
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
//new bar chart
bar, err := plotter.NewBarChart(dataY, vg.Points(20))
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
bar.LineStyle.Width = vg.Length(0)
bar.Color = plotutil.Color(2) //plotutil.SoftColors[2]
bar.Offset = 0
bar.Horizontal = false
p.Add(bar)
//legend
p.Legend.Add("New confirmed cases by date", bar)
p.Legend.Top = true //top
p.Legend.Left = false //right
p.Legend.XOffs = 0
p.Legend.YOffs = -10
//labels of X
p.NominalX(labelX...)
p.X.Label.Text = "Date"
p.X.Padding = 0
p.X.Width = p.Y.Width
p.X.Tick.Label.Rotation = math.Pi / 2.5
p.X.Tick.Label.XAlign = draw.XRight
p.X.Tick.Label.YAlign = draw.YCenter
//labels of Y
p.Y.Label.Text = "Cases"
p.Y.Padding = 0
p.Y.Min = 0
p.Y.Max = 800
//title
p.Title.Text = "Confirmed COVID-2019 Cases in Japan"
//output image
if err := p.Save(15*vg.Centimeter, 15*vg.Centimeter, "bar-chart-1.png"); err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
}
実行結果はこんな感じ。
Gonum でも日本語を使いたい
plot/vg
パッケージにはいくつかのフリー・フォントが含まれている。
どのようなフォントが使えるかについては vg
.FontMap
を参照すればよい。
package main
import (
"fmt"
"gonum.org/v1/plot/vg"
)
func main() {
for k, v := range vg.FontMap {
fmt.Println(k, ":", v)
}
//Output:
//Helvetica-Oblique : LiberationSans-Italic
//Helvetica-BoldOblique : LiberationSans-BoldItalic
//Times-Italic : LiberationSerif-Italic
//Courier : LiberationMono-Regular
//Courier-Bold : LiberationMono-Bold
//Courier-Oblique : LiberationMono-Italic
//Helvetica : LiberationSans-Regular
//Helvetica-Bold : LiberationSans-Bold
//Times-BoldItalic : LiberationSerif-BoldItalic
//Courier-BoldOblique : LiberationMono-BoldItalic
//Times-Roman : LiberationSerif-Regular
//Times-Bold : LiberationSerif-Bold
}
たとえば,先程のコードに
//default font
plot.DefaultFont = "Courier"
plotter.DefaultFont = "Courier"
を追加すれば
という感じに既定フォントを入れ換えることができる。
plot/vg
パッケージに含まれるフォントは当然ながら日本語の字体を含んでいない。
日本語が使いたいのであれば,別途日本語フォントを読み込む必要がある1。
こんな感じ。
//import japanese fonts
b, err := ioutil.ReadFile("/usr/local/texlive/2020/texmf-dist/fonts/truetype/public/ipaex/ipaexg.ttf")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
ft, err := truetype.Parse(b)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fontName := "ipaex"
vg.AddFont(fontName, ft)
//default font
plot.DefaultFont = fontName
plotter.DefaultFont = fontName
今回は TeX Live 2020 に収録されている IPAex フォントを流用してみた。 これを使って,更にラベルのいくつかを日本語に置き換えたのがこちら。
またグラフの各要素に対して個別にフォントを指定するのであれば
//set fonts
font, err := vg.MakeFont(fontName, 10)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
p.Title.Font = font
p.X.Label.Font = font
p.Y.Label.Font = font
p.X.Tick.Label.Font = font
p.Y.Tick.Label.Font = font
p.Legend.Font = font
のように書ける。
フォントの読み込みには github.com/golang/freetype/truetype
パッケージを使っているのだが,どうも TTC (TrueType Collections) ファイルには対応していない模様。
たとえば Ubuntu 19.10 に収録されている NOTO フォントを使おうとしたが
b, err := ioutil.ReadFile("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
ft, err := truetype.Parse(b)
if err != nil {
fmt.Fprintln(os.Stderr, err) //Output: freetype: invalid TrueType format: bad TTF version
return
}
実行時エラーになってしまった。 ちなみに OTF ファイルにも対応してない。 まぁ,文章を書くんじゃないから IPA フォントでも十分だよね。
ブックマーク
- gonum · GitHub
- Golangで棒グラフを描く - 逆さまにした
- Golangでローソク足チャートを描くパッケージを書いた - 逆さまにした
- Golangでグラフを描く - Qiita
- Go言語で折れ線グラフや棒グラフを描く - Qiita
- TeX Live 2020 へのアップグレード
参考図書
- プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- Alan A.A. Donovan (著), Brian W. Kernighan (著), 柴田 芳樹 (翻訳)
- 丸善出版 2016-06-20
- 単行本(ソフトカバー)
- 4621300253 (ASIN), 9784621300251 (EAN), 4621300253 (ISBN), 9784621300251 (ISBN)
- 評価
著者のひとりは(あの「バイブル」とも呼ばれる)通称 “K&R” の K のほうである。この本は Go 言語の教科書と言ってもいいだろう。