Tomographer  v4.0
Tomographer C++ Framework Documentation
histogram.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef HISTOGRAM_H
29 #define HISTOGRAM_H
30 
31 #include <cmath>
32 #include <cstdlib>
33 
34 #include <utility> // std::declval
35 #include <iostream>
36 #include <iomanip> // std::setprecision
37 #include <sstream> // std::stringstream
38 #include <stdexcept> // std::out_of_range
39 #include <type_traits> // std::enable_if
40 #include <algorithm> // std::max
41 
42 #include <boost/math/constants/constants.hpp>
43 
44 #include <Eigen/Core>
45 
46 #include <tomographer/tools/fmt.h>
48 #include <tomographer/tools/cxxutil.h> // TOMOGRAPHER_ENABLED_IF, tomographer_assert(), getWidthForTerminalOutput
50 
51 
59 namespace Tomographer {
60 
61 
62 
67 template<typename Scalar_ = double>
68 TOMOGRAPHER_EXPORT struct UniformBinsHistogramParams
69 {
71  typedef Scalar_ Scalar;
72 
74  UniformBinsHistogramParams(Scalar min_ = 0.0, Scalar max_ = 1.0, std::size_t num_bins_ = 50)
75  : min(min_), max(max_), num_bins(num_bins_)
76  {
77  }
79  template<typename Params2,
80  // enforce Params-like type by checking that properties 'min','max','num_bins' exist:
81  decltype((int)std::declval<const Params2>().min + (int)std::declval<const Params2>().max
82  + std::declval<Params2>().num_bins) dummyval = 0>
83  UniformBinsHistogramParams(const Params2& other)
84  : min(other.min), max(other.max), num_bins(other.num_bins)
85  {
86  }
87 
89  Scalar min;
91  Scalar max;
94 
100  inline bool isWithinBounds(Scalar value) const
101  {
102  return std::isfinite(value) && value >= min && value < max;
103  }
110  inline std::size_t binIndex(Scalar value) const
111  {
112  if ( !isWithinBounds(value) ) {
113  throw std::out_of_range(streamstr("UniformBinsHistogramParams: Value "<<value
114  <<" out of range ["<<min<<","<<max<<"["));
115  }
116  return binIndexUnsafe(value);
117  }
126  inline std::size_t binIndexUnsafe(Scalar value) const
127  {
128  return (std::size_t)((value-min) / (max-min) * num_bins);
129  }
138  inline Scalar binLowerValue(std::size_t index) const
139  {
140  tomographer_assert(Tools::isPositive(index) && (std::size_t)index < num_bins);
141  return min + index * (max-min) / num_bins;
142  }
150  inline Scalar binCenterValue(std::size_t index) const
151  {
152  tomographer_assert(Tools::isPositive(index) && (std::size_t)index < num_bins);
153  return min + (index+boost::math::constants::half<Scalar>()) * (max-min) / num_bins;
154  }
163  inline Scalar binUpperValue(std::size_t index) const
164  {
165  tomographer_assert(Tools::isPositive(index) && (std::size_t)index < num_bins);
166  return min + (index+1) * (max-min) / num_bins;
167  }
172  inline Scalar binResolution() const
173  {
174  return (max - min) / num_bins;
175  }
176 
180  {
181  const auto halfbinres = boost::math::constants::half<Scalar>() * binResolution();
182  return Eigen::Array<Scalar, Eigen::Dynamic, 1>::LinSpaced(num_bins, min+halfbinres, max-halfbinres);
183  }
184 
188  {
190  }
191 
195  {
197  }
198 };
199 
200 
201 
202 
210 template<typename Scalar_, typename CountType_ = int>
211 TOMOGRAPHER_EXPORT class UniformBinsHistogram
212  // inheriting from this has some advantages over EIGEN_MAKE_ALIGNED_OPERATOR_NEW, such
213  // as not needing to explicitly declare the specialization
214  // NeedOwnOperatorNew<UniformBinsHistogram>:
215  //
216  // -- really not needed because the matrices are dynamically sized
217  //
218  // : public virtual Tools::NeedOwnOperatorNew<Eigen::Array<CountType,Eigen::Dynamic,1> >::ProviderType
219 {
220 public:
222  typedef Scalar_ Scalar;
223 
225  typedef CountType_ CountType;
226 
228  static constexpr bool HasErrorBars = false;
229 
232 
234  Params params;
238  CountType off_chart;
239 
241  template<typename Params2 = Params,
242  // enforce Params-like type by checking that properties 'min','max','num_bins' exist:
243  decltype((int)std::declval<const Params2>().min + (int)std::declval<const Params2>().max
244  + std::declval<Params2>().num_bins) dummyval = 0>
245  UniformBinsHistogram(Params2 p = Params())
246  : params(p), bins(Eigen::Array<CountType,Eigen::Dynamic,1>::Zero(p.num_bins)),
247  off_chart(0)
248  {
249  }
250 
252  UniformBinsHistogram(Scalar min_, Scalar max_, std::size_t num_bins)
253  : params(min_, max_, num_bins), bins(Eigen::Array<CountType,Eigen::Dynamic,1>::Zero(num_bins)),
254  off_chart(0)
255  {
256  }
257 
259  template<typename HistogramType,// and enforce it's indeed a histogram type by testing its 'HasErrorBars' property:
260  TOMOGRAPHER_ENABLED_IF_TMPL(HistogramType::HasErrorBars == 0 || HistogramType::HasErrorBars == 1)>
261  UniformBinsHistogram(const HistogramType & other)
262  : params(other.params), bins(other.params.num_bins), off_chart(other.off_chart)
263  {
264  bins = other.bins.template cast<CountType>();
265  }
266 
268  inline void reset()
269  {
270  bins.resize(params.num_bins);
271  bins.setZero();
272  off_chart = 0;
273  }
274 
284  template<typename EigenType>
285  inline void load(const Eigen::DenseBase<EigenType> & x, CountType off_chart_ = 0)
286  {
287  tomographer_assert(x.cols() == 1);
288  tomographer_assert((std::size_t)x.rows() == params.num_bins);
289  bins = x.derived().template cast<CountType>();
290  off_chart = off_chart_;
291  }
292 
301  template<typename EigenType>
302  inline void add(const Eigen::ArrayBase<EigenType> & x, CountType off_chart_ = 0)
303  {
304  // the argument must be of ArrayBase type (as opposed to load() where we can
305  // also accept MatrixBase types) because Eigen doesn't allow operator+=
306  // between Arrays and Matrices, but has an operator= .
307  tomographer_assert(x.cols() == 1);
308  tomographer_assert((std::size_t)x.rows() == params.num_bins);
309  bins += x.derived().template cast<CountType>();
310  off_chart += off_chart_;
311  }
312 
321  template<typename OtherScalar, typename OtherCountType>
323  {
324  tomographer_assert(x.bins.cols() == 1);
325  tomographer_assert((std::size_t)x.bins.rows() == params.num_bins);
326  tomographer_assert(std::fabs(x.params.min - params.min) < 1e-8);
327  tomographer_assert(std::fabs(x.params.max - params.max) < 1e-8);
328  bins += x.bins.template cast<CountType>();
329  off_chart += x.off_chart;
330  }
331 
333  inline std::size_t numBins() const
334  {
335  return params.num_bins;
336  }
337 
339  inline CountType count(std::size_t i) const
340  {
341  return bins(i);
342  }
343 
345  inline bool isWithinBounds(Scalar value) const
346  {
347  return params.isWithinBounds(value);
348  }
350  inline std::size_t binIndex(Scalar value) const
351  {
352  return params.binIndex(value);
353  }
355  inline Scalar binLowerValue(int index) const
356  {
357  return params.binLowerValue(index);
358  }
360  inline Scalar binCenterValue(std::size_t index) const
361  {
362  return params.binCenterValue(index);
363  }
365  inline Scalar binUpperValue(std::size_t index) const
366  {
367  return params.binUpperValue(index);
368  }
369 
371  inline Scalar binResolution() const
372  {
373  return params.binResolution();
374  }
375 
385  inline std::size_t record(Scalar value)
386  {
387  if ( !isWithinBounds(value) ) {
388  ++off_chart;
390  }
391  // calling bin_index_unsafe because we have already checked that value is in range.
392  const std::size_t index = params.binIndexUnsafe(value);
393  ++bins( index );
394  return index;
395  }
396 
407  inline std::size_t record(Scalar value, CountType weight)
408  {
409  if ( !isWithinBounds(value) ) {
410  off_chart += weight;
412  }
413  // calling bin_index_unsafe is safe here because we have already checked that value is
414  // in range.
415  const std::size_t index = params.binIndexUnsafe(value);
416  bins(index) += weight;
417  return index;
418  }
419 
420 
434  template<typename NewCountType = decltype(Scalar(1) + CountType(1))>
435  inline NewCountType normalization() const
436  {
437  // DON'T DO NewCountType(binResolution())*NewCountType(bins.sum()) as we may loose
438  // precision (if NewCountType=int, for example)
439  return NewCountType(off_chart) + NewCountType(binResolution() * bins.sum());
440  }
441 
448  template<typename NewCountType = Scalar>
450  {
452  const NewCountType f = normalization<NewCountType>();
453  h.load(bins.template cast<NewCountType>() / f, NewCountType(off_chart) / f);
454  return h;
455  }
456 
461  inline std::string prettyPrint(int max_width = 0) const
462  {
463  return histogramPrettyPrint(*this, max_width);
464  }
465 
466 };
467 
468 
469 
470 
476 template<typename Scalar_, typename CountType_ = double>
477 TOMOGRAPHER_EXPORT class UniformBinsHistogramWithErrorBars
478  : public UniformBinsHistogram<Scalar_, CountType_>
479  // public virtual Tools::EigenAlignedOperatorNewProvider -- no need for dynamically-sized matrices
480 {
481 public:
483  typedef Scalar_ Scalar;
485  typedef CountType_ CountType;
486 
492  typedef typename Base_::Params Params;
493 
495  static constexpr bool HasErrorBars = true;
496 
499 
500  // make these accessible without having to use the "Base_::member" syntax all the time
501  using Base_::params;
502  using Base_::bins;
503  using Base_::off_chart;
504 
505 
511  UniformBinsHistogramWithErrorBars(Params params = Params())
512  : Base_(params), delta(Eigen::Array<CountType, Eigen::Dynamic, 1>::Zero(params.num_bins))
513  {
514  }
515 
522  : Base_(min, max, num_bins), delta(Eigen::Array<CountType, Eigen::Dynamic, 1>::Zero(num_bins))
523  {
524  }
525 
532  inline void reset()
533  {
534  Base_::reset();
535  delta.resize(Base_::numBins());
536  delta.setZero();
537  }
538 
543  inline CountType errorBar(std::size_t i) const
544  {
545  return delta(i);
546  }
547 
548 
561  template<typename EigenType, typename EigenType2 = EigenType>
562  inline void load(const Eigen::DenseBase<EigenType> & d,
563  const Eigen::DenseBase<EigenType2> & derr,
564  CountType off_chart_ = 0)
565  {
566  Base_::load(d, off_chart_);
567  tomographer_assert(derr.cols() == 1);
568  tomographer_assert((std::size_t)derr.rows() == params.num_bins);
569  delta = derr.derived().template cast<CountType>();
570  }
571 
572 
579  template<typename NewCountType = Scalar>
581  {
583  const NewCountType f = Base_::template normalization<NewCountType>();
584  h.load(bins.template cast<NewCountType>() / f,
585  delta.template cast<NewCountType>() / f,
586  NewCountType(off_chart) / f);
587  return h;
588  }
589 
590 
591 private:
595  template<typename... Args>
596  inline void add(Args && ... )
597  {
598  }
599 public:
600 
601 
609  std::string prettyPrint(int max_width = 0) const
610  {
611  return histogramPrettyPrint(*this, max_width);
612  }
613 
614 };
615 // static members:
616 template<typename Scalar_, typename CountType_>
618 
619 
620 
621 
622 
623 
657 template<typename HistogramType_, typename RealAvgType = double>
658 TOMOGRAPHER_EXPORT class AveragedHistogram
659  : public UniformBinsHistogramWithErrorBars<typename HistogramType_::Scalar, RealAvgType>
660 {
661 public:
667  typedef HistogramType_ HistogramType;
670 
672  typedef typename Base_::Params Params;
674  typedef typename Base_::Scalar Scalar;
676  typedef typename Base_::CountType CountType;
677 
679  static constexpr bool HasErrorBars = true;
680 
687 
688 
695  AveragedHistogram(const Params& params = Params())
696  : Base_(params), num_histograms(0)
697  {
698  }
699 
706  : Base_(min, max, num_bins), num_histograms(0)
707  {
708  }
709 
716  inline void reset(const Params& params_)
717  {
718  Base_::params = params_;
719  Base_::reset();
720  num_histograms = 0;
721  }
722 
729  inline void reset()
730  {
731  Base_::reset();
732  num_histograms = 0;
733  }
734 
735  // ---------------------------------------------------------------------------
736  // Implementation in case the added histograms don't have their own error bars
737  // ---------------------------------------------------------------------------
738 
753  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
754  inline void addHistogram(const HistogramType& histogram)
755  {
756  // bins collects the sum of the histograms
757  // delta for now collects the sum of squares. delta will be normalized in finalize().
758 
759  tomographer_assert((typename HistogramType::CountType)histogram.numBins() ==
760  (typename HistogramType::CountType)Base_::numBins());
761 
762  for (std::size_t k = 0; k < histogram.numBins(); ++k) {
763  RealAvgType binvalue = histogram.count(k);
764  Base_::bins(k) += binvalue;
765  Base_::delta(k) += binvalue * binvalue;
766  }
767 
768  Base_::off_chart += histogram.off_chart;
769  ++num_histograms;
770  }
785  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
786  inline void finalize()
787  {
788  Base_::bins /= num_histograms;
789  Base_::delta /= num_histograms;
790  Base_::off_chart /= num_histograms;
791 
792  // delta = sqrt(< X^2 > - < X >^2) / sqrt(Nrepeats-1)
793  auto finhist2 = Base_::bins*Base_::bins; // for array, this is c-wise product
794  Base_::delta = ( (Base_::delta - finhist2) / (num_histograms-1) ).sqrt();
795  }
796 
797  // ---------------------------------------------------------------------------
798  // Implementation in case the added histograms do have their own error bars
799  // ---------------------------------------------------------------------------
800 
815  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
816  inline void addHistogram(const HistogramType& histogram)
817  {
818  // bins collects the sum of the histograms
819  // delta for now collects the sum of squares. delta will be normalized in finished().
820 
821  tomographer_assert((typename HistogramType::CountType)histogram.numBins() == Base_::numBins());
822 
823  for (std::size_t k = 0; k < histogram.numBins(); ++k) {
824  RealAvgType binvalue = histogram.count(k);
825  Base_::bins(k) += binvalue;
826  RealAvgType bindelta = histogram.errorBar(k);
827  Base_::delta(k) += bindelta*bindelta;
828  }
829 
830  Base_::off_chart += histogram.off_chart;
831  ++num_histograms;
832  }
847  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
848  inline void finalize()
849  {
850  Base_::bins /= num_histograms;
851  Base_::off_chart /= num_histograms;
852 
853  Base_::delta = Base_::delta.sqrt();
854  Base_::delta /= num_histograms;
855  }
856 
857 };
858 
859 
860 
861 
862 
863 
864 
865 // -----------------------------------------------------------------------------
866 // Pretty Print Histogram Utilities
867 // -----------------------------------------------------------------------------
868 
869 
870 
871 namespace tomo_internal {
872 // internal helpers
873 //
874 // find maximum value in the list only among those values which are finite (not inf or nan)
875 //
876 template<typename Scalar, typename Fn>
877 inline Scalar max_finite_value(const std::size_t num_items, Fn val_generator,
878  const Scalar default_val = Scalar(1.0))
879 {
880  bool has_first_val = false;
881  Scalar max_val = default_val;
882  for (std::size_t k = 0; k < num_items; ++k) {
883  const Scalar this_val = val_generator(k);
884  if (std::isfinite(this_val) && (!has_first_val || this_val > max_val)) {
885  max_val = this_val;
886  has_first_val = true;
887  }
888  }
889  return max_val;
890 }
891 
892 //
893 // get labels left of histogram (generic HistogramType interface: no information, just bin #)
894 //
895 template<typename HistogramType>
896 struct histogram_pretty_print_label
897 {
898  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
899  {
900  labels.resize(hist.numBins());
901  for (std::size_t k = 0; k < hist.numBins(); ++k) {
902  labels[k] = std::to_string(k);
903  }
904  }
905 };
906 // get labels left of histogram (for the family of histograms with 'Params':
907 // UniformBinsHistogram, UniformBinsHistogramWithErrorBars etc.)
908 //
909 // common code for several specializations of histogram_pretty_print_label
910 template<typename HistogramType>
911 inline void histogram_get_labels_for_hist_params(std::vector<std::string> & labels, const HistogramType& hist)
912 {
913  labels.resize(hist.numBins());
914 
915  const double max_label_val = std::max(hist.binCenterValue(0), hist.binCenterValue(hist.numBins()-1));
916  const int powten = (int)std::floor(std::log10(max_label_val));
917  const int relprecision = 4;
918  const int precision = (powten > relprecision) ? 0 : (relprecision - powten - 1);
919 
920  for (std::size_t k = 0; k < hist.numBins(); ++k) {
922  ss << std::fixed << std::setprecision(precision) << std::right << hist.binCenterValue(k);
923  labels[k] = ss.str();
924  }
925 }
926 // specialize histogram pretty-print labels using the code above
927 template<typename Scalar_, typename CountType_>
928 struct histogram_pretty_print_label<UniformBinsHistogram<Scalar_, CountType_> >
929 {
931  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
932  {
933  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
934  }
935 };
936 // specialize histogram pretty-print labels using the code above
937 template<typename Scalar_, typename CountType_>
938 struct histogram_pretty_print_label<UniformBinsHistogramWithErrorBars<Scalar_, CountType_> >
939 {
941  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
942  {
943  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
944  }
945 };
946 // specialize histogram pretty-print labels using the code above
947 template<typename BaseHistogramType_, typename RealAvgType_>
948 struct histogram_pretty_print_label<AveragedHistogram<BaseHistogramType_, RealAvgType_> >
949 {
951  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
952  {
953  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
954  }
955 };
956 
957 // format bin counts nicely
958 template<typename HistogramType>
959 struct histogram_pretty_print_value
960 {
961  const HistogramType & hist;
962  histogram_pretty_print_value(const HistogramType & hist_) : hist(hist_) { }
963 
964  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
965  static inline void getStrValues(std::vector<std::string> & svalues, const HistogramType & hist)
966  {
967  svalues.resize(hist.numBins());
968 
969  double max_val = max_finite_value(hist.numBins(), [&](std::size_t k) { return hist.count(k); }, 1.0);
970 
971  const int powten = (int)std::floor(std::log10(max_val));
972  const int relprecision = 3;
973  const int precision = abs_precision_for(powten, relprecision);
974  const int w = (precision > 0) ? (precision+powten+1) : (relprecision+2);
975 
976  for (std::size_t k = 0; k < hist.numBins(); ++k) {
978  ss << std::setprecision(precision) << std::fixed << std::right << std::setw(w)
979  << hist.count(k);
980  svalues[k] = ss.str();
981  }
982  }
983 
984  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
985  static inline void getStrValues(std::vector<std::string> & svalues, const HistogramType & hist)
986  {
987  svalues.resize(hist.numBins());
988 
989  double max_val = max_finite_value(hist.numBins(), [&](std::size_t k) { return hist.count(k); }, 1.0);
990 
991  const int powten = (int)std::floor(std::log10(max_val)); // floor of log_{10}(...)
992  const int relprecision = 3;
993  const int precision = abs_precision_for(powten, relprecision);
994  const int w = (precision > 0) ? (precision+powten+2) : (relprecision+2);
995 
996  for (std::size_t k = 0; k < hist.numBins(); ++k) {
998  ss << std::setprecision(precision) << std::fixed << std::right << std::setw(w)
999  << hist.count(k) << " +- "
1000  << std::setprecision(abs_precision_for(powten-1, relprecision-1)) << std::setw(w)
1001  << hist.errorBar(k);
1002  svalues[k] = ss.str();
1003  }
1004  }
1005 private:
1006  static inline int abs_precision_for(const int powten, const int relprecision)
1007  {
1008  return (powten >= relprecision) ? 0 : (relprecision - powten - 1);
1009  }
1010 };
1011 
1013 //
1014 // access this with public API using histogram_pretty_print().
1015 //
1016 template<typename HistogramType>
1017 struct histogram_pretty_printer
1018 {
1019  const HistogramType & hist;
1020  const int max_width;
1021 
1022  const std::string lsep;
1023  const std::string rsep;
1024 
1025  std::vector<std::string> labels;
1026  int maxlabelwidth;
1027 
1028  std::vector<std::string> svalues;
1029  int maxsvaluewidth;
1030 
1031  double max_value;
1032 
1033  int max_bar_width;
1034  double barscale;
1035 
1036  histogram_pretty_printer(const HistogramType & hist_, const int max_width_)
1037  : hist(hist_), max_width(max_width_), lsep(" |"), rsep(" ")
1038  {
1039  // first pass:
1040  // - determine the maximum value attained in the histogram
1041  // - determine maximum width of formatted label & value fields.
1042 
1043  labels.resize(hist.numBins());
1044  svalues.resize(hist.numBins());
1045 
1046  histogram_pretty_print_label<HistogramType>::getLabels(labels, hist);
1047  histogram_pretty_print_value<HistogramType>::getStrValues(svalues, hist);
1048 
1049  bool has_maxval = false;
1050  for (std::size_t k = 0; k < hist.numBins(); ++k) {
1051  const double val = maxval(k);
1052 
1053  if (std::isfinite(val) && (!has_maxval || val > max_value)) {
1054  max_value = val;
1055  has_maxval = true;
1056  }
1057  if (k == 0 || (int)labels[k].size() > maxlabelwidth) {
1058  maxlabelwidth = (int)labels[k].size();
1059  }
1060  if (k == 0 || (int)svalues[k].size() > maxsvaluewidth) {
1061  maxsvaluewidth = (int)svalues[k].size();
1062  }
1063  }
1064  if (!has_maxval) {
1065  max_value = 1.0;
1066  }
1067 
1068  max_bar_width = max_width - maxlabelwidth - maxsvaluewidth - (int)lsep.size() - (int)rsep.size();
1069  if (max_bar_width < 2) {
1070  max_bar_width = 2;
1071  }
1072  barscale = ((max_value > 0) ? (max_value / max_bar_width) : 1.0);
1073  }
1074 
1075  inline int value_to_bar_length(double val) const
1076  {
1077  if (val < 0 || !std::isfinite(val)) {
1078  val = 0;
1079  }
1080  int l = (int)(val/barscale+0.5);
1081  if (l >= max_bar_width) {
1082  return max_bar_width-1;
1083  }
1084  return l;
1085  }
1086 
1087  inline void fill_str_len(std::string & s, double valstart, double valend,
1088  char c, char clside, char crside) const
1089  {
1090  int vs = value_to_bar_length(valstart);
1091  int ve = value_to_bar_length(valend);
1092  tomographer_assert(vs >= 0);
1093  tomographer_assert(vs < (int)s.size());
1094  tomographer_assert(ve >= 0);
1095  tomographer_assert(ve < (int)s.size());
1096  for (int j = vs; j < ve; ++j) {
1097  s[j] = c;
1098  }
1099  if (clside && crside && clside != crside && vs == ve) {
1100  if (ve < (int)s.size()-1) {
1101  ++ve;
1102  } else if (vs > 1) {
1103  --vs;
1104  }
1105  }
1106  if (clside) {
1107  s[vs] = clside;
1108  }
1109  if (crside) {
1110  s[ve] = crside;
1111  }
1112  }
1113 
1114  inline void pretty_print(std::ostream & str) const
1115  {
1116  // perform now second pass:
1117  // - display the histogram line by line, with the calculated widths.
1118 
1119  std::size_t k;
1120 
1121  for (k = 0; k < hist.numBins(); ++k) {
1122  str << std::setw(maxlabelwidth) << labels[k] << lsep
1123  << make_bar(k) << rsep << std::setw(maxsvaluewidth) << svalues[k] << "\n";
1124  }
1125  }
1126 
1127 private:
1128  // maxval(k): how much this bar may extend in length
1129  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
1130  inline double maxval(const std::size_t k) const
1131  {
1132  return (double)hist.count(k);
1133  }
1134  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
1135  inline double maxval(const std::size_t k) const
1136  {
1137  return (double)(hist.count(k) + hist.errorBar(k));
1138  }
1139  // make_bar(k): produce the histogram bar in characters...
1140  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
1141  inline std::string make_bar(std::size_t k) const
1142  {
1143  std::string sbar(max_bar_width, ' ');
1144  fill_str_len(sbar, 0.0, hist.count(k), '*', 0, 0);
1145  return sbar;
1146  }
1147  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
1148  inline std::string make_bar(std::size_t k) const
1149  {
1150  std::string sbar(max_bar_width, ' ');
1151  const double binval = hist.count(k);
1152  const double binerr = hist.errorBar(k);
1153  fill_str_len(sbar, 0.0, binval - binerr, '*', '*', '*');
1154  fill_str_len(sbar, binval - binerr, binval + binerr, '-', '|', '|');
1155  return sbar;
1156  }
1157 };
1158 
1159 template<typename HistogramType>
1160 inline std::string histogram_short_bar_fmt(const HistogramType & histogram, const bool log_scale,
1161  const int max_width)
1162 {
1163  std::string s = Tools::fmts("%.2g|", (double)histogram.binLowerValue(0));
1164  std::string send = Tools::fmts("|%.2g", (double)histogram.binUpperValue(histogram.numBins()-1));
1165  if (histogram.off_chart > 0) {
1166  send += Tools::fmts(" [+%.1g off]", (double)histogram.off_chart);
1167  }
1168 
1169  const int maxbarwidth = max_width - (int)s.size() - (int)send.size();
1170  const int numdiv = (int)(std::ceil((float)histogram.numBins() / maxbarwidth) + 0.5f);
1171  const int barwidth = (int)(std::ceil((float)histogram.numBins() / numdiv) + 0.5f);
1172 
1174  Eigen::ArrayXf veclog(barwidth);
1175 
1176  int k;
1177  float minlogval = 0;
1178  float maxlogval = 0;
1179  for (k = 0; k < barwidth; ++k) {
1180  vec(k) = histogram.bins.segment(numdiv*k, std::min((std::size_t)numdiv,
1181  (std::size_t)(histogram.bins.size()-numdiv*k))).sum();
1182  if (vec(k) > 0) {
1183  if (log_scale) {
1184  veclog(k) = std::log((float)vec(k));
1185  } else {
1186  veclog(k) = (float)vec(k);
1187  }
1188  if (k == 0 || minlogval > veclog(k)) {
1189  minlogval = veclog(k);
1190  }
1191  if (k == 0 || maxlogval < veclog(k)) {
1192  maxlogval = veclog(k) + 1e-6f;
1193  }
1194  } else {
1195  veclog(k) = 0.f;
1196  }
1197  }
1198 
1199  // now, prepare string
1200  const std::string chars = ".-+ox%#";
1201  for (k = 0; k < barwidth; ++k) {
1202  if (vec(k) <= 0) {
1203  s += ' ';
1204  } else {
1205  int i = (int)(chars.size() * (veclog(k) - minlogval) / (maxlogval - minlogval));
1206  if (i < 0) { i = 0; }
1207  if (i >= (int)chars.size()) { i = (int)chars.size()-1; }
1208  s += chars[i];
1209  }
1210  }
1211 
1212  s += send;
1213 
1214  return s;
1215 }
1216 
1217 } // namespace tomo_internal
1218 
1219 
1228 template<typename HistogramType>
1229 inline void histogramPrettyPrint(std::ostream & str, const HistogramType & histogram, int max_width = 0)
1230 {
1231  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1232 
1233  if (histogram.params.num_bins == 0) {
1234  str << "<empty histogram: no bins>\n";
1235  return;
1236  }
1237 
1238  max_width = Tools::getWidthForTerminalOutput(max_width);
1239  tomo_internal::histogram_pretty_printer<HistogramType>(histogram, max_width).pretty_print(str);
1240 }
1241 
1250 template<typename HistogramType>
1251 inline std::string histogramPrettyPrint(const HistogramType & histogram, int max_width = 0)
1252 {
1253  std::ostringstream ss;
1254  histogramPrettyPrint<HistogramType>(ss, histogram, max_width);
1255  return ss.str();
1256 }
1257 
1275 template<typename HistogramType>
1276 inline int histogramShortBar(std::ostream & str, const HistogramType & histogram,
1277  bool log_scale = true, int max_width = 0)
1278 {
1279  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1280 
1281  max_width = Tools::getWidthForTerminalOutput(max_width);
1282 
1283  std::string s;
1284  if (histogram.params.num_bins == 0) {
1285  s = "<empty histogram: no bins>";
1286  } else {
1287  s = tomo_internal::histogram_short_bar_fmt<HistogramType>(histogram, log_scale, max_width);
1288  }
1289 
1290  str << s;
1291  return max_width - (int)s.size();
1292 }
1303 template<typename HistogramType>
1304 inline std::string histogramShortBar(const HistogramType & histogram, bool log_scale = true, int max_width = 0)
1305 {
1306  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1307 
1308  if (histogram.params.num_bins == 0) {
1309  return "<empty histogram: no bins>";
1310  }
1311 
1312  max_width = Tools::getWidthForTerminalOutput(max_width);
1313  return tomo_internal::histogram_short_bar_fmt<HistogramType>(histogram, log_scale, max_width);
1314 }
1315 
1316 
1331 template<typename HistogramType>
1333  std::string head,
1334  const HistogramType& hist,
1335  std::string tail,
1336  bool log_scale = true,
1337  int full_max_width = 0)
1338 {
1339  full_max_width = Tools::getWidthForTerminalOutput(full_max_width);
1340 
1341  str << head;
1342  const int w = histogramShortBar(str, hist, log_scale, full_max_width - (int)head.size() - (int)tail.size());
1343  str << std::setw(w + (int)tail.size()) << std::right << tail << "\n";
1344 }
1345 
1360 template<typename HistogramType>
1362  const HistogramType& hist,
1363  std::string tail,
1364  bool log_scale = true,
1365  int full_max_width = 0)
1366 {
1367  std::ostringstream ss;
1368  histogramShortBarWithInfo(ss, head, hist, tail, log_scale, full_max_width);
1369  return ss.str();
1370 }
1371 
1372 
1373 
1374 
1375 
1376 
1377 
1378 } // namespace Tomographer
1379 
1380 
1381 
1382 
1383 #endif
Utilities for formatting strings.
Eigen::Array< CountType, Eigen::Dynamic, 1 > bins
The counts for each bin.
Definition: histogram.h:236
CountType_ CountType
The Type used to keep track of counts. See UniformBinsHistogram::CountType.
Definition: histogram.h:485
Scalar binLowerValue(std::size_t index) const
Returns the value which a given bin index represents (lower bin value limit)
Definition: histogram.h:138
UniformBinsHistogramWithErrorBars(Params params=Params())
Constructor, with given histogram parameters.
Definition: histogram.h:511
UniformBinsHistogramParams(const Params2 &other)
Copy constructor, from any other UniformBinsHistogram::Params type.
Definition: histogram.h:83
Base_::Params Params
Shortcut for our base class&#39; histogram parameters. See UniformBinsHistogram::Params.
Definition: histogram.h:492
Base namespace for the Tomographer project.
Definition: densellh.h:45
void histogramShortBarWithInfo(std::ostream &str, std::string head, const HistogramType &hist, std::string tail, bool log_scale=true, int full_max_width=0)
Format the histogram as a one-line bar, with some surrounding info.
Definition: histogram.h:1332
Stores a histogram along with error bars.
Definition: histogram.h:477
T ceil(T... args)
CountType_ CountType
The type that serves to count how many hits in each bin.
Definition: histogram.h:225
Scalar min
Lower range value.
Definition: histogram.h:89
T log(T... args)
T to_string(T... args)
T right(T... args)
Base_::Scalar Scalar
The histogram&#39;s X-axis scalar type. See UniformBinsHistogramWithErrorBars::Scalar.
Definition: histogram.h:674
std::size_t record(Scalar value, CountType weight)
Record a new value in the histogram, with a certain weight.
Definition: histogram.h:407
Scalar binUpperValue(std::size_t index) const
Shorthand for Params::binUpperValue()
Definition: histogram.h:365
UniformBinsHistogram< Scalar_, CountType_ > Base_
Shortcut for our base class type.
Definition: histogram.h:488
CountType errorBar(std::size_t i) const
For the Histogram Interface. Get error bar for bin number i.
Definition: histogram.h:543
Base_::Params Params
The histogram parameters&#39; type. See UniformBinsHistogramWithErrorBars::Params.
Definition: histogram.h:672
void add(const UniformBinsHistogram< OtherScalar, OtherCountType > &x)
Add data to the histogram.
Definition: histogram.h:322
UniformBinsHistogramParams(Scalar min_=0.0, Scalar max_=1.0, std::size_t num_bins_=50)
The obvious constructor.
Definition: histogram.h:74
T floor(T... args)
std::size_t binIndex(Scalar value) const
Returns which bin this value should be counted in (index in the histogram&#39;s bins array) ...
Definition: histogram.h:110
std::size_t record(Scalar value)
Record a new value in the histogram.
Definition: histogram.h:385
std::size_t binIndexUnsafe(Scalar value) const
Returns which bin this value should be counted in.
Definition: histogram.h:126
T log10(T... args)
Params params
Parameters of this histogram (range and # of bins)
Definition: histogram.h:234
std::size_t numBins() const
Shorthand for params.num_bins
Definition: histogram.h:333
int num_histograms
The number of histograms averaged.
Definition: histogram.h:686
SegmentReturnType segment(Index start, Index n)
void reset()
Resets the data keeping the exisiting params.
Definition: histogram.h:729
T setw(T... args)
T resize(T... args)
Scalar binResolution() const
Shorthand for Params::binResolution()
Definition: histogram.h:371
STL class.
T min(T... args)
void reset()
Resets the histogram to zero counts everywhere, and zero error bars.
Definition: histogram.h:532
AveragedHistogram(const Params &params=Params())
Constructs an AveragedHistogram with the given histogram parameters.
Definition: histogram.h:695
std::size_t num_bins
Number of bins to split the range into.
Definition: histogram.h:93
Combines several histograms (with same parameters) into an averaged histogram.
Definition: histogram.h:658
void histogramPrettyPrint(std::ostream &str, const HistogramType &histogram, int max_width=0)
pretty-print the given histogram.
Definition: histogram.h:1229
void add(const Eigen::ArrayBase< EigenType > &x, CountType off_chart_=0)
Add data to the histogram.
Definition: histogram.h:302
Eigen::Array< CountType, Eigen::Dynamic, 1 > delta
The error bars associated with each histogram bin.
Definition: histogram.h:498
Basic utilities for dealing with Eigen matrices and other types.
bool isWithinBounds(Scalar value) const
Tests whether the given value is in the range of the histogram.
Definition: histogram.h:100
UniformBinsHistogramWithErrorBars(Scalar min, Scalar max, std::size_t num_bins)
Constructor, with given histogram parameters.
Definition: histogram.h:521
UniformBinsHistogramWithErrorBars< typename HistogramType_::Scalar, RealAvgType > Base_
Shortcut for our base class&#39; type.
Definition: histogram.h:669
Scalar binUpperValue(std::size_t index) const
Returns the value which a given bin index represents (upper bin value limit)
Definition: histogram.h:163
Eigen::Array< Scalar, Eigen::Dynamic, 1 > valuesLower() const
Return an array of values corresponding to the lower value of each bin.
Definition: histogram.h:187
std::enable_if< std::is_unsigned< X >::value, bool >::type isPositive(const X)
Test whether the given value is positive or zero.
Definition: cxxutil.h:321
Base_::CountType CountType
The histogram&#39; count type. This is exactly the same as RealAvgType.
Definition: histogram.h:676
void load(const Eigen::DenseBase< EigenType > &d, const Eigen::DenseBase< EigenType2 > &derr, CountType off_chart_=0)
Load data for the histogram. Uses current histogram parameters, just sets the bin counts and the erro...
Definition: histogram.h:562
bool isWithinBounds(Scalar value) const
Shorthand for Params::isWithinBounds()
Definition: histogram.h:345
T str(T... args)
T isfinite(T... args)
UniformBinsHistogram(Scalar min_, Scalar max_, std::size_t num_bins)
Constructor: stores the parameters and initializes the histogram to zero counts everywhere.
Definition: histogram.h:252
UniformBinsHistogram(const HistogramType &other)
Constructor: copy another histogram type.
Definition: histogram.h:261
Some C++ utilities, with a tad of C++11 tricks.
NewCountType normalization() const
Calculate the total weight stored in this histogram.
Definition: histogram.h:435
T fabs(T... args)
T max(T... args)
Scalar binLowerValue(int index) const
Shorthand for Params::binLowerValue()
Definition: histogram.h:355
Scalar_ Scalar
The scalar type used to specify the "value" (horizongal axis) of the histogram.
Definition: histogram.h:71
void reset(const Params &params_)
Resets the data and sets new params.
Definition: histogram.h:716
T fixed(T... args)
AveragedHistogram(Scalar min, Scalar max, std::size_t num_bins)
Constructs an AveragedHistogram with the given histogram parameters.
Definition: histogram.h:705
Scalar max
Upper range value.
Definition: histogram.h:91
Managing the need for specific overrides to operator new() for some types (especially Eigen types) ...
T size(T... args)
std::string fmts(const char *fmt,...)
printf- format to a std::string
Definition: fmt.h:125
STL class.
Eigen::Array< Scalar, Eigen::Dynamic, 1 > valuesCenter() const
Return an array of values corresponding to the center of each bin.
Definition: histogram.h:179
UniformBinsHistogram< Scalar, NewCountType > normalized() const
Get a normalized version of this histogram.
Definition: histogram.h:449
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:878
Scalar_ Scalar
The Scalar (X-axis) Type. See UniformBinsHistogram::Scalar.
Definition: histogram.h:483
UniformBinsHistogramParams< Scalar_ > Params
The type for specifying parameters of this histogram (limits, number of bins)
Definition: histogram.h:231
Scalar_ Scalar
The scalar type of the "X"-axis of the histogram (usually double)
Definition: histogram.h:222
int getWidthForTerminalOutput(int max_width=0)
Return a suitable width for displaying stuff on the standard output.
Definition: cxxutil.h:434
HistogramType_ HistogramType
Type of the individual histograms we are averaging.
Definition: histogram.h:667
The parameters of a UniformBinsHistogram.
Definition: histogram.h:68
Eigen::Array< Scalar, Eigen::Dynamic, 1 > valuesUpper() const
Return an array of values corresponding to the upper value of each bin.
Definition: histogram.h:194
void load(const Eigen::DenseBase< EigenType > &x, CountType off_chart_=0)
Load data for the histogram. Uses current histogram parameters, just sets the bin counts...
Definition: histogram.h:285
void resize(Index nbRows, Index nbCols)
#define streamstr(tokens)
Utility macro to format stream tokens to a std::string.
Definition: fmt.h:146
int histogramShortBar(std::ostream &str, const HistogramType &histogram, bool log_scale=true, int max_width=0)
Format the histogram as a one-line bar.
Definition: histogram.h:1276
CountType off_chart
The number of points that fell outside of the given range.
Definition: histogram.h:238
Stores a histogram.
Definition: histogram.h:211
CountType count(std::size_t i) const
Shorthand for bins(i)
Definition: histogram.h:339
T setprecision(T... args)
std::string prettyPrint(int max_width=0) const
Pretty-print the histogram and return it as a string with horizontal bars.
Definition: histogram.h:461
Scalar binCenterValue(std::size_t index) const
Returns the value which a given bin index represents (center bin value)
Definition: histogram.h:150
STL class.
#define tomographer_assert(...)
Assertion test macro.
Definition: cxxdefs.h:83
void reset()
Resets the histogram to zero counts everywhere (including the off-chart counts)
Definition: histogram.h:268
Scalar binCenterValue(std::size_t index) const
Shorthand for Params::binCenterValue()
Definition: histogram.h:360
std::string prettyPrint(int max_width=0) const
Print the histogram in human readable form.
Definition: histogram.h:609
UniformBinsHistogramWithErrorBars< Scalar, NewCountType > normalized() const
Get a normalized version of this histogram.
Definition: histogram.h:580
Scalar binResolution() const
Returns the width of a bin.
Definition: histogram.h:172
std::size_t binIndex(Scalar value) const
Shorthand for Params::binIndex()
Definition: histogram.h:350
Derived & setZero(Index size)