Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
doplot.go 2.82 KiB
// 4 May 2021
// This does the plots for the Uebung.
// doplot makes a primitive plot without any interesting options
// If no plotname is given, it means no plot is wanted.
// We have to rewrite the data to fit into their format.
package main
import (
"fmt"
"math"
"os"
"gonum.org/v1/plot"
"gonum.org/v1/plot/font"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
"gonum.org/v1/plot/vg/vgimg"
)
const ( // plot size.. my arbitrary choice
pSizeHrznt font.Length = 20 * vg.Centimeter
pSizeVert font.Length = 28 * vg.Centimeter
)
// oneplot saves us doing the same point copying, adding three times.
func oneplot(y []float32) (*plot.Plot, error) {
p := plot.New()
points := make(plotter.XYs, len(y))
for i, piV := range y {
points[i] = plotter.XY{X: float64(i + 1), Y: float64(piV)}
}
if line, err := plotter.NewScatter(points); err != nil {
return nil, err
} else {
p.Add(line)
}
return p, nil
}
// fixStdErr takes the standard error slice and replaces all the
// initial zero entries with the first non-zero entry. This is a
// question of aesthetics, not numerics. It looks silly to have an
// error value that starts at zero and then jumps up.
func fixStdErr(stdErr []float32) {
n := 0
for n = range stdErr {
if stdErr[n] != 0.0 {
break
}
}
for j := 0; j < n; j++ {
stdErr[j] = stdErr[n]
}
}
// doplot copies the data and calls the plotters and writes a jpg
// file to plotname. If plotname has not been set, we just return.
// It is not an error.
func doplot(pi, stdErr []float32, plotName string) error {
if plotName == "" {
return nil
}
const step = "step"
var pPi, pStd, pAbs *plot.Plot
var err error
if pPi, err = oneplot(pi); err != nil { // pi estimate
return err }
pPi.Title.Text = "π estimate"
pPi.Y.Label.Text = "π"
fixStdErr(stdErr)
if pStd, err = oneplot(stdErr); err != nil { // std error
return err
}
pStd.Title.Text = "standard error"
pStd.Y.Label.Text = "std error"
{
tmperr := make([]float32, len(pi)) // the extra bracing makes
for i := range tmperr { // the lifetime of tmperr clear
tmperr[i] = pi[i] - math.Pi // for garbage collector
}
if pAbs, err = oneplot(tmperr); err != nil {
return err
}
}
pAbs.Title.Text = "absolute error"
pAbs.Y.Label.Text = "error"
pStd.X.Label.Text, pAbs.X.Label.Text, pPi.X.Label.Text = step, step, step
dt := draw.Tiles{Rows: 3, Cols: 1, PadTop: 2}
img := vgimg.New(pSizeHrznt, pSizeVert)
dc := draw.New(img)
dCnvs := plot.Align([][]*plot.Plot{{pPi}, {pStd}, {pAbs}}, dt, dc)
pPi.Draw(dCnvs[0][0])
pStd.Draw(dCnvs[1][0])
pAbs.Draw(dCnvs[2][0])
w, err := os.Create(plotName)
if err != nil {
return fmt.Errorf("Opening plotfile for writing %w", err)
}
defer w.Close()
jpg := vgimg.JpegCanvas{Canvas: img}
if _, err := jpg.WriteTo(w); err != nil {
return err
}
return nil
}