20 void GetHistBorders(TH1 *h);
21 void FromAbs2px(
double scaleUp,
double scaleDn);
23 static double Distance2(
const Rectangle &r1,
const Rectangle &r2);
43 void init(vector<TLegend *> legs, vector<double> &sizesX, vector<double> &sizesY);
44 pair<double,vector<int> > iterate();
45 void GetLegendsPositions();
46 void GetDistancesPx(
double scaleUp,
double scaleDn);
47 pair<double,double> GetSolution(vector<double> &xx, vector<double> &yy,
49 void LoadHistoBorders(vector<Borders> &borders);
50 double analyze(
const vector<int> &indx, vector<double> &dists);
58 PosIterator(
int _nSteps,
unsigned Pos) {
75 static double MinDistanceSingle(vector<Borders> &bor,
double minSkip,
double x,
double y,
double w,
double h);
76 static double MinDistanceSingle(vector<Borders> &bor, Borders bSingle,
double minSkip);
79 static double MinDistance2(
double minSkip,
const Borders &br1,
const Borders &br2);
98 TIter next(gPad->GetListOfPrimitives());
100 while ((obj = next())) {
101 if(obj->InheritsFrom(TH1::Class())) {
106 if(obj->InheritsFrom(TMultiGraph::Class())) {
107 TMultiGraph *mg = (TMultiGraph*)obj;
108 hobj = mg ? mg->GetHistogram() :
nullptr;
112 if(obj->InheritsFrom(TGraph::Class())) {
113 TGraph *g = (TGraph*)obj;
114 hobj = g ? g->GetHistogram() :
nullptr;
118 if(obj->InheritsFrom(THStack::Class())) {
119 THStack *hs = (THStack*)obj;
120 hobj = hs ? hs->GetHistogram() :
nullptr;
125 if(!hobj) {cerr <<
"No frame created in active pad" << endl;}
133 return frame ? frame->GetXaxis() :
nullptr;
139 return frame ? frame->GetYaxis() :
nullptr;
145 return frame ? frame->GetZaxis() :
nullptr;
163 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
164 double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
166 if(pxW < pxH)
return px/pxW;
183 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
184 double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
185 if(pxW < pxH)
return rel*pxW;
194 return (1. - gPad->GetLeftMargin() - gPad->GetRightMargin());
201 return (1. - gPad->GetBottomMargin() - gPad->GetTopMargin());
235 if(pxY < 0) pxY = pxX;
236 if(pxT < 0) pxT = pxX;
242 frame->GetXaxis()->SetTitleSize(relSizeX);
243 frame->GetXaxis()->SetLabelSize(relSizeX);
245 frame->GetYaxis()->SetTitleSize(relSizeY);
246 frame->GetYaxis()->SetLabelSize(relSizeY);
248 frame->SetTitleSize(relSizeT);
260 if(tickY < 0) tickY = tickX;
275 double labSize = frame->GetXaxis()->GetLabelSize();
277 if(gPad->GetLogx()) {
279 if(frame->GetXaxis()->GetNoExponent()) off0 += 0.33;
285 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
290 off += off0 * labSize;
291 frame->GetXaxis()->SetLabelOffset(off);
311 TAxis *ax = frame->GetXaxis();
313 ax->SetTitleOffset(off*
RelFontToPx(ax->GetTitleSize())/1.6 / ( gPad->GetWh()* ax->GetTitleSize()*gPad->GetAbsHNDC() ) );
327 TAxis *ax = frame->GetYaxis();
328 double labSize = ax->GetLabelSize();
329 double pxW = gPad->GetWw() * gPad->GetAbsWNDC() ;
338 ax->SetLabelOffset(off * fact + off0*labSize );
353 TAxis *ax = frame->GetYaxis();
355 ax->SetTitleOffset( off*
RelFontToPx(ax->GetTitleSize())/1.6 / ( gPad->GetWw()*ax->GetTitleSize()* gPad->GetAbsWNDC() ) );
386 void SetFTO(vector<double> fonts, vector<double> ticks, vector<double> offsets)
390 offsets.resize(4, 0);
392 SetFonts(fonts[0], fonts[1], fonts[2]);
394 SetOffsets(offsets[0], offsets[1], offsets[2], offsets[3]);
422 void DrawLatex(TVirtualPad *pad1, TVirtualPad *pad2,
double x,
double y, TString text,
double fSize, TString style)
424 TVirtualPad *padOrg = gPad;
425 assert(pad1->GetCanvas() == pad2->GetCanvas());
426 TCanvas *can = pad1->GetCanvas();
429 TLatex *tex =
new TLatex();
435 if(style.Contains(
'>')) {
436 if(style.Contains(
'l')) vAlign = 1;
437 if(style.Contains(
'r')) vAlign = 3;
438 if(style.Contains(
'b')) hAlign = 1;
439 if(style.Contains(
't')) hAlign = 3;
442 else if(style.Contains(
'<')) {
443 if(style.Contains(
'l')) vAlign = 3;
444 if(style.Contains(
'r')) vAlign = 1;
445 if(style.Contains(
'b')) hAlign = 3;
446 if(style.Contains(
't')) hAlign = 1;
449 else if(style.Contains(
'^')) {
450 if(style.Contains(
'l')) hAlign = 3;
451 if(style.Contains(
'r')) hAlign = 1;
452 if(style.Contains(
'b')) vAlign = 3;
453 if(style.Contains(
't')) vAlign = 1;
457 if(style.Contains(
'l')) hAlign = 1;
458 if(style.Contains(
'r')) hAlign = 3;
459 if(style.Contains(
'b')) vAlign = 1;
460 if(style.Contains(
't')) vAlign = 3;
464 tex->SetTextAlign(10*hAlign + vAlign);
465 tex->SetTextAngle(angle);
466 tex->SetTextFont(42);
468 double l[2], r[2], b[2], t[2];
470 TVirtualPad *pads[] = {pad1, pad2};
472 for(
int i = 0; i < 2; ++i) {
473 l[i] = pads[i]->GetAbsXlowNDC() + pads[i]->GetAbsWNDC()*pads[i]->GetLeftMargin();
474 r[i] = pads[i]->GetAbsXlowNDC() + pads[i]->GetAbsWNDC()*(1-pads[i]->GetRightMargin());
475 b[i] = pads[i]->GetAbsYlowNDC() + pads[i]->GetAbsHNDC()*pads[i]->GetBottomMargin();
476 t[i] = pads[i]->GetAbsYlowNDC() + pads[i]->GetAbsHNDC()*(1-pads[i]->GetTopMargin());
479 double left = min(l[0], l[1]);
480 double right = max(r[0], r[1]);
481 double bottom= min(b[0], b[1]);
482 double top = max(t[0], t[1]);
484 double xGlob = left + (right-left) *x;
485 double yGlob = bottom + (top-bottom) *y;
488 auto isBtw = [](
double low,
double x,
double high) {
return low < x && x < high;};
489 bool isInside =
false;
490 for(
int i = 0; (i < 2 && pads[0] != pads[1]) || (i<1); ++i) {
491 if(isBtw(l[i],xGlob,r[i]) && isBtw(b[i],yGlob,t[i]) ) {
495 fSize = frame ?
RelFontToPx(frame->GetTitleSize()) : 12;
499 double xFactor = (r[i] - l[i]) / (right - left);
500 double yFactor = (t[i] - b[i]) / (top - bottom);
501 assert(x / xFactor < 1);
502 assert(y / yFactor < 1);
505 double xLoc = pads[i]->GetLeftMargin() + x/xFactor *
506 (1 - pads[i]->GetLeftMargin() - pads[i]->GetRightMargin());
507 double yLoc = pads[i]->GetBottomMargin() + y/yFactor *
508 (1 - pads[i]->GetBottomMargin() - pads[i]->GetTopMargin());
513 tex->DrawLatexNDC(xLoc, yLoc, text);
522 fSize = frame ?
RelFontToPx(frame->GetTitleSize()) : 12;
526 tex->DrawLatexNDC(xGlob, yGlob, text);
537 void DrawLatex(TVirtualPad *pad,
double x,
double y, TString text,
double fSize, TString style)
539 DrawLatex(pad, pad, x, y, text, fSize, style);
546 void DrawLatex(
double x,
double y, TString text,
double fSize, TString style)
548 DrawLatex(gPad, x, y, text, fSize, style);
555 static void DrawLatexLRTB(TVirtualPad *pad1, TVirtualPad *pad2,
double Offset, TString text,
double fSize, TString style)
557 TVirtualPad *padOrg = gPad;
561 fSize = frame ?
RelFontToPx(frame->GetTitleSize()) : 12;
564 auto Close = [](
double x,
double val) {
return abs(x-1000*val) <1000;};
566 double x = 0.5, y = 0.5;
569 double b[2], t[2], l[2], r[2];
571 TVirtualPad *pads[] = {pad1, pad2};
572 for(
int i = 0; i < 2; ++i) {
573 l[i] = pads[i]->GetAbsXlowNDC() + pads[i]->GetAbsWNDC()*pads[i]->GetLeftMargin();
574 r[i] = pads[i]->GetAbsXlowNDC() + pads[i]->GetAbsWNDC()*(1-pads[i]->GetRightMargin());
575 b[i] = pads[i]->GetAbsYlowNDC() + pads[i]->GetAbsHNDC()*pads[i]->GetBottomMargin();
576 t[i] = pads[i]->GetAbsYlowNDC() + pads[i]->GetAbsHNDC()*(1-pads[i]->GetTopMargin());
579 double left = min(l[0], l[1]);
580 double right = max(r[0], r[1]);
581 double bottom= min(b[0], b[1]);
582 double top = max(t[0], t[1]);
584 if(Close(Offset,2) || Close(Offset, 8)) {
585 if(style.Contains(
'l')) x = 0.0;
586 if(style.Contains(
'r')) x = 1.0;
587 double unit = (fSize * 3./4) / ( pad1->GetWh() * (top - bottom) );
589 if(Close(Offset,2)) y = 1 + unit*(Offset - 2000);
590 else y = 0 - unit*(Offset - 8000);
593 else if(Close(Offset,4) || Close(Offset, 6)) {
594 if(style.Contains(
'b')) y = 0.0;
595 if(style.Contains(
't')) y = 1.0;
596 double unit = (fSize * 3./4) / ( pad1->GetWw() * (right - left) );
598 if(Close(Offset,6)) x = 1 + unit*(Offset - 6000);
599 else x = 0 - unit*(Offset - 4000);
604 DrawLatex(pad1, pad2, x, y, text, fSize, style);
611 void DrawLatexUp(TVirtualPad *pad1, TVirtualPad *pad2,
double Offset, TString text,
double fSize, TString style) {
612 DrawLatexLRTB(pad1, pad2, 2000 + Offset, text, fSize, style);
616 void DrawLatexDown(TVirtualPad *pad1,TVirtualPad *pad2,
double Offset, TString text,
double fSize, TString style) {
617 DrawLatexLRTB(pad1, pad2, 8000 + Offset, text, fSize, style);
621 void DrawLatexRight(TVirtualPad *pad1, TVirtualPad *pad2,
double Offset, TString text,
double fSize, TString style) {
622 DrawLatexLRTB(pad1, pad2, 6000 + Offset, text, fSize, style);
626 void DrawLatexLeft(TVirtualPad *pad1, TVirtualPad *pad2,
double Offset, TString text,
double fSize, TString style) {
627 DrawLatexLRTB(pad1, pad2, 4000 + Offset, text, fSize, style);
632 void DrawLatexUp(TVirtualPad *pad,
double Offset, TString text,
double fSize, TString style) {
637 void DrawLatexDown(TVirtualPad *pad,
double Offset, TString text,
double fSize, TString style) {
642 void DrawLatexRight(TVirtualPad *pad,
double Offset, TString text,
double fSize, TString style) {
647 void DrawLatexLeft(TVirtualPad *pad,
double Offset, TString text,
double fSize, TString style) {
653 void DrawLatexUp(
double Offset, TString text,
double fSize, TString style) {
657 void DrawLatexDown(
double Offset, TString text,
double fSize, TString style) {
665 void DrawLatexLeft(
double Offset, TString text,
double fSize, TString style) {
689 return to_string(pos);
693 static unsigned SimplifyPos(
unsigned pos)
712 int hAlign = lat->GetTextAlign() / 10 - 1;
713 int vAlign = lat->GetTextAlign() % 10 - 1;
714 if(vAlign == -1) vAlign = 0;
718 rTitle.
fHeight = lat->GetYsize() / (gPad->GetY2()-gPad->GetY1());
719 rTitle.
fWidth = lat->GetXsize() / (gPad->GetX2()-gPad->GetX1());
720 rTitle.
fX = lat->GetX();
721 rTitle.
fY = lat->GetY();
724 if(lat->GetTextAngle() == 0) {
725 rTitle.
fX -= hAlign*rTitle.
fWidth/2.;
730 double rat = gPad->GetWh() / double(gPad->GetWw());
731 rat /= gPad->GetAbsWNDC() / double(gPad->GetAbsHNDC());
735 if(lat->GetTextAngle() == 90) {
738 rTitle.
fX -=1.*vAlign*rTitle.
fWidth/2.;
740 else if(lat->GetTextAngle() == 270) {
743 rTitle.
fX -=1.*vAlign*rTitle.
fWidth/2.;
758 TLegend *leg =
new TLegend(0., 0., 0., 0.);
763 cerr <<
"There is no frame created, legend can't be plotted." << endl;
766 leg->SetTextSize(axY->GetTitleSize());
767 leg->SetNColumns(nCols);
775 void GetLegendSizes(TLegend *leg,
double &SizeX,
double &SizeY,
double &SizeYroot)
778 double lineSeparation = 1.0;
779 double markerSize = 1.5;
780 double columnSeparation = 0;
788 leg->SetBorderSize(0);
790 leg->SetFillStyle(0);
793 double fSizeNDCy = fontSize / (gPad->GetWh() * gPad->GetAbsHNDC());
794 double fSizeNDCx = fontSize / (gPad->GetWw() * gPad->GetAbsWNDC());
799 int nCols = leg->GetNColumns();
800 vector<double> maxC(nCols, 0);
803 for(
const auto &&entry : *leg->GetListOfPrimitives()) {
804 TString lab =
dynamic_cast<TLegendEntry *
>(entry)->GetLabel();
805 TString opt =
dynamic_cast<TLegendEntry *
>(entry)->GetOption();
807 TLatex *lat =
new TLatex(0.5, 0.5, lab);
808 lat->SetTextSize(leg->GetTextSize());
809 lat->SetTextFont(leg->GetTextFont());
813 headerW = max(headerW, textW);
818 maxC[colId] = max(maxC[colId], textW);
821 colId = (colId != nCols-1) ? colId + 1 : 0;
824 double maxW = accumulate(maxC.begin(),maxC.end(),0.);
826 int nRows = nHeaders + (nLegItems+nCols-1)/nCols;
828 SizeY = lineSeparation*fSizeNDCy*nRows;
830 headerW += 0.1*fSizeNDCx*markerSize;
832 SizeX = max(nCols*fSizeNDCx*markerSize +
833 (nCols-1)*fSizeNDCx*columnSeparation + maxW, headerW);
834 leg->SetMargin( nCols*fSizeNDCx*markerSize / SizeX);
836 leg->SetColumnSeparation((nCols-1)*fSizeNDCx*columnSeparation / SizeX);
839 SizeYroot = lineSeparation*fSizeNDCy*leg->GetNRows();
849 int nScaleSteps = keepRange ? 1 : 20;
851 vector<double> sizesX, sizesY, sizesYroot;
853 for(
unsigned i = 0; i < legs.size(); ++i) {
854 double SizeX, SizeY, SizeYroot;
856 sizesX.push_back(SizeX);
857 sizesY.push_back(SizeY);
858 sizesYroot.push_back(SizeYroot);
864 placer.init(legs, sizesX, sizesY);
866 vector<double> xx, yy;
867 double scaleUp, scaleDn;
868 tie(scaleUp, scaleDn) = placer.GetSolution(xx, yy, nScaleSteps);
871 for(
unsigned i = 0; i < legs.size(); ++i) {
872 legs[i]->SetX1(xx[i]);
873 legs[i]->SetY1(yy[i] + sizesY[i] - sizesYroot[i]);
874 legs[i]->SetX2(xx[i] + sizesX[i]);
875 legs[i]->SetY2(yy[i] + sizesY[i]);
880 if(gPad->GetLogy()) {
883 double Max = pow(10,gPad->GetUymax());
884 double Min = pow(10,gPad->GetUymin());
886 frameNow->SetMaximum(Min * pow(Max/Min, scaleUp));
887 frameNow->SetMinimum(Max / pow(Max/Min, scaleDn));
890 double Max = gPad->GetUymax();
891 double Min = gPad->GetUymin();
893 frameNow->SetMaximum(Min + (Max-Min)*scaleUp);
894 frameNow->SetMinimum(Max - (Max-Min)*scaleDn);
919 for(
auto & leg : legs)
925 bool PosIterator::Iterate() {
933 if((pos &
kPos9) && i==0 && j==last)
935 if((pos &
kPos7) && i==0 && j==0)
937 if((pos &
kPos1) && i==last && j==0)
939 if((pos &
kPos3) && i==last && j==last)
942 if((pos &
kPos8c) && i==0 && j==last/2)
944 if((pos &
kPos4c) && i==last/2 && j==0)
946 if((pos &
kPos6c) && i==last/2 && j==last)
948 if((pos &
kPos2c) && i==last && j==last/2)
951 if((pos &
kPos8) && i==0)
953 if((pos &
kPos2) && i==last)
955 if((pos &
kPos4) && j==0)
957 if((pos &
kPos6) && j==last)
977 void PLACER::init(vector<TLegend *> legs, vector<double> &sizesX, vector<double> &sizesY) {
979 for(
auto & leg : legs) {
980 unsigned layOut = atoi(leg->GetName());
982 vector<pair<int,int>>
pos;
984 PosIterator iter(
nSteps, layOut);
985 while(iter.Iterate()) {
986 pos.push_back(make_pair(iter.iSave, iter.jSave));
992 for(
unsigned i = 0; i <
dims.size(); ++i)
996 GetLegendsPositions();
1000 pair<double,vector<int>> PLACER::iterate() {
1001 vector<int> idxs(
dims.size());
1002 vector<double> distsNow(
dims.size());
1003 vector<double> distsBest(
dims.size());
1004 vector<int> bestLayout;
1010 double dist = analyze(idxs, distsNow);
1012 if(dist >= maxDist) {
1014 for(
int i = 0; i <
nLeg; ++i) {
1015 state = state && distsNow[i] >= distsBest[i];
1017 if(dist > maxDist || (dist == maxDist && state)) {
1019 distsBest = distsNow;
1026 for(j = 0; j <
dims.size(); ++j) {
1028 if (idxs[j] < static_cast<int>(
dims[j]))
break;
1031 if (j ==
dims.size())
break;
1033 return make_pair(maxDist, bestLayout);
1037 void PLACER::GetLegendsPositions() {
1047 double ytickLowNDC = frameNow->GetYaxis()->GetTickLength() *
GetAxisFractionY();
1048 double ytickHighNDC = ytickLowNDC * gPad->GetTicky();
1049 double xtickLowNDC = frameNow->GetXaxis()->GetTickLength() *
GetAxisFractionX();
1050 double xtickHighNDC = xtickLowNDC * gPad->GetTickx();
1052 double fSizeNDCy =
minSepar / (gPad->GetWh() * gPad->GetAbsHNDC());
1053 double fSizeNDCx =
minSepar / (gPad->GetWw() * gPad->GetAbsWNDC());
1056 for(
int k = 0; k <
nLeg; ++k) {
1058 double SizeX =
SizesX[k];
1059 double SizeY =
SizesY[k];
1061 double xMin = gPad->GetLeftMargin() + ytickLowNDC + fSizeNDCx;
1062 double xMax = 1 - gPad->GetRightMargin() - ytickHighNDC - SizeX - fSizeNDCx;
1063 double yMax = 1 - gPad->GetTopMargin() - xtickHighNDC - SizeY - fSizeNDCy;
1064 double yMin = gPad->GetBottomMargin() + xtickLowNDC + fSizeNDCy;
1069 for(
unsigned l = 0; l <
dims[k]; ++l) {
1073 double xx = xMin + (xMax-xMin)/(
nSteps-1) * j;
1074 double yy = yMax - (yMax-yMin)/(
nSteps-1) * i;
1078 legBorders[k][l].recs.push_back({xx, yy, SizeX, SizeY});
1086 void PLACER::GetDistancesPx(
double scaleUp,
double scaleDn) {
1088 for(
auto &b : bordersPx)
1089 b.FromAbs2px(scaleUp, scaleDn);
1093 for(
int i = 0; i <
nLeg; ++i) {
1095 for(
unsigned l = 0; l <
dims[i]; ++l)
1101 pair<double,double> PLACER::GetSolution(vector<double> &xx, vector<double> &yy,
1104 double scaleUp=1., scaleDn=1.;
1106 vector<int> bestLayout;
1108 for(
int sum = 0; sum < nScaleSteps; ++sum)
1109 for(
int iUp = sum; iUp >= 0; --iUp) {
1110 int iDn = sum - iUp;
1111 if(!gPad->GetLogy() && iDn != 0)
continue;
1112 scaleUp = pow(4, iUp/10.);
1113 scaleDn = pow(4, iDn/10.);
1115 GetDistancesPx(scaleUp, scaleDn);
1118 tie(dist, bestLayout) = iterate();
1121 goto gotoAfterScaleLoop;
1123 cerr <<
"No solution without overlaps found for legends" << endl;
1129 for(
int i = 0; i <
nLeg; ++i) {
1138 return {scaleUp, scaleDn};
1145 void PLACER::LoadHistoBorders(vector<Borders> &
borders)
1148 vector<TObject *> hists;
1149 for(
const auto &&prim : *gPad->GetListOfPrimitives()) {
1151 if(strcmp(prim->GetName(),
"hframe") && strcmp(prim->ClassName(),
"TH1F"))
1152 if(dynamic_cast<TH1*>(prim))
1153 hists.push_back(prim);
1160 if(hists.size() == 0) {
1165 for(
unsigned i = 0; i < hists.size(); ++i) {
1167 br.GetHistBorders(dynamic_cast<TH1*>(hists[i]));
1168 borders.push_back(br);
1174 double PLACER::analyze(
const vector<int> &indx, vector<double> &dists)
1176 double minDist = 1e40;
1178 for(
unsigned k = 0; k < indx.size(); ++k) {
1187 for(
unsigned k = 0; k < indx.size(); ++k)
1188 for(
unsigned l = k+1; l < indx.size(); ++l) {
1189 double dist = MinDistance2(0.99*
minSepar,
1191 minDist = min(minDist, dist);
1192 dists[k] = min(dists[k], dist);
1206 double valXmin = gPad->GetX1();
1207 double valXmax = gPad->GetX2();
1209 double valYmin = gPad->GetY2() - scaleDn*(gPad->GetY2()-gPad->GetY1());
1210 double valYmax = gPad->GetY1() + scaleUp*(gPad->GetY2()-gPad->GetY1());
1213 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1214 double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1217 if(gPad->GetLogx()) p.
x = log10(p.
x);
1218 if(gPad->GetLogy()) p.
y = log10(p.
y);
1220 p.
x = (p.
x - valXmin)/(valXmax-valXmin) * pxW;
1221 p.
y = (p.
y - valYmin)/(valYmax-valYmin) * pxH;
1229 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1230 double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1238 static double MinDistanceSingle(vector<Borders> &bor,
double minSkip,
double x,
double y,
double w,
double h)
1241 bS.recs.push_back( {x, y, w, h} );
1244 double minDist = 1e40;
1245 for(Borders &b : bor) {
1246 double d = MinDistance2(0.99*minSkip, b, bS);
1247 minDist = min(minDist, d);
1248 if(minDist <= minSkip)
return minDist;
1250 return sqrt(minDist);
1254 static double MinDistanceSingle(vector<Borders> &bor, Borders bSingle,
double minSkip)
1256 double minDist = 1e40;
1257 for(Borders &b : bor) {
1258 double d = MinDistance2(0.99*minSkip, b, bSingle);
1259 minDist = min(minDist, d);
1260 if(minDist <= minSkip)
return minDist;
1262 return sqrt(minDist);
1267 static double MinDistance2(
double minSkip,
const Borders &br1,
const Borders &br2)
1269 double minDist = 1e40;
1270 for(
const auto &r1 : br1.recs)
1271 for(
const auto &r2 : br2.recs) {
1272 double d = Borders::Distance2(r1, r2);
1273 minDist = min(minDist, d);
1274 if(minDist <= minSkip)
return minDist;
1281 void Borders::FromNDC2px()
1283 double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1284 double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1311 void Borders::FromAbs2px(
double scaleUp,
double scaleDn)
1314 Point p1(r.fX, r.fY);
1315 Point p2(r.fX+r.fWidth, r.fY+r.fHeight);
1317 p1 =
Abs2Px(p1, scaleUp, scaleDn);
1318 p2 =
Abs2Px(p2, scaleUp, scaleDn);
1321 r.fWidth = p2.
x-p1.
x;
1322 r.fHeight = p2.
y-p1.
y;
1329 void Borders::GetHistBorders(TH1 *h)
1331 for(
int i = 1; i <= h->GetNbinsX(); ++i) {
1332 double xMin = h->GetBinLowEdge(i);
1333 double xMax = h->GetBinLowEdge(i) + h->GetBinWidth(i);
1334 double yMin = h->GetBinContent(i)-h->GetBinError(i);
1335 double yMax = h->GetBinContent(i)+h->GetBinError(i);
1337 const double lim = 1e-30;
1339 if(gPad->GetLogx()) {
1340 xMin = max(lim, xMin);
1341 xMax = max(lim, xMax);
1343 if(gPad->GetLogy()) {
1344 yMin = max(lim, yMin);
1345 yMax = max(lim, yMax);
1347 recs.push_back({xMax, yMin, xMax-xMin, yMax-yMin});
1349 TString drawOpt = h->GetDrawOption();
1350 if(drawOpt.Contains(
"hist") && i > 1) {
1351 double yMinLeft = h->GetBinContent(i-1)-h->GetBinError(i-1);
1352 double yMaxLeft = h->GetBinContent(i-1)+h->GetBinError(i-1);
1353 if(gPad->GetLogy()) {
1354 yMinLeft = max(lim, yMinLeft);
1355 yMaxLeft = max(lim, yMaxLeft);
1357 double yMinNow = min(yMin, yMinLeft);
1358 double yMaxNow = max(yMax, yMaxLeft);
1359 recs.push_back({xMin, yMinNow, 0., yMaxNow-yMinNow});
1369 static double hypot2(
double x,
double y) {
return x*x+y*y;}
1384 bool left = x2b < x1;
1385 bool right = x1b < x2;
1386 bool bottom = y2b < y1;
1387 bool top = y1b < y2;
1389 return hypot2(x2b-x1, y2-y1b);
1390 else if(left && bottom)
1391 return hypot2(x2b-x1, y2b-y1);
1392 else if(bottom && right)
1393 return hypot2(x2-x1b, y2b-y1);
1394 else if(right && top)
1395 return hypot2(x2-x1b, y2-y1b);
1397 return hypot2(x1 - x2b,0.);
1399 return hypot2(x2 - x1b,0.);
1401 return hypot2(y1 - y2b,0.);
1403 return hypot2(y2 - y1b,0.);
1422 TFrame *fr = gPad->GetFrame();
1424 fr->SetFillStyle(0);
1428 cerr <<
"No frame at active pad" << endl;
1443 TAxis *ax = hFrame->GetXaxis();
1445 int iFirst = ax->GetFirst();
1446 int iLast = ax->GetLast();
1448 double xMin = ax->GetBinLowEdge(iFirst);
1449 double xMax = ax->GetBinLowEdge(iLast) + ax->GetBinWidth(iLast);
1452 double widthMin=0, widthMax=0;
1453 double centerMin=0, centerMax=0;
1455 double yMin = 1e100, yMax = -1e100;
1456 for(
auto && obj : *gPad->GetListOfPrimitives()) {
1458 if(obj->InheritsFrom(TH1::Class()))
1459 ((TH1*)obj)->
GetXaxis()->SetRangeUser(xMin, xMax);
1460 else if(obj->InheritsFrom(TMultiGraph::Class()))
1461 ((TMultiGraph*)obj)->
GetXaxis()->SetRangeUser(xMin, xMax);
1462 else if(obj->InheritsFrom(TGraph::Class()))
1463 ((TGraph*)obj)->
GetXaxis()->SetRangeUser(xMin, xMax);
1464 else if(obj->InheritsFrom(THStack::Class()))
1465 ((THStack*)obj)->
GetXaxis()->SetRangeUser(xMin, xMax);
1468 if(obj->InheritsFrom(TH1::Class()) ||
1469 obj->InheritsFrom(TMultiGraph::Class()) ||
1470 obj->InheritsFrom(TGraph::Class()) ||
1471 obj->InheritsFrom(THStack::Class()) ) {
1475 double yMinNow = gPad->GetUymin();
1476 double yMaxNow = gPad->GetUymax();
1478 if(yMinNow < yMin) {
1480 widthMin = yMaxNow - yMinNow;
1481 centerMin = (yMaxNow + yMinNow)/2.;
1483 if(yMaxNow > yMax) {
1485 widthMax = yMaxNow - yMinNow;
1486 centerMax = (yMaxNow + yMinNow)/2.;
1492 double width = yMax - yMin;
1495 double zoomMin = width / widthMin;
1496 double zoomMax = width / widthMax;
1498 if(yMin >= 0. && !gPad->GetLogy())
1499 yMin = max(0., centerMin - zoomMin * widthMin/2.);
1501 yMin = centerMin - zoomMin * widthMin/2.;
1502 yMax = centerMax + zoomMax * widthMax/2.;
1505 if(gPad->GetLogy()) {
1506 hFrame->SetMinimum(pow(10,yMin));
1507 hFrame->SetMaximum(pow(10,yMax));
1510 hFrame->SetMinimum(yMin);
1511 hFrame->SetMaximum(yMax);
1523 gPad->SetLeftMargin(0);
1524 gPad->SetRightMargin(0);
1525 gPad->SetLeftMargin(lMargin);
1526 gPad->SetRightMargin(rMargin);
1537 gPad->SetTopMargin(0);
1538 gPad->SetBottomMargin(0);
1539 gPad->SetTopMargin(tMargin);
1540 gPad->SetBottomMargin(bMargin);
1561 TVirtualPad *orgPad = gPad;
1563 double lMag = orgPad->GetLeftMargin();
1564 double rMag = orgPad->GetRightMargin();
1565 double tMag = orgPad->GetTopMargin();
1566 double bMag = orgPad->GetBottomMargin();
1568 int nx = xDivs.size();
1569 int ny = yDivs.size();
1571 double Nx = accumulate(xDivs.begin(), xDivs.end(), 0.);
1572 double Ny = accumulate(yDivs.begin(), yDivs.end(), 0.);
1573 vector<double> xPos(nx+1), yPos(ny+1);
1574 xPos[0] = yPos[0] = 0;
1575 for(
int i = 1; i <= nx; ++i)
1576 xPos[i] = xPos[i-1] + xDivs[i-1]/Nx * (1-lMag-rMag);
1577 for(
int i = 1; i <= ny; ++i)
1578 yPos[i] = yPos[i-1] + yDivs[i-1]/Ny * (1-tMag-bMag);
1581 for(
int ix = 0; ix < nx; ++ix)
1582 for(
int iy = 0; iy < ny; ++iy) {
1583 double xl = (ix == 0) ? 0 : lMag+xPos[ix];
1584 double xr = (ix == nx-1) ? 1 : lMag+xPos[ix+1];
1586 double yt = (iy == 0) ? 1 : 1-tMag-yPos[iy];
1587 double yb = (iy == ny-1) ? 0 : 1-tMag-yPos[iy+1];
1589 int id = iy*nx+ix+1;
1590 TPad *pad =
new TPad(
SF(
"%s_%d", orgPad->GetName(), id),
"", xl, yb, xr, yt);
1593 double lNew = (ix == 0) ? lMag/(xr - xl) : 0;
1594 double rNew = (ix == nx-1) ? rMag/(xr - xl) : 0;
1596 double tNew = (iy == 0) ? tMag/(yt - yb) : 0;
1597 double bNew = (iy == ny-1) ? bMag/(yt - yb) : 0;
1646 TVirtualPad *orgPad = gPad;
1648 if(divX.size() % 2 != 1 || int(divX.size()) < (3-2*useMargins) ) {
1649 cerr <<
"Wrong divX= " << divX.size() << endl;
1652 if(divY.size() % 2 != 1 || int(divY.size()) < (3-2*useMargins) ) {
1653 cerr <<
"Wrong divY= " << divY.size() << endl;
1659 double sumX = accumulate(divX.begin(), divX.end(), 0.0);
1660 double sumY = accumulate(divY.begin(), divY.end(), 0.0);
1662 if(useMargins ==
true) {
1663 double l = orgPad->GetLeftMargin();
1664 double r = orgPad->GetRightMargin();
1665 double t = orgPad->GetTopMargin();
1666 double b = orgPad->GetBottomMargin();
1669 vector<double> newX, newY;
1670 newX.push_back(l * sumX/(1-l-r));
1671 newX.insert(newX.end(), divX.begin(), divX.end());
1672 newX.push_back(r * sumX/(1-l-r));
1674 newY.push_back(t * sumY/(1-t-b));
1675 newY.insert(newY.end(), divY.begin(), divY.end());
1676 newY.push_back(b * sumY/(1-t-b));
1684 vector<double> edgesX(divX.size()+1);
1685 vector<double> edgesY(divY.size()+1);
1687 edgesX[0] = edgesY[0] = 0;
1688 for(
unsigned i = 1; i < edgesX.size(); ++i)
1689 edgesX[i] = edgesX[i-1] + divX[i-1]/sumX;
1690 for(
unsigned i = 1; i < edgesY.size(); ++i)
1691 edgesY[i] = edgesY[i-1] + divY[i-1]/sumY;
1693 int nPadsX = (divX.size()-1)/2;
1697 while(orgPad->GetPad(kStart))
1704 for(
int y = 1; y < int(edgesY.size())-1; y+=2)
1705 for(
int x = edgesX.size()-3; x >= 1; x-=2) {
1707 i = ((y-1)/2) * nPadsX + ((x-1)/2) + 1;
1709 TPad *pad =
new TPad(TString::Format(
"%s_%d", orgPad->GetName(), kStart+i),
"", 0.0, 0.0, 1, 1);
1710 pad->SetFillStyle(0);
1713 double l = max(0.,edgesX[x]);
1714 double r = max(0.,1-edgesX[x+1]);
1715 double t = max(0.,edgesY[y]);
1716 double b = max(0.,1-edgesY[y+1]);
1726 pad->SetNumber(kStart+i);
1735 vector<double>
merge(vector<double> v1, vector<double> v2, vector<double> v3, vector<double> v4, vector<double> v5, vector<double> v6, vector<double> v7)
1737 vector<vector<double>> v = {v1, v2, v3, v4, v5, v6, v7};
1739 for(
unsigned i = 0; i < v.size(); ++i)
1740 res.insert(res.end(), v[i].begin(), v[i].end());
1747 vector<double>
repeat(vector<double> x,
int n)
1749 vector<double> res = x;
1750 for(
int i = 1; i < n; ++i)
1751 res.insert(res.end(), x.begin(), x.end());
1759 vector<double>
group(
double frame,
double space,
int n)
1762 for(
int i = 0; i < n-1; ++i) {
1763 res.push_back(frame);
1764 res.push_back(space);
1766 res.push_back(frame);
vector< Borders > borders
TAxis * GetZaxis()
Return z-axis of the active frame.
double GetAxisFractionX()
Fraction of the pad width covered by x-axis.
double TickAbsToRelY(double tick)
Convert tick length in px of y-axis to the relative units.
double GetAxisFractionY()
Fraction of the pad height covered by y-axis.
TAxis * GetYaxis()
Return y-axis of the active frame.
vector< vector< double > > distToHists
TAxis * GetXaxis()
Return x-axis of the active frame.
double RelFontToPx(double rel)
Transform font size from relative units to pixels.
void SetLabelOffsetX(double off)
Set offset of the x-axis labels.
void CalcYaxisRange()
Calculate the automatic range of the vertical axis and apply it.
void PlaceLegends(vector< TLegend *> legs, bool keepRange=false)
Setup the position of legends provided in legs array.
vector< vector< Borders > > legBorders
void DrawLatexUp(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize=-1.0, TString style="")
Draw latex up of frame1 and frame2.
void DivideTransparent(vector< double > divX, vector< double > divY, bool useMargins=true)
Construct the lattice of frames according to the provided x and y sizes using transparency trick...
void SetLeftRight(double lMargin, double rMargin)
Set simultaneously left and right margin of active pad.
void SetOffsets(double lX, double tX, double lY, double tY)
Set offsets of x,y labels and titles.
void SetFonts(double pxX, double pxY=-1, double pxT=-1)
Set text size of x- and y-axis titles and labels to the frame title.
void DividePad(vector< double > xDivs, vector< double > yDivs)
Construct the lattice of pads according to the provided x and y sizes.
vector< vector< pair< int, int > > > layOuts
vector< double > group(double frame, double space, int n)
Construct group of frames.
vector< double > repeat(vector< double > x, int n)
Repeat the provided pattern.
void SetFontsTicks(double px, double tickX, double tickY=-1.)
Set of the fonts and ticks sizes.
void UpdateFrame()
Redraw the current frame and axis ticks.
void SetTopBottom(double tMargin, double bMargin)
Set simultaneously top and bottom margin of active pad.
The namespace of whole Plotting Helper utility.
double TickAbsToRelX(double tick)
Convert tick length in px of x-axis to the relative units.
Point Abs2Px(Point p, double scaleUp, double scaleDn)
void DrawLatexRight(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize=-1.0, TString style="")
Draw latex right of frame1 and frame2.
void SetFTO(vector< double > fonts, vector< double > ticks, vector< double > offsets)
Set Fonts, Ticks and Offsets.
vector< double > merge(vector< double > v1, vector< double > v2={}, vector< double > v3={}, vector< double > v4={}, vector< double > v5={}, vector< double > v6={}, vector< double > v7={})
Merge vectors into one.
Contains coordinates object rectangle envelope.
void SetTitleOffsetX(double off)
Set offset of the x-axis title.
void SetLabelOffsetY(double off)
Set offset of the y-axis labels.
void DrawLegends(vector< TLegend *> legs, bool keepRange=false)
Draw legends provided in vector legs in such a way that there is no overlap.
void SetTicks(double tickX, double tickY=-1)
Set ticks sizes of x and y-axis in px.
TString SetLayout(unsigned pos)
Convert layout bit to string.
void DrawLatexDown(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize=-1.0, TString style="")
Draw latex down of frame1 and frame2.
void DrawLatexLeft(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize=-1.0, TString style="")
Draw latex left of frame1 and frame2.
void SetTitleOffsetY(double off)
Set offset of the y-axis title.
TLegend * newLegend(unsigned pos, int nCols=1)
Define new legend at position pos with nCols columns.
RectangleNDC GetNDC(TLatex *lat)
Calculates positions and height and width of rectangle which encapsulates TLatex. ...
Struct containing NDC sizes and positions of the corresponding TLatex.
double PxFontToRel(double px)
Transform font size from px to the relative units.
TH1 * GetFrame()
The method returns current frame on the active pad.
void GetLegendSizes(TLegend *leg, double &SizeX, double &SizeY, double &SizeYroot)
Calculates sizes of the legend in NDC.
void DrawLatex(TVirtualPad *pad1, TVirtualPad *pad2, double x, double y, TString text, double fSize=-1.0, TString style="")
Draw latex in coordinates x,y give a hull of two frames in given TPads.