純golang實現的圖表庫

語言: CN / TW / HK

go-charts

go-charts 基於 go-chart ,更簡單方便的形式生成資料圖表,支援 svgpng 兩種方式的輸出,支援主題 light , dark , grafana 以及 ant 。預設的輸入格式為 png ,預設主題為 light

Apache ECharts 在前端開發中得到眾多開發者的認可,因此 go-charts 提供了相容 Apache ECharts 的配置引數,簡單快捷的生成相似的圖表( svgpng ),方便插入至Email或分享使用。下面為常用的圖表截圖(主題為light與grafana):

支援圖表型別

支援以下的圖表型別: line , bar , horizontal bar , pie , radar , funnel 以及 table

示例

下面的示例為 go-charts 兩種方式的引數配置:golang的引數配置、echarts的JSON配置,輸出相同的折線圖。 更多的示例參考: ./examples/ 目錄

Line Chart

package main

import (
	charts "github.com/vicanso/go-charts/v2"
)

func main() {
	values := [][]float64{
		{
			120,
			132,
			101,
			134,
			90,
			230,
			210,
		},
		{
			// snip...
		},
		{
			// snip...
		},
		{
			// snip...
		},
		{
			// snip...
		},
	}
	p, err := charts.LineRender(
		values,
		charts.TitleTextOptionFunc("Line"),
		charts.XAxisDataOptionFunc([]string{
			"Mon",
			"Tue",
			"Wed",
			"Thu",
			"Fri",
			"Sat",
			"Sun",
		}),
		charts.LegendLabelsOptionFunc([]string{
			"Email",
			"Union Ads",
			"Video Ads",
			"Direct",
			"Search Engine",
		}, charts.PositionCenter),
	)

	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

Bar Chart

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	values := [][]float64{
		{
			2.0,
			4.9,
			7.0,
			23.2,
			25.6,
			76.7,
			135.6,
			162.2,
			32.6,
			20.0,
			6.4,
			3.3,
		},
		{
			// snip...	
		},
	}
	p, err := charts.BarRender(
		values,
		charts.XAxisDataOptionFunc([]string{
			"Jan",
			"Feb",
			"Mar",
			"Apr",
			"May",
			"Jun",
			"Jul",
			"Aug",
			"Sep",
			"Oct",
			"Nov",
			"Dec",
		}),
		charts.LegendLabelsOptionFunc([]string{
			"Rainfall",
			"Evaporation",
		}, charts.PositionRight),
		charts.MarkLineOptionFunc(0, charts.SeriesMarkDataTypeAverage),
		charts.MarkPointOptionFunc(0, charts.SeriesMarkDataTypeMax,
			charts.SeriesMarkDataTypeMin),
		// custom option func
		func(opt *charts.ChartOption) {
			opt.SeriesList[1].MarkPoint = charts.NewMarkPoint(
				charts.SeriesMarkDataTypeMax,
				charts.SeriesMarkDataTypeMin,
			)
			opt.SeriesList[1].MarkLine = charts.NewMarkLine(
				charts.SeriesMarkDataTypeAverage,
			)
		},
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

Horizontal Bar Chart

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	values := [][]float64{
		{
			18203,
			23489,
			29034,
			104970,
			131744,
			630230,
		},
		{
			// snip...	
		},
	}
	p, err := charts.HorizontalBarRender(
		values,
		charts.TitleTextOptionFunc("World Population"),
		charts.PaddingOptionFunc(charts.Box{
			Top:    20,
			Right:  40,
			Bottom: 20,
			Left:   20,
		}),
		charts.LegendLabelsOptionFunc([]string{
			"2011",
			"2012",
		}),
		charts.YAxisDataOptionFunc([]string{
			"Brazil",
			"Indonesia",
			"USA",
			"India",
			"China",
			"World",
		}),
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

Pie Chart

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	values := []float64{
		1048,
		735,
		580,
		484,
		300,
	}
	p, err := charts.PieRender(
		values,
		charts.TitleOptionFunc(charts.TitleOption{
			Text:    "Rainfall vs Evaporation",
			Subtext: "Fake Data",
			Left:    charts.PositionCenter,
		}),
		charts.PaddingOptionFunc(charts.Box{
			Top:    20,
			Right:  20,
			Bottom: 20,
			Left:   20,
		}),
		charts.LegendOptionFunc(charts.LegendOption{
			Orient: charts.OrientVertical,
			Data: []string{
				"Search Engine",
				"Direct",
				"Email",
				"Union Ads",
				"Video Ads",
			},
			Left: charts.PositionLeft,
		}),
		charts.PieSeriesShowLabel(),
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...	
}

Radar Chart

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	values := [][]float64{
		{
			4200,
			3000,
			20000,
			35000,
			50000,
			18000,
		},
		{
			// snip...
		},
	}
	p, err := charts.RadarRender(
		values,
		charts.TitleTextOptionFunc("Basic Radar Chart"),
		charts.LegendLabelsOptionFunc([]string{
			"Allocated Budget",
			"Actual Spending",
		}),
		charts.RadarIndicatorOptionFunc([]string{
			"Sales",
			"Administration",
			"Information Technology",
			"Customer Support",
			"Development",
			"Marketing",
		}, []float64{
			6500,
			16000,
			30000,
			38000,
			52000,
			25000,
		}),
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

Funnel Chart

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	values := []float64{
		100,
		80,
		60,
		40,
		20,
	}
	p, err := charts.FunnelRender(
		values,
		charts.TitleTextOptionFunc("Funnel"),
		charts.LegendLabelsOptionFunc([]string{
			"Show",
			"Click",
			"Visit",
			"Inquiry",
			"Order",
		}),
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

Table

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	header := []string{
		"Name",
		"Age",
		"Address",
		"Tag",
		"Action",
	}
	data := [][]string{
		{
			"John Brown",
			"32",
			"New York No. 1 Lake Park",
			"nice, developer",
			"Send Mail",
		},
		{
			"Jim Green	",
			"42",
			"London No. 1 Lake Park",
			"wow",
			"Send Mail",
		},
		{
			"Joe Black	",
			"32",
			"Sidney No. 1 Lake Park",
			"cool, teacher",
			"Send Mail",
		},
	}
	spans := map[int]int{
		0: 2,
		1: 1,
		// 設定第三列的span
		2: 3,
		3: 2,
		4: 2,
	}
	p, err := charts.TableRender(
		header,
		data,
		spans,
	)
	if err != nil {
		panic(err)
	}

	buf, err := p.Bytes()
	if err != nil {
		panic(err)
	}
	// snip...
}

ECharts Render

package main

import (
	"github.com/vicanso/go-charts/v2"
)

func main() {
	buf, err := charts.RenderEChartsToPNG(`{
		"title": {
			"text": "Line"
		},
		"xAxis": {
			"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
		},
		"series": [
			{
				"data": [150, 230, 224, 218, 135, 147, 260]
			}
		]
	}`)
	// snip...
}

常用函式

go-charts 針對常用的幾種圖表提供了簡單的呼叫方式以及幾種常用的Option設定,便捷的生成常用圖表。

LineRender
BarRender
PieRender
RadarRender
FunnelRender
PNGTypeOption
FontFamilyOptionFunc
ThemeOptionFunc
TitleOptionFunc
LegendOptionFunc
XAxisOptionFunc
YAxisOptionFunc
WidthOptionFunc
HeightOptionFunc
PaddingOptionFunc
BoxOptionFunc
ChildOptionFunc
RadarIndicatorOptionFunc
BackgroundColorOptionFunc

ECharts引數說明

名稱有[]的引數非echarts的原有引數,為 go-charts 的新增引數,可根據實際使用場景新增。

  • [type] 畫布型別,支援 svgpng ,預設為 svg
  • [theme] 顏色主題,支援 darklight 以及 grafana 模式,預設為 light
  • [fontFamily] 字型,全域性的字型設定
  • [padding] 圖表的內邊距,單位px。支援以下幾種模式的設定
    • padding: 5 設定內邊距為5
    • padding: [5, 10] 設定上下的內邊距為 5,左右的內邊距為 10
    • padding:[5, 10, 5, 10] 分別設定 上右下左 邊距
  • [box] 圖表的區域,以{"left": Int, "right": Int, "top": Int, "bottom": Int}的形式配置
  • [width] 畫布寬度,預設為600
  • [height] 畫布高度,預設為400
  • title 圖表標題,包括標題內容、高度、顏色等
    • title.text 標題文字,支援以 \n 的形式換行
    • title.subtext 副標題文字,支援以 \n 的形式換行
    • title.left 標題與容器左側的距離,可設定為 left , right , center , 20% 以及 20 這樣的具體數值
    • title.top 標題與容器頂部的距離,暫僅支援具體數值,如 20
    • title.textStyle.color 標題文字顏色
    • title.textStyle.fontSize 標題文字字型大小
    • title.textStyle.fontFamily 標題文字的字體系列,需要注意此配置是會影響整個圖表的字型
  • xAxis 直角座標系grid中的x軸,由於go-charts僅支援單一個x軸,因此若引數為陣列多個x軸,只使用第一個配置
    • xAxis.boundaryGap 座標軸兩邊留白策略,僅支援三種設定方式 null , true 或者 falsenulltrue 時則資料點展示在兩個刻度中間
    • xAxis.splitNumber 座標軸的分割段數,需要注意的是這個分割段數只是個預估值,最後實際顯示的段數會在這個基礎上根據分割後坐標軸刻度顯示的易讀程度作調整
    • xAxis.data x軸的展示文案,暫只支援字串陣列,如["Mon", "Tue"],其數量需要與展示點一致
  • yAxis 直角座標系grid中的y軸,最多支援兩個y軸
    • yAxis.min 座標軸刻度最小值,若不設定則自動計算
    • yAxis.max 座標軸刻度最大值,若不設定則自動計算
    • yAxis.axisLabel.formatter 刻度標籤的內容格式器,如 "formatter": "{value} kg"
    • yAxis.axisLine.lineStyle.color 座標軸顏色
  • legend 圖表中不同系列的標記
    • legend.show 圖例是否顯示,如果不需要展示需要設定為 false
    • legend.data 圖例的資料陣列,為字串陣列,如["Email", "Video Ads"]
    • legend.align 圖例標記和文字的對齊,可設定為 left 或者 right ,預設為標記靠左 left
    • legend.padding legend的padding,配置方式與圖表的 padding 一致
    • legend.left legend離容器左側的距離,其值可以為具體的畫素值(20)或百分比(20%)、 left 或者 right
    • legend.top legend離容器頂部的距離,暫僅支援數值形式
  • radar 雷達圖的座標系
    • radar.indicator 雷達圖的指示器,用來指定雷達圖中的多個變數(維度)
      radar.indicator.name
      radar.indicator.max
      radar.indicator.min
      
  • series 圖表的資料項列表
    • series.name 圖表的名稱,與 legend.data 對應,兩者只只設置其一
    • series.type 圖表的展示型別,暫支援 line , bar , pie , radar 以及 funnel 。需要注意只有 linebar 可以混用
    • series.radius 餅圖的半徑值,如 50% ,預設為 40%
    • series.yAxisIndex 該資料項使用的y軸,預設為0,對yAxis的配置對應
    • series.label.show 是否顯示文字標籤(預設為對應的值)
    • series.label.distance 距離圖形元素的距離
    • series.label.color 文字標籤的顏色
    • series.itemStyle.color 該資料項展示時使用的顏色
    • series.markPoint 圖表的標註配置
    • series.markPoint.symbolSize 標註的大小,預設為30
    • series.markPoint.data 標註型別,僅支援陣列形式,其型別只支援 maxmin ,如:`[{"type": "max"}, {"type": "min"}]
    • series.markLine 圖表的標線配置
    • series.markPoint.data 標線型別,僅支援陣列形式,其型別只支援 maxmin 以及 average ,如:`[{"type": "max"}, {"type": "min"}, {"type": "average"}]
    • series.data 資料項對應的資料陣列,支援以下形式的資料:
      數值
      結構體
      
  • [children] 巢狀的子圖表引數列表,圖表支援巢狀的形式=

效能

簡單的圖表生成PNG在20ms左右,而SVG的效能則更快,效能上比起使用 chrome headless 載入 echarts 圖表展示頁面再截圖生成的方式大幅度提升,滿足簡單的圖表生成需求。

BenchmarkMultiChartPNGRender-8                78          15216336 ns/op         2298308 B/op       1148 allocs/op
BenchmarkMultiChartSVGRender-8               367           3356325 ns/op        20597282 B/op       3088 allocs/op

中文字元

預設使用的字元為 roboto 為英文字型庫,因此如果需要顯示中文字元需要增加中文字型庫, InstallFont 函式可新增對應的字型庫,成功新增之後則指定 title.textStyle.fontFamily 即可。 在瀏覽器中使用 svg 時,如果指定的 fontFamily 不支援中文字元,展示的中文並不會亂碼,但是會導致在計算字元寬度等錯誤。

字型檔案可以在 中文字型檔noto-cjk 下載,注意下載時選擇字型格式為 ttf 格式,如果選用 otf 格式可能會載入失敗。

示例見 examples/chinese/main.go