一个轻量级生成可视化图表的宝藏库,简洁且好用!


在日常工作中,我们经常需要生成数据的可视化图表以便更好地展示统计分析结果、监控应用运行状况或在报表中呈现数据趋势。

wcharczuk/go-chart 是 Go 语言生态中的一个轻量级库,用于生成常见的 2D 图表,适用于服务端和嵌入式环境。

它是一个纯 Go 实现的图表库支持直接生成 PNG 或 SVG 图像,免去了复杂的依赖配置,简洁且高效。

咱们一起来看一下,它是如何使用的。

一、安装和基础使用

首先,您可以使用 go get 命令来安装 go-chart

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

安装完成后,可以通过 import "github.com/wcharczuk/go-chart/v2" 在代码中使用该库。

二、主要特性

  1. 生成常见的 2D 图表:支持柱状图、折线图、散点图、饼图等基础图表类型。
  2. 无外部依赖:生成 PNG 或 SVG 格式的图表,无需依赖其他图形库(如 Cairo 等)。
  3. 高度可定制化:支持自定义图表样式、颜色、字体、边框等参数,满足不同场景下的视觉需求。
  4. 自动缩放与对齐:支持自动计算轴范围,并根据数据量动态调整刻度。
  5. 支持多图层叠加:允许在一个图表上叠加多个图形(如在柱状图上叠加折线图)。
  6. 导出 PNG、SVG:支持将生成的图表导出为 PNG 或 SVG 格式的文件,方便嵌入到网页或报告中。
  7. 简单的 API 接口:只需几行代码就能绘制图表,适合快速生成数据可视化。
  8. 无头渲染:无需 GUI 环境,即可在任何服务器上生成图表,特别适合在云环境中运行的服务。

三、详细使用说明

1. 绘制折线图
package main

import (
 "os"
 "time"

 "github.com/wcharczuk/go-chart/v2"
 "github.com/wcharczuk/go-chart/v2/drawing"
)

func main() {
 xv, yv := xvalues(), yvalues()

 priceSeries := chart.TimeSeries{
  Name: "SPY",
  Style: chart.Style{
   StrokeColor: chart.GetDefaultColor(0),
  },
  XValues: xv,
  YValues: yv,
 }

 smaSeries := chart.SMASeries{
  Name: "SPY - SMA",
  Style: chart.Style{
   StrokeColor:     drawing.ColorRed,
   StrokeDashArray: []float64{5.0, 5.0},
  },
  InnerSeries: priceSeries,
 }

 bbSeries := &chart.BollingerBandsSeries{
  Name: "SPY - Bol. Bands",
  Style: chart.Style{
   StrokeColor: drawing.ColorFromHex("efefef"),
   FillColor:   drawing.ColorFromHex("efefef").WithAlpha(64),
  },
  InnerSeries: priceSeries,
 }

 graph := chart.Chart{
  XAxis: chart.XAxis{
   TickPosition: chart.TickPositionBetweenTicks,
  },
  YAxis: chart.YAxis{
   Range: &chart.ContinuousRange{
    Max: 220.0,
    Min: 180.0,
   },
  },
  Series: []chart.Series{
   bbSeries,
   priceSeries,
   smaSeries,
  },
 }

 f, _ := os.Create("output.png")
 defer f.Close()
 graph.Render(chart.PNG, f)
}

