TPadManipulator.cxx
Go to the documentation of this file.
1 // TPadManipulator.cxx
2 
3 #include "TPadManipulator.h"
4 #include "StringManipulator.h"
5 #include <iostream>
6 #include <sstream>
7 #include "TPad.h"
8 #include "TCanvas.h"
9 #include "TAxis.h"
10 #include "TGaxis.h"
11 #include "TList.h"
12 #include "TStyle.h"
13 #include "TH1.h"
14 #include "TH2.h"
15 #include "TGraph.h"
16 #include "TFrame.h"
17 #include "TLine.h"
18 #include "TF1.h"
19 #include "TPaletteAxis.h"
20 #include "TError.h"
21 #include "TSystem.h"
22 #include "TBuffer.h"
23 #include "TClass.h"
24 #include "TDirectory.h"
25 #include "TFile.h"
26 #include "TExec.h"
27 #include "TROOT.h" // gROOT
28 
29 using std::string;
30 using std::cout;
31 using std::endl;
32 using std::ostringstream;
33 using Index = unsigned int;
34 
35 bool dbg = 0;
36 
37 //**********************************************************************
38 
39 namespace {
40 
41 //void EmptyErrorHandler(Int_t, Bool_t, const char*, const char*) { }
42 
43 } // end unnamed namespace
44 
45 //**********************************************************************
46 // Static members.
47 //**********************************************************************
48 
50  Name myname = "TPadManipulator::get: ";
51  TPadManipulator* ppad = nullptr;
52  TDirectory* pdir = tdir == nullptr ? gDirectory : tdir;
53  if ( pdir == nullptr ) {
54  cout << myname << "ERROR: Root directory not found." << endl;
55  return ppad;
56  }
57  pdir->GetObject(onam.c_str(), ppad);
58  return ppad;
59 }
60 
61 //**********************************************************************
62 
64  Name myname = "TPadManipulator::read: ";
65  TPadManipulator* ppad = nullptr;
66  TFile* pfil = TFile::Open(fnam.c_str(), "READ");
67  if ( pfil == nullptr || ! pfil->IsOpen() ) {
68  cout << myname << "Unable to open file " << fnam << endl;
69  } else {
70  ppad = get(onam, pfil);
71  }
72  delete pfil;
73  return ppad;
74 }
75 
76 //**********************************************************************
77 // Non-static members.
78 //**********************************************************************
79 
81 : m_parent(nullptr), m_ppad(nullptr),
83  m_exec("myexec", ""),
84  m_marginLeft(-999), m_marginRight(-999),
85  m_marginBottom(-999), m_marginTop(-999),
86  m_ph(nullptr),
87  m_pg(nullptr),
89  m_gridX(false), m_gridY(false),
90  m_logX(false), m_logY(false), m_logZ(false),
91  m_tickLengthX(0.03), m_tickLengthY(0.0),
92  m_ndivX(0), m_ndivY(0),
93  m_labSizeX(0.0), m_labSizeY(0.0), m_ttlSize(0.0),
94  m_flowHist(nullptr),
95  m_showUnderflow(false), m_showOverflow(false),
96  m_flowGraph(nullptr),
97  m_gflowMrk(0), m_gflowCol(0),
98  m_top(false), m_right(false), m_iobjLegend(0),
99  m_axisTitleOpt(0) {
100  const string myname = "TPadManipulator::ctor: ";
101  if ( dbg ) cout << myname << this << endl;
102  m_label.SetNDC();
103  m_label.SetX(0.01);
104  m_label.SetY(0.02);
105  m_label.SetTextFont(42);
106  m_label.SetTextSize(0.035);
107 }
108 
109 //**********************************************************************
110 
112 : TPadManipulator() {
113  const string myname = "TPadManipulator::ctor(pad): ";
114  cout << myname << "Not implemented--will copy objects from pad." << endl;
115  if ( dbg ) cout << myname << this << endl;
116 }
117 
118 //**********************************************************************
119 
121 : TPadManipulator() {
122  m_canvasWidth = wx;
123  m_canvasHeight = wy;
124  Index nx = nPadX;
125  Index ny = nPadY > 0 ? nPadY : nx;
126  if ( nx ) split(nx, ny);
127 }
128 
129 //**********************************************************************
130 
132 : TPadManipulator() {
133  *this = rhs;
134 }
135 
136 //**********************************************************************
137 
139  if ( this == &rhs ) return *this;
140  bool saveAddDirectory = TH1::AddDirectoryStatus();
141  TH1::AddDirectory(false);
142  if ( m_ppad != nullptr ) {
143  m_ppad->Clear();
144  }
147  m_exec = rhs.m_exec,
151  m_marginTop = rhs.m_marginTop;
152  // Clone drawn objects.
153  delete m_ph;
154  m_ph = nullptr;
155  delete m_pg;
156  m_pg = nullptr;
157  if ( rhs.haveHist() ) {
158  m_ph = dynamic_cast<TH1*>(rhs.hist()->Clone());
159  } else if ( rhs.m_pg ) {
160  m_pg = dynamic_cast<TGraph*>(rhs.m_pg->Clone());
161  }
162  m_dopt = rhs.m_dopt;
163  m_objs.clear();
164  for ( TObject* pobj : rhs.m_objs ) {
165  m_objs.push_back(pobj != nullptr ? pobj->Clone() : nullptr);
166  }
167  m_opts = rhs.m_opts;
168  TH1::AddDirectory(saveAddDirectory);
169  m_setBounds = rhs.m_setBounds;
171  // Copy decoration instructions.
172  m_fillColor = rhs.m_fillColor;
174  m_gridX = rhs.m_gridX;
175  m_gridY = rhs.m_gridY;
176  m_logX = rhs.m_logX;
177  m_logY = rhs.m_logY;
178  m_logZ = rhs.m_logZ;
181  m_ndivX = rhs.m_ndivX;
182  m_ndivY = rhs.m_ndivY;
183  m_labSizeX = rhs.m_labSizeX;
184  m_labSizeY = rhs.m_labSizeY;
185  m_ttlSize = rhs.m_ttlSize;
188  m_gflowOpt = rhs.m_gflowOpt;
189  m_gflowMrk = rhs.m_gflowMrk;
190  m_gflowCol = rhs.m_gflowCol;
191  m_top = rhs.m_top;
192  m_right = rhs.m_right;
194  rhs.m_title.Copy(m_title); m_title.SetNDC();
195  rhs.m_label.Copy(m_label); m_label.SetNDC();
196  m_histFuns = rhs.m_histFuns;
197  m_hmlXmod = rhs.m_hmlXmod;
198  m_hmlXoff = rhs.m_hmlXoff;
199  m_hmlXStyle = rhs.m_hmlXStyle;
201  m_vmlXmod = rhs.m_vmlXmod;
202  m_vmlXoff = rhs.m_vmlXoff;
203  m_vmlXStyle = rhs.m_vmlXStyle;
205  m_slSlop = rhs.m_slSlop;
206  m_slYoff = rhs.m_slYoff;
207  m_slStyl = rhs.m_slStyl;
214  m_subBounds = rhs.m_subBounds;
215  m_subMans.clear();
216  for ( const TPadManipulator& man : rhs.m_subMans ) {
217  m_subMans.emplace_back(man);
218  }
221  setParents(true);
222  update();
223  return *this;
224 }
225 
226 //**********************************************************************
227 
229  //cout << "Destroying manipulator " << this << " with pad " << m_ppad
230  // << " and parent " << m_parent << endl;
231  if ( m_ppad != nullptr && m_parent == nullptr ) {
232  // May 2020: If the pad is not in the Root list of canvases, then it may
233  // be that Root has already deleted it.
234  if ( gROOT->GetListOfCanvases()->IndexOf(m_ppad) >= 0 ) {
235  m_ppad->Close();
236  gSystem->ProcessEvents();
237  delete m_ppad;
238  m_ppad = nullptr;
239  }
240  }
241  for ( TObject* pobj : m_objs ) delete pobj;
242  m_objs.clear();
244 }
245 
246 //**********************************************************************
247 
248 double TPadManipulator::xmin() const {
249  if ( m_logX &&
250  m_setBoundsLog.x1 > 0.0 && m_setBoundsLog.x2 > 0.0 &&
252  if ( m_setBounds.x2 > m_setBounds.x1 ) return m_setBounds.x1;
253  if ( ! havePad() ) return 0.0;
254  double val = pad()->GetUxmin();
255  return pad()->GetLogx() ? pow(10,val) : val;
256 }
257 
258 //**********************************************************************
259 
260 double TPadManipulator::xmax() const {
261  if ( m_logX &&
262  m_setBoundsLog.x1 > 0.0 && m_setBoundsLog.x2 > 0.0 &&
264  if ( m_setBounds.x2 > m_setBounds.x1 ) return m_setBounds.x2;
265  if ( ! havePad() ) return 0.0;
266  double val = pad()->GetUxmax();
267  return pad()->GetLogx() ? pow(10,val) : val;
268 }
269 
270 //**********************************************************************
271 
272 double TPadManipulator::ymin() const {
273  if ( m_logY &&
274  m_setBoundsLog.y1 > 0.0 && m_setBoundsLog.y2 > 0.0 &&
276  if ( m_setBounds.y2 > m_setBounds.y1 ) return m_setBounds.y1;
277  if ( ! havePad() ) return 0.0;
278  double val = pad()->GetUymin();
279  return pad()->GetLogy() ? pow(10,val) : val;
280 }
281 
282 //**********************************************************************
283 
284 double TPadManipulator::ymax() const {
285  if ( m_logY &&
286  m_setBoundsLog.y1 > 0.0 && m_setBoundsLog.y2 > 0.0 &&
288  if ( m_setBounds.y2 > m_setBounds.y1 ) return m_setBounds.y2;
289  if ( ! havePad() ) return 0.0;
290  double val = pad()->GetUymax();
291  return pad()->GetLogy() ? pow(10,val) : val;
292 }
293 
294 //**********************************************************************
295 
296 double TPadManipulator::zmin() const {
297  if ( m_logZ &&
298  m_setBoundsLog.z1 > 0.0 && m_setBoundsLog.z2 > 0.0 &&
300  if ( m_setBounds.z2 > m_setBounds.z1 ) return m_setBounds.z1;
301  return 0.0;
302 }
303 
304 //**********************************************************************
305 
306 double TPadManipulator::zmax() const {
307  if ( m_logZ &&
308  m_setBoundsLog.z1 > 0.0 && m_setBoundsLog.z2 > 0.0 &&
310  if ( m_setBounds.z2 > m_setBounds.z1 ) return m_setBounds.z2;
311  return 0.0;
312 }
313 
314 //**********************************************************************
315 
316 TCanvas* TPadManipulator::canvas() const {
317  if ( m_parent ) return m_parent->canvas();
318  return dynamic_cast<TCanvas*>(m_ppad);
319 }
320 
321 //**********************************************************************
322 
323 TCanvas* TPadManipulator::canvas(bool doDraw) {
324  if ( m_parent ) return m_parent->canvas(doDraw);
325  if ( m_ppad == nullptr && doDraw ) draw();
326  return dynamic_cast<TCanvas*>(m_ppad);
327 }
328 
329 //**********************************************************************
330 
331 int TPadManipulator::put(Name onam, TDirectory* tdir) const {
332  Name myname = "TPadManipulator::put: ";
333  TDirectory* pdir = tdir == nullptr ? gDirectory : tdir;
334  if ( pdir == nullptr ) {
335  cout << myname << "ERROR: Root directory not found." << endl;
336  return 2;
337  }
338  if ( ! pdir->IsWritable() ) {
339  cout << myname << "Root directory " << pdir->GetName() << " is not writable." << endl;
340  return 3;
341  }
342  pdir->WriteObject(this, onam.c_str());
343  return 0;
344 }
345 
346 //**********************************************************************
347 
348 int TPadManipulator::write(Name fnam, Name onam) const {
349  Name myname = "TPadManipulator::write: ";
350  TFile* pfil = TFile::Open(fnam.c_str(), "UPDATE");
351  if ( pfil == nullptr || ! pfil->IsOpen() ) {
352  cout << myname << "Unable to open file " << fnam << endl;
353  return 1;
354  }
355  int wstat = put(onam, pfil);
356  delete pfil;
357  return wstat;
358 }
359 
360 //**********************************************************************
361 
363  // If fname has suffix .root or .tpad, we save this object.
364  Name::size_type idot = fname.rfind(".");
365  if ( idot != Name::npos ) {
366  Name suf = fname.substr(idot + 1);
367  if ( suf == "root" || suf == "tpad" ) {
368  write(fname);
369  return 0;
370  }
371  }
372  TCanvas* pcan = canvas(false);
373  // If canvas does not yet exist, draw in batch mode to avoid
374  // display on screen.
375  // We should (but don't yet) also remove the canvas after draw so
376  // there are no problems if a draw to screen is attempted later.
377  bool setBackToNonBatch = false;
378  if ( pcan == nullptr ) {
379  bool isBatch = gROOT->IsBatch();
380  if ( ! isBatch ) {
381  gROOT->SetBatch(true);
382  setBackToNonBatch = true;
383  }
384  pcan = canvas(true);
385  }
386  if ( pcan == nullptr ) {
387  if ( setBackToNonBatch ) gROOT->SetBatch(false);
388  return 1;
389  }
390  // Suppress printing message from Root.
391  int levelSave = gErrorIgnoreLevel;
392  gErrorIgnoreLevel = 1001;
393  // Block non-default (e.g. art) from handling the Root "error".
394  // We switch to the Root default handler while making the call to Print.
395  ErrorHandlerFunc_t pehSave = nullptr;
396  ErrorHandlerFunc_t pehDefault = DefaultErrorHandler;
397  if ( GetErrorHandler() != pehDefault ) {
398  pehSave = SetErrorHandler(pehDefault);
399  }
400  pcan->Print(fname.c_str());
401  if ( pehSave != nullptr ) SetErrorHandler(pehSave);
402  gErrorIgnoreLevel = levelSave;
403  if ( setBackToNonBatch ) gROOT->SetBatch(false);
404  return 0;
405 }
406 
407 //**********************************************************************
408 
409 int TPadManipulator::print(string fnamepat, string spat) {
410  StringManipulator sman(fnamepat, true);
411  int stats = 0;
412  for ( string fnam : sman.patternSplit(spat) ) stats += printOnce(fnam);
413  return stats;
414 }
415 
416 //**********************************************************************
417 
419  if ( haveParent() ) return parent()->progenitor();
420  return this;
421 }
422 
423 //**********************************************************************
424 
425 unsigned int TPadManipulator::npad() const {
426  return m_subMans.size();
427 }
428 
429 //**********************************************************************
430 
432  if ( npad() == 0 && ipad == 0 ) return this;
433  return ipad<npad() ? &m_subMans[ipad] : nullptr;
434 }
435 
436 //**********************************************************************
437 
438 TObject* TPadManipulator::object() const {
439  if ( haveHist() ) return hist();
440  return graph();
441 }
442 
443 //**********************************************************************
444 
445 TH1* TPadManipulator::getHist(unsigned int iobj) {
446  if ( iobj >= objects().size() ) return nullptr;
447  return dynamic_cast<TH1*>(objects()[iobj]);
448 }
449 
450 //**********************************************************************
451 
452 TObject* TPadManipulator::lastObject() const {
453  Index nobj = objects().size();
454  if ( nobj ) return objects().back();
455  return object();
456 }
457 
458 //**********************************************************************
459 
460 TH1* TPadManipulator::getHist(string hnam) {
461  if ( hist() != nullptr && hist()->GetName() == hnam ) return hist();
462  for ( TObject* pobj : objects() ) {
463  TH1* ph = dynamic_cast<TH1*>(pobj);
464  if ( ph == nullptr ) continue;
465  if ( ph->GetName() == hnam ) return ph;
466  }
467  return nullptr;
468 }
469 
470 //**********************************************************************
471 
473  if ( ! haveCanvas() ) return 0;
474  return canvas()->GetWw();
475 }
476 
477 //**********************************************************************
478 
480  if ( ! haveCanvas() ) return 0;
481  return canvas()->GetWh();
482 }
483 
484 //**********************************************************************
485 
487  if ( ! havePad() ) return 0.0;
488  double frac = pad()->GetAbsWNDC();
489  return frac*canvasPixelsX();
490 }
491 
492 //**********************************************************************
493 
495  if ( ! havePad() ) return 0.0;
496  double frac = pad()->GetAbsHNDC();
497  return frac*canvasPixelsY();
498 }
499 
500 //**********************************************************************
501 
502 TFrame* TPadManipulator::frame() const {
503  return havePad() ? pad()->GetFrame() : nullptr;
504 }
505 
506 //**********************************************************************
507 
509  return haveFrame() ? frame()->GetBBox().fWidth : 0;
510 }
511 
512 //**********************************************************************
513 
515  return haveFrame() ? frame()->GetBBox().fHeight : 0;
516 }
517 
518 //**********************************************************************
519 
521  if ( ! havePad() ) return nullptr;
522  return dynamic_cast<TH1*>(pad()->FindObject("hframe"));
523 }
524 
525 //**********************************************************************
526 
528  for ( TLine* pline : m_lines ) delete pline;
529  m_lines.clear();
530 }
531 
532 //**********************************************************************
533 
534 int TPadManipulator::addPad(double x1, double y1, double x2, double y2, int icol) {
535  if ( x2 <= x1 ) return 1;
536  if ( y2 <= y1 ) return 2;
537  if ( x1 < 0.0 ) return 3;
538  if ( x2 > 1.0 ) return 4;
539  if ( y1 < 0.0 ) return 5;
540  if ( y2 > 1.0 ) return 6;
541  m_subBounds.emplace_back(x1, y1, x2, y2);
542  m_subMans.emplace_back();
543  m_subMans.back().m_parent = this;
544  return 0;
545 }
546 
547 //**********************************************************************
548 
550  Index ny = nyin;
551  if ( nx < 1 ) return 1;
552  if ( ny < 1 ) ny = nx;
553  double dx = 1.0/nx;
554  double dy = 1.0/ny;
555  double y2 = 1.0;
556  for ( Index iy=0; iy<ny; ++iy ) {
557  double y1 = y2 - dy;
558  double x1 = 0.0;
559  for ( Index ix=0; ix<nx; ++ix ) {
560  double x2 = x1 + dx;
561  int rstat = addPad(x1, y1, x2, y2);
562  if ( rstat ) return 100 + rstat;
563  x1 = x2;
564  }
565  y2 = y1;
566  }
567  return 0;
568 }
569 
570 //**********************************************************************
571 
573  return split(nx, nx);
574 }
575 
576 //**********************************************************************
577 
579  string scom;
580  if ( pal >= 0 ) {
581  ostringstream sscom;
582  sscom << "RootPalette::set(" << pal << ")";
583  scom = sscom.str();
584  }
585  setTExec(scom);
586 }
587 
588 //**********************************************************************
589 
590 int TPadManipulator::add(Index ipad, TObject* pobj, string sopt, bool replace) {
591  const string myname = "TPadManipulator::add: ";
592  if ( dbg ) cout << myname << this << endl;
593  if ( pobj == nullptr ) return 101;
594  TPadManipulator* pman = man(ipad);
595  if ( pman == nullptr ) return 102;
596  TH1* ph = dynamic_cast<TH1*>(pobj);
597  TGraph* pg = dynamic_cast<TGraph*>(pobj);
598  bool isNotHistOrGraph = ph==nullptr && pg==nullptr;
599  // If we already have the primary histogram or graph, or this is not one of those,
600  // this is an overlaid object.
601  if ( (!replace && haveHistOrGraph()) || isNotHistOrGraph ) {
602  TObject* pobjc = pobj->Clone();
603  TH1* phc = dynamic_cast<TH1*>(pobjc);
604  if ( phc != nullptr ) phc->SetDirectory(nullptr);
605  m_objs.push_back(pobjc);
606  m_opts.push_back(sopt);
607  // Otherwise, the passed object becomes the primary object and must be
608  // a histogram or graph.
609  } else {
610  if ( ph == nullptr && pg == nullptr ) return 103;
611  if ( pman->hist() != nullptr ) {
612  if ( replace ) delete pman->m_ph;
613  else return 104;
614  }
615  if ( pman->graph() != nullptr ) {
616  if ( replace ) delete pman->m_pg;
617  else return 105;
618  }
619  //if ( m_ppad == nullptr ) return 106;
620  // Transfer the hist/graph title to the pad title.
621  pman->setTitle(pobj->GetTitle());
622  // Clone the primary object.
623  if ( ph != nullptr ) {
624  TH1* phc = (TH1*) ph->Clone();
625  phc->SetDirectory(nullptr);
626  phc->SetTitle("");
627  pman->m_ph = phc;
628  pman->m_dopt = sopt;
629  } else {
630  TGraph* pgc = (TGraph*) pg->Clone();
631  pgc->SetTitle("");
632  pman->m_pg = pgc;
633  string soptOut;
634  for ( Index ipos=0; ipos<sopt.size(); ++ipos ) {
635  char ch = sopt[ipos];
636  if ( ch == 'a' || ch == 'A' ) {
637  cout << myname << "WARNING: Dropping \"" << ch << "\" from drawing option string for graph "
638  << pgc->GetName() << "." << endl;
639  } else {
640  soptOut += ch;
641  }
642  }
643  pman->m_dopt = soptOut;
644  }
645  }
646  return update();
647 }
648 
649 //**********************************************************************
650 
651 int TPadManipulator::add(TObject* pobj, string sopt, bool replace) {
652  return add(0, pobj, sopt, replace);
653 }
654 
655 //**********************************************************************
656 
657 TLegend* TPadManipulator::addLegend(double x1, double y1, double x2, double y2) {
658  TLegend leg(x1, y1, x2, y2);
659  add(0, &leg, "");
660  TLegend* pleg = dynamic_cast<TLegend*>(objects().back());
661  m_iobjLegend = objects().size() - 1;
662  pleg->SetBorderSize(0);
663  pleg->SetFillStyle(0);
664  return pleg;
665 }
666 
667 //**********************************************************************
668 
669 int TPadManipulator::setTitle(string sttl, float height) {
670  m_title.SetTitle(sttl.c_str());
671  m_title.SetNDC();
672  m_title.SetTextAlign(22);
673  m_title.SetTextFont(42);
674  float tsiz = height;
675  if ( tsiz <= 0.0 ) {
676  tsiz = getTitleSize();
677  if ( tsiz <= 0.0 ) tsiz = 0.035;
678  }
679  m_title.SetTextSize(tsiz);
680  double xttl = 0.5;
681  double yttl = 1.0 - 0.70*tsiz;
682  m_title.SetText(xttl, yttl, sttl.c_str());
683  return 0;
684 }
685 
686 //**********************************************************************
687 
688 int TPadManipulator::setLabel(string slab) {
689  m_label.SetTitle(slab.c_str());
690  return 0;
691 }
692 
693 //**********************************************************************
694 
696  delete m_ph;
697  m_ph = nullptr;
698  delete m_pg;
699  m_pg = nullptr;
700  if ( pad() != nullptr && npad() == 0 ) pad()->Clear();
701  for ( TPadManipulator& man : m_subMans ) man.clear();
702  return 0;
703 }
704 
705 //**********************************************************************
706 
708  const string myname = "TPadManipulator::update: ";
709  if ( dbg ) cout << myname << this << endl;
710  int rstat = 0;
711  // No action if canvas/pad is not yet created.
712  // Call draw() to create the pad.
713  if ( ! havePad() ) return 0;
714  // Update the subpads.
715  // If needed, create the TPad for each subpad.
716  TVirtualPad* pPadSave = gPad;
717  m_ppad->cd();
718  if ( m_subMans.size() ) {
719  for ( Index isub=0; isub<m_subMans.size(); ++isub ) {
720  TPadManipulator& man = m_subMans[isub];
721  if ( man.m_ppad == nullptr ) {
722  if ( m_subBounds.size() <= isub ) {
723  cout << myname << "ERROR: Too few bounds." << endl;
724  break;
725  }
726  const Bounds& bnd = m_subBounds[isub];
727  ostringstream ssnam;
728  ssnam << m_ppad->GetName() << "_sub" << isub;
729  string spnam = ssnam.str();
730  string spttl = spnam;
731  TPad* ppad = new TPad(spnam.c_str(), spttl.c_str(), bnd.x1, bnd.y1, bnd.x2, bnd.y2);
732  ppad->Draw();
733  man.m_ppad = ppad;
734  man.m_parent = this;
735  }
736  int srstat = man.update();
737  if ( srstat ) {
738  cout << myname << "WARNING: Error " << srstat << " updating pad " << isub << endl;
739  rstat += srstat;
740  }
741  }
742  }
743  // If frame is not yet drawn, use the primary object to draw it.
744  // Note that we will later redraw the frame.
745  if ( ! haveFrameHist() ) {
746  // Fetch the set bounds.
747  if ( haveHist() ) {
748  hist()->Draw(m_dopt.c_str());
749  } else if ( m_pg ) {
750  // If the graph has no points, we add one because root (6.12/06) raises an
751  // exception if we draw an empty graph.
752  if ( m_pg->GetN() == 0 ) {
753  double xmin = m_pg->GetXaxis()->GetXmin();
754  double ymin = m_pg->GetYaxis()->GetXmin();
755  m_pg->SetPoint(0, xmin, ymin);
756  }
757  m_pg->Draw("AP");
758  }
759  }
760 /*
761  if ( ! haveHistOrGraph() ) {
762  const TList* prims = m_ppad->GetListOfPrimitives();
763  for ( TObjLink* plnk=prims->FirstLink(); plnk; plnk=plnk->Next() ) {
764  TObject* pobj = plnk->GetObject();
765  string sopt = plnk->GetOption();
766  TH1* ph = dynamic_cast<TH1*>(pobj);
767  if ( ph != nullptr ) {
768  m_ph.reset(dynamic_cast<TH1*>(ph->Clone("hmanip0")));
769  m_ph->SetDirectory(nullptr);
770  m_dopt = sopt;
771  break;
772  }
773  TGraph* pg = dynamic_cast<TGraph*>(pobj);
774  if ( pg != nullptr ) {
775  m_pg.reset(dynamic_cast<TGraph*>(pg->Clone("gmanip0")));
776  m_dopt = sopt;
777  break;
778  }
779  }
780  }
781 */
782  if ( ! haveHistOrGraph() ) {
783  if ( npad() == 0 && !haveParent() ) {
784  cout << myname << "Top-level pad does not have a histogram or graph or subpads!" << endl;
785  }
786  // Add the title and labels.
787  m_title.Draw();
788  if ( getLabel().size() ) m_label.Draw();
789  gPad = pPadSave;
790  return 0;
791  }
792  // Run TExec.
793  if ( string(m_exec.GetTitle()).size() ) {
794  m_exec.Draw();
795  }
796  // Set margins the first time the histogram is found.
797  // After this, user can override with pad()->SetRightMargin(...), ...
798  m_ppad->Update(); // This is needed to get color palette for 2D hists.
799  bool isTH = haveHist();
800  bool isTH2 = dynamic_cast<TH2*>(hist()) != nullptr;
801  bool isTH1 = isTH && !isTH2;
802  double xm0 = 0.015;
803  double wx = padPixelsX();
804  double wy = padPixelsY();
805  double asp = wx > 0 ? wy/wx : 1.0;
806  double aspx = asp < 1.0 ? asp : 1.0; // Font is proportional to this for asp < 1.0
807  double aspy = asp > 1.0 ? 1.0/asp : 1.0; // Font is proportional to this for asp > 1.0
808  if ( false ) {
809  aspx = 1.0;
810  aspy = 1.0/asp;
811  }
812  double xml = xm0 + 0.120*aspx;
813  double xmr = 0.05*aspx;
814  double xmb = 0.100*aspy;
815  double xmt = 0.070*aspy;
816  double xlb = -0.028 + 0.038*aspy;
817  double xlz = 0.005*aspx;
818  double xttl = 1.2*aspy;
819  double zttl = 1.5*aspx;
820  double yttl = 0.17 + 1.8*aspx;
821  //double httl = 1.0 - 0.5*xmt;
822  if ( m_marginLeft >= 0.0 ) {
823  // When left margin is changed, we leave the y-axis title at the edge of the pad.
824  xml = m_marginLeft;
825  //double scalefac = m_marginLeft/xml;
826  //yttl *= scalefac;
827  }
828  if ( m_marginRight >= 0.0 ) xmr = m_marginRight;
829  if ( m_marginBottom >= 0.0 ) {
830  xmb = m_marginBottom;
831  //double scalefac = m_marginBottom/xmb;
832  //xttl *= scalefac;
833  }
834  if ( m_marginTop >= 0.0 ) xmt = m_marginTop;
835  if ( isTH2 ) {
836  TPaletteAxis* pax = dynamic_cast<TPaletteAxis*>(hist()->GetListOfFunctions()->FindObject("palette"));
837  if ( pax != nullptr ) {
838  if ( m_marginRight < 0 ) xmr = xm0 + 0.150*aspx;
839  double xp1 = 1.0 - 1.00*xmr;
840  double xp2 = 1.0 - 0.65*xmr;
841  double yp1 = xmb;
842  double yp2 = 1.0 - xmt;
843  double tlen = 0.25*(xp2 - xp1);
844  //cout << myname << "Palette axis found." << endl;
845  pax->SetX1NDC(xp1);
846  pax->SetX2NDC(xp2);
847  pax->SetY1NDC(yp1);
848  pax->SetY2NDC(yp2);
849  hist()->GetZaxis()->SetTickLength(tlen);
850  //} else {
851  // cout << myname << "Palette axis not found." << endl;
852  // hist()->GetListOfFunctions()->Print();
853  }
854  }
855  m_ppad->SetRightMargin(xmr);
856  m_ppad->SetLeftMargin(xml);
857  m_ppad->SetTopMargin(xmt);
858  m_ppad->SetBottomMargin(xmb);
859  // Set the axis tick lengths.
860  // If the Y-size is zero, then they are drawn to have the same pixel length as the X-axis.
861  double ticklenx = m_tickLengthX;
862  double tickleny = m_tickLengthY;
863  if ( ticklenx < 0.0 ) ticklenx = 0.0;
864  if ( tickleny <= 0.0 ) {
865  if ( framePixelsY() ) {
866  double wx = framePixelsX();
867  double wy = framePixelsY();
868  if ( wy > wx ) {
869  tickleny = ticklenx;
870  ticklenx = (wx/wy)*tickleny;
871  } else {
872  tickleny = (wy/wx)*ticklenx;
873  }
874  }
875  }
876  int nbin = isTH1 ? hist()->GetNbinsX() : 0;
877  int flowcol = kAzure - 9;
878  // Build over/underflow histogram.
879  delete m_flowHist;
880  m_flowHist = nullptr;
881  if ( (m_showUnderflow || m_showOverflow) && nbin > 0 ) {
882  if ( m_flowHist == nullptr ) {
883  m_flowHist = dynamic_cast<TH1*>(hist()->Clone("hmaniptmp"));
884  m_flowHist->SetDirectory(nullptr);
885  m_flowHist->SetStats(0);
886  m_flowHist->SetLineColor(flowcol);
887  m_flowHist->SetFillColor(flowcol);
888  m_flowHist->SetLineWidth(1);
889  }
890  m_flowHist->Reset();
891  if ( m_showUnderflow ) {
892  if ( haveHist() ) {
893  double binWidth = hist()->GetBinWidth(1);
894  int binDisp1 = hist()->FindBin(xmin()+0.499*binWidth); // First displayed bin.
895  int binUnder2 = binDisp1 ? binDisp1 - 1 : 0; // Last bin below display.
896  double yunder = hist()->Integral(0, binUnder2);
897  m_flowHist->SetBinContent(binDisp1, yunder);
898  }
899  }
900  if ( m_showOverflow ) {
901  if ( haveHist() ) {
902  int binOver2 = hist()->GetNbinsX() + 1; // Last bin above display
903  double binWidth = hist()->GetBinWidth(1);
904  int binOver1 = hist()->FindBin(xmax()+0.501*binWidth); // First bin above display.
905  int binDisp2 = binOver1 - 1; // Last displayed bin.
906  double yover = hist()->Integral(binOver1, binOver2);
907  m_flowHist->SetBinContent(binDisp2, yover);
908  }
909  }
910  }
911  // Make frame so we have clean axis to overlay.
912  double xa1 = xmin();
913  double xa2 = xmax();
914  bool doLogx = m_logX;
915  if ( doLogx && xa1 <= 0.0 ) {
916  cout << myname << "WARNING: Must have range above 0.0 for logarithmic x-axis." << endl;
917  cout << myname << "WARNING: Use setLogRangeX(x1, x2) to set range." << endl;
918  cout << myname << "WARNING: Plot is displayed with linear axis." << endl;
919  doLogx = false;
920  }
921  double ya1 = ymin();
922  double ya2 = ymax();
923  bool doLogy = m_logY;
924  if ( doLogy && ya1 <= 0.0 ) {
925  cout << myname << "WARNING: Must have range above 0.0 for logarithmic y-axis." << endl;
926  cout << myname << "WARNING: Use setLogRangeY(y1, y2) to set range." << endl;
927  cout << myname << "WARNING: Plot is displayed with linear axis." << endl;
928  doLogy = false;
929  }
930  double za1 = zmin();
931  double za2 = zmax();
932  bool doLogz = m_logZ;
933  if ( doLogz && za1 <= 0.0 ) {
934  cout << myname << "WARNING: Must have range above 0.0 for logarithmic z-axis." << endl;
935  cout << myname << "WARNING: Use setLogRangeY(z1, z2) to set range." << endl;
936  cout << myname << "WARNING: Plot is displayed with linear axis." << endl;
937  doLogy = false;
938  }
939  string sattl = ";";
940  sattl += getXaxis()->GetTitle();
941  sattl += ";";
942  sattl += getYaxis()->GetTitle();
943  sattl += ";";
944  // Redraw everything.
945  m_ppad->Clear();
946  // Set the TPad attributes.
947  m_ppad->SetFillColor(m_fillColor);
948  m_ppad->SetFrameFillColor(m_frameFillColor);
949  m_ppad->SetGridx(m_gridX);
950  m_ppad->SetGridy(m_gridY);
951  m_ppad->SetLogx(doLogx);
952  m_ppad->SetLogy(doLogy);
953  m_ppad->SetLogz(doLogz);
954  // Draw frame and set axis parameters.
955  m_ppad->DrawFrame(xa1, ya1, xa2, ya2, sattl.c_str());
956  double labSizeX = getLabelSizeX();
957  if ( labSizeX > 0.0 ) {
958  getXaxis()->SetLabelSize(labSizeX);
959  getXaxis()->SetTitleSize(labSizeX);
960  //xttl *= labSizeX/0.035;
961  }
962  double labSizeY = getLabelSizeY();
963  if ( labSizeY > 0.0 ) {
964  getYaxis()->SetLabelSize(labSizeY);
965  getYaxis()->SetTitleSize(labSizeY);
966  //yttl *= labSizeY/0.035;
967  if ( getZaxis() != nullptr ) {
968  getZaxis()->SetLabelSize(labSizeY);
969  getZaxis()->SetTitleSize(labSizeY);
970  }
971  }
972  getXaxis()->SetLabelOffset(xlb);
973  getXaxis()->SetTitleOffset(xttl);
974  if ( getZaxis() != nullptr ) getZaxis()->SetTitleOffset(zttl);
975  getYaxis()->SetTitleOffset(yttl);
976  getXaxis()->SetTickLength(ticklenx);
977  getYaxis()->SetTickLength(tickleny);
978  if ( m_axisTitleOpt ) {
979  for ( TAxis* pax : { getXaxis(), getYaxis(), getZaxis() } ) {
980  if ( pax == nullptr ) continue;
981  pax->CenterTitle();
982  }
983  }
984  if ( m_ndivX ) getXaxis()->SetNdivisions(m_ndivX);
985  if ( m_ndivY ) getYaxis()->SetNdivisions(m_ndivY);
986  if ( m_timeFormatX.size() ) {
987  getXaxis()->SetTimeDisplay(1);
988  getXaxis()->SetTimeFormat(m_timeFormatX.c_str());
989  getXaxis()->SetTimeOffset(m_timeOffset, "gmt");
990  } else {
991  getXaxis()->SetTimeDisplay(0);
992  }
993  if ( m_timeFormatY.size() ) {
994  getYaxis()->SetTimeDisplay(1);
995  getYaxis()->SetTimeFormat(m_timeFormatY.c_str());
996  getYaxis()->SetTimeOffset(m_timeOffset, "gmt");
997  } else {
998  getYaxis()->SetTimeDisplay(0);
999  }
1000  // May 2019. Ensure frame axis has same binning as histogram.
1001  // And set bin labels.
1002  // July 2019: The calls to TAxis::Set cause problems if the drawing bounds are
1003  // set here. Make those calls iff bin labels are set.
1004  if ( haveHist() ) {
1005  if ( m_binLabelsX.size() ) {
1006  TAxis* pah = hist()->GetXaxis();
1007  getXaxis()->Set(pah->GetNbins(), pah->GetXmin(), pah->GetXmax());
1008  for ( Index ilab=0; ilab<m_binLabelsX.size(); ++ilab ) {
1009  getXaxis()->SetBinLabel(ilab+1, m_binLabelsX[ilab].c_str());
1010  }
1011  }
1012  if ( dynamic_cast<TH2*>(hist()) != nullptr && m_binLabelsY.size() ) {
1013  TAxis* pah = hist()->GetYaxis();
1014  getYaxis()->Set(pah->GetNbins(), pah->GetXmin(), pah->GetXmax());
1015  for ( Index ilab=0; ilab<m_binLabelsY.size(); ++ilab ) {
1016  getYaxis()->SetBinLabel(ilab+1, m_binLabelsY[ilab].c_str());
1017  }
1018  }
1019  }
1020  // Primary object.
1021  if ( haveHist() ) {
1022  if ( m_flowHist != nullptr ) {
1023  m_flowHist->Draw("same");
1024  }
1025  TAxis* paz = hist()->GetZaxis();
1026  if ( paz != nullptr && za2 > za1 ) {
1027  paz->SetRangeUser(za1, za2);
1028  paz->SetLabelOffset(xlz);
1029  }
1030  string dopt = m_dopt.size() ? m_dopt + " same" : "same";
1031  hist()->Draw(dopt.c_str());
1032  drawHistFuns();
1033  } else {
1034  m_pg->Draw(m_dopt.c_str());
1035  }
1036  // Secondary objects.
1037  for ( Index iobj=0; iobj<m_objs.size(); ++iobj ) {
1038  TObject* pobj = m_objs[iobj];
1039  string sopt = m_opts[iobj];
1040  if ( pobj != nullptr ) pobj->Draw(sopt.c_str());
1041  }
1042  // no longer needed? m_ppad->Update(); // Need an update here to get correct results for xmin, ymin, xmax, ymax
1043  // Make overflow graph.
1044  if ( m_gflowOpt.size() ) {
1045  bool doBot = m_gflowOpt.find("B") != string::npos;
1046  bool doTop = m_gflowOpt.find("T") != string::npos;
1047  bool doLef = m_gflowOpt.find("L") != string::npos;
1048  bool doRig = m_gflowOpt.find("R") != string::npos;
1049  TGraph* pgout = new TGraph();
1050  pgout->SetMarkerStyle(m_gflowMrk);
1051  pgout->SetMarkerColor(m_gflowCol);
1052  std::vector<TGraph*> gras;
1053  if ( haveGraph() ) gras.push_back(graph());
1054  for ( TObject* pobj : m_objs ) {
1055  TGraph* pgra = dynamic_cast<TGraph*>(pobj);
1056  if ( pgra != nullptr ) gras.push_back(pgra);
1057  }
1058  for ( TGraph* pgin : gras ) {
1059  for ( int ipt=0; ipt<pgin->GetN(); ++ipt ) {
1060  double x, y;
1061  pgin->GetPoint(ipt, x, y);
1062  double xout = x;
1063  double yout = y;
1064  bool doAdd = false;
1065  if ( doRig && x > xmax() ) { doAdd = true; xout = xmax(); }
1066  if ( doLef && x < xmin() ) { doAdd = true; xout = xmin(); }
1067  if ( doBot && y < ymin() ) { doAdd = true; yout = ymin(); }
1068  if ( doTop && y > ymax() ) { doAdd = true; yout = ymax(); }
1069  if ( doAdd ) pgout->SetPoint(pgout->GetN(), xout, yout);
1070  }
1071  }
1072  if ( pgout->GetN() == 0 ) {
1073  delete pgout;
1074  pgout = nullptr;
1075  } else {
1076  delete m_flowGraph;
1077  m_flowGraph = pgout;
1078  m_flowGraph->Draw("P");
1079  }
1080  }
1081  drawLines();
1082  if ( m_top ) drawAxisTop();
1083  if ( m_right ) drawAxisRight();
1084  pad()->RedrawAxis(); // In case they are covered
1085  pad()->RedrawAxis("G"); // In case they are covered
1086  // Add the title and labels.
1087  // First fix the title position and size (April 2020).
1088  // Title is positioned halfway up the top margin with text height no more
1089  // than 90% of the margin.
1090  float marg = m_ppad->GetTopMargin();
1091  float ttlY = 1.0 - 0.5*marg;
1092  m_title.SetY(ttlY);
1093  float ttlSizeMax = 0.90*marg;
1094  float ttlSize = m_ttlSize > 0 ? m_ttlSize : 0.035;
1095  if ( ttlSize > ttlSizeMax ) ttlSize = ttlSizeMax;
1096  m_title.SetTextSize(ttlSize);
1097  m_title.Draw();
1098  if ( getLabel().size() ) m_label.Draw();
1099  gPad = pPadSave;
1100  return rstat;
1101 }
1102 
1103 //**********************************************************************
1104 
1106  if ( haveFrameHist() ) return frameHist()->GetXaxis();
1107  if ( hist() != nullptr ) return hist()->GetXaxis();
1108  if ( m_pg != nullptr ) return m_pg->GetXaxis();
1109  return nullptr;
1110 }
1111 
1112 //**********************************************************************
1113 
1115  if ( haveFrameHist() ) return frameHist()->GetYaxis();
1116  if ( hist() != nullptr ) return hist()->GetYaxis();
1117  if ( m_pg != nullptr ) return m_pg->GetYaxis();
1118  return nullptr;
1119 }
1120 
1121 //**********************************************************************
1122 
1124  //if ( haveFrameHist() ) return frameHist()->GetZaxis();
1125  if ( hist() != nullptr ) return hist()->GetZaxis();
1126  return nullptr;
1127 }
1128 
1129 //**********************************************************************
1130 
1131 int TPadManipulator::setCanvasSize(int wx, int wy) {
1132  if ( haveParent() ) return parent()->setCanvasSize(wx, wy);
1133  m_canvasWidth = wx;
1134  m_canvasHeight = wy;
1135  if ( haveCanvas() ) {
1136  canvas()->SetWindowSize(wx, wy);
1137  return update();
1138  }
1139  return 0;
1140 }
1141 
1142 //**********************************************************************
1143 
1145  if ( m_labSizeX ) return m_labSizeX;
1146  if ( haveParent() ) {
1147  const TPadManipulator* pman = parent();
1148  double h1 = padPixelsY();
1149  double h2 = pman->padPixelsY();
1150  double h = h1 ? h2/h1*pman->getLabelSizeX() : 0.0;
1151  return h;
1152  }
1153  return 0.0;
1154 }
1155 
1156 //**********************************************************************
1157 
1159  if ( m_labSizeY ) return m_labSizeY;
1160  if ( haveParent() ) {
1161  const TPadManipulator* pman = parent();
1162  double h1 = padPixelsY();
1163  double h2 = pman->padPixelsY();
1164  double h = h1 ? h2/h1*pman->getLabelSizeY() : 0.0;
1165  return h;
1166  }
1167  return 0.0;
1168 }
1169 
1170 //**********************************************************************
1171 
1173  if ( m_ttlSize ) return m_ttlSize;
1174  if ( haveParent() ) {
1175  const TPadManipulator* pman = parent();
1176  double h1 = padPixelsY();
1177  double h2 = pman->padPixelsY();
1178  double h = h1 ? h2/h1*pman->getTitleSize() : 0.0;
1179  return h;
1180  }
1181  return 0.0;
1182 }
1183 
1184 //**********************************************************************
1185 
1186 int TPadManipulator::setRangeX(double x1, double x2) {
1187  m_setBounds.x1 = x1;
1188  m_setBounds.x2 = x2;
1189  return update();
1190 }
1191 
1192 //**********************************************************************
1193 
1194 int TPadManipulator::setRangeY(double y1, double y2) {
1195  m_setBounds.y1 = y1;
1196  m_setBounds.y2 = y2;
1197  return update();
1198 }
1199 
1200 //**********************************************************************
1201 
1202 int TPadManipulator::setRangeZ(double z1, double z2) {
1203  m_setBounds.z1 = z1;
1204  m_setBounds.z2 = z2;
1205  return update();
1206 }
1207 
1208 //**********************************************************************
1209 
1210 int TPadManipulator::setRangeXY(double x1, double x2, double y1, double y2) {
1211  m_setBounds.x1 = x1;
1212  m_setBounds.x2 = x2;
1213  m_setBounds.y1 = y1;
1214  m_setBounds.y2 = y2;
1215  return update();
1216 }
1217 
1218 //**********************************************************************
1219 
1220 int TPadManipulator::setLogRangeX(double x1, double x2) {
1221  m_setBoundsLog.x1 = x1;
1222  m_setBoundsLog.x2 = x2;
1223  return update();
1224 }
1225 
1226 //**********************************************************************
1227 
1228 int TPadManipulator::setLogRangeY(double y1, double y2) {
1229  m_setBoundsLog.y1 = y1;
1230  m_setBoundsLog.y2 = y2;
1231  return update();
1232 }
1233 
1234 //**********************************************************************
1235 
1236 int TPadManipulator::setLogRangeZ(double z1, double z2) {
1237  m_setBoundsLog.z1 = z1;
1238  m_setBoundsLog.z2 = z2;
1239  return update();
1240 }
1241 
1242 //**********************************************************************
1243 
1245  m_timeOffset = toff;
1246  return 0;
1247 }
1248 
1249 //**********************************************************************
1250 
1252  m_timeFormatX = sfmt;
1253  return 0;
1254 }
1255 
1256 //**********************************************************************
1257 
1259  m_timeFormatY = sfmt;
1260  return 0;
1261 }
1262 
1263 //**********************************************************************
1264 
1266  return addAxisTop(flag) + addAxisRight(flag);
1267 }
1268 
1269 //**********************************************************************
1270 
1272  m_top = flag;
1273  return update();
1274 }
1275 
1276 //**********************************************************************
1277 
1279  m_right = flag;
1280  return update();
1281 }
1282 
1283 //**********************************************************************
1284 
1285 int TPadManipulator::addHistFun(unsigned int ifun) {
1286  m_histFuns.push_back(ifun);
1287  return update();
1288 }
1289 
1290 //**********************************************************************
1291 
1293  if ( show == m_showUnderflow ) return 0;
1294  m_showUnderflow = show;
1295  return update();
1296 }
1297 
1298 //**********************************************************************
1299 
1301  if ( show == m_showOverflow ) return 0;
1302  m_showOverflow = show;
1303  return update();
1304 }
1305 
1306 //**********************************************************************
1307 
1308 int TPadManipulator::showGraphOverflow(std::string sopt, int imrk, int icol) {
1309  delete m_flowGraph;
1310  m_flowGraph = nullptr;
1311  m_gflowOpt = sopt;
1312  m_gflowMrk = imrk;
1313  m_gflowCol = icol;
1314  return 0;
1315 }
1316 
1317 //**********************************************************************
1318 
1320  m_vmlXmod.clear();
1321  m_vmlXoff.clear();
1322  m_vmlXStyle.clear();
1323  m_vmlXLength.clear();
1324  m_hmlXmod.clear();
1325  m_hmlXoff.clear();
1326  m_hmlXStyle.clear();
1327  m_hmlXLength.clear();
1328  return update();
1329 }
1330 
1331 //**********************************************************************
1332 
1333 int TPadManipulator::addVerticalLine(double xoff, double lenfrac, int isty) {
1334  m_vmlXmod.push_back(0.0);
1335  m_vmlXoff.push_back(xoff);
1336  m_vmlXStyle.push_back(isty);
1337  m_vmlXLength.push_back(lenfrac);
1338  return update();
1339 }
1340 //**********************************************************************
1341 
1342 int TPadManipulator::addHorizontalLine(double xoff, double lenfrac, int isty) {
1343  m_hmlXmod.push_back(0.0);
1344  m_hmlXoff.push_back(xoff);
1345  m_hmlXStyle.push_back(isty);
1346  m_hmlXLength.push_back(lenfrac);
1347  drawLines();
1348  return 0;
1349 }
1350 //**********************************************************************
1351 
1352 int TPadManipulator::addSlopedLine(double slop, double yoff, int isty) {
1353  m_slSlop.push_back(slop);
1354  m_slYoff.push_back(yoff);
1355  m_slStyl.push_back(isty);
1356  drawLines();
1357  return 0;
1358 }
1359 //**********************************************************************
1360 
1361 int TPadManipulator::addVerticalModLines(double xmod, double xoff, double lenfrac, int isty) {
1362  m_vmlXmod.push_back(xmod);
1363  m_vmlXoff.push_back(xoff);
1364  m_vmlXStyle.push_back(isty);
1365  m_vmlXLength.push_back(lenfrac);
1366  drawLines();
1367  return 0;
1368 }
1369 
1370 //**********************************************************************
1371 
1372 int TPadManipulator::addHorizontalModLines(double xmod, double xoff, double lenfrac, int isty) {
1373  m_hmlXmod.push_back(xmod);
1374  m_hmlXoff.push_back(xoff);
1375  m_hmlXStyle.push_back(isty);
1376  m_hmlXLength.push_back(lenfrac);
1377  drawLines();
1378  return 0;
1379 }
1380 
1381 //**********************************************************************
1382 
1384  m_binLabelsX = labs;
1385  return 0;
1386 }
1387 
1388 //**********************************************************************
1389 
1391  m_binLabelsY = labs;
1392  return 0;
1393 }
1394 
1395 //**********************************************************************
1396 
1398  if ( gStyle == nullptr ) return 2;
1399  m_ppad->SetFrameFillColor(gStyle->GetColorPalette(0));
1400  return 0;
1401 }
1402 
1403 //**********************************************************************
1404 
1406  if ( haveParent() ) return parent()->draw();
1407  if ( m_ppad == nullptr ) {
1408  if ( ! haveHistOrGraph() && npad() == 0 ) return 1;
1409  TCanvas* pcan = new TCanvas;
1410  if ( m_canvasWidth > 0 && m_canvasHeight > 0 ) {
1411  string snam = pcan->GetName();
1412  string sttl = pcan->GetTitle();
1413  delete pcan;
1414  pcan = new TCanvas(snam.c_str(), sttl.c_str(), m_canvasWidth, m_canvasHeight);
1415  //pcan->SetCanvasSize(m_canvasWidth, m_canvasHeight);
1416  //pcan->SetWindowSize(m_canvasWidth, m_canvasHeight);
1417  }
1418  m_ppad = pcan;
1419  }
1420  return update();
1421 }
1422 
1423 //**********************************************************************
1424 
1426  if ( haveParent() ) return parent()->erase();
1427  if ( m_ppad == nullptr ) return 0;
1428  delete m_ppad;
1429  m_ppad = nullptr;
1430  return 0;
1431 }
1432 
1433 //**********************************************************************
1434 
1436  if ( haveParent() ) return parent()->redraw();
1437  erase();
1438  return draw();
1439 }
1440 
1441 //**********************************************************************
1442 
1444  if ( ! m_top ) return 0;
1445  if ( m_ppad == nullptr ) return 1;
1446  TVirtualPad* pPadSave = gPad;
1447  m_ppad->cd();
1448  double xminPad, yminPad, xmaxPad, ymaxPad;
1449  m_ppad->GetRangeAxis(xminPad, yminPad, xmaxPad, ymaxPad);
1450  string sopt = "-US";
1451  double x1 = xmin();
1452  double x2 = xmax();
1453  if ( m_ppad->GetLogx() ) {
1454  xminPad = pow(10.0, xminPad);
1455  xmaxPad = pow(10.0, xmaxPad);
1456  x1 = pow(10.0, x1);
1457  x2 = pow(10.0, x2);
1458  sopt += "G";
1459  }
1460  if ( m_ppad->GetLogy() ) {
1461  yminPad = pow(10.0, yminPad);
1462  ymaxPad = pow(10.0, ymaxPad);
1463  }
1464  TAxis* paxold = getXaxis();
1465  if ( paxold == 0 ) return 2;
1466  double ticksize = paxold->GetTickLength();
1467  int ndiv = paxold->GetNdivisions();
1468  TGaxis* paxnew = new TGaxis(xminPad, ymaxPad, xmaxPad, ymaxPad,
1469  x1, x2, ndiv, sopt.c_str());
1470  if ( ticksize > 0 ) paxnew->SetTickLength(ticksize);
1471  string name = "TopAxis";
1472  paxnew->SetName(name.c_str());
1473  TList* pobjs = m_ppad->GetListOfPrimitives();
1474  for ( int iobj=pobjs->GetEntries()-1; iobj>=0; --iobj ) {
1475  TGaxis* paxold = dynamic_cast<TGaxis*>(pobjs->At(iobj));
1476  if ( paxold == nullptr ) continue;
1477  if ( paxold->GetName() == name ) {
1478  pobjs->RemoveAt(iobj);
1479  break;
1480  }
1481  }
1482  if ( m_timeFormatX.size() ) {
1483  //paxnew->SetTimeDisplay(1);
1484  paxnew->SetTimeFormat(m_timeFormatX.c_str());
1485  paxnew->SetTimeOffset(m_timeOffset, "gmt");
1486  } else {
1487  //paxnew->SetTimeDisplay(0);
1488  }
1489  paxnew->Draw();
1490  gPad = pPadSave;
1491  return 0;
1492 }
1493 
1494 //**********************************************************************
1495 
1497  if ( ! m_right ) return 0;
1498  if ( m_ppad == nullptr ) return 1;
1499  TVirtualPad* pPadSave = gPad;
1500  m_ppad->cd();
1501  double xminPad, yminPad, xmaxPad, ymaxPad;
1502  m_ppad->GetRangeAxis(xminPad, yminPad, xmaxPad, ymaxPad);
1503  double y1 = ymin();
1504  double y2 = ymax();
1505  string sopt = "+US";
1506  if ( m_ppad->GetLogx() ) {
1507  xminPad = pow(10.0, xminPad);
1508  xmaxPad = pow(10.0, xmaxPad);
1509  }
1510  if ( m_ppad->GetLogy() ) {
1511  yminPad = pow(10.0, yminPad);
1512  ymaxPad = pow(10.0, ymaxPad);
1513  sopt += "G";
1514  }
1515  TAxis* paxold = getYaxis();
1516  if ( paxold == 0 ) return 2;
1517  double ticksize = paxold->GetTickLength();
1518  int ndiv = paxold->GetNdivisions();
1519  TGaxis* paxnew = new TGaxis(xmaxPad, yminPad, xmaxPad, ymaxPad,
1520  y1, y2, ndiv, sopt.c_str());
1521  if ( ticksize > 0 ) paxnew->SetTickLength(ticksize);
1522  string name = "RightAxis";
1523  paxnew->SetName(name.c_str());
1524  TList* pobjs = m_ppad->GetListOfPrimitives();
1525  for ( int iobj=pobjs->GetEntries()-1; iobj>=0; --iobj ) {
1526  TGaxis* paxold = dynamic_cast<TGaxis*>(pobjs->At(iobj));
1527  if ( paxold == nullptr ) continue;
1528  if ( paxold->GetName() == name ) {
1529  pobjs->RemoveAt(iobj);
1530  break;
1531  }
1532  }
1533  paxnew->Draw("");
1534  gPad = pPadSave;
1535  return 0;
1536 }
1537 
1538 //**********************************************************************
1539 
1541  if ( m_ppad == nullptr ) return 1;
1542  const TList* pfuns = nullptr;
1543  if ( haveHist() ) pfuns = hist()->GetListOfFunctions();
1544  else if ( m_pg != nullptr ) pfuns = m_pg->GetListOfFunctions();
1545  else return 1;
1546  const TList& funs = *pfuns;
1547  unsigned int nfun = funs.GetEntries();
1548  TVirtualPad* pPadSave = gPad;
1549  m_ppad->cd();
1550  for ( unsigned int ifun : m_histFuns ) {
1551  if ( ifun >= nfun ) continue;
1552  TF1* pfun = dynamic_cast<TF1*>(funs.At(ifun));
1553  if ( pfun != nullptr ) pfun->Draw("same");
1554  }
1555  gPad = pPadSave;
1556  return 0;
1557 }
1558 
1559 //**********************************************************************
1560 
1562  if ( m_ppad == nullptr ) return 1;
1563  TVirtualPad* pPadSave = gPad;
1564  m_ppad->cd();
1565  clearLineObjects();
1566  for ( Index iset=0; iset<m_vmlXmod.size(); ++iset ) {
1567  double xmod = m_vmlXmod[iset];
1568  double xoff = m_vmlXoff[iset];
1569  double xlen = m_vmlXLength[iset];
1570  int isty = m_vmlXStyle[iset];
1571  if ( xmod < 0.0 ) continue;
1572  double x = xoff;
1573  if ( xmod > 0.0 ) {
1574  while ( x >= xmin() ) x -= xmod;
1575  while ( x < xmin() ) x += xmod;
1576  }
1577  double ytop = ymax() + (xlen - 1.0)*(ymax() - ymin());
1578  while ( x <= xmax() ) {
1579  TLine* pline = new TLine(x, ymin(), x, ytop);
1580  pline->SetLineStyle(isty);
1581  m_lines.push_back(pline);
1582  pline->Draw();
1583  if ( xmod == 0.0 ) break;
1584  x += xmod;
1585  }
1586  }
1587  for ( Index iset=0; iset<m_hmlXmod.size(); ++iset ) {
1588  double ymod = m_hmlXmod[iset];
1589  double yoff = m_hmlXoff[iset];
1590  double ylen = m_hmlXLength[iset];
1591  int isty = m_hmlXStyle[iset];
1592  if ( ymod < 0.0 ) continue;
1593  double y = yoff;
1594  if ( ymod > 0.0 ) {
1595  while ( y >= ymin() ) y -= ymod;
1596  while ( y < ymin() ) y += ymod;
1597  }
1598  double xtop = xmax() + (ylen - 1.0)*(xmax() - xmin());
1599  while ( y <= ymax() ) {
1600  TLine* pline = new TLine(xmin(), y, xtop, y);
1601  pline->SetLineStyle(isty);
1602  m_lines.push_back(pline);
1603  pline->Draw();
1604  if ( ymod == 0.0 ) break;
1605  y += ymod;
1606  }
1607  }
1608  for ( Index iset=0; iset<m_slSlop.size(); ++iset ) {
1609  double slop = m_slSlop[iset];
1610  double yoff = m_slYoff[iset];
1611  double isty = m_slStyl[iset];
1612  double wx = xmax() - xmin();
1613  double wy = ymax() - ymin();
1614  if ( wx < 0.0 || wy < 0.0 ) continue;
1615  double xlef = xmin();
1616  double xrig = xmax();
1617  double ybot = ymin();
1618  double ytop = ymax();
1619  double ylef = slop*xlef + yoff;
1620  double yrig = slop*xrig + yoff;
1621  double xbot = slop == 0.0 ? xmin() - wx : (ybot - yoff)/slop;
1622  double xtop = slop == 0.0 ? xmax() + wx : (ytop - yoff)/slop;
1623  double x1 = 0.0;
1624  double y1 = 0.0;
1625  if ( ylef > ybot && ylef < ytop ) {
1626  x1 = xlef;
1627  y1 = ylef;
1628  } else if ( ylef <= ybot && slop > 0.0 && xbot < xrig ) {
1629  x1 = xbot;
1630  y1 = ybot;
1631  } else if ( ylef >= ytop && slop < 0.0 && xtop < xrig ) {
1632  x1 = xtop;
1633  y1 = ytop;
1634  } else {
1635  continue;
1636  }
1637  double x2 = 0.0;
1638  double y2 = 0.0;
1639  if ( slop > 0.0 && xtop < xrig ) {
1640  x2 = xtop;
1641  y2 = ytop;
1642  } else if ( slop < 0.0 && xbot < xrig ) {
1643  x2 = xbot;
1644  y2 = ybot;
1645  } else {
1646  x2 = xrig;
1647  y2 = yrig;
1648  }
1649  TLine* pline = new TLine(x1, y1, x2, y2);
1650  pline->SetLineStyle(isty);
1651  m_lines.push_back(pline);
1652  pline->Draw();
1653  }
1654  gPad = pPadSave;
1655  return 0;
1656 }
1657 
1658 //**********************************************************************
1659 
1660 void TPadManipulator::Streamer(TBuffer& buf) {
1661  const string myname = "TPadManipulator::Streamer: ";
1662  int dbg = 0;
1663  TClass* pclass = TClass::GetClass("TPadManipulator");
1664  if ( buf.IsReading() ) {
1665  if ( pclass == nullptr ) {
1666  cout << myname << "Dictionary not found for read." << endl;
1667  return;
1668  }
1669  // Stream in.
1670  pclass->ReadBuffer(buf, this);
1671  // Set the parents. This only needs to be done for the top level object
1672  // but I don't know how to tell if this is the case.
1673  setParents(true);
1674  // Log message.
1675  string msg = haveHist() ? "histogram" : haveGraph() ? "graph" : "no primary";
1676  cout << myname << "Read pad with " << msg << " and "
1677  << objects().size() << " extra objects and "
1678  << m_subMans.size() << " subpads." << endl;
1679  } else {
1680  if ( pclass == nullptr ) {
1681  cout << myname << "Dictionary not found for write." << endl;
1682  return;
1683  }
1684  // Log message.
1685  if ( dbg ) {
1686  string msg = haveHist() ? "histogram" : haveGraph() ? "graph" : "no primary";
1687  cout << myname << "Writing pad with " << msg << " and "
1688  << objects().size() << " extra objects and "
1689  << m_subMans.size() << " subpads." << endl;
1690  if ( haveHistOrGraph() ) object()->Print();
1691  }
1692  // Stream out.
1693  pclass->WriteBuffer(buf, this);
1694  }
1695 }
1696 
1697 //**********************************************************************
1698 
1699 void TPadManipulator::setParents(bool recurse) {
1700  for ( TPadManipulator& man : m_subMans ) {
1701  man.m_parent = this;
1702  if ( recurse ) man.setParents(true);
1703  }
1704  }
1705 
1706 //**********************************************************************
static QCString name
Definition: declinfo.cpp:673
std::vector< unsigned int > m_histFuns
std::vector< double > m_vmlXLength
TPadManipulator * progenitor()
void setTExec(Name com)
std::vector< double > m_hmlXoff
TAxis * getYaxis() const
const StringVector & patternSplit(std::string spat)
TPadManipulator * parent()
TFrame * frame() const
double xmax() const
TObject * object() const
double zmax() const
bool haveHist() const
int setTimeOffset(double toff)
std::string m_timeFormatY
BoundsVector m_subBounds
void msg(const char *fmt,...)
Definition: message.cpp:107
TPadManipulator * m_parent
TH1 * getHist(unsigned int iobj)
double getLabelSizeX() const
bool dbg
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
TLegend * addLegend(double x1, double y1, double x2, double y2)
bool haveCanvas() const
std::string string
Definition: nybbler.cc:12
int m_canvasWidth
==> Do not stream.
int addPad(double x1, double y1, double x2, double y2, int icol=-1)
double ymin() const
TH1 * frameHist() const
TCanvas * canvas() const
LineVector m_lines
constexpr T pow(T x)
Definition: pow.h:72
std::string getLabel() const
int addSlopedLine(double slop, double yoff=0.0, int isty=1)
int setRangeZ(double y1, double y2)
int framePixelsY() const
std::vector< int > m_hmlXStyle
int setCanvasSize(int wx, int wy)
int canvasPixelsY() const
int split(Index nx, Index ny)
bool haveHistOrGraph() const
std::vector< double > m_vmlXmod
unsigned int Index
bool havePad() const
TVirtualPad * m_ppad
==> Do not stream
int setLabel(std::string slab)
TH1 * hist() const
bool haveFrameHist() const
std::string m_gflowOpt
==> Do not stream.
int setLogRangeZ(double y1, double y2)
int showOverflow(bool show=true)
int framePixelsX() const
double getTitleSize() const
int setTitle(std::string sttl, float height=-1.0)
int canvasPixelsX() const
int addHorizontalLine(double yoff=0.0, double lenfrac=1.0, int isty=1)
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
std::vector< double > m_slYoff
static TPadManipulator * get(Name onam="tpad", TDirectory *tdir=nullptr)
NameVector m_binLabelsX
==> Do not stream.
int printOnce(std::string fname)
unsigned int Index
int setBinLabelsX(const NameVector &labs)
double zmin() const
TAxis * getXaxis() const
double padPixelsX() const
int addAxisRight(bool flag=true)
static TPadManipulator * read(Name fnam, Name onam="tpad")
int showGraphOverflow(std::string sopt="BTLR", int imrk=38, int icol=1)
std::vector< Name > NameVector
std::vector< double > m_vmlXoff
int showUnderflow(bool show=true)
bool m_showUnderflow
==> Do not stream.
void Streamer(TBuffer &buf)
int addAxis(bool flag=true)
int setRangeXY(double x1, double x2, double y1, double y2)
TAxis * getZaxis() const
unsigned int npad() const
int put(Name onam="tpad", TDirectory *tdir=nullptr) const
double xmin() const
TPadManipulator * man(unsigned int ipad=0)
TObject * lastObject() const
std::vector< int > m_vmlXStyle
double padPixelsY() const
TGraph * graph() const
bool haveParent() const
int addVerticalModLines(double xmod, double xoff=0.0, double lenfrac=1.0, int isty=3)
std::vector< double > m_hmlXLength
std::string Name
int addHistFun(unsigned int ifun=0)
std::vector< double > m_slSlop
double ymax() const
std::vector< int > m_slStyl
int setLogRangeY(double y1, double y2)
int setRangeX(double x1, double x2)
int addVerticalLine(double xoff=0.0, double lenfrac=1.0, int isty=1)
std::vector< TPadManipulator > m_subMans
TPadManipulator & operator=(const TPadManipulator &rhs)
int setBinLabelsY(const NameVector &labs)
std::vector< std::string > m_opts
bool haveFrame() const
int setTimeFormatX(std::string sfmt)
list x
Definition: train.py:276
std::string m_dopt
void setParents(bool recurse)
TVirtualPad * pad() const
const TObjVector & objects() const
int addAxisTop(bool flag=true)
NameVector m_binLabelsY
int addHorizontalModLines(double ymod, double yoff=0.0, double lenfrac=1.0, int isty=3)
int write(Name fnam, Name onam="tpad") const
void setPalette(int ipal)
int setRangeY(double y1, double y2)
bool haveGraph() const
int print(std::string fname, std::string spat="{,}")
double getLabelSizeY() const
std::vector< double > m_hmlXmod
QTextStream & endl(QTextStream &s)
int setTimeFormatY(std::string sfmt)
int setLogRangeX(double x1, double x2)
std::string m_timeFormatX