This notebook demonstrates lgo works with gonum, the most popular numerical computation packages in Go.
In [ ]:
import (
"bytes"
"fmt"
"image/color"
"math"
"math/rand"
"gonum.org/v1/gonum/mat"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
"gonum.org/v1/plot/vg/vgimg"
)
In [ ]:
func DisplayPlot(p *plot.Plot) {
// Save the plot to a PNG file.
var buf bytes.Buffer
c, err := p.WriterTo(4*vg.Inch, 4*vg.Inch, "png")
if err != nil {
panic(err)
}
if _, err := c.WriteTo(&buf); err != nil {
panic(err)
}
_ctx.Display.PNG(buf.Bytes(), nil)
}
In [ ]:
{
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "Plotutil example"
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
err = plotutil.AddLinePoints(
p,
"First", randomPoints(15),
"Second", randomPoints(15),
"Third", randomPoints(15))
if err != nil {
panic(err)
}
DisplayPlot(p)
}
// randomPoints returns some random x, y points.
func randomPoints(n int) plotter.XYs {
pts := make(plotter.XYs, n)
for i := range pts {
if i == 0 {
pts[i].X = rand.Float64()
} else {
pts[i].X = pts[i-1].X + rand.Float64()
}
pts[i].Y = pts[i].X + 10*rand.Float64()
}
return pts
}
https://github.com/gonum/plot/wiki/Example-plots#more-detailed-style-settings
In [ ]:
{
// Get some random points
n := 15
scatterData := randomPoints(n)
lineData := randomPoints(n)
linePointsData := randomPoints(n)
// Create a new plot, set its title and
// axis labels.
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "Points Example"
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
// Draw a grid behind the data
p.Add(plotter.NewGrid())
// Make a scatter plotter and set its style.
s, err := plotter.NewScatter(scatterData)
if err != nil {
panic(err)
}
s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255}
// Make a line plotter and set its style.
l, err := plotter.NewLine(lineData)
if err != nil {
panic(err)
}
l.LineStyle.Width = vg.Points(1)
l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
l.LineStyle.Color = color.RGBA{B: 255, A: 255}
// Make a line plotter with points and set its style.
lpLine, lpPoints, err := plotter.NewLinePoints(linePointsData)
if err != nil {
panic(err)
}
lpLine.Color = color.RGBA{G: 255, A: 255}
lpPoints.Shape = draw.PyramidGlyph{}
lpPoints.Color = color.RGBA{R: 255, A: 255}
// Add the plotters to the plot, with a legend
// entry for each
p.Add(s, l, lpLine, lpPoints)
p.Legend.Add("scatter", s)
p.Legend.Add("line", l)
p.Legend.Add("line points", lpLine, lpPoints)
DisplayPlot(p)
}
// randomPoints returns some random x, y points.
func randomPoints(n int) plotter.XYs {
pts := make(plotter.XYs, n)
for i := range pts {
if i == 0 {
pts[i].X = rand.Float64()
} else {
pts[i].X = pts[i-1].X + rand.Float64()
}
pts[i].Y = pts[i].X + 10*rand.Float64()
}
return pts
}
In [ ]:
{
groupA := plotter.Values{20, 35, 30, 35, 27}
groupB := plotter.Values{25, 32, 34, 20, 25}
groupC := plotter.Values{12, 28, 15, 21, 8}
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "Bar chart"
p.Y.Label.Text = "Heights"
w := vg.Points(20)
barsA, err := plotter.NewBarChart(groupA, w)
if err != nil {
panic(err)
}
barsA.LineStyle.Width = vg.Length(0)
barsA.Color = plotutil.Color(0)
barsA.Offset = -w
barsB, err := plotter.NewBarChart(groupB, w)
if err != nil {
panic(err)
}
barsB.LineStyle.Width = vg.Length(0)
barsB.Color = plotutil.Color(1)
barsC, err := plotter.NewBarChart(groupC, w)
if err != nil {
panic(err)
}
barsC.LineStyle.Width = vg.Length(0)
barsC.Color = plotutil.Color(2)
barsC.Offset = w
p.Add(barsA, barsB, barsC)
p.Legend.Add("Group A", barsA)
p.Legend.Add("Group B", barsB)
p.Legend.Add("Group C", barsC)
p.Legend.Top = true
p.NominalX("One", "Two", "Three", "Four", "Five")
DisplayPlot(p)
}
In [ ]:
{
p, err := plot.New()
if err != nil {
panic(err)
}
p.Title.Text = "Functions"
p.X.Label.Text = "X"
p.Y.Label.Text = "Y"
// A quadratic function x^2
quad := plotter.NewFunction(func(x float64) float64 { return x * x })
quad.Color = color.RGBA{B: 255, A: 255}
// An exponential function 2^x
exp := plotter.NewFunction(func(x float64) float64 { return math.Pow(2, x) })
exp.Dashes = []vg.Length{vg.Points(2), vg.Points(2)}
exp.Width = vg.Points(2)
exp.Color = color.RGBA{G: 255, A: 255}
// The sine function, shifted and scaled
// to be nicely visible on the plot.
sin := plotter.NewFunction(func(x float64) float64 { return 10*math.Sin(x) + 50 })
sin.Dashes = []vg.Length{vg.Points(4), vg.Points(5)}
sin.Width = vg.Points(4)
sin.Color = color.RGBA{R: 255, A: 255}
// Add the functions and their legend entries.
p.Add(quad, exp, sin)
p.Legend.Add("x^2", quad)
p.Legend.Add("2^x", exp)
p.Legend.Add("10*sin(x)+50", sin)
p.Legend.ThumbnailWidth = vg.Inch*0.5
// Set the axis ranges. Unlike other data sets,
// functions don't set the axis ranges automatically
// since functions don't necessarily have a
// finite range of x and y values.
p.X.Min = 0
p.X.Max = 10
p.Y.Min = 0
p.Y.Max = 100
DisplayPlot(p)
}
In [ ]:
import (
"fmt"
"gonum.org/v1/gonum/mat"
)
In [ ]:
// https://godoc.org/gonum.org/v1/gonum/mat#example-Dense-Mul
{
// Initialize two matrices, a and b.
a := mat.NewDense(2, 2, []float64{
4, 0,
0, 4,
})
b := mat.NewDense(2, 3, []float64{
4, 0, 0,
0, 0, 4,
})
// Take the matrix product of a and b and place the result in c.
var c mat.Dense
c.Mul(a, b)
// Print the result using the formatter.
fc := mat.Formatted(&c, mat.Prefix(" "), mat.Squeeze())
fmt.Printf("c = %v\n", fc)
}
In [ ]:
// https://godoc.org/gonum.org/v1/gonum/mat#example-Dense-Inverse
{
// Initialize two matrices, a and ia.
a := mat.NewDense(2, 2, []float64{
4, 0,
0, 4,
})
var ia mat.Dense
// Take the inverse of a and place the result in ia.
ia.Inverse(a)
// Print the result using the formatter.
fa := mat.Formatted(&ia, mat.Prefix(" "), mat.Squeeze())
fmt.Printf("ia = %.2g\n\n", fa)
// Confirm that A * A^-1 = I
var r mat.Dense
r.Mul(a, &ia)
fr := mat.Formatted(&r, mat.Prefix(" "), mat.Squeeze())
fmt.Printf("r = %v\n\n", fr)
// The Inverse operation, however, is numerically unstable,
// and should typically be avoided.
// For example, a common need is to find x = A^-1 * b.
// In this case, the SolveVec method of VecDense
// (if b is a Vector) or Solve method of Dense (if b is a
// matrix) should used instead of computing the Inverse of A.
b := mat.NewDense(2, 2, []float64{
2, 0,
0, 2,
})
var x mat.Dense
x.Solve(a, b)
// Print the result using the formatter.
fx := mat.Formatted(&x, mat.Prefix(" "), mat.Squeeze())
fmt.Printf("x = %v\n", fx)
}
In [ ]:
import (
"fmt"
"gonum.org/v1/gonum/integrate"
"gonum.org/v1/gonum/stat"
)
{
y := []float64{0.1, 0.35, 0.4, 0.8}
classes := []bool{true, false, true, false}
tpr, fpr := stat.ROC(0, y, classes, nil)
// compute Area Under Curve
auc := integrate.Trapezoidal(fpr, tpr)
fmt.Printf("true positive rate: %v\n", tpr)
fmt.Printf("false positive rate: %v\n", fpr)
fmt.Printf("auc: %v\n", auc)
}
In [ ]:
import (
"fmt"
"os"
"gonum.org/v1/gonum/optimize"
"gonum.org/v1/gonum/optimize/functions"
)
{
p := optimize.Problem{
Func: functions.ExtendedRosenbrock{}.Func,
Grad: functions.ExtendedRosenbrock{}.Grad,
}
x := []float64{1.3, 0.7, 0.8, 1.9, 1.2}
settings := optimize.DefaultSettings()
settings.Recorder = nil
settings.GradientThreshold = 1e-12
settings.FunctionConverge = nil
result, err := optimize.Local(p, x, settings, &optimize.BFGS{})
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if err = result.Status.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
fmt.Printf("result.Status: %v\n", result.Status)
fmt.Printf("result.X: %v\n", result.X)
fmt.Printf("result.F: %v\n", result.F)
fmt.Printf("result.Stats.FuncEvaluations: %d\n", result.Stats.FuncEvaluations)
}