Skip to main content
Sign in
Snippets Groups Projects
Select Git revision
  • 2583f46ca6f2bcb7e609b3e186d189ac2765391d
  • master default protected
  • devel
  • adaptive_step_size
4 results

scrnplt.go

Blame
  • 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
    }