// NewErrorPoints returns a new ErrorPoints where each // point in the ErrorPoints is given by evaluating the // center function on the Xs and Ys for the corresponding // set of XY values in the pts parameter. The XError // and YError are computed likewise, using the err // function. // // This function can be useful for summarizing sets of // scatter points using a single point and error bars for // each element of the scatter. func NewErrorPoints(f func([]float64) (c, l, h float64), pts ...plotter.XYer) (*ErrorPoints, error) { c := &ErrorPoints{ XYs: make(plotter.XYs, len(pts)), XErrors: make(plotter.XErrors, len(pts)), YErrors: make(plotter.YErrors, len(pts)), } for i, xy := range pts { xs := make([]float64, xy.Len()) ys := make([]float64, xy.Len()) for j := 0; j < xy.Len(); j++ { xs[j], ys[j] = xy.XY(j) if err := plotter.CheckFloats(xs[j], ys[j]); err != nil { return nil, err } } c.XYs[i].X, c.XErrors[i].Low, c.XErrors[i].High = f(xs) if err := plotter.CheckFloats(c.XYs[i].X, c.XErrors[i].Low, c.XErrors[i].High); err != nil { return nil, err } c.XYs[i].Y, c.YErrors[i].Low, c.YErrors[i].High = f(ys) if err := plotter.CheckFloats(c.XYs[i].Y, c.YErrors[i].Low, c.YErrors[i].High); err != nil { return nil, err } } return c, nil }
func NewErrorPointsXSpaced(f func([]float64) (c, l, h float64), howManyPoints, howManyErrorBars int64, dataRange Float64Range, pointsGenerators []PointGenerator) (*[]PointsAndErrorPoints, error) { if howManyPoints < 2 { panic("NewErrorPointsXSpaced: only 2 or more points can be used") } dataMin := dataRange.min dataMax := dataRange.max ptsNerrs := make([]PointsAndErrorPoints, len(pointsGenerators)) //Figure out where the data points go xIncr := (dataMax - dataMin) / (float64(howManyPoints) - 1.0) for curGeneratorIndex, pointsGenerator := range pointsGenerators { //create and instantiate the PointsAndErrorPoints object points := make(plotter.XYs, howManyPoints) ptsNerrs[curGeneratorIndex].points = &points errorPoints := ErrorPoints{ XYs: make(plotter.XYs, howManyErrorBars), XErrors: make(plotter.XErrors, howManyErrorBars), YErrors: make(plotter.YErrors, howManyErrorBars), } ptsNerrs[curGeneratorIndex].errorPoints = &errorPoints //rename a few things for ease of reading the code genRangeMin := pointsGenerator.pointRange.min genRangeMax := pointsGenerator.pointRange.max generator := pointsGenerator.generator //start by generating the data points that will define the line ptsAdded := 0 for curX := dataMin; ptsAdded < points.Len() && curX <= dataMax+xIncr; curX += xIncr { //if the current x value is outside of the generator range skip it if curX < genRangeMin || curX > genRangeMax { continue } //make sure that the x value we're going to use is okay if err := plotter.CheckFloats(curX); err != nil { return nil, err } //generate the set of y values at this given x value ys := generator(curX) //make sure that all the y values returned are okay if err := plotter.CheckFloats(ys...); err != nil { return nil, err } //set the x value for this point points[ptsAdded].X = curX //set the y value for this point as returned by this function //we only want the points so ignore the range-type of data also returned points[ptsAdded].Y, _, _ = f(ys) //make sure that the returned value is okay if err := plotter.CheckFloats(points[ptsAdded].Y); err != nil { return nil, err } //We need to keep track of how many points we're actually adding //because not all the x's will fall within the generators range //and we might have to shrink the array to avoid problems when plotting ptsAdded++ } points = points[0:ptsAdded] //Now figure out where the error bars go xIncr = (dataMax - dataMin) / float64(howManyErrorBars) //we want to space out the error bars so they don't all overlap xOffset := (xIncr / 4.0) + float64(curGeneratorIndex)*(xIncr/2.0)/float64(len(pointsGenerators)) numErrsAdded := 0 for curX := dataMin; numErrsAdded < errorPoints.XYs.Len() && curX <= dataMax+xIncr; curX += xIncr { x := curX + xOffset if curX < genRangeMin || curX > genRangeMax || x < genRangeMin || x > genRangeMax { continue } if err := plotter.CheckFloats(x); err != nil { return nil, err } ys := generator(x) if err := plotter.CheckFloats(ys...); err != nil { return nil, err } errorPoints.XYs[numErrsAdded].X = x errorPoints.XErrors[numErrsAdded].Low = 0.0 errorPoints.XErrors[numErrsAdded].High = 0.0 y, low, high := f(ys) errorPoints.XYs[numErrsAdded].Y = y errorPoints.YErrors[numErrsAdded].Low = low errorPoints.YErrors[numErrsAdded].High = high if err := plotter.CheckFloats(errorPoints.YErrors[numErrsAdded].Low, errorPoints.YErrors[numErrsAdded].High); err != nil { return nil, err } numErrsAdded++ } ptsNerrs[curGeneratorIndex].errorPoints.XYs = errorPoints.XYs[0:numErrsAdded] ptsNerrs[curGeneratorIndex].errorPoints.XErrors = errorPoints.XErrors[0:numErrsAdded] ptsNerrs[curGeneratorIndex].errorPoints.YErrors = errorPoints.YErrors[0:numErrsAdded] } return &ptsNerrs, nil }
func NewErrorPointsSpaced(f func([]float64) (c, l, h float64), pointSet, totalNumberOfPointSets, howManyPoints, howManyErrorBars int64, minX, maxX float64, pointsGenerator func(float64) []float64, minRange, maxRange float64) (*plotter.XYs, *ErrorPoints, error) { if howManyPoints < 2 { panic("NewErrorPointsXSpaced: only 2 or more points can be used") } points := make(plotter.XYs, howManyPoints) errorBars := &ErrorPoints{ XYs: make(plotter.XYs, howManyErrorBars), XErrors: make(plotter.XErrors, howManyErrorBars), YErrors: make(plotter.YErrors, howManyErrorBars), } //generate the points first xIncr := (maxX - minX) / (float64(howManyPoints) - 1.0) i := 0 for curX := minX; i < points.Len() && curX <= maxX+xIncr; curX += xIncr { if curX < minRange || curX > maxRange { continue } if err := plotter.CheckFloats(curX); err != nil { return nil, nil, err } ys := pointsGenerator(curX) for j := 0; j < len(ys); j++ { if err := plotter.CheckFloats(ys[j]); err != nil { return nil, nil, err } } points[i].X = curX points[i].Y, _, _ = f(ys) if err := plotter.CheckFloats(points[i].Y); err != nil { return nil, nil, err } i++ } points = points[0:i] //generate the error bars xIncr = (maxX - minX) / float64(howManyErrorBars) xOffset := (xIncr / 4.0) + float64(pointSet)*(xIncr/2.0)/float64(totalNumberOfPointSets) i = 0 for curX := minX; i < errorBars.XYs.Len() && curX <= maxX+xIncr; curX += xIncr { x := curX + xOffset if curX < minRange || curX > maxRange || x < minRange || x > maxRange { continue } if err := plotter.CheckFloats(x); err != nil { return nil, nil, err } ys := pointsGenerator(x) for j := 0; j < len(ys); j++ { if err := plotter.CheckFloats(ys[j]); err != nil { return nil, nil, err } } errorBars.XYs[i].X, errorBars.XErrors[i].Low, errorBars.XErrors[i].High = x, 0.0, 0.0 errorBars.XYs[i].Y, errorBars.YErrors[i].Low, errorBars.YErrors[i].High = f(ys) if err := plotter.CheckFloats(errorBars.YErrors[i].Low, errorBars.YErrors[i].High); err != nil { return nil, nil, err } i++ } errorBars.XYs = errorBars.XYs[0:i] errorBars.XErrors = errorBars.XErrors[0:i] errorBars.YErrors = errorBars.YErrors[0:i] return &points, errorBars, nil }