func xvalues() []time.Time {
 rawx := []string{"2015-07-17", "2015-07-20", "2015-07-21", "2015-07-22", "2015-07-23", "2015-07-24", "2015-07-27", "2015-07-28", "2015-07-29", "2015-07-30", "2015-07-31", "2015-08-03", "2015-08-04", "2015-08-05", "2015-08-06", "2015-08-07", "2015-08-10", "2015-08-11", "2015-08-12", "2015-08-13", "2015-08-14", "2015-08-17", "2015-08-18", "2015-08-19", "2015-08-20", "2015-08-21", "2015-08-24", "2015-08-25", "2015-08-26", "2015-08-27", "2015-08-28", "2015-08-31", "2015-09-01", "2015-09-02", "2015-09-03", "2015-09-04", "2015-09-08", "2015-09-09", "2015-09-10", "2015-09-11", "2015-09-14", "2015-09-15", "2015-09-16", "2015-09-17", "2015-09-18", "2015-09-21", "2015-09-22", "2015-09-23", "2015-09-24", "2015-09-25", "2015-09-28", "2015-09-29", "2015-09-30", "2015-10-01", "2015-10-02", "2015-10-05", "2015-10-06", "2015-10-07", "2015-10-08", "2015-10-09", "2015-10-12", "2015-10-13", "2015-10-14", "2015-10-15", "2015-10-16", "2015-10-19", "2015-10-20", "2015-10-21", "2015-10-22", "2015-10-23", "2015-10-26", "2015-10-27", "2015-10-28", "2015-10-29", "2015-10-30", "2015-11-02", "2015-11-03", "2015-11-04", "2015-11-05", "2015-11-06", "2015-11-09", "2015-11-10", "2015-11-11", "2015-11-12", "2015-11-13", "2015-11-16", "2015-11-17", "2015-11-18", "2015-11-19", "2015-11-20", "2015-11-23", "2015-11-24", "2015-11-25", "2015-11-27", "2015-11-30", "2015-12-01", "2015-12-02", "2015-12-03", "2015-12-04", "2015-12-07", "2015-12-08", "2015-12-09", "2015-12-10", "2015-12-11", "2015-12-14", "2015-12-15", "2015-12-16", "2015-12-17", "2015-12-18", "2015-12-21", "2015-12-22", "2015-12-23", "2015-12-24", "2015-12-28", "2015-12-29", "2015-12-30", "2015-12-31", "2016-01-04", "2016-01-05", "2016-01-06", "2016-01-07", "2016-01-08", "2016-01-11", "2016-01-12", "2016-01-13", "2016-01-14", "2016-01-15", "2016-01-19", "2016-01-20", "2016-01-21", "2016-01-22", "2016-01-25", "2016-01-26", "2016-01-27", "2016-01-28", "2016-01-29", "2016-02-01", "2016-02-02", "2016-02-03", "2016-02-04", "2016-02-05", "2016-02-08", "2016-02-09", "2016-02-10", "2016-02-11", "2016-02-12", "2016-02-16", "2016-02-17", "2016-02-18", "2016-02-19", "2016-02-22", "2016-02-23", "2016-02-24", "2016-02-25", "2016-02-26", "2016-02-29", "2016-03-01", "2016-03-02", "2016-03-03", "2016-03-04", "2016-03-07", "2016-03-08", "2016-03-09", "2016-03-10", "2016-03-11", "2016-03-14", "2016-03-15", "2016-03-16", "2016-03-17", "2016-03-18", "2016-03-21", "2016-03-22", "2016-03-23", "2016-03-24", "2016-03-28", "2016-03-29", "2016-03-30", "2016-03-31", "2016-04-01", "2016-04-04", "2016-04-05", "2016-04-06", "2016-04-07", "2016-04-08", "2016-04-11", "2016-04-12", "2016-04-13", "2016-04-14", "2016-04-15", "2016-04-18", "2016-04-19", "2016-04-20", "2016-04-21", "2016-04-22", "2016-04-25", "2016-04-26", "2016-04-27", "2016-04-28", "2016-04-29", "2016-05-02", "2016-05-03", "2016-05-04", "2016-05-05", "2016-05-06", "2016-05-09", "2016-05-10", "2016-05-11", "2016-05-12", "2016-05-13", "2016-05-16", "2016-05-17", "2016-05-18", "2016-05-19", "2016-05-20", "2016-05-23", "2016-05-24", "2016-05-25", "2016-05-26", "2016-05-27", "2016-05-31", "2016-06-01", "2016-06-02", "2016-06-03", "2016-06-06", "2016-06-07", "2016-06-08", "2016-06-09", "2016-06-10", "2016-06-13", "2016-06-14", "2016-06-15", "2016-06-16", "2016-06-17", "2016-06-20", "2016-06-21", "2016-06-22", "2016-06-23", "2016-06-24", "2016-06-27", "2016-06-28", "2016-06-29", "2016-06-30", "2016-07-01", "2016-07-05", "2016-07-06", "2016-07-07", "2016-07-08", "2016-07-11", "2016-07-12", "2016-07-13", "2016-07-14", "2016-07-15"}

 var dates []time.Time
 for _, ts := range rawx {
  parsed, _ := time.Parse(chart.DefaultDateFormat, ts)
  dates = append(dates, parsed)
 }
 return dates
}

