使用 Golang 程式碼生成圖表的開源庫對比

本文的目標讀者

對用 Golang 程式碼生成折線圖、扇形圖等圖表有興趣的朋友。

本文摘要

主要介紹 Go 中用以繪圖的開源庫,分別是:

我的需求是生成一個時間軸類型折線圖的圖片插入到我的報告中,前面兩個庫與我的需求比較符合,所以我會著重介紹;後面三個庫不滿足我的需求,在本文會大略帶過。如果懶得看正文,這是我總結的表格:

go-chart go-charts chart plot go-echarts
使用文檔/示例完善
學習成本
支援的圖表種類
支援時間軸
支援輸出圖片
支援設置標籤
支援折線圖
支援自定義圖表
UI美觀 ⭐️⭐️⭐️ ⭐️⭐️⭐️⭐️ ⭐️⭐️ ⭐️⭐️ ⭐️⭐️⭐️⭐️⭐️

還有一些庫,例如ggGo 內部自帶的 image/draw 包,在這裡就不介紹了,因為它們倆都屬於是繪製基礎圖形(圓形、正方形和矩形等)或者是對影像本身進行旋轉、縮放、添加文字等處理的,與本文所討論的繪製圖表不太一樣。

go-chart

go-chart是一個簡單的 Golang 原生圖表庫,支援時間序列和連續折線圖。因此,go-chart 其實對數據量特別多的情況無法很好地適應,以及如果要在圖表中使用中文時,需要額外修改字體為支援中文的字體。

官方效果圖

  1. 曲線圖

  2. 單軸折線圖

  3. 雙軸折線圖

  4. 餅狀圖

  5. 柱狀圖

安裝

go get -u github.com/wcharczuk/go-chart

實際使用

我的需求是,從 influxdb 查詢數據,再將數據渲染為折線圖,程式碼如下:

/*
	前面省略查詢 influxdb 過程
*/
xValue := []string{}
yValue := []float64{}

// 處理查詢到的結果數據
for _, value := range allRequest[0].Series[0].Values {
	if value[1] == nil {
		yValue = append(yValue, 0)
		t := value[0].(string)
		xValue = append(xValue, t)
	} else {
		fmt.Println("value:", value[1])
		x, _ := value[1].(json.Number)
		s, _ := x.Float64()
		yValue = append(yValue, s)
		fmt.Println(reflect.TypeOf(value[0]))
		t := value[0].(string)
		xValue = append(xValue, t)
	}
}

// 時間軸的顯示格式
format := chart.TimeValueFormatterWithFormat("15:04")
lenX := len(xValue)

// X軸內容 xValues 及 X軸坐標 ticks
var xValues []time.Time
var ticks []chart.Tick
for i := 0; i < lenX; i++ {
	t, _ := time.Parse(
		time.RFC3339,
		xValue[i])
	x := t.Local()
	xValues = append(xValues, x)
	ticks = append(ticks, chart.Tick{Value: getNsec(t), Label: format(t)})
}

// 定義曲線
var series []chart.Series
series = append(series, chart.TimeSeries{
	XValues: xValues,
	YValues: yValue,
	Style: chart.Style{
		StrokeColor: chart.GetDefaultColor(0).WithAlpha(64),
		FillColor:   drawing.ColorFromHex("9ADFEA"),
	},
})

// 設置圖表的樣式
lineChartStyle := chart.Style{
	Padding: chart.Box{
		Top:  30,
		Left: 30,
		Right: 30,
		Bottom: 30,
	},
}

graph := chart.Chart{
	Title:      "All Requests",
	Background: lineChartStyle,
	Width:      1280,
	Height:     500,
	XAxis: chart.XAxis{
		Name:           "",
		ValueFormatter: format,
		Ticks:          ticks,
	},
	YAxis: chart.YAxis{
		Name: "",
	},
	Series: series,
}
graph.Elements = []chart.Renderable{
	chart.LegendLeft(&graph),
}

// 生成圖片
var imgContent bytes.Buffer
err = graph.Render(chart.PNG, &imgContent)
if err != nil {
	fmt.Println(err)
}

