binPoints returns a slice containing the given number of bins, and the width of each bin. If the given number of bins is not positive then a reasonable default is used. The default is the square root of the sum of the y values.
(xys XYer, n int)
| 183 | // default is the square root of the sum of |
| 184 | // the y values. |
| 185 | func binPoints(xys XYer, n int) (bins []HistogramBin, width float64) { |
| 186 | xmin, xmax := Range(XValues{xys}) |
| 187 | if n <= 0 { |
| 188 | m := 0.0 |
| 189 | for i := range xys.Len() { |
| 190 | _, y := xys.XY(i) |
| 191 | m += math.Max(y, 1.0) |
| 192 | } |
| 193 | n = int(math.Ceil(math.Sqrt(m))) |
| 194 | } |
| 195 | if n < 1 || xmax <= xmin { |
| 196 | n = 1 |
| 197 | } |
| 198 | |
| 199 | bins = make([]HistogramBin, n) |
| 200 | |
| 201 | w := (xmax - xmin) / float64(n) |
| 202 | if w == 0 { |
| 203 | w = 1 |
| 204 | } |
| 205 | for i := range bins { |
| 206 | bins[i].Min = xmin + float64(i)*w |
| 207 | bins[i].Max = xmin + float64(i+1)*w |
| 208 | } |
| 209 | |
| 210 | for i := range xys.Len() { |
| 211 | x, y := xys.XY(i) |
| 212 | bin := int((x - xmin) / w) |
| 213 | if x == xmax { |
| 214 | bin = n - 1 |
| 215 | } |
| 216 | if bin < 0 || bin >= n { |
| 217 | panic(fmt.Sprintf("%g, xmin=%g, xmax=%g, w=%g, bin=%d, n=%d\n", |
| 218 | x, xmin, xmax, w, bin, n)) |
| 219 | } |
| 220 | bins[bin].Weight += y |
| 221 | } |
| 222 | return bins, w |
| 223 | } |
| 224 | |
| 225 | // A HistogramBin approximates the number of values |
| 226 | // within a range by a single number (the weight). |
no test coverage detected