func yvalues() []float64 {
 return []float64{212.47, 212.59, 211.76, 211.37, 210.18, 208.00, 206.79, 209.33, 210.77, 210.82, 210.50, 209.79, 209.38, 210.07, 208.35, 207.95, 210.57, 208.66, 208.92, 208.66, 209.42, 210.59, 209.98, 208.32, 203.97, 197.83, 189.50, 187.27, 194.46, 199.27, 199.28, 197.67, 191.77, 195.41, 195.55, 192.59, 197.43, 194.79, 195.85, 196.74, 196.01, 198.45, 200.18, 199.73, 195.45, 196.46, 193.90, 193.60, 192.90, 192.87, 188.01, 188.12, 191.63, 192.13, 195.00, 198.47, 197.79, 199.41, 201.21, 201.33, 201.52, 200.25, 199.29, 202.35, 203.27, 203.37, 203.11, 201.85, 205.26, 207.51, 207.00, 206.60, 208.95, 208.83, 207.93, 210.39, 211.00, 210.36, 210.15, 210.04, 208.08, 208.56, 207.74, 204.84, 202.54, 205.62, 205.47, 208.73, 208.55, 209.31, 209.07, 209.35, 209.32, 209.56, 208.69, 210.68, 208.53, 205.61, 209.62, 208.35, 206.95, 205.34, 205.87, 201.88, 202.90, 205.03, 208.03, 204.86, 200.02, 201.67, 203.50, 206.02, 205.68, 205.21, 207.40, 205.93, 203.87, 201.02, 201.36, 198.82, 194.05, 191.92, 192.11, 193.66, 188.83, 191.93, 187.81, 188.06, 185.65, 186.69, 190.52, 187.64, 190.20, 188.13, 189.11, 193.72, 193.65, 190.16, 191.30, 191.60, 187.95, 185.42, 185.43, 185.27, 182.86, 186.63, 189.78, 192.88, 192.09, 192.00, 194.78, 192.32, 193.20, 195.54, 195.09, 193.56, 198.11, 199.00, 199.78, 200.43, 200.59, 198.40, 199.38, 199.54, 202.76, 202.50, 202.17, 203.34, 204.63, 204.38, 204.67, 204.56, 203.21, 203.12, 203.24, 205.12, 206.02, 205.52, 206.92, 206.25, 204.19, 206.42, 203.95, 204.50, 204.02, 205.92, 208.00, 208.01, 207.78, 209.24, 209.90, 210.10, 208.97, 208.97, 208.61, 208.92, 209.35, 207.45, 206.33, 207.97, 206.16, 205.01, 204.97, 205.72, 205.89, 208.45, 206.50, 206.56, 204.76, 206.78, 204.85, 204.91, 204.20, 205.49, 205.21, 207.87, 209.28, 209.34, 210.24, 209.84, 210.27, 210.91, 210.28, 211.35, 211.68, 212.37, 212.08, 210.07, 208.45, 208.04, 207.75, 208.37, 206.52, 207.85, 208.44, 208.10, 210.81, 203.24, 199.60, 203.20, 206.66, 209.48, 209.92, 208.41, 209.66, 209.53, 212.65, 213.40, 214.95, 214.92, 216.12, 215.83}
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_github

2. 绘制柱状图
package main

import (
 "os"

 "github.com/wcharczuk/go-chart/v2"
)

func main() {
 graph := chart.BarChart{
  Title: "Test Bar Chart",
  Background: chart.Style{
   Padding: chart.Box{
    Top: 40,
   },
  },
  Height:   512,
  BarWidth: 60,
  Bars: []chart.Value{
   {Value: 5.25, Label: "Blue"},
   {Value: 4.88, Label: "Green"},
   {Value: 4.74, Label: "Gray"},
   {Value: 3.22, Label: "Orange"},
   {Value: 3, Label: "Test"},
   {Value: 2.27, Label: "??"},
   {Value: 1, Label: "!!"},
  },
 }

 f, _ := os.Create("output.png")
 defer f.Close()
 graph.Render(chart.PNG, f)
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_信息可视化_02

3. 饼图
package main

import (
 "os"

 "github.com/wcharczuk/go-chart/v2"
)

func main() {
 pie := chart.PieChart{
  Width:  512,
  Height: 512,
  Values: []chart.Value{
   {Value: 5, Label: "Blue"},
   {Value: 5, Label: "Green"},
   {Value: 4, Label: "Gray"},
   {Value: 4, Label: "Orange"},
   {Value: 3, Label: "Deep Blue"},
   {Value: 3, Label: "??"},
   {Value: 1, Label: "!!"},
  },
 }

 f, _ := os.Create("output.png")
 defer f.Close()
 pie.Render(chart.PNG, f)
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_SVG_03

4. 自定义样式一
package main

import (
 "os"

 "github.com/wcharczuk/go-chart/v2"
 "github.com/wcharczuk/go-chart/v2/drawing"
)

func main() {
 graph := chart.Chart{
  Background: chart.Style{
   Padding: chart.Box{
    Top:    50,
    Left:   25,
    Right:  25,
    Bottom: 10,
   },
   FillColor: drawing.ColorFromHex("efefef"),
  },
  Series: []chart.Series{
   chart.ContinuousSeries{
    XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(1.0).WithEnd(100.0)}.Values(),
    YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(100).WithMin(100).WithMax(512)}.Values(),
   },
  },
 }

 f, _ := os.Create("output.png")
 defer f.Close()
 graph.Render(chart.PNG, f)
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_github_04

5. 自定义样式二
package main

import (
 "os"

 "github.com/wcharczuk/go-chart/v2"
 "github.com/wcharczuk/go-chart/v2/drawing"
)

func main() {
 chart.DefaultBackgroundColor = chart.ColorTransparent
 chart.DefaultCanvasColor = chart.ColorTransparent

 barWidth := 80

 var (
  colorWhite          = drawing.Color{R: 241, G: 241, B: 241, A: 255}
  colorMariner        = drawing.Color{R: 60, G: 100, B: 148, A: 255}
  colorLightSteelBlue = drawing.Color{R: 182, G: 195, B: 220, A: 255}
  colorPoloBlue       = drawing.Color{R: 126, G: 155, B: 200, A: 255}
  colorSteelBlue      = drawing.Color{R: 73, G: 120, B: 177, A: 255}
 )

 stackedBarChart := chart.StackedBarChart{
  Title:      "Quarterly Sales",
  TitleStyle: chart.Shown(),
  Background: chart.Style{
   Padding: chart.Box{
    Top: 75,
   },
  },
  Width:        800,
  Height:       600,
  XAxis:        chart.Shown(),
  YAxis:        chart.Shown(),
  BarSpacing:   40,
  IsHorizontal: true,
  Bars: []chart.StackedBar{
   {
    Name:  "Q1",
    Width: barWidth,
    Values: []chart.Value{
     {
      Label: "32K",
      Value: 32,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorMariner,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "46K",
      Value: 46,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorLightSteelBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "48K",
      Value: 48,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorPoloBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "42K",
      Value: 42,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorSteelBlue,
       FontColor:   colorWhite,
      },
     },
    },
   },
   {
    Name:  "Q2",
    Width: barWidth,
    Values: []chart.Value{
     {
      Label: "45K",
      Value: 45,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorMariner,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "60K",
      Value: 60,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorLightSteelBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "62K",
      Value: 62,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorPoloBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "53K",
      Value: 53,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorSteelBlue,
       FontColor:   colorWhite,
      },
     },
    },
   },
   {
    Name:  "Q3",
    Width: barWidth,
    Values: []chart.Value{
     {
      Label: "54K",
      Value: 54,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorMariner,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "58K",
      Value: 58,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorLightSteelBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "55K",
      Value: 55,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorPoloBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "47K",
      Value: 47,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorSteelBlue,
       FontColor:   colorWhite,
      },
     },
    },
   },
   {
    Name:  "Q4",
    Width: barWidth,
    Values: []chart.Value{
     {
      Label: "46K",
      Value: 46,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorMariner,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "70K",
      Value: 70,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorLightSteelBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "74K",
      Value: 74,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorPoloBlue,
       FontColor:   colorWhite,
      },
     },
     {
      Label: "60K",
      Value: 60,
      Style: chart.Style{
       StrokeWidth: .01,
       FillColor:   colorSteelBlue,
       FontColor:   colorWhite,
      },
     },
    },
   },
  },
 }

 pngFile, err := os.Create("output.png")
 if err != nil {
  panic(err)
 }

 if err := stackedBarChart.Render(chart.PNG, pngFile); err != nil {
  panic(err)
 }

 if err := pngFile.Close(); err != nil {
  panic(err)
 }
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_github_05

