diff --git a/doplot.go b/doplot.go
new file mode 100644
index 0000000000000000000000000000000000000000..c674b3065cc1e7c9152251ba1a01e0da5f2dff4f
--- /dev/null
+++ b/doplot.go
@@ -0,0 +1,100 @@
+// 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.
+// I also toss out the first two points. They are a bit silly and
+// have massive errors.
+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)}
+	} // Toss out the first two y-values...
+	points[0].Y, points[1].Y = points[2].Y, points[2].Y
+	if line, err := plotter.NewScatter(points); err != nil {
+		return nil, err
+	} else {
+		p.Add(line)
+	}
+	return p, nil
+}
+
+// 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 = "π"
+
+	if pStd, err = oneplot(stdErr); err != nil { // std error
+		return err
+	}
+	pStd.Title.Text = "standard error"
+	pStd.Y.Label.Text = "std error"
+
+	pAbs = plot.New()
+	{
+		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
+}