f, _ := os.Create("test.png")
_, _ = f.Write(imgContent.Bytes())

這裡查詢了10分鐘的數據,生成的圖片為

可以看到圖表上的 x 軸已經看不清了,這是因為數據點非常多,而 go-chart 沒有對此進行適配。

在數據點較少的情況下,比如只查詢1分鐘的數據,生成的圖片為:

優點

  • 圖表的自定義程度高,例如可以選擇給曲線填充顏色等

缺點

  • 使用比較複雜
    我想畫的圖表的 x 軸是時間軸類型,在這個庫中繪製時間軸類型的 x 軸需要額外把數據進行處理為 Time.time類型。如使用 float64 類型的 x 軸的程式碼會比較簡單,示例如下:
graph := chart.Chart{
    Series: []chart.Series{
        chart.ContinuousSeries{
            XValues: []float64{1.0, 2.0, 3.0, 4.0},
            YValues: []float64{1.0, 2.0, 3.0, 4.0},
        },
    },
}

buffer := bytes.NewBuffer([]byte{})
err := graph.Render(chart.PNG, buffer)
  • 圖表的樣式不夠精美
    下面有go-charts的 demo 圖,可以對比一下,確實是不如它好看。

go-charts

Go-charts 是中國的程式設計師在 go-chart 的基礎上優化了圖表的生成方式,同時還優化了圖表的樣式。目前支援 line, bar, horizontal bar, pie ,radar, funnel 以及table類型的圖表。

官方效果圖

主題為 lightgrafana

安裝

go get -u github.com/vicanso/go-charts/v2

實際使用

同樣是從 influxdb 查詢數據,再處理數據生成圖表,程式碼如下:

xValue := []string{}
yValue := [][]float64{}

// 處理結果
for _, value := range allRequest[0].Series[0].Values {
	tempY := []float64{}
	resultX := value[0].(string)
	xValue = append(xValue, resultX)
	number, _ := value[1].(json.Number)
	resultY, _ := number.Float64()
	tempY = append(tempY, resultY)
}

// 對 x 軸格式化 原:2022-07-29T09:24:10Z,新:09:24:10
formatXValue := []string{}
for _, x := range xValue {
	formatTime, err := time.Parse(time.RFC3339, x)
	if err != nil {

	}
	formatX := formatTime.Local().Format("15:04:05")
	formatXValue = append(formatXValue, formatX)
}

f := false // 設置 x 軸的樣式

// 字體文件需要自行下載
buff, err := ioutil.ReadFile("./TencentSans-W7.ttf")
if err != nil {
	panic(err)
}
err = charts.InstallFont("noto", buff)
if err != nil {
	panic(err)
}

// 渲染圖表
p, err := charts.LineRender(
	yValue,
	charts.FontFamilyOptionFunc("noto"),
	charts.TitleTextOptionFunc("全部請求"),
	charts.XAxisDataOptionFunc(xValue),
	func(opt *charts.ChartOption) {
		opt.XAxis.BoundaryGap = &f
		opt.Padding = charts.Box{Left: 20, Right: 50, Top: 20, Bottom: 20}
	},
	charts.ThemeOptionFunc("grafana"),
	charts.WidthOptionFunc(1000),
)

查詢10分鐘的數據,生成的效果圖為:

如果將主題換為 light,效果圖如下

如果只查詢1分鐘的數據,效果圖如下

從上面的效果圖中可以發現,go-charts在數據量比較大的情況下,優化了 x 軸的展示,讓數據不會擠在一起;以及樣式也更好看一點。

優點

  • 樣式好看
    看上面的圖,一目了然
  • 使用簡單
    從程式碼中也可以看出來,go-charts對 x 軸和 y 軸的類型做了額外一層封裝,x 軸的類型為 string,y 軸的類型為 [][]float64,只需要傳相應類型的數據就可以直接渲染圖表。
    並且由於 y 軸的 []float64 就表示一條曲線,所以如果要在圖表中增加渲染的曲線也比在 go-chart中要更簡單——直接給 y 軸數據 append 一個新的 []float64 數據即可。