6. 自定义样式三
package main

import (
 "log"
 "net/http"

 _ "net/http/pprof"

 "github.com/wcharczuk/go-chart/v2"
 "github.com/wcharczuk/go-chart/v2/drawing"
)

func drawChart(res http.ResponseWriter, req *http.Request) {

 viridisByY := func(xr, yr chart.Range, index int, x, y float64) drawing.Color {
  return chart.Viridis(y, yr.GetMin(), yr.GetMax())
 }

 graph := chart.Chart{
  Series: []chart.Series{
   chart.ContinuousSeries{
    Style: chart.Style{
     StrokeWidth:      chart.Disabled,
     DotWidth:         5,
     DotColorProvider: viridisByY,
    },
    XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(127)}.Values(),
    YValues: chart.Seq{Sequence: chart.NewRandomSequence().WithLen(128).WithMin(0).WithMax(1024)}.Values(),
   },
  },
 }

 res.Header().Set("Content-Type", chart.ContentTypePNG)
 err := graph.Render(chart.PNG, res)
 if err != nil {
  log.Println(err.Error())
 }
}

func unit(res http.ResponseWriter, req *http.Request) {
 graph := chart.Chart{
  Height: 50,
  Width:  50,
  Canvas: chart.Style{
   Padding: chart.BoxZero,
  },
  Background: chart.Style{
   Padding: chart.BoxZero,
  },
  Series: []chart.Series{
   chart.ContinuousSeries{
    XValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
    YValues: chart.Seq{Sequence: chart.NewLinearSequence().WithStart(0).WithEnd(4)}.Values(),
   },
  },
 }

 res.Header().Set("Content-Type", chart.ContentTypePNG)
 err := graph.Render(chart.PNG, res)
 if err != nil {
  log.Println(err.Error())
 }
}

