go使用plot包实现自定义的趋势图代码,而且可以实现自定义的坐标轴

package utils

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"time"

	"gonum.org/v1/plot/plotutil"

	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
)

type myXTick struct {
}

// Ticks 返回一个包含从min到max的每隔86400*2秒的时间戳,并且对应的标签是格式化为"1/2"的日期字符串的切片。
//
// 参数:
//   - min (float64) - 最小时间戳,单位为秒
//   - max (float64) - 最大时间戳,单位为秒
//
// 返回值:
//   - []plot.Tick ([]plot.Tick) - 包含每个时间戳和对应的标签的切片,类型为plot.Tick,其中Value是时间戳,Label是格式化为"1/2"的日期字符串
func (myXTick *myXTick) Ticks(min, max float64) []plot.Tick {
	ticks := []plot.Tick{}
	for i := min; i <= max; i += 86400 * 7 {
		ticks = append(ticks, plot.Tick{Value: i, Label: time.Unix(int64(i), 0).Format("2006/1/2")})
	}
	return ticks
}

type myYTick struct {
	addSetp float64
}

// Ticks 返回一个包含最小值和最大值之间的所有tick,并且每个tick的label是tick的百分比或者数字。
// 如果最大值小于1,则tick的label为百分比,否则为数字。
//
// 参数:
//   - min (float64) - tick的最小值
//   - max (float64) - tick的最大值
//
// 返回值:
//   - []plot.Tick ([]plot.Tick) - 包含所有tick的切片,每个tick包括value(float64)和label(string)两个属性
func (myYTick *myYTick) Ticks(min, max float64) []plot.Tick {
	ticks := []plot.Tick{}
	if max < 1 {
		for i := min; i <= max; i += 0.05 {
			ticks = append(ticks, plot.Tick{Value: i, Label: fmt.Sprintf("%.2f%%", i*100)})
		}
	} else {
		for i := 0.; i <= max+myYTick.addSetp; i += myYTick.addSetp {
			v := float64(int(i/100) * 100)
			ticks = append(ticks, plot.Tick{Value: v, Label: fmt.Sprintf("%.2f", v)})
		}
	}
	return ticks
}

// GenerateChart2Base64 根据给定的数据,生成一张基于Plot库的折线图,并返回该图片的Base64编码。
// 参数:
//   - title string:图表的标题。
//   - yList [][]float64:二维切片,每一行代表一条折线,每一列代表一个点的Y值。
//   - xList []int32:一维切片,每一个元素代表一个点的X值。
//
// 返回值:
//   - string:返回一个Base64编码的字符串,包含了生成的图片。
//   - error:如果发生错误,则返回非nil的error。
func GenerateChart2Base64(title string, yList [][]float64, xList []int32, legend []string, lineColors []int, addSetp float64) (string, error) {
	if len(yList) != len(legend) {
		return "", fmt.Errorf("yList和legend的长度不一致")
	}
	// 创建一个新的绘图对象
	p := plot.New()

	//设置标题
	p.Title.TextStyle.Font.Size = vg.Length(16) // 标题字体大小
	p.Title.Text = title

	// 打开网格线
	p.Add(plotter.NewGrid())

	// 设置绘图的大小
	p.X.Scale = plot.LinearScale{}
	p.Y.Scale = plot.LinearScale{}

	p.Y.Tick.Marker = &myYTick{addSetp: addSetp}
	p.Y.Tick.Label.Font.Size = vg.Length(12) // X轴的标签字体大小
	p.Y.Tick.Width = vg.Length(2)            // X轴的网格线宽度

	//p.X.Tick.Marker = plot.TimeTicks{Format: "20060102"}

	p.X.Tick.Marker = &myXTick{}
	p.X.Tick.Label.Font.Size = vg.Length(12) // Y轴的标签字体大小
	p.X.Tick.Width = vg.Length(2)            // Y轴的网格线宽度

	var maxY float64
	if lineColors == nil {
		lineColors = []int{8, 14, 16}
	}
	for i := 0; i < len(yList); i++ {
		xys := plotter.XYs{}
		for j := 0; j < len(yList[i]); j++ {
			xys = append(xys, plotter.XY{
				X: float64(xList[j]),
				Y: yList[i][j],
			})
			if yList[i][j] > maxY {
				maxY = yList[i][j]
			}
		}
		// 创建折线图
		line, err := plotter.NewLine(xys)
		if err != nil {
			return "", err
		}

		line.LineStyle.Width = vg.Points(4)
		line.LineStyle.Color = plotutil.Color(lineColors[i])
		p.Add(line)
		p.Legend.Add(legend[i], line)
	}
	p.Legend.TextStyle.Font.Size = vg.Length(12) // 图例字体大小
	p.Legend.Top = true                          // 图例在上方显示
	p.Legend.Left = true

	// 创建折线图
	line, err := plotter.NewLine(plotter.XYs{{
		X: float64(xList[0]),
		Y: 0,
	}, {
		X: float64(xList[0]),
		Y: maxY + addSetp,
	}})
	if err != nil {
		return "", err
	}

	line.LineStyle.Width = vg.Points(0)
	p.Add(line)

	// 将图表渲染为PNG格式的图片
	var buf bytes.Buffer
	// p.Save(1200*vg.Millimeter, 400*vg.Millimeter, "./123.png")
	i, err := p.WriterTo(317*vg.Millimeter, 100*vg.Millimeter, "png")
	if err != nil {
		return "", err
	}
	_, err = i.WriteTo(&buf)
	if err != nil {
		return "", err
	}

	// 将图片转换为Base64字符串
	encoded := base64.StdEncoding.EncodeToString(buf.Bytes())
	// log.Println(encoded)
	return encoded, nil
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值