Plot a chart with plot

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

As a programmer, a lot of times although I like to stare at the console output of a bunch of numbers to see some system change indicators, but as the saying goes, a picture wins thousands of words, if you can automatically generate a lot of data graph display, will be more clear, and can directly from the curve above the change to learn more information. This is why I particularly like Prometheus + Grafana.

But a lot of projects, especially some temporary test projects, I can't build a Prometheus + Grafana system to look at a data graph, which is too inefficient, and more often I want to have a simpler tool to show some data.

Fortunately, we can do it very conveniently through plot. Plot is a drawing library implemented in the Go language, where we can draw very rich charts and output them in many formats. In addition, plot provides a very handy interface that we can use to customize our own charts.

Simple example

We can draw simple graphs by plotting the plotutil tools we provide ourselves.

Line and Points

Since I was recently looking at the microeconomics of Khan Academy, as the first example of price and quantity demand, the number of prices and requirements is usually inversely proportional, and the plotted figure should be a downward curve. To simplify the number of lines of code, error handling is deliberately removed here.

import (    "github.com/gonum/plot"    "github.com/gonum/plot/plotter"    "github.com/gonum/plot/plotutil"    "github.com/gonum/plot/vg")func main() {    p, _ := plot.New()    p.Title.Text = "Hello Price"    p.X.Label.Text = "Quantity Demand"    p.Y.Label.Text = "Price"    points := plotter.XYs{        {2.0, 60000.0},        {4.0, 40000.0},        {6.0, 30000.0},        {8.0, 25000.0},        {10.0, 23000.0},    }    plotutil.AddLinePoints(p, points)    p.Save(4*vg.Inch, 4*vg.Inch, "price.png")}

After execution, we can get a PNG file named Price, which looks like this:


Histograms

When using Prometheus and Grafana, I was actually not satisfied with some of the histogram's metric, because the X-axis of Grafana was time-dependent, so it was not possible to display histograms, only to use histogram_quantile or other functions to get the relevant changes. Line, with plot can be very convenient to Prometheus data out of the drawing.

A simple example:

import (    "github.com/gonum/plot"    "github.com/gonum/plot/plotter"    "github.com/gonum/plot/vg")func main() {    p, _ := plot.New()    p.Title.Text = "Histogram"    bins := plotter.XYs{        {10, 10},        {20, 20},        {30, 50},        {40, 20},        {50, 10},    }    h, _ := plotter.NewHistogram(bins, 5)    p.Add(h)    p.Save(4*vg.Inch, 4*vg.Inch, "histogram.png")}

The bar chart is as follows:


Self-customizing Plotter

Plotter

In addition to using plot-provided charts, we can easily customize our own charts. Here we simply draw a square with a side length of 20. First define the Sqaures:

type Squares struct {    plotter.XYs}

Squares There is only a batch of points, used to represent the center point of each square. We then implement the Plotter's Plot function, as follows:

func (s *Squares) Plot(c draw.Canvas, plt *plot.Plot) {    trX, trY := plt.Transforms(&c)    c.SetColor(color.RGBA{R: 196, B: 128, A: 255})    r := vg.Length(10.0)    for _, p := range s.XYs {        p1 := vg.Point{trX(p.X) - r, trY(p.Y) - r}        p2 := vg.Point{trX(p.X) - r, trY(p.Y) + r}        p3 := vg.Point{trX(p.X) + r, trY(p.Y) + r}        p4 := vg.Point{trX(p.X) + r, trY(p.Y) - r}        var p vg.Path        p.Move(p1)        p.Line(p2)        p.Line(p3)        p.Line(p4)        p.Line(p1)        p.Close()        c.Fill(p)    }}

In the above Plot function, we used plt.Transforms(&c) to get two conversion functions that could convert the point of a square from the back to the actual canvas point.

func main() {    points := plotter.XYs{        {2, 2},        {4, 4},        {6, 6},        {8, 8},        {10, 10},    }    s := Squares{points}    p, _ := plot.New()    p.Title.Text = "Squares"    p.X.Label.Text = "X"    p.Y.Label.Text = "Y"    p.X.Min = 0    p.X.Max = 20    p.Y.Min = 0    p.Y.Max = 20    p.Add(&s)    p.Save(4*vg.Inch, 4*vg.Inch, "squares.png")}

Create a sqaures and then execute to get the chart:


Dataranger

In the example above, we used a similar p.X.Min = 0 p.X.Max = 20 way to set the scope of the entire chart, but actually we want to be able to adjust dynamically, because it is impossible to estimate how large the actual range is, which can be used DataRange to achieve:

func (s *Squares) DataRange() (float64, float64, float64, float64) {    return plotter.XYRange(s.XYs)}

Get the chart as follows:


Glyphboxer

Although it is possible to solve the problem by DataRange, we find that some squares have been cut off on the boundary, mainly because we are drawn in the center of the square, and one solution is to return the DataRange to a larger range, covering the entire positive direction. But another better way is to use it to GlyphBoxes show the position and size of the chart you want to draw.

func (s *Squares) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {    boxes := make([]plot.GlyphBox, len(s.XYs))    r := vg.Length(10.0)    for i, p := range s.XYs {        boxes[i].X = plt.X.Norm(p.X)        boxes[i].Y = plt.Y.Norm(p.Y)        boxes[i].Rectangle = vg.Rectangle{            Min: vg.Point{X: -r, Y: -r},            Max: vg.Point{X: +r, Y: +r},        }    }    return boxes}

Now it looks like this:


Postscript

As you can see, using plot, we can easily draw a chart. Of course, the function of plot is much more than that, for example, we can get Prometheus data directly and then draw it, send it to Slack, or draw a piechart.

Later, we also consider using plot on some internal systems, such as the performance test framework, running many performance tests after each commit, collecting the results of each performance test, using plot plots, and so on.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.