func main() {
 http.HandleFunc("/", drawChart)
 http.HandleFunc("/unit", unit)
 log.Fatal(http.ListenAndServe(":8080", nil))
}

一个轻量级生成可视化图表的宝藏库,简洁且好用!_github_06

四、特性列表

  1. 图表类型
  • 折线图(Line Chart)
  • 柱状图(Bar Chart)
  • 饼图(Pie Chart)
  • 散点图(Scatter Plot)
  • 堆叠柱状图(Stacked Bar Chart)

导出格式

  • PNG
  • SVG

  • 支持 X 轴和 Y 轴的自定义标签、范围和刻度。
  • 自动缩放(Auto-scaling)和自定义轴范围。

样式定制

  • 支持颜色、线宽、透明度等自定义属性。
  • 支持不同的字体和文本对齐。

多系列支持

  • 支持在同一图表上绘制多个数据系列,支持叠加展示。

交互式图表

  • 支持为图表中的元素(如数据点、线条等)添加名称,支持悬停和点击交互。

图例

  • 自动生成图例,标注不同数据系列的含义。

自定义渲染器

  • 用户可以自定义绘图渲染器,绘制非标准的形状或样式。

无头渲染

  • 支持在无 GUI 环境中生成图表,如云服务器。

多语言支持

  • 支持多种语言的文本标注,特别适用于国际化应用场景。

五、最佳实践

1. 数据预处理

在生成图表之前,建议对数据进行清理和预处理,尤其是处理空值或异常值。数据预处理有助于避免图表的扭曲或不准确的展示。

2. 使用 GCM 模式提升性能

在生成大量图表时,可以使用 SVG 格式,它相对于 PNG 更适合在前端展示且文件体积较小。

3. 图表样式的合理设计

使用 go-chart 时,尽量选择合适的颜色、线条样式、字体大小,以确保图表的可读性。合理的样式设计不仅美观,还能更好地传达数据的含义。

六、最后

简单总结一下子,它是一种轻量、高效的方式来在 Go 语言环境中生成图表。

它的无外部依赖特性使得在任何服务器上生成图表变得简单,并且通过其简洁的 API 接口和高度的可定制性,能够满足各种数据可视化的需求。

无论是简单的数据展示,还是复杂的图表定制,go-chart 都是一款值得推荐的 Go 图表库。


上一篇:互联网运维工作规划


下一篇:第二百五十九节 JPA教程 - JPA查询选择两个属性示例