func NewLinePoints(xys XYer) (*Line, *Scatter, error) {
	s, err := NewScatter(xys)
	if err != nil {
		return nil, nil, err
	}
	l := &Line{
		XYs:       s.XYs,
		LineStyle: DefaultLineStyle,
	}
	return l, s, nil
}
NewLinePoints returns both a Line and a
Points for the given point data.
package plotter
import (
	"image/color"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)
type StepKind int
const (
	NoStep StepKind = iota
	PreStep
	MidStep
	PostStep
)
type Line struct {
	XYs
	StepStyle StepKind
	draw.LineStyle
	FillColor color.Color
}
func NewLine(xys XYer) (*Line, error) {
	data, err := CopyXYs(xys)
	if err != nil {
		return nil, err
	}
	return &Line{
		XYs:       data,
		LineStyle: DefaultLineStyle,
	}, nil
}
func (pts *Line) Plot(c draw.Canvas, plt *plot.Plot) {
	trX, trY := plt.Transforms(&c)
	ps := make([]vg.Point, len(pts.XYs))
	for i, p := range pts.XYs {
		ps[i].X = trX(p.X)
		ps[i].Y = trY(p.Y)
	}
	if pts.FillColor != nil && len(ps) > 0 {
		minY := trY(plt.Y.Min)
		fillPoly := []vg.Point{{X: ps[0].X, Y: minY}}
		switch pts.StepStyle {
		case PreStep:
			fillPoly = append(fillPoly, ps[1:]...)
		case PostStep:
			fillPoly = append(fillPoly, ps[:len(ps)-1]...)
		default:
			fillPoly = append(fillPoly, ps...)
		}
		fillPoly = append(fillPoly, vg.Point{X: ps[len(ps)-1].X, Y: minY})
		fillPoly = c.ClipPolygonXY(fillPoly)
		if len(fillPoly) > 0 {
			c.SetColor(pts.FillColor)
			var pa vg.Path
			prev := fillPoly[0]
			pa.Move(prev)
			for _, pt := range fillPoly[1:] {
				switch pts.StepStyle {
				case NoStep:
					pa.Line(pt)
				case PreStep:
					pa.Line(vg.Point{X: prev.X, Y: pt.Y})
					pa.Line(pt)
				case MidStep:
					pa.Line(vg.Point{X: (prev.X + pt.X) / 2, Y: prev.Y})
					pa.Line(vg.Point{X: (prev.X + pt.X) / 2, Y: pt.Y})
					pa.Line(pt)
				case PostStep:
					pa.Line(vg.Point{X: pt.X, Y: prev.Y})
					pa.Line(pt)
				}
				prev = pt
			}
			pa.Close()
			c.Fill(pa)
		}
	}
	lines := c.ClipLinesXY(ps)
	if pts.LineStyle.Width != 0 && len(lines) != 0 {
		c.SetLineStyle(pts.LineStyle)
		for _, l := range lines {
			if len(l) == 0 {
				continue
			}
			var p vg.Path
			prev := l[0]
			p.Move(prev)
			for _, pt := range l[1:] {
				switch pts.StepStyle {
				case PreStep:
					p.Line(vg.Point{X: prev.X, Y: pt.Y})
				case MidStep:
					p.Line(vg.Point{X: (prev.X + pt.X) / 2, Y: prev.Y})
					p.Line(vg.Point{X: (prev.X + pt.X) / 2, Y: pt.Y})
				case PostStep:
					p.Line(vg.Point{X: pt.X, Y: prev.Y})
				}
				p.Line(pt)
				prev = pt
			}
			c.Stroke(p)
		}
	}
}
func (pts *Line) DataRange() (xmin, xmax, ymin, ymax float64) {
	return XYRange(pts)
}
func (pts *Line) Thumbnail(c *draw.Canvas) {
	if pts.FillColor != nil {
		var topY vg.Length
		if pts.LineStyle.Width == 0 {
			topY = c.Max.Y
		} else {
			topY = (c.Min.Y + c.Max.Y) / 2
		}
		points := []vg.Point{
			{X: c.Min.X, Y: c.Min.Y},
			{X: c.Min.X, Y: topY},
			{X: c.Max.X, Y: topY},
			{X: c.Max.X, Y: c.Min.Y},
		}
		poly := c.ClipPolygonY(points)
		c.FillPolygon(pts.FillColor, poly)
	}
	if pts.LineStyle.Width != 0 {
		y := c.Center().Y
		c.StrokeLine2(pts.LineStyle, c.Min.X, y, c.Max.X, y)
	}
}