Avatar (Fabio Alessandro Locati|Fale)'s blog

Sensible integer scale for Gonum Plot

January 20, 2021

Over the years, I found myself multiple times using Gonum Plot. I do find it as a very good and easy to use plotting tool for Go.

The problem I found myself, over and over, dealing with is the tickers scale. If you know before-hand the values that can be expected to be created by the application, it is very straightforward, but the majority of times, this is not the case. I often find myself creating a plotting application on data that track events that have not yet happened and cannot predict their range.

To solve the issue, I create a package that has a struct that implements the Ticker interface and provides tickers that are usually sensible. Since this struct only works for integer scales, I called it sit, which stands for “Sensible Int Ticks”.

You can find the sit package here, and an example of its usage is:

package main

import (
	"github.com/fale/sit"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/plotutil"
	"gonum.org/v1/plot/vg"
)

func main() {
	p, err := plot.New()
	if err != nil {
		return
	}

	line := plotter.XYs{
		plotter.XY{X: float64(1), Y: float64(1)},
		plotter.XY{X: float64(2), Y: float64(11)},
		plotter.XY{X: float64(3), Y: float64(5)},
		plotter.XY{X: float64(4), Y: float64(2)},
		plotter.XY{X: float64(5), Y: float64(7)},
	}

	p.Add(plotter.NewGrid())
	err = plotutil.AddLinePoints(p,
		"First", line,
	)
	if err != nil {
		return
	}

	p.Y.Tick.Marker = sit.Ticker{}
	p.Y.Min = sit.Min(p.Y.Min, p.Y.Max)
	p.Y.Max = sit.Max(p.Y.Min, p.Y.Max)

	if err := p.Save(10*vg.Inch, 5*vg.Inch, "points.png"); err != nil {
		return
	}
	return
}

The important part is the block between line 33 and 35, that - to be clear - is the following:

p.Y.Tick.Marker = sit.Ticker{}
p.Y.Min = sit.Min(p.Y.Min, p.Y.Max)
p.Y.Max = sit.Max(p.Y.Min, p.Y.Max)

The first line of the block ensures that the object that implements the Ticker interface from GoNum Plot is used for the Y axes, while the other two make sure that the provided functions from the sit package adequately set the min and max Y values.

You can also use it for X ax in a similar way by exchanging Y with X in the three highlighted lines.

I hope this helps other people as much as it helped me!