14 # pragma warning( disable : 2259 )
17 #include <AIDA/IAnnotation.h>
18 #include <AIDA/IAxis.h>
19 #include <AIDA/IHistogram1D.h>
20 #include <AIDA/IProfile1D.h>
29 #include <fmt/format.h>
40 constexpr
bool essentiallyEqual(
double const a,
double const b ) {
41 return std::abs( a - b ) <= std::min( std::abs( a ), std::abs( b ) ) * std::numeric_limits<double>::epsilon();
61 Bin(
const double h = 0,
const double e = 0,
const double l = -1 ) : height(
h ), error( e ), lower(
l ) {}
70 Bin& operator+=(
const Bin& right ) {
71 height += right.height;
72 const double e2 = error * error + right.error * right.error;
80 double maxY(
const bool withErr )
const {
83 [&](
double m,
const Bin& b ) { return std::max( m, withErr ? b.height + b.error : b.height ); } );
86 double minY(
const bool withErr )
const {
89 [&](
double m,
const Bin& b ) { return std::min( m, withErr ? b.height - b.error : b.height ); } );
92 Histo rebin(
const unsigned int bin )
const {
99 for (
unsigned int ibin = 0; ibin < bins.size(); ++ibin ) {
100 const Bin& current = bins[ibin];
101 if ( nh.bins.empty() ) {
102 nh.bins.push_back( current );
103 }
else if ( 0 == ibin % bin ) {
104 nh.bins.push_back( current );
106 nh.bins.back() += current;
112 int nullBin()
const {
113 for (
auto ib = bins.cbegin(); bins.cend() != ib + 1; ++ib ) {
114 if ( ib->lower <= 0 && 0 < ( ib + 1 )->lower ) {
return ib - bins.cbegin(); }
119 typedef std::vector<Bin> Bins;
142 const TAxis* axis =
root->GetXaxis();
144 const int nbins = axis->GetNbins();
148 hist.under = Histo::Bin(
root->GetBinContent( 0 ),
root->GetBinError( 0 ), axis->GetXmin() );
150 hist.over = Histo::Bin(
root->GetBinContent( nbins + 1 ),
root->GetBinError( nbins + 1 ), axis->GetXmax() );
153 for (
int ibin = 1; ibin <= nbins; ++ibin ) {
155 hist.bins.emplace_back(
root->GetBinContent( ibin ),
root->GetBinError( ibin ), axis->GetBinLowEdge( ibin ) );
167 StatusCode _getHisto(
const TProfile*
root, Histo& hist,
const bool ) {
168 const TH1* histo =
root;
169 return _getHisto( histo, hist );
179 StatusCode _getHisto(
const AIDA::IHistogram1D* aida, Histo& hist ) {
185 const AIDA::IAxis& axis = aida->axis();
186 const int nbins = axis.bins();
189 hist.under = Histo::Bin( aida->binHeight( AIDA::IAxis::UNDERFLOW_BIN ),
190 aida->binError( AIDA::IAxis::UNDERFLOW_BIN ), axis.lowerEdge() );
192 hist.over = Histo::Bin( aida->binHeight( AIDA::IAxis::OVERFLOW_BIN ), aida->binError( AIDA::IAxis::OVERFLOW_BIN ),
195 for (
int ibin = 0; ibin < nbins; ++ibin ) {
197 hist.bins.emplace_back( aida->binHeight( ibin ), aida->binError( ibin ), axis.binLowerEdge( ibin ) );
209 StatusCode _getHisto(
const AIDA::IProfile1D* aida, Histo& hist,
const bool spread ) {
215 const AIDA::IAxis& axis = aida->axis();
216 const int nbins = axis.bins();
220 Histo::Bin( aida->binHeight( AIDA::IAxis::UNDERFLOW_BIN ),
221 spread ? aida->binRms( AIDA::IAxis::UNDERFLOW_BIN ) : aida->binError( AIDA::IAxis::UNDERFLOW_BIN ),
225 Histo::Bin( aida->binHeight( AIDA::IAxis::OVERFLOW_BIN ),
226 spread ? aida->binRms( AIDA::IAxis::OVERFLOW_BIN ) : aida->binError( AIDA::IAxis::OVERFLOW_BIN ),
229 for (
int ibin = 0; ibin < nbins; ++ibin ) {
231 hist.bins.emplace_back( aida->binHeight( ibin ), spread ? aida->binRms( ibin ) : aida->binError( ibin ),
232 axis.binLowerEdge( ibin ) );
242 inline unsigned int rebin(
const unsigned int bins,
const unsigned int imax ) {
243 if ( 0 == imax ) {
return 1; }
244 unsigned int ibin = 1;
245 while ( bins > imax * ibin ) { ++ibin; }
254 std::pair<double, int> decompose(
double v ) {
255 if ( std::abs(
v ) < std::numeric_limits<double>::epsilon() ) {
258 else if ( essentiallyEqual( 1.0,
v ) ) {
262 auto r = decompose( -
v );
263 return { -r.first, r.second };
264 }
else if ( 0.1 >
v ) {
271 }
else if ( 1 <
v ) {
286 inline double _pow(
double x,
unsigned long n ) {
287 double y =
n % 2 ? x : 1;
290 if (
n % 2 ) { y *= x; }
295 inline double rValMin(
double v );
301 inline double rValMax(
double v ) {
302 if ( 0 >
v ) {
return -1 * rValMin( -
v ); }
304 std::pair<double, int> r = decompose(
v );
306 const double f = std::ceil( 20 * r.first ) / 2;
307 const int l = r.second - 1;
308 return 0 <
l ? f * _pow( 10,
l ) : f / _pow( 10, -
l );
315 inline double rValMin(
double v ) {
316 if ( 0 >
v ) {
return -1 * rValMax( -
v ); }
318 std::pair<double, int> r = decompose(
v );
319 const double f = std::floor( 20 * r.first ) / 2;
320 const int l = r.second - 1;
321 return 0 <
l ? f * _pow( 10,
l ) : f / _pow( 10, -
l );
328 inline std::string yLabel(
double value ) {
return fmt::format(
"{:10.3g}", value ); }
334 inline std::string xLabel(
const double value ) {
return fmt::format(
"{:9.3g}", value ); }
337 char symbBin(
const Histo::Bin& bin,
const double yLow,
const double yHigh,
const bool yNull,
const bool errors ) {
338 if ( errors && yLow <= bin.height && bin.height < yHigh ) {
341 else if ( errors && yHigh < bin.height - bin.error ) {
343 }
else if ( errors && yLow >= bin.height + bin.error ) {
345 }
else if ( errors ) {
347 }
else if ( yLow <= bin.height && bin.height < yHigh ) {
349 }
else if ( 0 <= bin.height && yLow <= bin.height && 0 < yHigh && !yNull ) {
352 else if ( 0 > bin.height && yHigh > bin.height && 0 >= yLow && !yNull ) {
363 std::ostringstream& dumpText(
const Histo& histo,
const std::size_t width,
const std::size_t height,
364 const bool errors, std::ostringstream&
stream ) {
365 if ( 40 > width ) {
return dumpText( histo, 40, height, errors,
stream ); }
366 if ( 200 < width ) {
return dumpText( histo, 200, height, errors,
stream ); }
367 if ( 150 < height ) {
return dumpText( histo, width, 150, errors,
stream ); }
368 if ( 20 > height ) {
return dumpText( histo, width, 20, errors,
stream ); }
369 if ( height > width ) {
return dumpText( histo, width, width, errors,
stream ); }
371 const unsigned int nBins = histo.bins.size();
372 if ( nBins > width ) {
374 Histo r = histo.rebin( rebin( nBins, width ) );
375 return dumpText( r, width, height, errors,
stream );
379 double yMax = std::max( rValMax( histo.maxY( errors ) ), 0.0 );
380 double yMin = std::min( rValMin( histo.minY( errors ) ), 0.0 );
382 if ( essentiallyEqual( yMin, yMax ) ) { yMax = yMin + 1; }
384 std::pair<double, int> r = decompose( yMax - yMin );
385 double _ny = std::ceil( 10 * r.first );
386 if ( 1 >= _ny ) { _ny = 10; }
387 int yBins = (int)std::max( 1., std::ceil( height / _ny ) );
390 if ( 20 > yBins ) { yBins = 20; }
391 const double yScale = ( yMax - yMin ) / yBins;
394 const int ySkip = 0 == yBins % 13 ? 13
395 : 0 == yBins % 11 ? 11
412 int iNull = histo.nullBin();
422 for (
int yLine = -1; yLine < yBins; ++yLine ) {
423 const double yHigh = yMax - yScale * yLine;
425 const double yLow = yMax - yScale * ( yLine + 1 );
427 std::string line1 =
" ";
429 const bool ynull = ( yLow <= 0 && 0 < yHigh );
430 const bool yfirst = -1 == yLine || yBins - 1 == yLine;
431 const bool ylab = ( 0 == ( yLine + 1 ) % ySkip ) || yfirst || ynull;
434 line1 += yLabel( ( yLow <= 0 && 0 < yHigh ) ? 0.0 : yLow );
436 line1 += std::string( 10,
' ' );
442 line1 += symbBin( histo.under, yLow, yHigh, ynull, errors );
444 line1 += ynull ?
"-+" : ylab ?
" +" :
" |";
448 for (
auto ibin = histo.bins.cbegin(); histo.bins.cend() != ibin; ++ibin ) {
450 const int i = ibin - histo.bins.cbegin();
452 const bool xnull = ibin->lower <= 0 && ( ibin + 1 ) != histo.bins.cend() && 0 < ( ibin + 1 )->lower;
453 const bool xlab = iNull == i % xSkip;
455 char symb = symbBin( *ibin, yLow, yHigh, ynull, errors );
458 if ( ( ynull || yfirst ) && xlab ) {
460 }
else if ( ynull || yfirst ) {
464 else if ( ylab && xnull ) {
466 }
else if ( xnull ) {
470 else if ( ylab || xlab ) {
479 std::string line3 = ynull ?
"->" : ylab ?
"+ " :
"| ";
482 line3 += symbBin( histo.over, yLow, yHigh, ynull, errors );
484 stream << line1 << line2 << line3 << std::endl;
489 std::vector<std::string> xlabels;
490 for (
auto ib = histo.bins.cbegin(); histo.bins.cend() != ib; ++ib ) { xlabels.push_back( xLabel( ib->lower ) ); }
492 const std::string oLabel = xLabel( histo.over.lower );
493 const std::string uLabel = xLabel( histo.under.lower );
495 static const std::string s_UNDERFLOW(
"UNDERFLOW" );
496 static const std::string s_OVERFLOW(
" OVERFLOW" );
499 for (
unsigned int yLine = 0; yLine < 12; ++yLine ) {
500 std::string
line = std::string( 12,
' ' );
502 if ( yLine < s_UNDERFLOW.size() ) {
503 line += s_UNDERFLOW[yLine];
510 if ( uLabel.size() > yLine ) {
511 line += uLabel[yLine];
516 for (
auto ibin = histo.bins.cbegin(); histo.bins.cend() != ibin; ++ibin ) {
517 int ib = ibin - histo.bins.cbegin();
518 const bool xlab = ( iNull == ib % xSkip );
519 if ( xlab && yLine < xlabels[ib].
size() ) {
520 line += xlabels[ib][yLine];
526 if ( oLabel.size() > yLine ) {
527 line += oLabel[yLine];
534 if ( yLine < s_OVERFLOW.size() ) {
535 line += s_OVERFLOW[yLine];
560 const std::size_t height,
const bool errors ) {
561 std::ostringstream
stream;
563 if ( !histo ) {
return stream.str(); }
571 Mean : {:11.5g} +- {:<10.4g}
572 Rms : {:11.5g} +- {:<10.4g}
573 Skewness : {:11.5g} +- {:<10.4g}
574 Kurtosis : {:11.5g} +- {:<10.4g}
577 | All | In Range | Underflow | Overflow | #Equivalent | Integral | Total |
578 | {:^9} | {:^9} | {:^9} | {:^9} | {:^11.5g} | {:^11.5g} | {:^11.5g} |
581 path( histo ), histo->title(),
586 histo->allEntries(), histo->entries(), histo->binEntries( AIDA::IAxis::UNDERFLOW_BIN ),
587 histo->binEntries( AIDA::IAxis::OVERFLOW_BIN ), histo->equivalentBinEntries(),
588 histo->sumBinHeights(), histo->sumAllBinHeights() );
590 const AIDA::IAnnotation& a = histo->annotation();
592 stream <<
" Annotation\n";
593 for (
int i = 0; i < a.size(); ++i ) {
594 stream <<
fmt::format(
" | {:<25.25s} : {:<45.45s} |\n", a.key( i ), a.value( i ) );
599 return dumpText( hist, width, height, errors,
stream ).str();
611 const std::size_t height,
const bool spread ) {
612 std::ostringstream
stream;
614 if ( !histo ) {
return stream.str(); }
616 StatusCode sc = _getHisto( histo, hist, spread );
626 | All | In Range | Underflow | Overflow | Integral | Total |
627 | {:^9} | {:^9} | {:^9} | {:^9} | {:^11.5g} | {:^11.5g} |
630 path( histo ), histo->title(),
631 histo->mean(), histo->rms(), histo->allEntries(), histo->entries(),
632 histo->binEntries( AIDA::IAxis::UNDERFLOW_BIN ),
633 histo->binEntries( AIDA::IAxis::OVERFLOW_BIN ), histo->sumBinHeights(),
634 histo->sumAllBinHeights() );
636 const AIDA::IAnnotation& a = histo->annotation();
638 stream <<
" Annotation\n";
639 for (
int i = 0; i < a.size(); ++i ) {
640 stream <<
fmt::format(
" | {:<25.25s} : {:<45.45s} |\n", a.key( i ), a.value( i ) );
645 return dumpText( hist, width, height,
true,
stream ).str();
657 const bool errors ) {
658 const TProfile* profile =
dynamic_cast<const TProfile*
>( histo );
659 if ( profile ) {
return histoDump( profile, width, height ); }
661 std::ostringstream
stream;
663 if ( !histo ) {
return stream.str(); }
671 Mean : {:11.5g} +- {:<10.4g}
672 Rms : {:11.5g} +- {:<10.4g}
677 | All | Underflow | Overflow | #Equivalent | Integral |
678 | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} |
681 histo->GetName(), histo->GetTitle(),
682 histo->GetMean(), histo->GetMeanError(), histo->GetRMS(), histo->GetRMSError(),
683 histo->GetSkewness(), histo->GetKurtosis(), histo->GetEntries(), histo->GetBinContent( 0 ),
684 histo->GetBinContent( histo->GetNbinsX() + 1 ), histo->GetEffectiveEntries(),
687 return dumpText( hist, width, height, errors,
stream ).str();
699 const std::size_t height ) {
700 std::ostringstream
stream;
702 if ( !histo ) {
return stream.str(); }
704 StatusCode sc = _getHisto( histo, hist,
true );
714 | All | Underflow | Overflow | Integral |
715 | {:^11.5g} | {:^11.5g} | {:^11.5g} | {:^11.5g} |
718 histo->GetName(), histo->GetTitle(),
719 histo->GetMean(), histo->GetRMS(), histo->GetSkewness(), histo->GetKurtosis(),
720 histo->GetEntries(), histo->GetBinContent( 0 ), histo->GetBinContent( histo->GetNbinsX() + 1 ),
723 return dumpText( hist, width, height,
true,
stream ).str();