缺點

  • 自定義的自由度沒有 go-chart
    例如go-charts中暫不支援用顏色填充曲線,以及不能自定義曲線的顏色等。

  • 當曲線超過9條後,曲線的顏色會開始重複

作者的回復是他自己的使用場景只需要用到5條曲線左右,建議如果涉及到太多的曲線,最好分開畫圖。

不過都不是什麼大問題,是一個很好用的開源庫。

chart

前面這三個庫的名字真是太像了,並且這三個庫都提供基礎圖表的繪製功能。但是這個庫更關注自動縮放、誤差線和對數圖等圖表,並且對漂亮UI完全不在乎。

官方效果圖

安裝

go get -u github.com/vdobler/chart 

詳細說明

這個庫支援的圖表類型有

  • 帶狀圖
  • 散點圖/函數圖
  • 直方圖
  • 條形圖和分類條形圖
  • 扇形圖/環形圖
  • 箱形圖

由上所述,這個介紹為「Provide basic charts「的開源庫並不支援我需要的折線圖……

以及在介紹裡面,這個庫有以下幾個特點:

  • 軸的值可以是線性、對數、分類或者時間/日期軸。
  • 自動縮放具有很多選項。
  • 抽動和標籤的精細控制。

輸出格式有txtgsvggimgg這三種格式

plot

plot的前身是code.google.com/p/plotinum,它提供了用於 Go 中構建和繪製圖表的 API,主要用於將數據可視化。

官方效果圖

  • 默認樣式

  • 更細粒度的控制

  • 自定義刻度線

  • 帶誤差的點

  • 條形圖

  • 函數

  • 直方圖

  • 垂直箱形圖

  • 水平箱形圖

  • 四分點陣圖

  • 氣泡圖

安裝

go get gonum.org/v1/plot/...

詳細說明

plot庫其實包含以下四個部分:

  1. plot:提供了布局和繪圖的簡單介面;
  2. plotter:使用plot提供的介面實現了一組標準的繪圖器,例如散點圖、條形圖、箱狀圖等。可以使用plotter提供的介面實現自己的繪圖器;
  3. plotutil:為繪製常見圖形提供簡便的方法;
  4. vg:封裝各種後端,並提供了一個通用矢量圖形 API。
    引自《Go 每日一庫之 plot》

由上所述,我在使用 plot 庫時,發現裡面自帶的基本API不能滿足我的需求——我需要一個時間軸作為 x 軸,但是plot庫默認的API中 x 軸只支援float64類型的數據。

但是在plotter中,你可以自定義一個繪圖器實現一些特殊的需求,以及你還可以使用社區製作的繪圖器,可以在這個網頁中查看其中一部分社區繪圖器:Community Plotters · gonum/plot Wiki · GitHub

一些社區繪圖器的示例圖:

  1. plotters/piechart at master · benoitmasson/plotters · GitHub

  2. GitHub – pplcc/plotext: Extensions and custom plotters for the gonum plot packages

go-echarts

go-echarts是一個專註數據可視化的圖表庫,參考了pyecharts的一些設計思想;目前有 v1 和 v2 兩個版本,其中 v1 已經不再維護。

官方效果圖


安裝

go get -u github.com/go-echarts/go-echarts/v2 

詳細介紹

go-echarts是通過實現Apache ECharts的相關介面,來輕鬆生成全面又美觀的圖表。

因此,在編寫完生成圖表的程式碼後,你還需要將圖表渲染成一個HTML文件,或者是用一個HTTP伺服器去渲染圖表,如圖:

以及這個開源庫渲染出來的圖表也是這幾個庫裡面最美觀的(畢竟是用HTML程式碼渲染出來的)

總結

本文介紹了Go中最主要的幾個繪製圖表的繪圖庫,其中對最為接近的兩個開源庫go-chartgo-charts進行了比較詳細的對比,其餘三個開源庫chartplotgo-echarts則是簡單介紹了一下。
這些開源庫各有各的特點,沒有絕對的優劣,希望能在大家需要挑選開源庫時給予一些參考。

Tags: