CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Plot2D.h
Go to the documentation of this file.
1 #ifndef PLOT_2D__H
2 #define PLOT_2D__H
3 
4 #include "Plot1D.h"
5 #include "PlotCompareUtility.h"
6 #include "PlotTypes.h"
7 
8 #include <TGaxis.h>
9 #include <TH1F.h>
10 #include <TH2F.h>
11 #include <TLine.h>
12 #include <TProfile.h>
13 
14 #include <cmath>
15 #include <cstdio>
16 #include <fstream>
17 #include <iostream>
18 #include <string>
19 
20 template <>
21 inline bool PlotCompareUtility::compare<Plot2D>(HistoData *HD) {
22  // get the reference and comparison histograms
23  TH2F *href2d = (TH2F *)HD->getRefHisto();
24  TH2F *hnew2d = (TH2F *)HD->getNewHisto();
25 
26  // do not run comparisons if either histogram is empty/broken
27  if (hnew2d == nullptr || href2d == nullptr || hnew2d->GetEntries() <= 1 || href2d->GetEntries() <= 1) {
28  // std::cerr << HD->getName() << " error: unable to retrieve histogram (or
29  // no entries)\n";
30  HD->setIsEmpty(true);
31  return false;
32  }
33 
34  // prepare an overall result
35  bool projectionsPassed = true;
36 
37  // loop over axes (projections on one or both may be requested)
38  for (int axis = axisX; axis <= axisY; ++axis) {
39  // for X: verify projections requested and proper Y binning of href2d and
40  // hnew2d
41  if (axis == axisX && !HD->getDoProjectionsX())
42  continue;
43  if (axis == axisX && href2d->GetNbinsY() != hnew2d->GetNbinsY()) {
44  std::cerr << HD->getName() << " error: incorrect number of bins for X projection tests\n";
45  projectionsPassed = false;
46  continue;
47  }
48 
49  // for Y: verify projections requested and proper X binning of href2d and
50  // hnew2d
51  if (axis == axisY && !HD->getDoProjectionsY())
52  continue;
53  if (axis == axisY && href2d->GetNbinsX() != hnew2d->GetNbinsX()) {
54  std::cerr << HD->getName() << " error: incorrect number of bins for Y projection tests\n";
55  projectionsPassed = false;
56  continue;
57  }
58 
59  // setup the rebinning variables
60  int nBins = (axis == axisX) ? href2d->GetNbinsY() : href2d->GetNbinsX();
61  int nProjections = (axis == axisX) ? HD->getMaxProjectionsX() : HD->getMaxProjectionsY();
62  int nGroups = (int)ceil(float(nBins) / nProjections);
63  bool rebinned = false;
64 
65  // for X projections: if required rebin a clone of href2d and hnew2d
66  if (axis == axisX && HD->getDoAllow2DRebinningX() && nGroups > 1) {
67  href2d = (TH2F *)(((TH2F *)(href2d->Clone()))->RebinY(nGroups));
68  hnew2d = (TH2F *)(((TH2F *)(hnew2d->Clone()))->RebinY(nGroups));
69  nBins = href2d->GetNbinsY();
70  rebinned = true;
71  }
72 
73  // for Y projections: if required rebin a clone of href2d and hnew2d
74  if (axis == axisY && HD->getDoAllow2DRebinningY() && nGroups > 1) {
75  href2d = (TH2F *)(((TH2F *)(href2d->Clone()))->RebinX(nGroups));
76  hnew2d = (TH2F *)(((TH2F *)(hnew2d->Clone()))->RebinX(nGroups));
77  nBins = href2d->GetNbinsX();
78  rebinned = true;
79  }
80 
81  // loop over bins in histograms (go backwords to keep in order)
82  // for (int bin = nBins; bin >= 1; --bin) {
83  for (int bin = 1; bin <= nBins; ++bin) {
84  std::cout << "bin " << bin << " of " << nBins << std::endl;
85  // create some unique identifiers for the histogram names
86  TString projName = HD->getName() + (axis == axisX ? "_px" : "_py");
87  projName += bin;
88  TString newProjName = "new_";
89  newProjName += projName;
90  TString refProjName = "ref_";
91  refProjName += projName;
92 
93  // get the 1d projections for this bin out of the histogram
94  TH1D *hnew = (axis == axisX) ? hnew2d->ProjectionX(newProjName.Data(), bin, bin)
95  : hnew2d->ProjectionY(newProjName.Data(), bin, bin);
96  TH1D *href = (axis == axisX) ? href2d->ProjectionX(refProjName.Data(), bin, bin)
97  : href2d->ProjectionY(refProjName.Data(), bin, bin);
98 
99  // set histogram axis labels
100  hnew->GetXaxis()->SetTitle((axis == axisX ? hnew2d->GetXaxis()->GetTitle() : hnew2d->GetYaxis()->GetTitle()));
101  href->GetXaxis()->SetTitle((axis == axisX ? href2d->GetXaxis()->GetTitle() : href2d->GetYaxis()->GetTitle()));
102 
103  // allow Root to delete these histograms after display
104  hnew->SetBit(kCanDelete);
105  href->SetBit(kCanDelete);
106 
107  // create a new HistoData based on this projection
108  HistoData *proj = (axis == axisX) ? addProjectionXData(HD, projName.Data(), Plot1D, bin, hnew, href)
109  : addProjectionYData(HD, projName.Data(), Plot1D, bin, hnew, href);
110 
111  // ignore empty bins
112  // if (hnew->Integral() == 0 || href->Integral() == 0) continue;
113  if (hnew->GetEntries() <= 1 || href->GetEntries() <= 1 || hnew->Integral() == 0 || href->Integral() == 0)
114  continue;
115 
116  // run this new HistoData through compare<Plot1D>
117  projectionsPassed &= compare<Plot1D>(proj);
118 
119  // get the high and low scores from this comparison
120  float lowScore = proj->getLowScore();
121  float highScore = proj->getHighScore();
122  if (lowScore < HD->getLowScore())
123  HD->setLowScore(lowScore);
124  if (highScore > HD->getHighScore())
125  HD->setHighScore(highScore);
126  }
127 
128  // if 2d histograms were rebinned, delete the clone and re-get the original
129  if (rebinned) {
130  delete href2d;
131  href2d = (TH2F *)HD->getRefHisto();
132  delete hnew2d;
133  hnew2d = (TH2F *)HD->getNewHisto();
134  }
135  }
136 
137  // check overall result
138  HD->setResult(projectionsPassed);
139  HD->setIsEmpty(false);
140 
141  // returns true on test passed and false on test failed
142  return projectionsPassed;
143 }
144 
145 template <>
146 inline void PlotCompareUtility::makePlots<Plot2D>(HistoData *HD) {
147  // do not make any new plot if empty
148  if (HD->getIsEmpty()) {
149  HD->setResultImage("NoData_Results.gif");
150  HD->setResultTarget("NoData_Results.gif");
151  return;
152  }
153 
154  // loop over the projections to make 1D plots
155  std::vector<HistoData>::iterator hd;
156  for (hd = projectionsX[HD].begin(); hd != projectionsX[HD].end(); hd++)
157  makePlots<Plot1D>(&(*hd));
158  for (hd = projectionsY[HD].begin(); hd != projectionsY[HD].end(); hd++)
159  makePlots<Plot1D>(&(*hd));
160 
161  // make projection summaries
162  for (int axis = axisX; axis <= axisY; ++axis) {
163  // get the list of projections associated with this HistoData
164  std::vector<HistoData> *proj = (axis == axisX) ? &projectionsX[HD] : &projectionsY[HD];
165  if (proj == nullptr || proj->empty())
166  continue;
167 
168  // get the 2d histograms
169  TH2F *hnew2d = (TH2F *)HD->getNewHisto();
170  TH2F *href2d = (TH2F *)HD->getRefHisto();
171 
172  // generate a reasonable width for the projections summary
173  int numHistos = proj->size();
174  int bodyWidth = int(float(numHistos * projectionsBarsThickness) * 1.5);
175  projectionsWidth = projectionsLeftMargin + projectionsRightMargin + bodyWidth;
176 
177  // the canvas is rescaled during gif conversion, so add padding to Canvas
178  // dimensions
179  int projectionsCanvasWidth = projectionsWidth + 4;
180  int projectionsCanvasHeight = projectionsHeight + 28;
181 
182  // create and setup projections canvas
183  TCanvas projectionsCanvas(
184  "projectionsCanvas", "projectionsCanvas", projectionsCanvasWidth, projectionsCanvasHeight);
185  projectionsCanvas.SetFrameFillColor(10);
186  projectionsCanvas.SetLogy(1);
187  projectionsCanvas.SetTopMargin(float(projectionsTopMargin) / projectionsHeight);
188  projectionsCanvas.SetLeftMargin(float(projectionsLeftMargin) / projectionsWidth);
189  projectionsCanvas.SetRightMargin(float(projectionsRightMargin) / projectionsWidth);
190  projectionsCanvas.SetBottomMargin(float(projectionsBottomMargin) / projectionsHeight);
191  projectionsCanvas.Draw();
192 
193  // create and setup the summary histogram
194  TH1F projectionsSummary(
195  "projectionsSummary", "Compatibility with Reference Histograms", numHistos, 1, numHistos + 1);
196  projectionsSummary.GetYaxis()->SetRangeUser(getThreshold() / 10, 2);
197  projectionsSummary.SetStats(false);
198 
199  // display histogram (take axis from original histogram)
200  projectionsSummary.Draw("AH");
201 
202  // draw X axis
203  float xMin = hnew2d->GetXaxis()->GetXmin();
204  float xMax = hnew2d->GetXaxis()->GetXmax();
205  int ticksNDiv = numHistos * 20 + bodyWidth / 50; // formerly *20
206  TGaxis *xAxis = new TGaxis(1, 0, numHistos + 1, 0, xMin, xMax, ticksNDiv, "");
207  if (axis == axisX)
208  xAxis->SetTitle(hnew2d->GetYaxis()->GetTitle());
209  if (axis == axisY)
210  xAxis->SetTitle(hnew2d->GetXaxis()->GetTitle());
211  xAxis->Draw();
212 
213  // draw Y axis
214  float yMin = getThreshold() / 10;
215  float yMax = 2;
216  TGaxis *yAxis = new TGaxis(1, yMin, 1, yMax, yMin, yMax, 510, "G");
217  yAxis->SetTitle("Compatibility");
218  yAxis->Draw();
219 
220  // loop over projections and draw result
221  std::vector<HistoData>::iterator pd;
222  for (pd = proj->begin(); pd != proj->end(); pd++)
223  pd->drawResult(&projectionsSummary, true, false);
224 
225  // draw the pass/fail cutoff line
226  TLine passLine(1, getThreshold(), numHistos + 1, getThreshold());
227  passLine.SetLineColor(kRed);
228  passLine.SetLineWidth(2);
229  passLine.SetLineStyle(2);
230  passLine.Draw("SAME");
231 
232  // create the summary image
233  std::string gifName = HD->getName() + (axis == axisX ? "_Results_px.gif" : "_Results_py.gif");
234  projectionsCanvas.Print(gifName.c_str());
235 
236  // make overall projection plot of the original 2d histogram
237  std::string projName = HD->getName() + (axis == axisX ? "_py" : "_px");
238  std::string newBinsProj = projName + "_new";
239  std::string refBinsProj = projName + "_ref";
240  TH1D *href = (axis == axisX) ? href2d->ProjectionY(refBinsProj.c_str()) : href2d->ProjectionX(refBinsProj.c_str());
241  TH1D *hnew = (axis == axisX) ? hnew2d->ProjectionY(newBinsProj.c_str()) : hnew2d->ProjectionX(newBinsProj.c_str());
242 
243  // allow Root to delete these histograms after display
244  href->SetBit(kCanDelete);
245  hnew->SetBit(kCanDelete);
246 
247  // create a new HistoData based on this projection and plot it
248  HistoData allBins(projName, Plot1D, 0, hnew, href);
249  allBins.setIsEmpty(false);
250  allBins.setShadedFillColor(HD->getShadedFillColor());
251  allBins.setShadedFillStyle(HD->getShadedFillStyle());
252  allBins.setShadedLineColor(HD->getShadedLineColor());
253  makePlots<Plot1D>(&allBins);
254 
255  // set the default image (axisY takes priority by default)
256  if (HD->getResultImage().empty() || axis == axisY)
257  HD->setResultImage(projName + "_Results.gif");
258 
259  // set the default target (in case additional HTML code is/was not produced)
260  std::string currentTarget = HD->getResultTarget();
261  std::string xImgTarget = HD->getName() + "_px_Results.gif";
262  if (currentTarget.empty() || (axis == axisY && currentTarget == xImgTarget))
263  HD->setResultTarget(projName + "_Results.gif");
264  }
265 
266  /*
267  // make overall profile plot of the original 2d histogram
268  for (int axis = axisX; axis <= axisY; ++axis) {
269 
270  // make profile plots out of original 2D histograms
271  TProfile *pref = (axis == axisX) ? ((TH2F *)HD->getRefHisto())->ProfileY() :
272  ((TH2F *)HD->getRefHisto())->ProfileX(); TProfile *pnew = (axis == axisX) ?
273  ((TH2F *)HD->getNewHisto())->ProfileY() : ((TH2F
274  *)HD->getNewHisto())->ProfileX();
275 
276  // renormalize results for display
277  renormalize(pref,pnew);
278 
279  // do not allow Root to deallocate this memory after drawing (tries to free
280  twice?) pref->SetBit(kCanDelete); pnew->SetBit(kCanDelete);
281 
282  // set drawing options on the reference histogram
283  pref->SetStats(0);
284  pref->SetLineColor(kBlack);
285  pref->SetMarkerColor(kBlack);
286 
287  // set drawing options on the new histogram
288  pnew->SetStats(0);
289  pnew->SetLineColor(HD->getSolidLineColor());
290 
291  // place the test results as the title
292  TString title = HD->getName();
293 
294  // the canvas is rescaled during gif conversion, so add padding to Canvas
295  dimensions int plotsCanvasWidth = plotsWidth + 4; int plotsCanvasHeight =
296  plotsHeight + 28;
297 
298  // setup canvas for displaying the compared histograms
299  TCanvas hCanvas("hCanvas",title.Data(),plotsCanvasWidth,plotsCanvasHeight);
300  hCanvas.SetTopMargin(float(plotsTopMargin) / plotsHeight);
301  hCanvas.SetLeftMargin(float(plotsLeftMargin) / plotsWidth);
302  hCanvas.SetRightMargin(float(plotsRightMargin) / plotsWidth);
303  hCanvas.SetBottomMargin(float(plotsBottomMargin) / plotsHeight);
304  hCanvas.SetFrameFillColor(10);
305  hCanvas.SetGrid();
306  //hCanvas.SetLogy(1);
307  hCanvas.Draw();
308 
309  // draw the profiles
310  pref->Draw();
311  pnew->Draw("SAME");
312  if (HD->getDoDrawErrorBars()) pnew->Draw("E1SAME");
313 
314  // draw a legend
315  TLegend legend(0.15,0.01,0.3, 0.08);
316  legend.AddEntry(pnew,"New","lF");
317  legend.AddEntry(pref,"Reference","lF");
318  legend.SetFillColor(kNone);
319  legend.Draw("SAME");
320 
321  // create the plots overlay image
322  std::string gifName = HD->getName() + (axis == axisX ? "_pfx.gif" :
323  "_pfy.gif"); hCanvas.Print(gifName.c_str());
324 
325  // set the default image (axisY takes priority by default)
326  if (HD->getResultImage() == "" || axis == axisY)
327  HD->setResultImage(gifName);
328 
329  // set the default target (in case additional HTML code is/was not produced)
330  std::string currentTarget = HD->getResultTarget();
331  std::string xImgTarget = HD->getName() + "_pfx.gif";
332  if (currentTarget == "" || (axis == axisY && currentTarget == xImgTarget))
333  HD->setResultTarget(gifName);
334 
335  }
336  */
337 }
338 
339 template <>
340 inline void PlotCompareUtility::makeHTML<Plot2D>(HistoData *HD) {
341  /* at present, makeHTML<Plot1D> does nothing, so don't waste the CPU cycles
342  // loop over projections and produce HTML
343  std::vector<HistoData>::iterator hd;
344  for (hd = projectionsX[HD].begin(); hd != projectionsX[HD].end(); hd++)
345  makePlots<Plot1D>(&(*hd)); for (hd = projectionsY[HD].begin(); hd !=
346  projectionsY[HD].end(); hd++) makePlots<Plot1D>(&(*hd));
347  */
348 
349  // get the HistoData name for later reuse
350  std::string Name = HD->getName();
351 
352  // loop over the axes to see if projections were produced
353  bool pfDone[2] = {false, false};
354  for (int axis = axisX; axis <= axisY; axis++) {
355  // get the list of projections associated with this HistoData
356  std::vector<HistoData> *proj = (axis == axisX) ? &projectionsX[HD] : &projectionsY[HD];
357  if (proj == nullptr || proj->empty())
358  continue;
359  else
360  pfDone[axis] = true;
361 
362  // setup some names, etc. for insertion into the HTML
363  std::string gifNameProjections = Name + (axis == axisX ? "_Results_px.gif" : "_Results_py.gif");
364  std::string gifNameAllProj = Name + (axis == axisX ? "_py_Results.gif" : "_px_Results.gif");
365  std::string gifNameProfile = Name + (axis == axisX ? "_pfx.gif" : "_pfy.gif");
366  std::string gifBinPrefix = Name + (axis == axisX ? "_px" : "_py");
367 
368  // setup some locations to put thumbnails, etc.
369  int offset = 10;
370  int thumbWidth = plotsWidth / 4;
371  int thumbHeight = plotsHeight / 4;
372  int bodyWidth = projectionsWidth - projectionsLeftMargin - projectionsRightMargin;
373  int leftThumbPos = offset + projectionsLeftMargin + bodyWidth / 4 - thumbWidth / 2;
374  int rightThumbPos = leftThumbPos + bodyWidth / 2;
375  int thumbsLoc = projectionsTopMargin + thumbHeight / 2;
376 
377  // create the profile's HTML document
378  std::string htmlNameProfile = Name + (axis == axisX ? "_Results_px.html" : "_Results_py.html");
379  std::ofstream fout(htmlNameProfile.c_str());
380 
381  // print top portion of document
382  fout << "<!DOCTYPE gif PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>" << std::endl
383  << "<html>" << std::endl
384  << " <head>" << std::endl
385  << " <title>Compatibility of Projections for " << HD->getRefHisto()->GetTitle() << "</title>" << std::endl
386  << " <script type='text/javascript'>" << std::endl
387  << std::endl
388  << " function tn(target,image,class) {" << std::endl
389  << " clear()" << std::endl
390  << " "
391  "document.getElementById('thumb_div').setAttribute('class',class)"
392  << std::endl
393  << " "
394  "document.getElementById('thumb_div').setAttribute('className',"
395  "class)"
396  << std::endl
397  << " document.getElementById('thumb_link').href = target" << std::endl
398  << " document.getElementById('thumb_img').src = image" << std::endl
399  << " document.getElementById('thumb_img').width = '" << thumbWidth << "'" << std::endl
400  << " document.getElementById('thumb_img').height = '" << thumbHeight << "'" << std::endl
401  << " document.getElementById('thumb_img').border = '1'" << std::endl
402  << " }" << std::endl
403  << std::endl
404  << " function clear() {" << std::endl
405  << " document.getElementById('thumb_link').href = '#'" << std::endl
406  << " document.getElementById('thumb_img').src = ''" << std::endl
407  << " document.getElementById('thumb_img').width = '0'" << std::endl
408  << " document.getElementById('thumb_img').height = '0'" << std::endl
409  << " document.getElementById('thumb_img').border = '0'" << std::endl
410  << " }" << std::endl
411  << std::endl
412  << " </script>" << std::endl
413  << " </head>" << std::endl
414  << " <body onClick=\"window.location.href='index.html'\">"
415  << std::endl
416  // << "<a href='index.html'>"
417  << " <style type='text/css'>" << std::endl
418  << " #thumb_div {}" << std::endl
419  << " div.thumb_left {position: absolute; left: " << leftThumbPos << "px; top: " << thumbsLoc << "px;}"
420  << std::endl
421  << " div.thumb_right {position: absolute; left: " << rightThumbPos << "px; top: " << thumbsLoc << "px;}"
422  << std::endl
423  << " #main_d {position: absolute; left: " << offset << "px;}" << std::endl
424  << " a:link {color: #000000}" << std::endl
425  << " a:visited {color: #000000}" << std::endl
426  << " a:hover {color: #000000}" << std::endl
427  << " a:active {color: #000000}" << std::endl
428  << " </style>" << std::endl
429  << " <div id='main_d'>"
430  << std::endl
431  // << " <p>" << HD->getRefHisto()->GetTitle() << "</p>" //include
432  // the Title of the Plot as a title of the page
433  << " <img src='" << gifNameProjections << "' usemap='#results' alt=''"
434  << " height=" << projectionsHeight << " width=" << projectionsWidth << " border=0>" << std::endl
435  << " <map id='#results' name='results' onMouseOut=\"clear()\">" << std::endl;
436 
437  // loop over projections
438  std::vector<HistoData>::iterator pd;
439  for (pd = proj->begin(); pd != proj->end(); pd++) {
440  // determine map coordinates for this bin (1 pixel offset due to borders?)
441  int bin = pd->getBin();
442  int x1 = projectionsLeftMargin + int(float(bin * 1.5 - 1.25) * projectionsBarsThickness);
443  int x2 = x1 + projectionsBarsThickness;
444  int y1 = projectionsTopMargin + 1;
445  int y2 = projectionsHeight - projectionsBottomMargin;
446  std::string image = pd->getResultImage();
447  std::string target = pd->getResultTarget();
448 
449  // add coordinates area to image map
450  std::string tnClass = (bin - 1 >= float(proj->size()) / 2 ? "thumb_left" : "thumb_right");
451  fout << " <area shape='rect' alt='' coords='" << x1 << "," << y1 << "," << x2 << "," << y2 << "'"
452  << " href='" << target << "' onMouseOver=\"tn('" << target << "','" << image << "','" << tnClass << "')\" "
453  << "onMouseDown=\"window.location.href='" << target << "'\">" << std::endl;
454  }
455 
456  fout << " <area shape='default' nohref='nohref' "
457  "onMouseDown='window.location.reload()' alt=''>"
458  << std::endl
459  << " </map>" << std::endl
460  << " <br><img src=\"" << gifNameAllProj << "\">" << std::endl
461  << " </div>" << std::endl
462  << " <div id='thumb_div'><a href='#' id='thumb_link'><img src='' "
463  "id='thumb_img' width=0 height=0 border=0></a></div>"
464  << std::endl
465  // << " </a>"
466  << " </body>" << std::endl
467  << "</html>" << std::endl;
468 
469  // close the file
470  HD->setResultTarget(htmlNameProfile);
471  fout.close();
472  }
473 
474  // if both profile dimensions were filled, we need an additional HTML document
475  if (pfDone[axisX] && pfDone[axisY]) {
476  // create HTML support code for this HistoData
477  std::string html = Name + "_Results_Profiles.html";
478  std::ofstream fout(html.c_str());
479 
480  // make a simple frames portal to show both profile
481  fout << "<html>" << std::endl
482  << " <frameset rows=\"50%,50%\">" << std::endl
483  << " <frame src=\"" << Name << "_Results_py.html\">" << std::endl
484  << " <frame src=\"" << Name << "_Results_px.html\">" << std::endl
485  << " <noframes><body>" << std::endl
486  << " unable to display frames -- click to select desired page" << std::endl
487  << " <br><a href =\"" << Name << "_Results_py.html\">Y Projections</a>" << std::endl
488  << " <br><a href =\"" << Name << "_Results_px.html\">X Projections</a>" << std::endl
489  << " </body></noframes>" << std::endl
490  << " </frameset>" << std::endl
491  << "</html>" << std::endl;
492 
493  // close the file
494  HD->setResultTarget(html);
495  fout.close();
496  }
497 }
498 
499 #endif // PLOT_2D__H
constexpr int32_t ceil(float num)
float getLowScore() const
Definition: HistoData.h:40
float getHighScore() const
Definition: HistoData.h:41
tuple cout
Definition: gather_cfg.py:144
TH1 * getNewHisto() const
Definition: HistoData.h:21