The residuals plotter

A deeper look at the canvasing system will be explored later in the chapter. For now, let's return to the Plot method that satisfies the plot.Plotter interface. 

Most interesting are the following lines:

  trX, trY := p.Transforms(&c)
zero := trY(0)
lineStyle := r.LineStyle
for _, xy := range r.XYs {
x := trX(xy.X)
y := trY(xy.Y)
c.StrokeLine2(lineStyle, x, zero, x, y)
}

p.Transforms(&c) returns two functions, which will transform the coordinate of our data point to the coordinate of the backend. This way we wouldn't have to worry about the absolute location of each point. Instead, it will be treated in relation to the absolute location in the final image.

Having gotten the transformation functions, we then loop through the residuals that we have, and transform each to the coordinate (x := trX(xy.X) and y := trY(xy.Y)) within the canvas.

Finally, we tell the canvas to draw a straight line between two points: (x, 0) and (x, y). This draws a straight line up or down from the X axis.

Thus, we have created our own plot.Plotter interface, which we can now add to the plot object. But adding to a *plot.Plot object directly requires a lot of tinkering. So, here's a function to nicely wrap all that up:

func newResidPlot(xs []time.Time, ys []float64) *plot.Plot {
p, err := plot.New()
dieIfErr(err)
xys := make(plotter.XYs, len(ys))
for i := range ys {
xys[i].X = float64(xs[i].Unix())
xys[i].Y = ys[i]
}
r := &residChart{XYs: xys, LineStyle: plotter.DefaultLineStyle}
r.LineStyle.Color = color.RGBA{A: 255}
p.Add(r)
p.Legend.Add("Residuals", r)

p.Legend.TextStyle.Font = defaultFont
p.X.Tick.Marker = plot.TimeTicks{Format: "2006-01-01"}
p.Y.Label.TextStyle.Font = defaultFont
p.X.Label.TextStyle.Font = defaultFont
p.X.Tick.Label.Font = defaultFont
p.Y.Tick.Label.Font = defaultFont
p.Title.Font.Size = 16
return p
}

This function is reminiscent of newTSPlot—you provide it the X and Y values, and get a *plot.Plot object back out, with everything properly styled and formatted.

You may note that we're also adding the plotter object as a legend. To do this without an error, the residChart type needs to implement plot.Thumbnailer. Again, that's fairly straightforward:

func (r *residChart) Thumbnail(c *draw.Canvas) {
y := c.Center().Y
c.StrokeLine2(r.LineStyle, c.Min.X, y, c.Max.X, y)
}

At this point, you may be wondering about the canvas object. If we are to draw a line between the canvas's minimum X to maximum X, wouldn't that just cause a horizontal line across the entire canvas?

The answer is not really. Recall earlier that the canvas is provided in the backend, and draw.Canvas is simply a tuple of a canvas backend and a rectangle? The rectangle actually serves to subset and constrain the canvas upon which it is being drawn.

We shall see this in action. Now that we've finished, we can turn our attention to the next section, which depicts a combination of all the plots into one image.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.111.179