Example #1
0
// 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
}
Example #2
0
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
}
Example #3
0
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
}