Tomographer  v3.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>
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>
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>:
216 {
217 public:
219  typedef Scalar_ Scalar;
220 
222  typedef CountType_ CountType;
223 
225  static constexpr bool HasErrorBars = false;
226 
229 
231  Params params;
235  CountType off_chart;
236 
238  template<typename Params2 = Params,
239  // enforce Params-like type by checking that properties 'min','max','num_bins' exist:
240  decltype((int)std::declval<const Params2>().min + (int)std::declval<const Params2>().max
241  + std::declval<Params2>().num_bins) dummyval = 0>
242  UniformBinsHistogram(Params2 p = Params())
243  : params(p), bins(Eigen::Array<CountType,Eigen::Dynamic,1>::Zero(p.num_bins)),
244  off_chart(0)
245  {
246  }
247 
249  UniformBinsHistogram(Scalar min_, Scalar max_, std::size_t num_bins)
250  : params(min_, max_, num_bins), bins(Eigen::Array<CountType,Eigen::Dynamic,1>::Zero(num_bins)),
251  off_chart(0)
252  {
253  }
254 
256  template<typename HistogramType,// and enforce it's indeed a histogram type by testing its 'HasErrorBars' property:
257  TOMOGRAPHER_ENABLED_IF_TMPL(HistogramType::HasErrorBars == 0 || HistogramType::HasErrorBars == 1)>
258  UniformBinsHistogram(const HistogramType & other)
259  : params(other.params), bins(other.params.num_bins), off_chart(other.off_chart)
260  {
261  bins = other.bins.template cast<CountType>();
262  }
263 
265  inline void reset()
266  {
267  bins.resize(params.num_bins);
268  bins.setZero();
269  off_chart = 0;
270  }
271 
281  template<typename EigenType>
282  inline void load(const Eigen::DenseBase<EigenType> & x, CountType off_chart_ = 0)
283  {
284  tomographer_assert(x.cols() == 1);
285  tomographer_assert((std::size_t)x.rows() == params.num_bins);
286  bins = x.derived().template cast<CountType>();
287  off_chart = off_chart_;
288  }
289 
298  template<typename EigenType>
299  inline void add(const Eigen::ArrayBase<EigenType> & x, CountType off_chart_ = 0)
300  {
301  // the argument must be of ArrayBase type (as opposed to load() where we can
302  // also accept MatrixBase types) because Eigen doesn't allow operator+=
303  // between Arrays and Matrices, but has an operator= .
304  tomographer_assert(x.cols() == 1);
305  tomographer_assert((std::size_t)x.rows() == params.num_bins);
306  bins += x.derived().template cast<CountType>();
307  off_chart += off_chart_;
308  }
309 
318  template<typename OtherScalar, typename OtherCountType>
320  {
321  tomographer_assert(x.bins.cols() == 1);
322  tomographer_assert((std::size_t)x.bins.rows() == params.num_bins);
323  tomographer_assert(std::fabs(x.params.min - params.min) < 1e-8);
324  tomographer_assert(std::fabs(x.params.max - params.max) < 1e-8);
325  bins += x.bins.template cast<CountType>();
326  off_chart += x.off_chart;
327  }
328 
330  inline std::size_t numBins() const
331  {
332  return params.num_bins;
333  }
334 
336  inline CountType count(std::size_t i) const
337  {
338  return bins(i);
339  }
340 
342  inline bool isWithinBounds(Scalar value) const
343  {
344  return params.isWithinBounds(value);
345  }
347  inline std::size_t binIndex(Scalar value) const
348  {
349  return params.binIndex(value);
350  }
352  inline Scalar binLowerValue(int index) const
353  {
354  return params.binLowerValue(index);
355  }
357  inline Scalar binCenterValue(std::size_t index) const
358  {
359  return params.binCenterValue(index);
360  }
362  inline Scalar binUpperValue(std::size_t index) const
363  {
364  return params.binUpperValue(index);
365  }
366 
368  inline Scalar binResolution() const
369  {
370  return params.binResolution();
371  }
372 
382  inline std::size_t record(Scalar value)
383  {
384  if ( !isWithinBounds(value) ) {
385  ++off_chart;
387  }
388  // calling bin_index_unsafe because we have already checked that value is in range.
389  const std::size_t index = params.binIndexUnsafe(value);
390  ++bins( index );
391  return index;
392  }
393 
404  inline std::size_t record(Scalar value, CountType weight)
405  {
406  if ( !isWithinBounds(value) ) {
407  off_chart += weight;
409  }
410  // calling bin_index_unsafe is safe here because we have already checked that value is
411  // in range.
412  const std::size_t index = params.binIndexUnsafe(value);
413  bins(index) += weight;
414  return index;
415  }
416 
417 
431  template<typename NewCountType = decltype(Scalar(1) + CountType(1))>
432  inline NewCountType normalization() const
433  {
434  // DON'T DO NewCountType(binResolution())*NewCountType(bins.sum()) as we may loose
435  // precision (if NewCountType=int, for example)
436  return NewCountType(off_chart) + NewCountType(binResolution() * bins.sum());
437  }
438 
445  template<typename NewCountType = Scalar>
447  {
449  const NewCountType f = normalization<NewCountType>();
450  h.load(bins.template cast<NewCountType>() / f, NewCountType(off_chart) / f);
451  return h;
452  }
453 
458  inline std::string prettyPrint(int max_width = 0) const
459  {
460  return histogramPrettyPrint(*this, max_width);
461  }
462 
463 };
464 
465 
466 
467 
473 template<typename Scalar_, typename CountType_ = double>
475  : public UniformBinsHistogram<Scalar_, CountType_>,
477 {
478 public:
480  typedef Scalar_ Scalar;
482  typedef CountType_ CountType;
483 
489  typedef typename Base_::Params Params;
490 
492  static constexpr bool HasErrorBars = true;
493 
496 
497  // make these accessible without having to use the "Base_::member" syntax all the time
498  using Base_::params;
499  using Base_::bins;
500  using Base_::off_chart;
501 
502 
508  UniformBinsHistogramWithErrorBars(Params params = Params())
509  : Base_(params), delta(Eigen::Array<CountType, Eigen::Dynamic, 1>::Zero(params.num_bins))
510  {
511  }
512 
519  : Base_(min, max, num_bins), delta(Eigen::Array<CountType, Eigen::Dynamic, 1>::Zero(num_bins))
520  {
521  }
522 
529  inline void reset()
530  {
531  Base_::reset();
532  delta.resize(Base_::numBins());
533  delta.setZero();
534  }
535 
540  inline CountType errorBar(std::size_t i) const
541  {
542  return delta(i);
543  }
544 
545 
558  template<typename EigenType, typename EigenType2 = EigenType>
559  inline void load(const Eigen::DenseBase<EigenType> & d,
560  const Eigen::DenseBase<EigenType2> & derr,
561  CountType off_chart_ = 0)
562  {
563  Base_::load(d, off_chart_);
564  tomographer_assert(derr.cols() == 1);
565  tomographer_assert((std::size_t)derr.rows() == params.num_bins);
566  delta = derr.derived().template cast<CountType>();
567  }
568 
569 
576  template<typename NewCountType = Scalar>
578  {
580  const NewCountType f = Base_::template normalization<NewCountType>();
581  h.load(bins.template cast<NewCountType>() / f,
582  delta.template cast<NewCountType>() / f,
583  NewCountType(off_chart) / f);
584  return h;
585  }
586 
587 
588 private:
592  template<typename... Args>
593  inline void add(Args && ... )
594  {
595  }
596 public:
597 
598 
606  std::string prettyPrint(int max_width = 0) const
607  {
608  return histogramPrettyPrint(*this, max_width);
609  }
610 
611 };
612 // static members:
613 template<typename Scalar_, typename CountType_>
615 
616 
617 
618 
619 
620 
654 template<typename HistogramType_, typename RealAvgType = double>
656  : public UniformBinsHistogramWithErrorBars<typename HistogramType_::Scalar, RealAvgType>
657 {
658 public:
664  typedef HistogramType_ HistogramType;
667 
669  typedef typename Base_::Params Params;
671  typedef typename Base_::Scalar Scalar;
673  typedef typename Base_::CountType CountType;
674 
676  static constexpr bool HasErrorBars = true;
677 
684 
685 
692  AveragedHistogram(const Params& params = Params())
693  : Base_(params), num_histograms(0)
694  {
695  }
696 
703  : Base_(min, max, num_bins), num_histograms(0)
704  {
705  }
706 
713  inline void reset(const Params& params_)
714  {
715  Base_::params = params_;
716  Base_::reset();
717  num_histograms = 0;
718  }
719 
726  inline void reset()
727  {
728  Base_::reset();
729  num_histograms = 0;
730  }
731 
732  // ---------------------------------------------------------------------------
733  // Implementation in case the added histograms don't have their own error bars
734  // ---------------------------------------------------------------------------
735 
750  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
751  inline void addHistogram(const HistogramType& histogram)
752  {
753  // bins collects the sum of the histograms
754  // delta for now collects the sum of squares. delta will be normalized in finalize().
755 
756  tomographer_assert((typename HistogramType::CountType)histogram.numBins() ==
757  (typename HistogramType::CountType)Base_::numBins());
758 
759  for (std::size_t k = 0; k < histogram.numBins(); ++k) {
760  RealAvgType binvalue = histogram.count(k);
761  Base_::bins(k) += binvalue;
762  Base_::delta(k) += binvalue * binvalue;
763  }
764 
765  Base_::off_chart += histogram.off_chart;
766  ++num_histograms;
767  }
782  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
783  inline void finalize()
784  {
785  Base_::bins /= num_histograms;
786  Base_::delta /= num_histograms;
787  Base_::off_chart /= num_histograms;
788 
789  // delta = sqrt(< X^2 > - < X >^2) / sqrt(Nrepeats-1)
790  auto finhist2 = Base_::bins*Base_::bins; // for array, this is c-wise product
791  Base_::delta = ( (Base_::delta - finhist2) / (num_histograms-1) ).sqrt();
792  }
793 
794  // ---------------------------------------------------------------------------
795  // Implementation in case the added histograms do have their own error bars
796  // ---------------------------------------------------------------------------
797 
812  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
813  inline void addHistogram(const HistogramType& histogram)
814  {
815  // bins collects the sum of the histograms
816  // delta for now collects the sum of squares. delta will be normalized in finished().
817 
818  tomographer_assert((typename HistogramType::CountType)histogram.numBins() == Base_::numBins());
819 
820  for (std::size_t k = 0; k < histogram.numBins(); ++k) {
821  RealAvgType binvalue = histogram.count(k);
822  Base_::bins(k) += binvalue;
823  RealAvgType bindelta = histogram.errorBar(k);
824  Base_::delta(k) += bindelta*bindelta;
825  }
826 
827  Base_::off_chart += histogram.off_chart;
828  ++num_histograms;
829  }
844  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
845  inline void finalize()
846  {
847  Base_::bins /= num_histograms;
848  Base_::off_chart /= num_histograms;
849 
850  Base_::delta = Base_::delta.sqrt();
851  Base_::delta /= num_histograms;
852  }
853 
854 };
855 
856 
857 
858 
859 
860 
861 
862 // -----------------------------------------------------------------------------
863 // Pretty Print Histogram Utilities
864 // -----------------------------------------------------------------------------
865 
866 
867 
868 namespace tomo_internal {
869 // internal helpers
870 //
871 // find maximum value in the list only among those values which are finite (not inf or nan)
872 //
873 template<typename Scalar, typename Fn>
874 inline Scalar max_finite_value(const std::size_t num_items, Fn val_generator,
875  const Scalar default_val = Scalar(1.0))
876 {
877  bool has_first_val = false;
878  Scalar max_val = default_val;
879  for (std::size_t k = 0; k < num_items; ++k) {
880  const Scalar this_val = val_generator(k);
881  if (std::isfinite(this_val) && (!has_first_val || this_val > max_val)) {
882  max_val = this_val;
883  has_first_val = true;
884  }
885  }
886  return max_val;
887 }
888 
889 //
890 // get labels left of histogram (generic HistogramType interface: no information, just bin #)
891 //
892 template<typename HistogramType>
893 struct histogram_pretty_print_label
894 {
895  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
896  {
897  labels.resize(hist.numBins());
898  for (std::size_t k = 0; k < hist.numBins(); ++k) {
899  labels[k] = std::to_string(k);
900  }
901  }
902 };
903 // get labels left of histogram (for the family of histograms with 'Params':
904 // UniformBinsHistogram, UniformBinsHistogramWithErrorBars etc.)
905 //
906 // common code for several specializations of histogram_pretty_print_label
907 template<typename HistogramType>
908 inline void histogram_get_labels_for_hist_params(std::vector<std::string> & labels, const HistogramType& hist)
909 {
910  labels.resize(hist.numBins());
911 
912  const double max_label_val = std::max(hist.binCenterValue(0), hist.binCenterValue(hist.numBins()-1));
913  const int powten = (int)std::floor(std::log10(max_label_val));
914  const int relprecision = 4;
915  const int precision = (powten > relprecision) ? 0 : (relprecision - powten - 1);
916 
917  for (std::size_t k = 0; k < hist.numBins(); ++k) {
919  ss << std::fixed << std::setprecision(precision) << std::right << hist.binCenterValue(k);
920  labels[k] = ss.str();
921  }
922 }
923 // specialize histogram pretty-print labels using the code above
924 template<typename Scalar_, typename CountType_>
925 struct histogram_pretty_print_label<UniformBinsHistogram<Scalar_, CountType_> >
926 {
928  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
929  {
930  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
931  }
932 };
933 // specialize histogram pretty-print labels using the code above
934 template<typename Scalar_, typename CountType_>
935 struct histogram_pretty_print_label<UniformBinsHistogramWithErrorBars<Scalar_, CountType_> >
936 {
938  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
939  {
940  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
941  }
942 };
943 // specialize histogram pretty-print labels using the code above
944 template<typename BaseHistogramType_, typename RealAvgType_>
945 struct histogram_pretty_print_label<AveragedHistogram<BaseHistogramType_, RealAvgType_> >
946 {
948  static inline void getLabels(std::vector<std::string> & labels, const HistogramType & hist)
949  {
950  histogram_get_labels_for_hist_params<HistogramType>(labels, hist);
951  }
952 };
953 
954 // format bin counts nicely
955 template<typename HistogramType>
956 struct histogram_pretty_print_value
957 {
958  const HistogramType & hist;
959  histogram_pretty_print_value(const HistogramType & hist_) : hist(hist_) { }
960 
961  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
962  static inline void getStrValues(std::vector<std::string> & svalues, const HistogramType & hist)
963  {
964  svalues.resize(hist.numBins());
965 
966  double max_val = max_finite_value(hist.numBins(), [&](std::size_t k) { return hist.count(k); }, 1.0);
967 
968  const int powten = (int)std::floor(std::log10(max_val));
969  const int relprecision = 3;
970  const int precision = abs_precision_for(powten, relprecision);
971  const int w = (precision > 0) ? (precision+powten+1) : (relprecision+2);
972 
973  for (std::size_t k = 0; k < hist.numBins(); ++k) {
975  ss << std::setprecision(precision) << std::fixed << std::right << std::setw(w)
976  << hist.count(k);
977  svalues[k] = ss.str();
978  }
979  }
980 
981  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
982  static inline void getStrValues(std::vector<std::string> & svalues, const HistogramType & hist)
983  {
984  svalues.resize(hist.numBins());
985 
986  double max_val = max_finite_value(hist.numBins(), [&](std::size_t k) { return hist.count(k); }, 1.0);
987 
988  const int powten = (int)std::floor(std::log10(max_val)); // floor of log_{10}(...)
989  const int relprecision = 3;
990  const int precision = abs_precision_for(powten, relprecision);
991  const int w = (precision > 0) ? (precision+powten+2) : (relprecision+2);
992 
993  for (std::size_t k = 0; k < hist.numBins(); ++k) {
995  ss << std::setprecision(precision) << std::fixed << std::right << std::setw(w)
996  << hist.count(k) << " +- "
997  << std::setprecision(abs_precision_for(powten-1, relprecision-1)) << std::setw(w)
998  << hist.errorBar(k);
999  svalues[k] = ss.str();
1000  }
1001  }
1002 private:
1003  static inline int abs_precision_for(const int powten, const int relprecision)
1004  {
1005  return (powten >= relprecision) ? 0 : (relprecision - powten - 1);
1006  }
1007 };
1008 
1010 //
1011 // access this with public API using histogram_pretty_print().
1012 //
1013 template<typename HistogramType>
1014 struct histogram_pretty_printer
1015 {
1016  const HistogramType & hist;
1017  const int max_width;
1018 
1019  const std::string lsep;
1020  const std::string rsep;
1021 
1022  std::vector<std::string> labels;
1023  int maxlabelwidth;
1024 
1025  std::vector<std::string> svalues;
1026  int maxsvaluewidth;
1027 
1028  double max_value;
1029 
1030  int max_bar_width;
1031  double barscale;
1032 
1033  histogram_pretty_printer(const HistogramType & hist_, const int max_width_)
1034  : hist(hist_), max_width(max_width_), lsep(" |"), rsep(" ")
1035  {
1036  // first pass:
1037  // - determine the maximum value attained in the histogram
1038  // - determine maximum width of formatted label & value fields.
1039 
1040  labels.resize(hist.numBins());
1041  svalues.resize(hist.numBins());
1042 
1043  histogram_pretty_print_label<HistogramType>::getLabels(labels, hist);
1044  histogram_pretty_print_value<HistogramType>::getStrValues(svalues, hist);
1045 
1046  bool has_maxval = false;
1047  for (std::size_t k = 0; k < hist.numBins(); ++k) {
1048  const double val = maxval(k);
1049 
1050  if (std::isfinite(val) && (!has_maxval || val > max_value)) {
1051  max_value = val;
1052  has_maxval = true;
1053  }
1054  if (k == 0 || (int)labels[k].size() > maxlabelwidth) {
1055  maxlabelwidth = labels[k].size();
1056  }
1057  if (k == 0 || (int)svalues[k].size() > maxsvaluewidth) {
1058  maxsvaluewidth = svalues[k].size();
1059  }
1060  }
1061  if (!has_maxval) {
1062  max_value = 1.0;
1063  }
1064 
1065  max_bar_width = max_width - maxlabelwidth - maxsvaluewidth - lsep.size() - rsep.size();
1066  if (max_bar_width < 2) {
1067  max_bar_width = 2;
1068  }
1069  barscale = ((max_value > 0) ? (max_value / max_bar_width) : 1.0);
1070  }
1071 
1072  inline int value_to_bar_length(double val) const
1073  {
1074  if (val < 0 || !std::isfinite(val)) {
1075  val = 0;
1076  }
1077  int l = (int)(val/barscale+0.5);
1078  if (l >= max_bar_width) {
1079  return max_bar_width-1;
1080  }
1081  return l;
1082  }
1083 
1084  inline void fill_str_len(std::string & s, double valstart, double valend,
1085  char c, char clside, char crside) const
1086  {
1087  int vs = value_to_bar_length(valstart);
1088  int ve = value_to_bar_length(valend);
1089  tomographer_assert(vs >= 0);
1090  tomographer_assert(vs < (int)s.size());
1091  tomographer_assert(ve >= 0);
1092  tomographer_assert(ve < (int)s.size());
1093  for (int j = vs; j < ve; ++j) {
1094  s[j] = c;
1095  }
1096  if (clside && crside && clside != crside && vs == ve) {
1097  if (ve < (int)s.size()-1) {
1098  ++ve;
1099  } else if (vs > 1) {
1100  --vs;
1101  }
1102  }
1103  if (clside) {
1104  s[vs] = clside;
1105  }
1106  if (crside) {
1107  s[ve] = crside;
1108  }
1109  }
1110 
1111  inline void pretty_print(std::ostream & str) const
1112  {
1113  // perform now second pass:
1114  // - display the histogram line by line, with the calculated widths.
1115 
1116  std::size_t k;
1117 
1118  for (k = 0; k < hist.numBins(); ++k) {
1119  str << std::setw(maxlabelwidth) << labels[k] << lsep
1120  << make_bar(k) << rsep << std::setw(maxsvaluewidth) << svalues[k] << "\n";
1121  }
1122  }
1123 
1124 private:
1125  // maxval(k): how much this bar may extend in length
1126  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
1127  inline double maxval(const std::size_t k) const
1128  {
1129  return (double)hist.count(k);
1130  }
1131  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
1132  inline double maxval(const std::size_t k) const
1133  {
1134  return (double)(hist.count(k) + hist.errorBar(k));
1135  }
1136  // make_bar(k): produce the histogram bar in characters...
1137  TOMOGRAPHER_ENABLED_IF(!HistogramType::HasErrorBars)
1138  inline std::string make_bar(std::size_t k) const
1139  {
1140  std::string sbar(max_bar_width, ' ');
1141  fill_str_len(sbar, 0.0, hist.count(k), '*', 0, 0);
1142  return sbar;
1143  }
1144  TOMOGRAPHER_ENABLED_IF(HistogramType::HasErrorBars)
1145  inline std::string make_bar(std::size_t k) const
1146  {
1147  std::string sbar(max_bar_width, ' ');
1148  const double binval = hist.count(k);
1149  const double binerr = hist.errorBar(k);
1150  fill_str_len(sbar, 0.0, binval - binerr, '*', '*', '*');
1151  fill_str_len(sbar, binval - binerr, binval + binerr, '-', '|', '|');
1152  return sbar;
1153  }
1154 };
1155 
1156 template<typename HistogramType>
1157 inline std::string histogram_short_bar_fmt(const HistogramType & histogram, const bool log_scale,
1158  const int max_width)
1159 {
1160  std::string s = Tools::fmts("%.2g|", (double)histogram.binLowerValue(0));
1161  std::string send = Tools::fmts("|%.2g", (double)histogram.binUpperValue(histogram.numBins()-1));
1162  if (histogram.off_chart > 0) {
1163  send += Tools::fmts(" [+%.1g off]", (double)histogram.off_chart);
1164  }
1165 
1166  const int maxbarwidth = max_width - (int)s.size() - (int)send.size();
1167  const int numdiv = (int)(std::ceil((float)histogram.numBins() / maxbarwidth) + 0.5f);
1168  const int barwidth = (int)(std::ceil((float)histogram.numBins() / numdiv) + 0.5f);
1169 
1171  Eigen::ArrayXf veclog(barwidth);
1172 
1173  int k;
1174  float minlogval = 0;
1175  float maxlogval = 0;
1176  for (k = 0; k < barwidth; ++k) {
1177  vec(k) = histogram.bins.segment(numdiv*k, std::min((std::size_t)numdiv,
1178  (std::size_t)(histogram.bins.size()-numdiv*k))).sum();
1179  if (vec(k) > 0) {
1180  if (log_scale) {
1181  veclog(k) = std::log((float)vec(k));
1182  } else {
1183  veclog(k) = (float)vec(k);
1184  }
1185  if (k == 0 || minlogval > veclog(k)) {
1186  minlogval = veclog(k);
1187  }
1188  if (k == 0 || maxlogval < veclog(k)) {
1189  maxlogval = veclog(k) + 1e-6f;
1190  }
1191  } else {
1192  veclog(k) = 0.f;
1193  }
1194  }
1195 
1196  // now, prepare string
1197  const std::string chars = ".-+ox%#";
1198  for (k = 0; k < barwidth; ++k) {
1199  if (vec(k) <= 0) {
1200  s += ' ';
1201  } else {
1202  int i = (int)(chars.size() * (veclog(k) - minlogval) / (maxlogval - minlogval));
1203  if (i < 0) { i = 0; }
1204  if (i >= (int)chars.size()) { i = (int)chars.size()-1; }
1205  s += chars[i];
1206  }
1207  }
1208 
1209  s += send;
1210 
1211  return s;
1212 }
1213 
1214 } // namespace tomo_internal
1215 
1216 
1225 template<typename HistogramType>
1226 inline void histogramPrettyPrint(std::ostream & str, const HistogramType & histogram, int max_width = 0)
1227 {
1228  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1229 
1230  if (histogram.params.num_bins == 0) {
1231  str << "<empty histogram: no bins>\n";
1232  return;
1233  }
1234 
1235  max_width = Tools::getWidthForTerminalOutput(max_width);
1236  tomo_internal::histogram_pretty_printer<HistogramType>(histogram, max_width).pretty_print(str);
1237 }
1238 
1247 template<typename HistogramType>
1248 inline std::string histogramPrettyPrint(const HistogramType & histogram, int max_width = 0)
1249 {
1250  std::ostringstream ss;
1251  histogramPrettyPrint<HistogramType>(ss, histogram, max_width);
1252  return ss.str();
1253 }
1254 
1272 template<typename HistogramType>
1273 inline int histogramShortBar(std::ostream & str, const HistogramType & histogram,
1274  bool log_scale = true, int max_width = 0)
1275 {
1276  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1277 
1278  max_width = Tools::getWidthForTerminalOutput(max_width);
1279 
1280  std::string s;
1281  if (histogram.params.num_bins == 0) {
1282  s = "<empty histogram: no bins>";
1283  } else {
1284  s = tomo_internal::histogram_short_bar_fmt<HistogramType>(histogram, log_scale, max_width);
1285  }
1286 
1287  str << s;
1288  return max_width - (int)s.size();
1289 }
1300 template<typename HistogramType>
1301 inline std::string histogramShortBar(const HistogramType & histogram, bool log_scale = true, int max_width = 0)
1302 {
1303  tomographer_assert(Tools::isPositive(histogram.params.num_bins));
1304 
1305  if (histogram.params.num_bins == 0) {
1306  return "<empty histogram: no bins>";
1307  }
1308 
1309  max_width = Tools::getWidthForTerminalOutput(max_width);
1310  return tomo_internal::histogram_short_bar_fmt<HistogramType>(histogram, log_scale, max_width);
1311 }
1312 
1313 
1328 template<typename HistogramType>
1330  std::string head,
1331  const HistogramType& hist,
1332  std::string tail,
1333  bool log_scale = true,
1334  int full_max_width = 0)
1335 {
1336  full_max_width = Tools::getWidthForTerminalOutput(full_max_width);
1337 
1338  str << head;
1339  int w = histogramShortBar(str, hist, log_scale, full_max_width - head.size() - tail.size());
1340  str << std::setw(w + (int)tail.size()) << std::right << tail << "\n";
1341 }
1342 
1357 template<typename HistogramType>
1359  const HistogramType& hist,
1360  std::string tail,
1361  bool log_scale = true,
1362  int full_max_width = 0)
1363 {
1364  std::ostringstream ss;
1365  histogramShortBarWithInfo(ss, head, hist, tail, log_scale, full_max_width);
1366  return ss.str();
1367 }
1368 
1369 
1370 
1371 
1372 
1373 
1374 
1375 } // namespace Tomographer
1376 
1377 
1378 
1379 
1380 #endif
Utilities for formatting strings.
Eigen::Array< CountType, Eigen::Dynamic, 1 > bins
The counts for each bin.
Definition: histogram.h:233
CountType_ CountType
The Type used to keep track of counts. See UniformBinsHistogram::CountType.
Definition: histogram.h:482
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:508
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:489
Provides correct operator-new implementation for Eigen types via the NeedOwnOperatorNew mechanism...
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:1329
Stores a histogram along with error bars.
Definition: histogram.h:474
T ceil(T... args)
CountType_ CountType
The type that serves to count how many hits in each bin.
Definition: histogram.h:222
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:671
std::size_t record(Scalar value, CountType weight)
Record a new value in the histogram, with a certain weight.
Definition: histogram.h:404
Scalar binUpperValue(std::size_t index) const
Shorthand for Params::binUpperValue()
Definition: histogram.h:362
UniformBinsHistogram< Scalar_, CountType_ > Base_
Shortcut for our base class type.
Definition: histogram.h:485
CountType errorBar(std::size_t i) const
For the Histogram Interface. Get error bar for bin number i.
Definition: histogram.h:540
Base_::Params Params
The histogram parameters&#39; type. See UniformBinsHistogramWithErrorBars::Params.
Definition: histogram.h:669
void add(const UniformBinsHistogram< OtherScalar, OtherCountType > &x)
Add data to the histogram.
Definition: histogram.h:319
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:382
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:231
std::size_t numBins() const
Shorthand for params.num_bins
Definition: histogram.h:330
int num_histograms
The number of histograms averaged.
Definition: histogram.h:683
SegmentReturnType segment(Index start, Index n)
void reset()
Resets the data keeping the exisiting params.
Definition: histogram.h:726
T setw(T... args)
T resize(T... args)
Scalar binResolution() const
Shorthand for Params::binResolution()
Definition: histogram.h:368
STL class.
T min(T... args)
void reset()
Resets the histogram to zero counts everywhere, and zero error bars.
Definition: histogram.h:529
AveragedHistogram(const Params &params=Params())
Constructs an AveragedHistogram with the given histogram parameters.
Definition: histogram.h:692
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:655
void histogramPrettyPrint(std::ostream &str, const HistogramType &histogram, int max_width=0)
pretty-print the given histogram.
Definition: histogram.h:1226
void add(const Eigen::ArrayBase< EigenType > &x, CountType off_chart_=0)
Add data to the histogram.
Definition: histogram.h:299
Eigen::Array< CountType, Eigen::Dynamic, 1 > delta
The error bars associated with each histogram bin.
Definition: histogram.h:495
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:518
UniformBinsHistogramWithErrorBars< typename HistogramType_::Scalar, RealAvgType > Base_
Shortcut for our base class&#39; type.
Definition: histogram.h:666
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:379
Base_::CountType CountType
The histogram&#39; count type. This is exactly the same as RealAvgType.
Definition: histogram.h:673
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:559
bool isWithinBounds(Scalar value) const
Shorthand for Params::isWithinBounds()
Definition: histogram.h:342
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:249
UniformBinsHistogram(const HistogramType &other)
Constructor: copy another histogram type.
Definition: histogram.h:258
Some C++ utilities, with a tad of C++11 tricks.
NewCountType normalization() const
Calculate the total weight stored in this histogram.
Definition: histogram.h:432
T fabs(T... args)
T max(T... args)
Scalar binLowerValue(int index) const
Shorthand for Params::binLowerValue()
Definition: histogram.h:352
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:713
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:702
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:446
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:871
Scalar_ Scalar
The Scalar (X-axis) Type. See UniformBinsHistogram::Scalar.
Definition: histogram.h:480
UniformBinsHistogramParams< Scalar_ > Params
The type for specifying parameters of this histogram (limits, number of bins)
Definition: histogram.h:228
Scalar_ Scalar
The scalar type of the "X"-axis of the histogram (usually double)
Definition: histogram.h:219
int getWidthForTerminalOutput(int max_width=0)
Return a suitable width for displaying stuff on the standard output.
Definition: cxxutil.h:492
HistogramType_ HistogramType
Type of the individual histograms we are averaging.
Definition: histogram.h:664
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:282
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:1273
CountType off_chart
The number of points that fell outside of the given range.
Definition: histogram.h:235
Stores a histogram.
Definition: histogram.h:211
CountType count(std::size_t i) const
Shorthand for bins(i)
Definition: histogram.h:336
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:458
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.
void reset()
Resets the histogram to zero counts everywhere (including the off-chart counts)
Definition: histogram.h:265
Scalar binCenterValue(std::size_t index) const
Shorthand for Params::binCenterValue()
Definition: histogram.h:357
std::string prettyPrint(int max_width=0) const
Print the histogram in human readable form.
Definition: histogram.h:606
UniformBinsHistogramWithErrorBars< Scalar, NewCountType > normalized() const
Get a normalized version of this histogram.
Definition: histogram.h:577
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:347
Derived & setZero(Index size)