func (b *ErrBarChart) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
	boxes := make([]plot.GlyphBox, len(b.Values))
	for i := range b.Values {
		cat := b.Start + float64(i)*b.Stride
		if !b.Horizontal {
			boxes[i].X = plt.X.Norm(cat)
			xr := plt.X.Max - plt.X.Min
			wd := vg.Length((b.Width / 2) / xr)
			boxes[i].Rectangle = vg.Rectangle{
				Min: vg.Point{X: -wd},
				Max: vg.Point{X: wd},
			}
		} else {
			boxes[i].Y = plt.Y.Norm(cat)
			xr := plt.Y.Max - plt.Y.Min
			wd := vg.Length((b.Width / 2) / xr)
			boxes[i].Rectangle = vg.Rectangle{
				Min: vg.Point{Y: -wd},
				Max: vg.Point{Y: wd},
			}
		}
	}
	return boxes
}
GlyphBoxes implements the GlyphBoxer interface.
package eplot
import (
	"image/color"
	"math"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)
type ErrBarChart struct {
	Values plotter.Values
	Errors plotter.Values
	Start float64
	Stride float64
	Width float64
	Pad float64
	Color color.Color
	draw.LineStyle
	Offset vg.Length
	Horizontal bool
	stackedOn *ErrBarChart
}
func NewErrBarChart(vs, ers plotter.Valuer) (*ErrBarChart, error) {
	values, err := plotter.CopyValues(vs)
	if err != nil {
		return nil, err
	}
	var errs plotter.Values
	if ers != nil {
		errs, err = plotter.CopyValues(ers)
		if err != nil {
			return nil, err
		}
	}
	b := &ErrBarChart{
		Values: values,
		Errors: errs,
	}
	b.Defaults()
	return b, nil
}
func (b *ErrBarChart) Defaults() {
	b.Start = 1
	b.Stride = 1
	b.Width = .8
	b.Pad = 1
	b.Color = color.Black
	b.LineStyle = plotter.DefaultLineStyle
}
func (b *ErrBarChart) BarHeight(i int) float64 {
	ht := 0.0
	if b == nil {
		return 0
	}
	if i >= 0 && i < len(b.Values) {
		ht += b.Values[i]
	}
	if b.stackedOn != nil {
		ht += b.stackedOn.BarHeight(i)
	}
	return ht
}
func (b *ErrBarChart) StackOn(on *ErrBarChart) {
	b.Start = on.Start
	b.Stride = on.Stride
	b.Pad = on.Pad
	b.stackedOn = on
}
func (b *ErrBarChart) Plot(c draw.Canvas, plt *plot.Plot) {
	trCat, trVal := plt.Transforms(&c)
	if b.Horizontal {
		trCat, trVal = trVal, trCat
	}
	for i, ht := range b.Values {
		cat := b.Start + float64(i)*b.Stride
		catVal := trCat(cat)
		if !b.Horizontal {
			if !c.ContainsX(catVal) {
				continue
			}
		} else {
			if !c.ContainsY(catVal) {
				continue
			}
		}
		catMin := trCat(cat - b.Width/2)
		catMax := trCat(cat + b.Width/2)
		bottom := b.stackedOn.BarHeight(i)  
		valMin := trVal(bottom)
		valMax := trVal(bottom + ht)
		var pts []vg.Point
		var poly []vg.Point
		if !b.Horizontal {
			pts = []vg.Point{
				{catMin, valMin},
				{catMin, valMax},
				{catMax, valMax},
				{catMax, valMin},
			}
			poly = c.ClipPolygonY(pts)
		} else {
			pts = []vg.Point{
				{valMin, catMin},
				{valMin, catMax},
				{valMax, catMax},
				{valMax, catMin},
			}
			poly = c.ClipPolygonX(pts)
		}
		c.FillPolygon(b.Color, poly)
		var outline [][]vg.Point
		if !b.Horizontal {
			pts = append(pts, vg.Point{X: catMin, Y: valMin})
			outline = c.ClipLinesY(pts)
		} else {
			pts = append(pts, vg.Point{X: valMin, Y: catMin})
			outline = c.ClipLinesX(pts)
		}
		c.StrokeLines(b.LineStyle, outline...)
		if i < len(b.Errors) {
			errval := b.Errors[i]
			eVal := trVal(bottom + ht + math.Abs(errval))
			if !b.Horizontal {
				bar := c.ClipLinesY([]vg.Point{{catVal, valMax}, {catVal, eVal}})
				c.StrokeLines(b.LineStyle, bar...)
				c.StrokeLine2(b.LineStyle, trCat(cat-b.Width/3), eVal, trCat(cat+b.Width/3), eVal)
			} else {
				bar := c.ClipLinesY([]vg.Point{{valMax, catVal}, {eVal, catVal}})
				c.StrokeLines(b.LineStyle, bar...)
				c.StrokeLine2(b.LineStyle, eVal, trCat(cat-b.Width/3), eVal, trCat(cat+b.Width/3))
			}
		}
	}
}
func (b *ErrBarChart) DataRange() (xmin, xmax, ymin, ymax float64) {
	catMin := b.Start - b.Pad
	catMax := b.Start + float64(len(b.Values)-1)*b.Stride + b.Pad
	valMin := math.Inf(1)
	valMax := math.Inf(-1)
	for i, val := range b.Values {
		valBot := b.stackedOn.BarHeight(i)
		valTop := valBot + val
		if i < len(b.Errors) {
			valTop += math.Abs(b.Errors[i])
		}
		valMin = math.Min(valMin, math.Min(valBot, valTop))
		valMax = math.Max(valMax, math.Max(valBot, valTop))
	}
	if !b.Horizontal {
		return catMin, catMax, valMin, valMax
	}
	return valMin, valMax, catMin, catMax
}