Plotting Helper
plottingHelper.C
Go to the documentation of this file.
1 #include "plottingHelper.h"
2 
3 
7 namespace PlottingHelper {
8 
9 using namespace std;
10 
12 //Declaration of internal classes and structs
14 
15 namespace {
16 // Struct specifying borders of some object which can be approximated by rectangles
17 // We use such approach to define position of histograms
18 struct Borders{
19  vector<Rectangle> recs;
20  void GetHistBorders(TH1 *h);
21  void FromAbs2px(double scaleUp, double scaleDn);
22  void FromNDC2px();
23  static double Distance2(const Rectangle &r1, const Rectangle &r2);
24 };
25 
26 
27 
28 //Contains internal methods for automatic placement of legends
29 struct PLACER {
30  int nLeg;
31  vector<unsigned> dims;
32  vector<vector<pair<int,int>>> layOuts;
33  vector<vector<double>> distToHists;
34 
35  vector<vector<Borders>> legBorders;
36  vector<Borders> borders;
37 
38  vector<double> SizesX, SizesY;
39 
40  int nSteps = 11;
41  double minSepar;
42 
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,
48  int nScaleSteps=10);
49  void LoadHistoBorders(vector<Borders> &borders);
50  double analyze(const vector<int> &indx, vector<double> &dists);
51 
52 };
53 
54 // Iterator which goes over all positions specified in the constructor
55 //
56 // Note that bitwise "or" operator | can be used to select more complex layout
57 struct PosIterator {
58  PosIterator(int _nSteps, unsigned Pos) {
59  pos = Pos;
60  nSteps = _nSteps;
61  last = nSteps-1;
62  iSave = -1; jSave = nSteps;
63  //Iterate();
64  }
65  bool Iterate();
66 
67  int nSteps, last;
68  int iSave, jSave;
69  unsigned pos;
70 };
71 
72 }
73 
74 //Don't search for lower distance if minSkip reach
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);
77 
78 //Don't search for lower distance if minSkip reach
79 static double MinDistance2(double minSkip, const Borders &br1, const Borders &br2);
80 
81 
82 
83 
84 
88 
92 TH1 *GetFrame()
93 {
94  // get first histogram in the list of primitives
95 
96  TH1 *hobj = nullptr;
97 
98  TIter next(gPad->GetListOfPrimitives());
99  TObject *obj;
100  while ((obj = next())) {
101  if(obj->InheritsFrom(TH1::Class())) {
102  hobj = (TH1*)obj;
103  //hobj->DrawCopy("sameaxis");
104  break;
105  }
106  if(obj->InheritsFrom(TMultiGraph::Class())) {
107  TMultiGraph *mg = (TMultiGraph*)obj;
108  hobj = mg ? mg->GetHistogram() : nullptr;
109  //if (hobj) hobj->DrawCopy("sameaxis");
110  break;
111  }
112  if(obj->InheritsFrom(TGraph::Class())) {
113  TGraph *g = (TGraph*)obj;
114  hobj = g ? g->GetHistogram() : nullptr;
115  //hobj->DrawCopy("sameaxis");
116  break;
117  }
118  if(obj->InheritsFrom(THStack::Class())) {
119  THStack *hs = (THStack*)obj;
120  hobj = hs ? hs->GetHistogram() : nullptr;
121  //hobj->DrawCopy("sameaxis");
122  break;
123  }
124  }
125  if(!hobj) {cerr << "No frame created in active pad" << endl;}
126 
127  return hobj;
128 }
129 
131 TAxis *GetXaxis() {
132  TH1 *frame = GetFrame();
133  return frame ? frame->GetXaxis() : nullptr;
134 }
135 
137 TAxis *GetYaxis() {
138  TH1 *frame = GetFrame();
139  return frame ? frame->GetYaxis() : nullptr;
140 }
141 
143 TAxis *GetZaxis() {
144  TH1 *frame = GetFrame();
145  return frame ? frame->GetZaxis() : nullptr;
146 }
147 
149 
150 
151 
155 
161 double PxFontToRel(double px)
162 {
163  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
164  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
165 
166  if(pxW < pxH) return px/pxW;
167  else return px/pxH;
168 
169  //double pad_width = gPad->XtoPixel(gPad->GetX2());
170  //double pad_height = gPad->YtoPixel(gPad->GetY1());
171  //if(pxW < pxH) return px/pad_width / corX;
172  //else return px/pad_height / corY;
173 }
174 
175 
181 double RelFontToPx(double rel)
182 {
183  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
184  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
185  if(pxW < pxH) return rel*pxW;
186  else return rel*pxH;
187 }
188 
189 
192 {
193  //return (gPad->GetUxmax() - gPad->GetUxmin())/(gPad->GetX2() - gPad->GetX1());
194  return (1. - gPad->GetLeftMargin() - gPad->GetRightMargin());
195 }
196 
199 {
200  //return (gPad->GetUymax() - gPad->GetUymin())/(gPad->GetY2() - gPad->GetY1());
201  return (1. - gPad->GetBottomMargin() - gPad->GetTopMargin());
202 }
203 
205 double TickAbsToRelX(double tick)
206 {
207  double nom = GetAxisFractionX() * gPad->GetAbsHNDC() * gPad->GetWh();
208  return tick/nom;
209 }
210 
211 
213 double TickAbsToRelY(double tick)
214 {
215  double nom = GetAxisFractionY() * gPad->GetAbsWNDC() * gPad->GetWw();
216  return tick/nom;
217 }
218 
220 
224 
230 void SetFonts(double pxX, double pxY, double pxT)
231 {
232  TH1 *frame = GetFrame();
233  if(!frame) return;
234 
235  if(pxY < 0) pxY = pxX;
236  if(pxT < 0) pxT = pxX;
237 
238  double relSizeX = PxFontToRel(pxX);
239  double relSizeY = PxFontToRel(pxY);
240  double relSizeT = PxFontToRel(pxT);
241 
242  frame->GetXaxis()->SetTitleSize(relSizeX);
243  frame->GetXaxis()->SetLabelSize(relSizeX);
244 
245  frame->GetYaxis()->SetTitleSize(relSizeY);
246  frame->GetYaxis()->SetLabelSize(relSizeY);
247 
248  frame->SetTitleSize(relSizeT);
249 }
250 
254 void SetTicks(double tickX, double tickY)
255 {
256  TH1 *frame = GetFrame();
257  if(!frame) return;
258 
259  //gPad->Update();
260  if(tickY < 0) tickY = tickX;
261  frame->GetXaxis()->SetTickSize(TickAbsToRelX(tickX) );
262  frame->GetYaxis()->SetTickSize(TickAbsToRelY(tickY) );
263 }
264 
270 void SetLabelOffsetX(double off)
271 {
272  TH1 *frame = GetFrame();
273  if(!frame) return;
274 
275  double labSize = frame->GetXaxis()->GetLabelSize();
276  double off0 = 0;
277  if(gPad->GetLogx()) {
278  off0 = -1.15;
279  if(frame->GetXaxis()->GetNoExponent()) off0 += 0.33;
280  }
281  else {
282  off0 = -0.8;
283  }
284 
285  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
286  double fact = RelFontToPx(labSize)/pxH;
287  off *= fact *3/4.; //conversion to "1354" height
288 
289 
290  off += off0 * labSize;
291  frame->GetXaxis()->SetLabelOffset(off);
292 }
293 
294 
295 
296 
306 void SetTitleOffsetX(double off)
307 {
308  TH1 *frame = GetFrame();
309  if(!frame) return;
310 
311  TAxis *ax = frame->GetXaxis();
312  off *= 3/4.;
313  ax->SetTitleOffset(off* RelFontToPx(ax->GetTitleSize())/1.6 / ( gPad->GetWh()* ax->GetTitleSize()*gPad->GetAbsHNDC() ) );
314 }
315 
323 void SetLabelOffsetY(double off)
324 {
325  TH1 *frame = GetFrame();
326  if(!frame) return;
327  TAxis *ax = frame->GetYaxis();
328  double labSize = ax->GetLabelSize();
329  double pxW = gPad->GetWw() * gPad->GetAbsWNDC() ;
330  double fact = RelFontToPx(labSize)/pxW;
331 
332  double off0 = 0;
333  if(gPad->GetLogy())
334  off0 = -0.08;
335 
336 
337  off *= 3/4.;
338  ax->SetLabelOffset(off * fact + off0*labSize );
339 }
340 
349 void SetTitleOffsetY(double off)
350 {
351  TH1 *frame = GetFrame();
352  if(!frame) return;
353  TAxis *ax = frame->GetYaxis();
354  off *= 3/4.;//to vertical size of "0"
355  ax->SetTitleOffset( off* RelFontToPx(ax->GetTitleSize())/1.6 / ( gPad->GetWw()*ax->GetTitleSize()* gPad->GetAbsWNDC() ) );
356 }
357 
362 void SetFontsTicks(double px, double tickX, double tickY)
363 {
364  SetFonts(px);
365  SetTicks(tickX, tickY);
366 }
367 
374 void SetOffsets(double lX, double tX, double lY, double tY)
375 {
376  SetLabelOffsetX(lX);
377  SetTitleOffsetX(tX);
378  SetLabelOffsetY(lY);
379  SetTitleOffsetY(tY);
380 }
381 
386 void SetFTO(vector<double> fonts, vector<double> ticks, vector<double> offsets)
387 {
388  fonts.resize(3, -1);
389  ticks.resize(2, -1);
390  offsets.resize(4, 0);
391 
392  SetFonts(fonts[0], fonts[1], fonts[2]);
393  SetTicks(ticks[0], ticks[1]);
394  SetOffsets(offsets[0], offsets[1], offsets[2], offsets[3]);
395 }
396 
398 
399 
400 
407 
422 void DrawLatex(TVirtualPad *pad1, TVirtualPad *pad2, double x, double y, TString text, double fSize, TString style)
423 {
424  TVirtualPad *padOrg = gPad;
425  assert(pad1->GetCanvas() == pad2->GetCanvas());
426  TCanvas *can = pad1->GetCanvas();
427 
428  //Setting of style
429  TLatex *tex = new TLatex();
430 
431  int hAlign = 2;
432  int vAlign = 2;
433 
434  double angle;
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;
440  angle = 90;
441  }
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;
447  angle = 270;
448  }
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;
454  angle = 180;
455  }
456  else {
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;
461  angle = 0;
462  }
463 
464  tex->SetTextAlign(10*hAlign + vAlign);
465  tex->SetTextAngle(angle);
466  tex->SetTextFont(42);
467 
468  double l[2], r[2], b[2], t[2];
469 
470  TVirtualPad *pads[] = {pad1, pad2};
471 
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());
477  }
478 
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]);
483 
484  double xGlob = left + (right-left) *x;
485  double yGlob = bottom + (top-bottom) *y;
486 
487 
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]) ) {
492  pads[i]->cd();
493  if(fSize < 0) {
494  TH1 *frame = GetFrame();
495  fSize = frame ? RelFontToPx(frame->GetTitleSize()) : 12;
496  }
497  tex->SetTextSize(PxFontToRel(fSize));
498 
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);
503 
504 
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());
509 
510  //TLine *l = new TLine();
511  //l->SetLineColor(kRed);
512  //l->DrawLineNDC(xLoc, yLoc, xLoc + 0.1, yLoc);
513  tex->DrawLatexNDC(xLoc, yLoc, text);
514  isInside = true;
515  }
516  }
517 
518  if(!isInside) {
519  if(fSize < 0) {
520  pads[0]->cd();
521  TH1 *frame = GetFrame();
522  fSize = frame ? RelFontToPx(frame->GetTitleSize()) : 12;
523  }
524  can->cd();
525  tex->SetTextSize(PxFontToRel(fSize));
526  tex->DrawLatexNDC(xGlob, yGlob, text);
527  }
528 
529  gPad->Update();
530  padOrg->cd();
531 }
532 
533 
537 void DrawLatex(TVirtualPad *pad, double x, double y, TString text, double fSize, TString style)
538 {
539  DrawLatex(pad, pad, x, y, text, fSize, style);
540 }
541 
542 
546 void DrawLatex(double x, double y, TString text, double fSize, TString style)
547 {
548  DrawLatex(gPad, x, y, text, fSize, style);
549 }
550 
551 
555 static void DrawLatexLRTB(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize, TString style)
556 {
557  TVirtualPad *padOrg = gPad;
558  if(fSize < 0) {
559  pad1->cd();
560  TH1 *frame = GetFrame();
561  fSize = frame ? RelFontToPx(frame->GetTitleSize()) : 12;
562  padOrg->cd();
563  }
564  auto Close = [](double x, double val) {return abs(x-1000*val) <1000;};
565 
566  double x = 0.5, y = 0.5;
567 
568 
569  double b[2], t[2], l[2], r[2];
570 
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());
577  }
578 
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]);
583 
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) );
588 
589  if(Close(Offset,2)) y = 1 + unit*(Offset - 2000);
590  else y = 0 - unit*(Offset - 8000);
591 
592  }
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) );
597 
598  if(Close(Offset,6)) x = 1 + unit*(Offset - 6000);
599  else x = 0 - unit*(Offset - 4000);
600  }
601  else
602  assert(0);
603 
604  DrawLatex(pad1, pad2, x, y, text, fSize, style);
605 }
606 
611 void DrawLatexUp(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize, TString style) {
612  DrawLatexLRTB(pad1, pad2, 2000 + Offset, text, fSize, style);
613 }
614 
616 void DrawLatexDown(TVirtualPad *pad1,TVirtualPad *pad2, double Offset, TString text, double fSize, TString style) {
617  DrawLatexLRTB(pad1, pad2, 8000 + Offset, text, fSize, style);
618 }
619 
621 void DrawLatexRight(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize, TString style) {
622  DrawLatexLRTB(pad1, pad2, 6000 + Offset, text, fSize, style);
623 }
624 
626 void DrawLatexLeft(TVirtualPad *pad1, TVirtualPad *pad2, double Offset, TString text, double fSize, TString style) {
627  DrawLatexLRTB(pad1, pad2, 4000 + Offset, text, fSize, style);
628 }
629 
630 
632 void DrawLatexUp(TVirtualPad *pad, double Offset, TString text, double fSize, TString style) {
633  DrawLatexUp(pad, pad, Offset, text, fSize, style);
634 }
635 
637 void DrawLatexDown(TVirtualPad *pad, double Offset, TString text, double fSize, TString style) {
638  DrawLatexDown(pad, pad, Offset, text, fSize, style);
639 }
640 
642 void DrawLatexRight(TVirtualPad *pad, double Offset, TString text, double fSize, TString style) {
643  DrawLatexRight(pad, pad, Offset, text, fSize, style);
644 }
645 
647 void DrawLatexLeft(TVirtualPad *pad, double Offset, TString text, double fSize, TString style) {
648  DrawLatexLeft(pad, pad, Offset, text, fSize, style);
649 }
650 
651 
653 void DrawLatexUp(double Offset, TString text, double fSize, TString style) {
654  DrawLatexUp(gPad, Offset, text, fSize, style);
655 }
657 void DrawLatexDown(double Offset, TString text, double fSize, TString style) {
658  DrawLatexDown(gPad, Offset, text, fSize, style);
659 }
661 void DrawLatexRight(double Offset, TString text, double fSize, TString style) {
662  DrawLatexRight(gPad, Offset, text, fSize, style);
663 }
665 void DrawLatexLeft(double Offset, TString text, double fSize, TString style) {
666  DrawLatexLeft(gPad, Offset, text, fSize, style);
667 }
668 
669 
670 
671 
673 
674 
678 
687 TString SetLayout(unsigned pos)
688 {
689  return to_string(pos);
690 }
691 
692 
693 static unsigned SimplifyPos(unsigned pos)
694 {
695  if(pos & kPos5) return kPos5;
696  if(pos & kPos2) pos &= !kPos1 & !kPos3;
697  if(pos & kPos4) pos &= !kPos1 & !kPos7;
698  if(pos & kPos6) pos &= !kPos3 & !kPos9;
699  if(pos & kPos8) pos &= !kPos7 & !kPos9;
700  return pos;
701 }
702 
703 
709 RectangleNDC GetNDC(TLatex *lat)
710 {
711 
712  int hAlign = lat->GetTextAlign() / 10 - 1;
713  int vAlign = lat->GetTextAlign() % 10 - 1;
714  if(vAlign == -1) vAlign = 0;
715 
716  RectangleNDC rTitle;
717 
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();
722 
723 
724  if(lat->GetTextAngle() == 0) {
725  rTitle.fX -= hAlign*rTitle.fWidth/2.;
726  rTitle.fY -= vAlign*rTitle.fHeight/2.;
727  }
728  else {
729  swap(rTitle.fWidth, rTitle.fHeight);
730  double rat = gPad->GetWh() / double(gPad->GetWw());
731  rat /= gPad->GetAbsWNDC() / double(gPad->GetAbsHNDC());
732  rTitle.fWidth *= rat;
733  rTitle.fHeight *= 1./rat;
734 
735  if(lat->GetTextAngle() == 90) {
736  rTitle.fY -= (hAlign)*rTitle.fHeight/2.;
737  vAlign = 2-vAlign;
738  rTitle.fX -=1.*vAlign*rTitle.fWidth/2.;
739  }
740  else if(lat->GetTextAngle() == 270) {
741  hAlign = 2-hAlign;
742  rTitle.fY -= (hAlign)*rTitle.fHeight/2.;
743  rTitle.fX -=1.*vAlign*rTitle.fWidth/2.;
744  }
745  }
746  rTitle.lat = lat;
747  return rTitle;
748 }
749 
756 TLegend *newLegend(unsigned pos, int nCols)
757 {
758  TLegend *leg = new TLegend(0., 0., 0., 0.);
759  leg->SetName(SetLayout(pos));
760 
761  TAxis *axY = GetYaxis();
762  if(axY == nullptr) {
763  cerr << "There is no frame created, legend can't be plotted." << endl;
764  assert(0);
765  }
766  leg->SetTextSize(axY->GetTitleSize());
767  leg->SetNColumns(nCols);
768  return leg;
769 }
770 
775 void GetLegendSizes(TLegend *leg, double &SizeX, double &SizeY, double &SizeYroot)
776 {
777 
778  double lineSeparation = 1.0;
779  double markerSize = 1.5;
780  double columnSeparation = 0;
781 
782  //double fontSize = RelFontToPx(GetYaxis()->GetTitleSize());
783  double fontSize = RelFontToPx(leg->GetTextSize());
784 
785  gPad->Update();
786  //cout <<"There is just start " << gPad->GetUymax() << " "<< gPad->GetUymin() << endl;
787 
788  leg->SetBorderSize(0);
789  //leg->SetLineStyle(2);
790  leg->SetFillStyle(0);
791  leg->SetTextSize(PxFontToRel(fontSize));
792 
793  double fSizeNDCy = fontSize / (gPad->GetWh() * gPad->GetAbsHNDC());
794  double fSizeNDCx = fontSize / (gPad->GetWw() * gPad->GetAbsWNDC());
795 
796  int nHeaders = 0;
797  int nLegItems = 0;
798 
799  int nCols = leg->GetNColumns();
800  vector<double> maxC(nCols, 0);
801  double headerW = 0;
802  int colId = 0;
803  for(const auto &&entry : *leg->GetListOfPrimitives()) {
804  TString lab = dynamic_cast<TLegendEntry *>(entry)->GetLabel();
805  TString opt = dynamic_cast<TLegendEntry *>(entry)->GetOption();
806  //cout << "Label "<< leg->GetNRows()<<" " << lab << endl;
807  TLatex *lat = new TLatex(0.5, 0.5, lab);
808  lat->SetTextSize(leg->GetTextSize());
809  lat->SetTextFont(leg->GetTextFont());
810 
811  double textW = GetNDC(lat).fWidth;
812  if(opt == "h") {
813  headerW = max(headerW, textW);
814  ++nHeaders;
815  colId = -1;
816  }
817  else {
818  maxC[colId] = max(maxC[colId], textW);
819  ++nLegItems;
820  }
821  colId = (colId != nCols-1) ? colId + 1 : 0;
822  delete lat;
823  }
824  double maxW = accumulate(maxC.begin(),maxC.end(),0.);
825 
826  int nRows = nHeaders + (nLegItems+nCols-1)/nCols;
827  //cout << "MyTag nRows " << nRows << endl;
828  SizeY = lineSeparation*fSizeNDCy*nRows;
829 
830  headerW += 0.1*fSizeNDCx*markerSize;
831 
832  SizeX = max(nCols*fSizeNDCx*markerSize +
833  (nCols-1)*fSizeNDCx*columnSeparation + maxW, headerW);
834  leg->SetMargin( nCols*fSizeNDCx*markerSize / SizeX);
835 
836  leg->SetColumnSeparation((nCols-1)*fSizeNDCx*columnSeparation / SizeX);
837 
838 
839  SizeYroot = lineSeparation*fSizeNDCy*leg->GetNRows();
840 
841 }
842 
847 void PlaceLegends(vector<TLegend*> legs, bool keepRange)
848 {
849  int nScaleSteps = keepRange ? 1 : 20;
850 
851  vector<double> sizesX, sizesY, sizesYroot;
852 
853  for(unsigned i = 0; i < legs.size(); ++i) {
854  double SizeX, SizeY, SizeYroot;
855  GetLegendSizes(legs[i], SizeX, SizeY, SizeYroot);
856  sizesX.push_back(SizeX);
857  sizesY.push_back(SizeY);
858  sizesYroot.push_back(SizeYroot);
859  }
860 
861  PLACER placer;
862  gPad->Update();
863 
864  placer.init(legs, sizesX, sizesY);
865 
866  vector<double> xx, yy;
867  double scaleUp, scaleDn;
868  tie(scaleUp, scaleDn) = placer.GetSolution(xx, yy, nScaleSteps);
869  //return;
870 
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]);
876  }
877 
878 
879  TH1 *frameNow = GetFrame();
880  if(gPad->GetLogy()) {
881  //double Max = frameNow->GetMaximum();
882  //double Min = frameNow->GetMinimum();
883  double Max = pow(10,gPad->GetUymax());
884  double Min = pow(10,gPad->GetUymin());
885 
886  frameNow->SetMaximum(Min * pow(Max/Min, scaleUp));
887  frameNow->SetMinimum(Max / pow(Max/Min, scaleDn));
888  }
889  else {
890  double Max = gPad->GetUymax();
891  double Min = gPad->GetUymin();
892 
893  frameNow->SetMaximum(Min + (Max-Min)*scaleUp);
894  frameNow->SetMinimum(Max - (Max-Min)*scaleDn);
895  }
896 
897  /*
898  for(unsigned i = 0; i < legs.size(); ++i) {
899  TLine *l = new TLine;
900  l->SetNDC();
901  l->DrawLineNDC(xx[i], yy[i], xx[i]+sizesX[i], yy[i]);
902  l->DrawLineNDC(xx[i], yy[i]+sizesY[i], xx[i]+sizesX[i], yy[i]+sizesY[i]);
903  l->DrawLineNDC(xx[i], yy[i], xx[i], yy[i]+sizesY[i]);
904  l->DrawLineNDC(xx[i]+sizesX[i], yy[i], xx[i]+sizesX[i], yy[i]+sizesY[i]);
905  }
906  */
907 
908 
909 }
910 
916 void DrawLegends(vector<TLegend*> legs, bool keepRange)
917 {
918  PlaceLegends(legs, keepRange);
919  for(auto & leg : legs)
920  leg->Draw();
921 }
922 
924 
925  bool PosIterator::Iterate() {
926  int last = nSteps-1;
927  int i=0, j=0;
928  //cout << iSave <<" "<< jSave <<" "<< nSteps<< endl;
929  for(i = iSave; i < nSteps; ++i)
930  for(j = (jSave+1)*(i==iSave); j < nSteps; ++j) {
931  if(pos & kPos5)
932  goto after;
933  if((pos & kPos9) && i==0 && j==last)
934  goto after;
935  if((pos & kPos7) && i==0 && j==0)
936  goto after;
937  if((pos & kPos1) && i==last && j==0)
938  goto after;
939  if((pos & kPos3) && i==last && j==last)
940  goto after;
941 
942  if((pos & kPos8c) && i==0 && j==last/2)
943  goto after;
944  if((pos & kPos4c) && i==last/2 && j==0)
945  goto after;
946  if((pos & kPos6c) && i==last/2 && j==last)
947  goto after;
948  if((pos & kPos2c) && i==last && j==last/2)
949  goto after;
950 
951  if((pos & kPos8) && i==0)
952  goto after;
953  if((pos & kPos2) && i==last)
954  goto after;
955  if((pos & kPos4) && j==0)
956  goto after;
957  if((pos & kPos6) && j==last)
958  goto after;
959 
960  }
961  after:
962  iSave = i;
963  jSave = j;
964  //cout << "myTag2 " << i << " "<< j << endl;
965  if(i > last)
966  return false;
967  else
968  return true;
969  }
970 
971 
972 
973 
974 
975 
976  //Initalize layOuts, dims, legBorders, borders
977  void PLACER::init(vector<TLegend *> legs, vector<double> &sizesX, vector<double> &sizesY) {
978  nLeg = legs.size();
979  for(auto & leg : legs) {
980  unsigned layOut = atoi(leg->GetName());
981 
982  vector<pair<int,int>> pos;
983 
984  PosIterator iter(nSteps, layOut);
985  while(iter.Iterate()) {
986  pos.push_back(make_pair(iter.iSave, iter.jSave));
987  }
988  layOuts.push_back(pos);
989  }
990 
991  dims.resize(layOuts.size());
992  for(unsigned i = 0; i < dims.size(); ++i)
993  dims[i] = layOuts[i].size();
994  SizesX = sizesX;
995  SizesY = sizesY;
996  GetLegendsPositions();
997 
998  }
999 
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;
1005 
1006  double maxDist = 0;
1007 
1008  while (1) {
1009  // Print
1010  double dist = analyze(idxs, distsNow);
1011 
1012  if(dist >= maxDist) {
1013  bool state = true;
1014  for(int i = 0; i < nLeg; ++i) {
1015  state = state && distsNow[i] >= distsBest[i];
1016  }
1017  if(dist > maxDist || (dist == maxDist && state)) {
1018  bestLayout = idxs;
1019  distsBest = distsNow;
1020  }
1021  maxDist = dist;
1022  }
1023 
1024  // Update
1025  unsigned j;
1026  for(j = 0; j < dims.size(); ++j) {
1027  idxs[j]++;
1028  if (idxs[j] < static_cast<int>(dims[j])) break;
1029  idxs[j] = 0;
1030  }
1031  if (j == dims.size()) break;
1032  }
1033  return make_pair(maxDist, bestLayout);
1034  }
1035 
1036 
1037  void PLACER::GetLegendsPositions() {
1038 
1039  LoadHistoBorders(borders);
1040 
1041  legBorders.resize(nLeg);
1042 
1043  double fontSize = RelFontToPx(GetYaxis()->GetTitleSize());
1044  minSepar = 0.5*fontSize; //inPixels
1045 
1046  TH1 *frameNow = GetFrame();
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();
1051 
1052  double fSizeNDCy = minSepar / (gPad->GetWh() * gPad->GetAbsHNDC());
1053  double fSizeNDCx = minSepar / (gPad->GetWw() * gPad->GetAbsWNDC());
1054 
1055 
1056  for(int k = 0; k < nLeg; ++k) {
1057 
1058  double SizeX = SizesX[k];
1059  double SizeY = SizesY[k];
1060 
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;
1065 
1066 
1067  legBorders[k].resize(dims[k]);
1068 
1069  for(unsigned l = 0; l < dims[k]; ++l) {
1070  int i = layOuts[k][l].first;
1071  int j = layOuts[k][l].second;
1072 
1073  double xx = xMin + (xMax-xMin)/(nSteps-1) * j;
1074  double yy = yMax - (yMax-yMin)/(nSteps-1) * i;
1075 
1076 
1077  //Legend borders
1078  legBorders[k][l].recs.push_back({xx, yy, SizeX, SizeY});
1079  legBorders[k][l].FromNDC2px();
1080 
1081  }
1082  }
1083  }
1084 
1085 
1086  void PLACER::GetDistancesPx(double scaleUp, double scaleDn) {
1087  auto bordersPx = borders;
1088  for(auto &b : bordersPx)
1089  b.FromAbs2px(scaleUp, scaleDn);
1090 
1091  distToHists.resize(nLeg);
1092 
1093  for(int i = 0; i < nLeg; ++i) {
1094  distToHists[i].resize(dims[i]);
1095  for(unsigned l = 0; l < dims[i]; ++l)
1096  distToHists[i][l] = MinDistanceSingle(bordersPx, legBorders[i][l], 0.99*minSepar);
1097  }
1098  }
1099 
1100 
1101  pair<double,double> PLACER::GetSolution(vector<double> &xx, vector<double> &yy,
1102  int nScaleSteps) {
1103 
1104  double scaleUp=1., scaleDn=1.;
1105 
1106  vector<int> bestLayout;
1107 
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.);
1114 
1115  GetDistancesPx(scaleUp, scaleDn);
1116  //double dist = iterate(&bestLayout);
1117  double dist;
1118  tie(dist, bestLayout) = iterate();
1119 
1120  if(dist > minSepar)
1121  goto gotoAfterScaleLoop;
1122  }
1123  cerr << "No solution without overlaps found for legends" << endl;
1124 
1125  gotoAfterScaleLoop:
1126 
1127  xx.resize(nLeg);
1128  yy.resize(nLeg);
1129  for(int i = 0; i < nLeg; ++i) {
1130  Point p;
1131  p.x = legBorders[i][bestLayout[i]].recs[0].fX;
1132  p.y = legBorders[i][bestLayout[i]].recs[0].fY;
1133  p = Px2NDC(p);
1134  xx[i] = p.x;
1135  yy[i] = p.y;
1136  }
1137 
1138  return {scaleUp, scaleDn};
1139  //cout << "done " << maxDist << endl;
1140  }
1141 
1142 
1143 
1144 
1145  void PLACER::LoadHistoBorders(vector<Borders> &borders)
1146  {
1147  //Load histograms
1148  vector<TObject *> hists;
1149  for(const auto &&prim : *gPad->GetListOfPrimitives()) {
1150  //cout << prim->GetName() <<" "<< prim->ClassName() << endl;
1151  if(strcmp(prim->GetName(),"hframe") && strcmp(prim->ClassName(),"TH1F"))
1152  if(dynamic_cast<TH1*>(prim))
1153  hists.push_back(prim);
1154  }
1155 
1156 
1158  //GetDistance
1160  if(hists.size() == 0) {
1161  gPad->Modified();
1162  return;
1163  }
1164 
1165  for(unsigned i = 0; i < hists.size(); ++i) {
1166  Borders br;
1167  br.GetHistBorders(dynamic_cast<TH1*>(hists[i]));
1168  borders.push_back(br);
1169  }
1170 
1171  }
1172 
1173 
1174  double PLACER::analyze(const vector<int> &indx, vector<double> &dists)
1175  {
1176  double minDist = 1e40;
1177  //Distances to histograms
1178  for(unsigned k = 0; k < indx.size(); ++k) {
1179  //cout << "BBB " << distToHists[k].size()<<" "<< indx[k] << endl;
1180  //cout << "MinDist " << minDist <<" "<< distToHists[k][indx[k]] << endl;
1181  minDist = min(minDist, distToHists[k][indx[k]]);
1182  dists[k] = distToHists[k][indx[k]];
1183  if(minDist < minSepar)
1184  return minDist;
1185  }
1186 
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,
1190  legBorders[k][indx[k]], legBorders[l][indx[l]]);
1191  minDist = min(minDist, dist);
1192  dists[k] = min(dists[k], dist);
1193  if(minDist < minSepar)
1194  return minDist;
1195  }
1196 
1197 
1198  return minDist;
1199 
1200  }
1201 
1202 
1203 
1204 Point Abs2Px(Point p, double scaleUp, double scaleDn)
1205 {
1206  double valXmin = gPad->GetX1();
1207  double valXmax = gPad->GetX2();
1208 
1209  double valYmin = gPad->GetY2() - scaleDn*(gPad->GetY2()-gPad->GetY1());
1210  double valYmax = gPad->GetY1() + scaleUp*(gPad->GetY2()-gPad->GetY1());
1211 
1212 
1213  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1214  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1215 
1216 
1217  if(gPad->GetLogx()) p.x = log10(p.x);
1218  if(gPad->GetLogy()) p.y = log10(p.y);
1219 
1220  p.x = (p.x - valXmin)/(valXmax-valXmin) * pxW;
1221  p.y = (p.y - valYmin)/(valYmax-valYmin) * pxH;
1222 
1223  //cout << p.x <<" "<< p.y << endl;
1224  return p;
1225 }
1226 
1228 {
1229  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1230  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1231  p.x = p.x/pxW;
1232  p.y = p.y/pxH;
1233  return p;
1234 }
1235 
1236 
1237 
1238 static double MinDistanceSingle(vector<Borders> &bor, double minSkip, double x, double y, double w, double h)
1239 {
1240  Borders bS;
1241  bS.recs.push_back( {x, y, w, h} );
1242  bS.FromNDC2px();
1243 
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;
1249  }
1250  return sqrt(minDist);
1251 }
1252 
1253 
1254 static double MinDistanceSingle(vector<Borders> &bor, Borders bSingle, double minSkip)
1255 {
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;
1261  }
1262  return sqrt(minDist);
1263 }
1264 
1265 
1266 
1267 static double MinDistance2(double minSkip, const Borders &br1, const Borders &br2)
1268 {
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;
1275  }
1276  return minDist;
1277 
1278 }
1279 
1280 
1281 void Borders::FromNDC2px()
1282 {
1283  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1284  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1285 
1286  for(Rectangle &r : recs) {
1287  r.fX *= pxW;
1288  r.fY *= pxH;
1289  r.fWidth *= pxW;
1290  r.fHeight *= pxH;
1291  }
1292 }
1293 
1294 /*
1295 void Borders::FromPx2NDC()
1296 {
1297  double pxH = gPad->GetWh()*gPad->GetAbsHNDC();
1298  double pxW = gPad->GetWw()*gPad->GetAbsWNDC();
1299 
1300  for(Rectangle &r : recs) {
1301  r.fX /= pxW;
1302  r.fY /= pxH;
1303  r.fWidth /= pxW;
1304  r.fHeight /= pxH;
1305  }
1306 }
1307 */
1308 
1309 
1310 
1311 void Borders::FromAbs2px(double scaleUp, double scaleDn)
1312 {
1313  for(Rectangle &r : recs) {
1314  Point p1(r.fX, r.fY);
1315  Point p2(r.fX+r.fWidth, r.fY+r.fHeight);
1316 
1317  p1 = Abs2Px(p1, scaleUp, scaleDn);
1318  p2 = Abs2Px(p2, scaleUp, scaleDn);
1319  r.fX = p1.x;
1320  r.fY = p1.y;
1321  r.fWidth = p2.x-p1.x;
1322  r.fHeight = p2.y-p1.y;
1323  }
1324 }
1325 
1329 void Borders::GetHistBorders(TH1 *h)
1330 {
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);
1336 
1337  const double lim = 1e-30;
1338 
1339  if(gPad->GetLogx()) {
1340  xMin = max(lim, xMin);
1341  xMax = max(lim, xMax);
1342  }
1343  if(gPad->GetLogy()) {
1344  yMin = max(lim, yMin);
1345  yMax = max(lim, yMax);
1346  }
1347  recs.push_back({xMax, yMin, xMax-xMin, yMax-yMin});
1348 
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);
1356  }
1357  double yMinNow = min(yMin, yMinLeft);
1358  double yMaxNow = max(yMax, yMaxLeft);
1359  recs.push_back({xMin, yMinNow, 0., yMaxNow-yMinNow});
1360  }
1361  }
1362 }
1363 
1364 
1365 
1366 
1367 
1368 
1369 static double hypot2(double x, double y) {return x*x+y*y;}
1370 
1372 double Borders::Distance2(const Rectangle &r1, const Rectangle &r2)
1373 {
1374  double x1 = r1.fX;
1375  double x1b = r1.fX + r1.fWidth;
1376  double x2 = r2.fX;
1377  double x2b = r2.fX + r2.fWidth;
1378 
1379  double y1 = r1.fY;
1380  double y1b = r1.fY + r1.fHeight;
1381  double y2 = r2.fY;
1382  double y2b = r2.fY + r2.fHeight;
1383 
1384  bool left = x2b < x1;
1385  bool right = x1b < x2;
1386  bool bottom = y2b < y1;
1387  bool top = y1b < y2;
1388  if(top && left)
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);
1396  else if(left)
1397  return hypot2(x1 - x2b,0.);
1398  else if(right)
1399  return hypot2(x2 - x1b,0.);
1400  else if(bottom)
1401  return hypot2(y1 - y2b,0.);
1402  else if(top)
1403  return hypot2(y2 - y1b,0.);
1404  else
1405  return 0.;
1406 }
1407 
1408 
1409 
1413 
1419 {
1420  gPad->Update();
1421  gPad->RedrawAxis();
1422  TFrame *fr = gPad->GetFrame();
1423  if(fr) {
1424  fr->SetFillStyle(0);
1425  fr->Draw();
1426  }
1427  else
1428  cerr << "No frame at active pad" << endl;
1429  gPad->Update();
1430 }
1431 
1432 
1440 {
1441  TH1 *hFrame = GetFrame();
1442  if(!hFrame) return;
1443  TAxis *ax = hFrame->GetXaxis();
1444 
1445  int iFirst = ax->GetFirst();
1446  int iLast = ax->GetLast();
1447 
1448  double xMin = ax->GetBinLowEdge(iFirst);
1449  double xMax = ax->GetBinLowEdge(iLast) + ax->GetBinWidth(iLast);
1450 
1451 
1452  double widthMin=0, widthMax=0;
1453  double centerMin=0, centerMax=0;
1454  //return ;
1455  double yMin = 1e100, yMax = -1e100;
1456  for(auto && obj : *gPad->GetListOfPrimitives()) {
1457 
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);
1466 
1467 
1468  if(obj->InheritsFrom(TH1::Class()) ||
1469  obj->InheritsFrom(TMultiGraph::Class()) ||
1470  obj->InheritsFrom(TGraph::Class()) ||
1471  obj->InheritsFrom(THStack::Class()) ) {
1472 
1473  obj->Paint();
1474  //double zoom = gPad->GetUymax() - gPad->GetUymin();
1475  double yMinNow = gPad->GetUymin();
1476  double yMaxNow = gPad->GetUymax();
1477 
1478  if(yMinNow < yMin) {
1479  yMin = yMinNow;
1480  widthMin = yMaxNow - yMinNow;
1481  centerMin = (yMaxNow + yMinNow)/2.;
1482  }
1483  if(yMaxNow > yMax) {
1484  yMax = yMaxNow;
1485  widthMax = yMaxNow - yMinNow;
1486  centerMax = (yMaxNow + yMinNow)/2.;
1487  }
1488  }
1489  }
1490 
1491 
1492  double width = yMax - yMin;
1493 
1494 
1495  double zoomMin = width / widthMin;
1496  double zoomMax = width / widthMax;
1497 
1498  if(yMin >= 0. && !gPad->GetLogy())
1499  yMin = max(0., centerMin - zoomMin * widthMin/2.);
1500  else
1501  yMin = centerMin - zoomMin * widthMin/2.;
1502  yMax = centerMax + zoomMax * widthMax/2.;
1503 
1504 
1505  if(gPad->GetLogy()) {
1506  hFrame->SetMinimum(pow(10,yMin));
1507  hFrame->SetMaximum(pow(10,yMax));
1508  }
1509  else {
1510  hFrame->SetMinimum(yMin);
1511  hFrame->SetMaximum(yMax);
1512  }
1513 }
1514 
1521 void SetLeftRight(double lMargin, double rMargin)
1522 {
1523  gPad->SetLeftMargin(0);
1524  gPad->SetRightMargin(0);
1525  gPad->SetLeftMargin(lMargin);
1526  gPad->SetRightMargin(rMargin);
1527 }
1528 
1535 void SetTopBottom(double tMargin, double bMargin)
1536 {
1537  gPad->SetTopMargin(0);
1538  gPad->SetBottomMargin(0);
1539  gPad->SetTopMargin(tMargin);
1540  gPad->SetBottomMargin(bMargin);
1541 }
1542 
1543 
1544 
1559 void DividePad(vector<double> xDivs, vector<double> yDivs)
1560 {
1561  TVirtualPad *orgPad = gPad;
1562 
1563  double lMag = orgPad->GetLeftMargin();
1564  double rMag = orgPad->GetRightMargin();
1565  double tMag = orgPad->GetTopMargin();
1566  double bMag = orgPad->GetBottomMargin();
1567 
1568  int nx = xDivs.size();
1569  int ny = yDivs.size();
1570 
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);
1579 
1580 
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];
1585 
1586  double yt = (iy == 0) ? 1 : 1-tMag-yPos[iy];
1587  double yb = (iy == ny-1) ? 0 : 1-tMag-yPos[iy+1];
1588 
1589  int id = iy*nx+ix+1;
1590  TPad *pad = new TPad(SF("%s_%d", orgPad->GetName(), id), "", xl, yb, xr, yt);
1591 
1592 
1593  double lNew = (ix == 0) ? lMag/(xr - xl) : 0;
1594  double rNew = (ix == nx-1) ? rMag/(xr - xl) : 0;
1595 
1596  double tNew = (iy == 0) ? tMag/(yt - yb) : 0;
1597  double bNew = (iy == ny-1) ? bMag/(yt - yb) : 0;
1598 
1599 
1600 
1601 
1602  pad->cd();
1603  SetLeftRight(lNew, rNew);
1604  SetTopBottom(tNew, bNew);
1605  orgPad->cd();
1606 
1607 // if(ix == nx-1) {
1608 // cout << "Hela : " << lMag + xPos[nx-1] << endl;
1609 // cout << "lMag rMag : " <<lMag <<" "<< rMag << endl;
1610 // cout << "Ratio " << rMag / (1-lMag-xPos[nx-1]) << endl;
1611 // }
1612 
1613  pad->SetNumber(id);
1614  pad->Draw();
1615  }
1616 }
1617 
1618 
1619 
1620 
1643 void DivideTransparent(vector<double> divX, vector<double> divY, bool useMargins)
1644 {
1645 
1646  TVirtualPad *orgPad = gPad;
1647 
1648  if(divX.size() % 2 != 1 || int(divX.size()) < (3-2*useMargins) ) {
1649  cerr << "Wrong divX= " << divX.size() << endl;
1650  return;
1651  }
1652  if(divY.size() % 2 != 1 || int(divY.size()) < (3-2*useMargins) ) {
1653  cerr << "Wrong divY= " << divY.size() << endl;
1654  return;
1655  }
1656 
1657 
1658 
1659  double sumX = accumulate(divX.begin(), divX.end(), 0.0);
1660  double sumY = accumulate(divY.begin(), divY.end(), 0.0);
1661 
1662  if(useMargins == true) {
1663  double l = orgPad->GetLeftMargin();
1664  double r = orgPad->GetRightMargin();
1665  double t = orgPad->GetTopMargin();
1666  double b = orgPad->GetBottomMargin();
1667 
1668 
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));
1673 
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));
1677 
1678  DivideTransparent(newX, newY, false);
1679  return;
1680  }
1681 
1682 
1683 
1684  vector<double> edgesX(divX.size()+1);
1685  vector<double> edgesY(divY.size()+1);
1686 
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;
1692 
1693  int nPadsX = (divX.size()-1)/2;
1694  //int nPadsY = (divY.size()-1)/2;
1695 
1696  int kStart = 1;
1697  while(orgPad->GetPad(kStart))
1698  ++kStart;
1699  --kStart;
1700 
1701 
1702  int i = 1;
1703  //for(int x = 1; x < edgesX.size()-1; x+=2)
1704  for(int y = 1; y < int(edgesY.size())-1; y+=2)
1705  for(int x = edgesX.size()-3; x >= 1; x-=2) {
1706  //i = (nPadsY-1-(y-1)/2) * nPadsX + (nPadsX-1-(x-1)/2) + 1;
1707  i = ((y-1)/2) * nPadsX + ((x-1)/2) + 1;
1708 
1709  TPad *pad = new TPad(TString::Format("%s_%d", orgPad->GetName(), kStart+i), "", 0.0, 0.0, 1, 1);
1710  pad->SetFillStyle(0);
1711 
1712 
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]);
1717 
1718  //cout <<"LeftRight " << l <<" "<< r <<" "<< (1-l-r) <<" "<< i<< endl;
1719 
1720  pad->cd();
1721  SetLeftRight(l, r);
1722  SetTopBottom(t, b);
1723  orgPad->cd();
1724 
1725 
1726  pad->SetNumber(kStart+i);
1727  pad->Draw();
1728  ++i;
1729  }
1730 }
1731 
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)
1736 {
1737  vector<vector<double>> v = {v1, v2, v3, v4, v5, v6, v7};
1738  vector<double> res;
1739  for(unsigned i = 0; i < v.size(); ++i)
1740  res.insert(res.end(), v[i].begin(), v[i].end());
1741  return res;
1742 }
1743 
1747 vector<double> repeat(vector<double> x, int n)
1748 {
1749  vector<double> res = x;
1750  for(int i = 1; i < n; ++i)
1751  res.insert(res.end(), x.begin(), x.end());
1752  return res;
1753 }
1754 
1759 vector<double> group(double frame, double space, int n)
1760 {
1761  vector<double> res;
1762  for(int i = 0; i < n-1; ++i) {
1763  res.push_back(frame);
1764  res.push_back(space);
1765  }
1766  res.push_back(frame);
1767  return res;
1768 }
1769 
1770 
1771 
1772 
1774 
1775 
1776 
1777 }
1778 
1779 //dummy function
1781 {
1782 }
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.
Point Px2NDC(Point p)
TAxis * GetYaxis()
Return y-axis of the active frame.
Left bottom corner.
vector< vector< double > > distToHists
TAxis * GetXaxis()
Return x-axis of the active frame.
vector< unsigned > dims
double RelFontToPx(double rel)
Transform font size from relative units to pixels.
Center of bottom side.
void SetLabelOffsetX(double off)
Set offset of the x-axis labels.
Right bottom corner.
#define SF
void CalcYaxisRange()
Calculate the automatic range of the vertical axis and apply it.
Center of left side.
void PlaceLegends(vector< TLegend *> legs, bool keepRange=false)
Setup the position of legends provided in legs array.
vector< double > SizesX
vector< double > SizesY
int iSave
vector< vector< Borders > > legBorders
void plottingHelper()
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...
Center of top side.
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.
Center of right side.
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.
Arbitrary position.
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.
int jSave
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.
unsigned pos
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.
Left top corner.
double minSepar
vector< Rectangle > recs
int nSteps
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.
Right top corner.
int last
double PxFontToRel(double px)
Transform font size from px to the relative units.
TH1 * GetFrame()
The method returns current frame on the active pad.
int nLeg
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.