TPadManipulator.h
Go to the documentation of this file.
1 // TPadManipulator.h
2 //
3 // David Adams
4 // Octobe 2017
5 //
6 // Root macro to manipulate a root drawing pad.
7 //
8 // The first histogram or graph in the pad is cloned and the pad is updated
9 // using the clone. Caller then has the options to
10 // change X and Y range
11 // add top and bottom axis
12 // display underflow and overflow (histograms only)
13 // add vertical lines at regular intervals
14 // display any of the functions (e.g. the fit) associated with the histogram or graph
15 //
16 // It is also posssible to and multiple subpads and draw into those instead of the
17 // top-level pad. There is a manipulator for each subpad.
18 
19 #ifndef TPadManipulator_H
20 #define TPadManipulator_H
21 
22 #include <vector>
23 #include <memory>
24 #include "TLatex.h"
25 #include "TLine.h"
26 #include "TLegend.h"
27 #include "TExec.h"
28 
29 class TVirtualPad;
30 class TCanvas;
31 class TH1;
32 class TGraph;
33 class TAxis;
34 class TLegend;
35 class TFrame;
36 class TBuffer;
37 class TDirectory;
38 
40 
41 public:
42 
43  struct Bounds {
44  double x1;
45  double y1;
46  double x2;
47  double y2;
48  Bounds() : x1(0.0), y1(0.0), x2(0.0), y2(0.0) { }
49  Bounds(double ax1, double ay1, double ax2, double ay2)
50  : x1(ax1), y1(ay1), x2(ax2), y2(ay2) { }
51  };
52 
53  struct Bounds3 : public Bounds {
54  double z1;
55  double z2;
56  Bounds3() : z1(0.0), z2(0.0) { }
57  Bounds3(double ax1, double ay1, double ax2, double ay2, double az1, double az2)
58  : Bounds(ax1, ay1, ax2, ay2), z1(az1), z2(az2) { }
59  };
60 
61  using Index = unsigned int;
62  using LineVector = std::vector<TLine*>;
63  using TObjVector = std::vector<TObject*>;
64  using BoundsVector = std::vector<Bounds>;
65  using Name = std::string;
66  using NameVector = std::vector<Name>;
67  using HistPtr = std::shared_ptr<TH1>;
68 
69  // Get object with name onam from Root directory rdir.
70  static TPadManipulator* get(Name onam ="tpad", TDirectory* tdir =nullptr);
71 
72  // Read object with name onam from the Root file fnam.
73  static TPadManipulator* read(Name fnam, Name onam ="tpad");
74 
75  // Default ctor.
76  // Creates an empty top-level object.
78 
79  // Ctor from a pad. Use ppad = gPad to grab the current pad.
80  // Copies the objects from the pad.
81  TPadManipulator(TVirtualPad* ppad);
82 
83  // Ctors that creates a new canvas.
84  // The canvas size is wx x wy.
85  // If nPadX > 0, calls split(nPadX, nPadY) if nPadY > 0
86  // or split(nPadX, nPadX) if nPadY == 0
87  TPadManipulator(Index wx, Index wy, Index nPadX =0, Index nPadY =0);
88 
89  // Copy and assignment.
90  // Objects from the RHS are cloned so that mods in one pad don't affect the other.
91  // These can be used to copy an existing pad into a subpad of another.
92  // In assignment, the original objects belonging to this pad are deleted.
93  TPadManipulator(const TPadManipulator& rhs);
95 
96  // Dtor.
97  // This removes the lines.
99 
100  // Return the axis coordinates in pad units (pixels).
101  //double xminPad() const { return m_xminPad; }
102  //double xmaxPad() const { return m_xmaxPad; }
103  //double yminPad() const { return m_yminPad; }
104  //double ymaxPad() const { return m_ymaxPad; }
105 
106  // Return the axis limits in drawn units.
107  // These will be the user-specified range if valid or, for X and Y, the drawn pad.
108  double xmin() const;
109  double xmax() const;
110  double ymin() const;
111  double ymax() const;
112  double zmin() const;
113  double zmax() const;
114 
115  // Return the pad.
116  // Use pad()->SetFillColor(...), etc. to change the appearance of the pad.
117  // and pad()->SetFrameFillColor(...), etc. to change the appearance of the frame in the pad.
118  TVirtualPad* pad() const { return m_ppad; }
119  bool havePad() const { return pad() != nullptr; }
120 
121  // Return the canvas holding this pad. It may be held by an ancestor.
122  // If doDraw is true, a draw is done if the canvas does not yet exist.
123  TCanvas* canvas() const;
124  TCanvas* canvas(bool doDraw =false);
125  bool haveCanvas() const { return canvas() != nullptr; }
126 
127  // Save this object with name onam to root directory tdir.
128  // If tdir is null, the current Root directory is used.
129  int put(Name onam ="tpad", TDirectory* tdir =nullptr) const;
130 
131  // Save this object with name onam to root file fnam.
132  // If tdir is null, the current Root directory is used.
133  // The root file is opened in update mode and then closed.
134  int write(Name fnam, Name onam ="tpad") const;
135 
136  // Create an image file. Name suffix should be a known format: png, pdf, ....
137  // If the suffix is .root or .tpad, then the object is written to that file.
139 
140  // Print one or more image files using StringManipulator pattern split.
141  // E.g. myfile.{png,pdf,tpad} --> myfile.png, myfile.pdf and myfile.tpad.
142  int print(std::string fname, std::string spat ="{,}");
143 
144  // Return the top-level manipulator, i.e. the ancestor that holds (or would hold)
145  // the canvas for this pad.
147 
148  // Return the number of subpads.
149  unsigned int npad() const;
150 
151  // Return the manipulator for a subpad.
152  // If there are no subpads and ipad=0, the top manipulator is returned.
153  TPadManipulator* man(unsigned int ipad =0);
154 
155  // Return the parent pad.
157  const TPadManipulator* parent() const { return m_parent; }
158  bool haveParent() const { return m_parent != nullptr; }
159 
160  // Return the primary histogram or graph for this pad.
161  TH1* hist() const { return m_ph; }
162  bool haveHist() const { return hist() != nullptr; }
163  TGraph* graph() const { return m_pg; }
164  bool haveGraph() const { return graph() != nullptr; }
165  TObject* object() const;
166  bool haveHistOrGraph() const { return object() != nullptr; }
167  std::string drawOpt() const { return m_dopt; }
168 
169  // Return the overlaid objects and options.
170  const TObjVector& objects() const { return m_objs; }
171  TObject* object(Index iobj) const { return iobj<objects().size() ? objects()[iobj] : nullptr; }
172  TH1* getHist(unsigned int iobj);
173  const std::vector<std::string>& objOpts() const { return m_opts; }
174 
175  // Return a histogram (primary or secondary) by name.
176  // This is the drawn hist and may be used to changes its visible properties
177  // or reference those in a legend.
178  TH1* getHist(std::string hnam);
179 
180  // Return the last object added to the pad.
181  TObject* lastObject() const;
182 
183  // Return information about the canvas holding this pad.
184  int canvasPixelsX() const;
185  int canvasPixelsY() const;
186 
187  // Return information about the full drawing area for this pad.
188  // Pad must be drawn (or printed) to set these values for subpads.
189  double padPixelsX() const;
190  double padPixelsY() const;
191 
192  // Return info about the frame that holds the histogram or graph.
193  // The frame does not exist until draw() is called..
194  // The frame histogram has the drawn axis.
195  TFrame* frame() const;
196  bool haveFrame() const { return frame() != nullptr; }
197  int framePixelsX() const;
198  int framePixelsY() const;
199  TH1* frameHist() const;
200  bool haveFrameHist() const { return frameHist() != nullptr; }
201 
202  // Delete the line objects.
203  void clearLineObjects();
204 
205  // Return the lines associated with this pad.
206  const LineVector& verticalModLines() const { return m_lines; }
207 
208  // Add a subpad covering (x1, y1) to (x2, y2) in NDC units, i.e. 0 < x,y < 1.
209  int addPad(double x1, double y1, double x2, double y2, int icol =-1);
210 
211  // Tile the top pad with nx x ny or nx x nx subpads.
212  int split(Index nx, Index ny);
213  int split(Index nx);
214 
215  // Add an object (histogram or graph) to the pad.
216  // The first object must be a histogram or graph.
217  int add(unsigned int ipad, TObject* pobj, std::string sopt ="", bool replace =false);
218  int add(TObject* pobj, std::string sopt ="", bool replace =false);
219 
220  // Set and fetch the TExec command run when the pad is drawn.
221  void setTExec(Name com) { m_exec.SetTitle(com.c_str()); }
222  const TExec& getTExec() const { return m_exec; }
223 
224  // Set the palette for this pad.
225  // Added to TExec.
226  // Negative for no platte command.
227  void setPalette(int ipal);
228 
229  // Set margins. Negative value uses default margin.
230  // The default is set here to be reasonable for a wide range of aspect ratio.
231  // The margin is the fraction of the pad between the frame and pad edges.
232  // The corresponding axis title offset is also changed so that the title
233  // does not move relative to the pad, i.e. remains close to the pad edge.
234  // This behavior is not (yet) implemented for the z-axis (right) or title (top).
235  void setMarginLeft(double xmar) { m_marginLeft = xmar; }
236  void setMarginRight(double xmar) { m_marginRight = xmar; }
237  void setMarginBottom(double xmar) { m_marginBottom = xmar; }
238  void setMarginTop(double xmar) { m_marginTop = xmar; }
239 
240  // Center axis labels.
242 
243  // Add a legend.
244  // This is added to the list of objects.
245  TLegend* addLegend(double x1, double y1, double x2, double y2);
246 
247  // Return the legend.
248  TLegend* getLegend() const { return dynamic_cast<TLegend*>(object(m_iobjLegend)); }
249 
250  // Set and get the title associated with this pad.
251  // The initial value for this is taken from the primary object.
252  // The title is positioned in the middle of the top margin and its
253  // size is limited to 90% of the margin height.
254  int setTitle(std::string sttl, float height =-1.0);
255  std::string getTitle() const { return m_title.GetTitle(); }
256 
257  // Set and get the label associated with this pad.
258  // The label object can be used to modify the label.
259  // This is written in the lower left corner.
260  int setLabel(std::string slab);
261  std::string getLabel() const { return m_label.GetTitle(); }
262  TLatex& getLabelObject() { return m_label; }
263 
264  // Remove histograms and graphs from top and subpads.
265  int clear();
266 
267  // Update the coordinates and histogram for this pad.
268  int update();
269 
270  // Get the axes of the histogram or graph.
271  TAxis* getXaxis() const;
272  TAxis* getYaxis() const;
273  TAxis* getZaxis() const;
274 
275  // Set drawing attributes.
276  int setCanvasSize(int wx, int wy);
277  int setFillColor(int col) { m_fillColor = col; return update(); }
278  int setFrameFillColor(int col) { m_frameFillColor = col; return update(); }
279  int setGridX(bool flag =true) { m_gridX = flag; return update(); }
280  int setGridY(bool flag =true) { m_gridY = flag; return update(); }
281  int setGrid(bool flag =true) { m_gridX = flag; m_gridY=flag; return update(); }
282  int setLogX(bool flag =true) { m_logX = flag; return update(); }
283  int setLogY(bool flag =true) { m_logY = flag; return update(); }
284  int setLogZ(bool flag =true) { m_logZ = flag; return update(); }
285 
286  // Set the tick lengths. This is a fraction of the axis length.
287  // If the X length is zero, those ticks are not drawn.
288  // If the Y length is zero, those ticks on both axis have the same pixel lengths and
289  // that length is detemined by the shorter axis.
290  int setTickLength(double len) { m_tickLengthX = len; m_tickLengthY = 0.0; return update(); }
291  int setTickLengthX(double len) { m_tickLengthX = len; return update(); }
292  int setTickLengthY(double len) { m_tickLengthY = len; return update(); }
293 
294  // Set the tick/label division guides.
295  int setNdivisionsX(int ndiv) { m_ndivX = ndiv; return 0; };
296  int setNdivisionsY(int ndiv) { m_ndivY = ndiv; return 0; };
297 
298  // Set the axis label sizes. Default is zero.
299  // Unless set explcitely, Sub-pads will use a scaled version of this
300  // so all labels are the same size.
301  // The z-axis label size is the same as that for y.
302  int setLabelSizeX(double siz) { m_labSizeX = siz; return 0; }
303  int setLabelSizeY(double siz) { m_labSizeY = siz; return 0; }
304  int setTitleSize(double siz) { m_ttlSize = siz; return 0; }
305 
306  // Fetch the label size for this pad.
307  // Returns the set value if nonzero, otherwise
308  // if parent, returns the parent value scaled by ratio of pad heights
309  // otherwise returns zero.
310  double getLabelSizeX() const;
311  double getLabelSizeY() const;
312  double getTitleSize() const;
313 
314  // Set the displayed ranges.
315  // If x1 >= x2 (default), then the range is that of the primary object.
316  int setRangeX(double x1, double x2);
317  int setRangeY(double y1, double y2);
318  int setRangeZ(double y1, double y2);
319  int setRangeXY(double x1, double x2, double y1, double y2);
320 
321  // Set the displayed ranges for logarithmic axes.
322  // If x1 >= x2 or either <=0, then the standard range is used.
323  int setLogRangeX(double x1, double x2);
324  int setLogRangeY(double y1, double y2);
325  int setLogRangeZ(double y1, double y2);
326 
327  // Set the time offset in second for axes using time format.
328  // 0 (default) is UTC (GMT).
329  int setTimeOffset(double toff);
330 
331  // Set the time format for an axis.
332  // If blank (default), time format is not used.
333  // The format is similar to that of strftime.
334  // See TAxis::SetTimeFormat for more information.
335  // Append "%Fyyyy-mm-dd hh:mm:ss" to set the time offset.
336  int setTimeFormatX(std::string sfmt);
337  int setTimeFormatY(std::string sfmt);
338 
339  // Add or remove top and right axis.
340  int addAxis(bool flag =true);
341 
342  // Add or remove top x-axis.
343  int addAxisTop(bool flag =true);
344 
345  // Add or remove right y-axis.
346  int addAxisRight(bool flag =true);
347 
348  // Add underflow bin to the plot (false to remove it).
349  int showUnderflow(bool show =true);
350  int showOverflow(bool show =true);
351 
352  // Return the under/overflow histogram.
353  TH1* flowHistogram() { return m_flowHist; }
354 
355  // Show overflow points for graphs.
356  // Any point off scale in any of the indicated directions is drawn at
357  // that boundary with the indicated marker and color.
358  // Direction: B=bottom, T=top, L=left, R=right, "" to show nothing.
359  int showGraphOverflow(std::string sopt ="BTLR", int imrk =38, int icol =1);
360 
361  // Return the under/overflow graph.
362  TGraph* flowGraph() { return m_flowGraph; }
363 
364  // Remove all lines.
365  int clearLines();
366 
367  // Add a vertical line at x=xoff or horizontal at y=yoff.
368  // The lines are draw with style isty from the low edge to lenfrac*width
369  int addVerticalLine(double xoff =0.0, double lenfrac =1.0, int isty =1);
370  int addHorizontalLine(double yoff =0.0, double lenfrac =1.0, int isty =1);
371 
372  // Add a line with slop dydx and y = y0 at x = 0.
373  // The lines are draw with style isty between frame boundaries.
374  int addSlopedLine(double slop, double yoff =0.0, int isty =1);
375 
376  // Add vertical modulus lines.
377  // I.e at x = xoff, xoff+/-xmod, xoff+/-2*xmod, ...
378  // The lines are draw with style isty from the low edge to lenfrac*width
379  int addVerticalModLines(double xmod, double xoff =0.0, double lenfrac =1.0, int isty =3);
380  int addHorizontalModLines(double ymod, double yoff =0.0, double lenfrac =1.0, int isty =3);
381 
382  // Set text bin labels.
383  // Only used if primary object is a histogram (2D for y).
384  int setBinLabelsX(const NameVector& labs);
385  int setBinLabelsY(const NameVector& labs);
386 
387  // Add histogram function ifun to the pad.
388  int addHistFun(unsigned int ifun =0);
389 
390  // Fix the BG color for 2D histos to be the same as the lowest color.
391  // Otherwise underflows have the color of zeros.
392  int fixFrameFillColor();
393 
394  // Draw the canvas.
395  // Until this is called, nothing will apear on the screen.
396  // If this is a subpad, then the parent is drawn.
397  int draw();
398 
399  // Delete the canvas holding this pad.
400  int erase();
401 
402  // Redraw a canvas.
403  // The current canvas is deleted and a new one created.
404  // This is useful if the batch mode has changed or to bring a window to the top.
405  int redraw();
406 
407  // Draw the top axis.
408  int drawAxisTop();
409 
410  // Draw right y-axis.
411  int drawAxisRight();
412 
413  // Draw the hist functions.
414  int drawHistFuns();
415 
416  // Draw the current lines.
417  int drawLines();
418 
419  // Custom streamer.
420  void Streamer(TBuffer& buf);
421 
422 private:
423 
424  // Set the parent for all children.
425  // If recurse is true, the operation is also performed on their children.
426  void setParents(bool recurse);
427 
428 private:
429 
430  TPadManipulator* m_parent; //! ==> Do not stream
431  TVirtualPad* m_ppad; //! ==> Do not stream.
434  TExec m_exec;
435  double m_marginLeft;
438  double m_marginTop;
439  TH1* m_ph;
440  TGraph* m_pg;
443  std::vector<std::string> m_opts;
448  bool m_gridX;
449  bool m_gridY;
450  bool m_logX;
451  bool m_logY;
452  bool m_logZ;
455  int m_ndivX;
456  int m_ndivY;
457  double m_labSizeX;
458  double m_labSizeY;
459  double m_ttlSize;
460  TH1* m_flowHist; //! ==> Do not stream.
463  TGraph* m_flowGraph; //! ==> Do not stream.
467  bool m_top;
468  bool m_right;
469  TLatex m_title;
470  TLatex m_label;
471  std::vector<unsigned int> m_histFuns;
472  std::vector<double> m_hmlXmod;
473  std::vector<double> m_hmlXoff;
474  std::vector<int> m_hmlXStyle;
475  std::vector<double> m_hmlXLength;
476  std::vector<double> m_vmlXmod;
477  std::vector<double> m_vmlXoff;
478  std::vector<int> m_vmlXStyle;
479  std::vector<double> m_vmlXLength;
480  std::vector<double> m_slSlop;
481  std::vector<double> m_slYoff;
482  std::vector<int> m_slStyl;
483  LineVector m_lines; //! ==> Do not stream.
486  double m_timeOffset =0.0;
490  std::vector<TPadManipulator> m_subMans;
493 
494 };
495 
496 #endif
std::vector< unsigned int > m_histFuns
std::vector< double > m_vmlXLength
TPadManipulator * progenitor()
void setTExec(Name com)
int setGridY(bool flag=true)
std::vector< double > m_hmlXoff
TAxis * getYaxis() const
TPadManipulator * parent()
TFrame * frame() const
double xmax() const
TObject * object() const
double zmax() const
bool haveHist() const
int setTimeOffset(double toff)
int setLabelSizeX(double siz)
std::string m_timeFormatY
BoundsVector m_subBounds
TPadManipulator * m_parent
TH1 * getHist(unsigned int iobj)
double getLabelSizeX() const
int setTitleSize(double siz)
int add(unsigned int ipad, TObject *pobj, std::string sopt="", bool replace=false)
TLegend * addLegend(double x1, double y1, double x2, double y2)
void setMarginLeft(double xmar)
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
const TPadManipulator * parent() const
std::string getLabel() const
int addSlopedLine(double slop, double yoff=0.0, int isty=1)
int setLabelSizeY(double siz)
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)
int setTickLengthY(double len)
bool haveHistOrGraph() const
const LineVector & verticalModLines() const
std::vector< double > m_vmlXmod
bool havePad() const
int setFrameFillColor(int col)
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 setNdivisionsX(int ndiv)
Bounds(double ax1, double ay1, double ax2, double ay2)
int framePixelsX() const
const TExec & getTExec() 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)
std::vector< double > m_slYoff
Bounds3(double ax1, double ay1, double ax2, double ay2, double az1, double az2)
NameVector m_binLabelsX
==> Do not stream.
int printOnce(std::string fname)
int setLogZ(bool flag=true)
unsigned int Index
int setBinLabelsX(const NameVector &labs)
double zmin() const
TAxis * getXaxis() const
TLegend * getLegend() const
double padPixelsX() const
int addAxisRight(bool flag=true)
TLatex & getLabelObject()
static TPadManipulator * read(Name fnam, Name onam="tpad")
int showGraphOverflow(std::string sopt="BTLR", int imrk=38, int icol=1)
std::vector< Name > NameVector
int setLogY(bool flag=true)
int setTickLength(double len)
std::vector< double > m_vmlXoff
int showUnderflow(bool show=true)
bool m_showUnderflow
==> Do not stream.
void Streamer(TBuffer &buf)
int setFillColor(int col)
int addAxis(bool flag=true)
int setRangeXY(double x1, double x2, double y1, double y2)
TAxis * getZaxis() const
int setGrid(bool flag=true)
unsigned int npad() const
int put(Name onam="tpad", TDirectory *tdir=nullptr) const
std::string getTitle() 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)
TGraph * flowGraph()
std::vector< double > m_hmlXLength
void setMarginTop(double xmar)
TObject * object(Index iobj) const
std::string Name
std::string drawOpt() const
void centerAxisTitles(bool center=true)
int addHistFun(unsigned int ifun=0)
std::vector< double > m_slSlop
double ymax() const
const std::vector< std::string > & objOpts() const
std::vector< Bounds > BoundsVector
std::vector< int > m_slStyl
int setLogRangeY(double y1, double y2)
int setRangeX(double x1, double x2)
def center(depos, point)
Definition: depos.py:117
int addVerticalLine(double xoff=0.0, double lenfrac=1.0, int isty=1)
std::vector< TLine * > LineVector
int setTickLengthX(double len)
std::vector< TObject * > TObjVector
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)
void setMarginBottom(double xmar)
std::string m_dopt
void setParents(bool recurse)
TVirtualPad * pad() const
const TObjVector & objects() const
int addAxisTop(bool flag=true)
NameVector m_binLabelsY
int setGridX(bool flag=true)
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)
std::shared_ptr< TH1 > HistPtr
int setRangeY(double y1, double y2)
bool haveGraph() const
int setLogX(bool flag=true)
void setMarginRight(double xmar)
int print(std::string fname, std::string spat="{,}")
double getLabelSizeY() const
std::vector< double > m_hmlXmod
int setNdivisionsY(int ndiv)
int setTimeFormatY(std::string sfmt)
int setLogRangeX(double x1, double x2)
std::string m_timeFormatX