Calculate edges given max values and a target width This will round the bin edges to values more appropriate for visualization
| 267 | /// This will round the bin edges to values more appropriate for |
| 268 | /// visualization |
| 269 | std::vector<double> histogram::bin_picker(double xmin, double xmax, |
| 270 | size_t nbins, double bin_width) { |
| 271 | double xscale = std::max(std::abs(xmin), std::abs(xmax)); |
| 272 | double xrange = xmax - xmin; |
| 273 | bin_width = std::max(bin_width, nextafter(xscale, xscale + 1) - xscale); |
| 274 | double left_edge = 0.; |
| 275 | double right_edge = 0.; |
| 276 | double n_bins_actual = 0.; |
| 277 | const bool data_is_not_constant = |
| 278 | xrange > std::max(sqrt(nextafter(xscale, xscale + 1) - xscale), |
| 279 | std::numeric_limits<double>::min()); |
| 280 | if (data_is_not_constant) { |
| 281 | double pow_of_ten = pow(10., floor(log10(bin_width))); |
| 282 | double relative_size = bin_width / pow_of_ten; |
| 283 | if (nbins == 0) { |
| 284 | if (relative_size < 1.5) { |
| 285 | bin_width = 1 * pow_of_ten; |
| 286 | } else if (relative_size < 2.5) { |
| 287 | bin_width = 2 * pow_of_ten; |
| 288 | } else if (relative_size < 4) { |
| 289 | bin_width = 3 * pow_of_ten; |
| 290 | } else if (relative_size < 7.5) { |
| 291 | bin_width = 5 * pow_of_ten; |
| 292 | } else { |
| 293 | bin_width = 10 * pow_of_ten; |
| 294 | } |
| 295 | left_edge = std::max( |
| 296 | std::min(bin_width * floor(xmin / bin_width), xmin), |
| 297 | -std::numeric_limits<double>::max()); |
| 298 | n_bins_actual = |
| 299 | std::max(1., ceil((xmax - left_edge) / bin_width)); |
| 300 | right_edge = std::min( |
| 301 | std::max(left_edge + n_bins_actual * bin_width, xmax), |
| 302 | std::numeric_limits<double>::max()); |
| 303 | } else { |
| 304 | bin_width = pow_of_ten * floor(relative_size); |
| 305 | left_edge = std::max( |
| 306 | std::min(bin_width * floor(xmin / bin_width), xmin), |
| 307 | -std::numeric_limits<double>::max()); |
| 308 | if (nbins > 1) { |
| 309 | double ll = (xmax - left_edge) / nbins; |
| 310 | double ul = |
| 311 | (xmax - left_edge) / (static_cast<double>(nbins - 1)); |
| 312 | double p_10 = pow(10, floor(log10(ul - ll))); |
| 313 | bin_width = p_10 * ceil(ll / p_10); |
| 314 | } |
| 315 | n_bins_actual = static_cast<double>(nbins); |
| 316 | right_edge = std::min( |
| 317 | std::max(left_edge + n_bins_actual * bin_width, xmax), |
| 318 | std::numeric_limits<double>::max()); |
| 319 | } |
| 320 | } else { |
| 321 | if (nbins == 0) { |
| 322 | nbins = 1; |
| 323 | } |
| 324 | double bin_range = std::max( |
| 325 | 1., ceil(nbins * nextafter(xscale, xscale + 1) - xscale)); |
| 326 | left_edge = floor(2 * (xmin - bin_range / 4)) / 2; |