Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
mvaeffs.cxx
Go to the documentation of this file.
1 #include "TApplication.h"
2 #include "TCanvas.h"
3 #include "TClass.h"
4 #include "TFile.h"
5 #include "TFormula.h"
6 #include "TGButton.h"
7 #include "TGLabel.h"
8 #include "TGNumberEntry.h"
9 #include "TGWindow.h"
10 #include "TGaxis.h"
11 #include "TH1.h"
12 #include "TH2.h"
13 #include "TIterator.h"
14 #include "TKey.h"
15 #include "TLatex.h"
16 #include "TLegend.h"
17 #include "TLine.h"
18 #include "TList.h"
19 #include "TMVA/mvaeffs.h"
20 #include "TMVA/tmvaglob.h"
21 #include "TPad.h"
22 #include "TROOT.h"
23 #include "TStyle.h"
24 
25 #include <iomanip>
26 #include <iostream>
27 
28 using std::cout;
29 using std::endl;
30 using std::setfill;
31 using std::setw;
32 
33 // this macro plots the signal and background efficiencies
34 // as a function of the MVA cut.
35 
36 TMVA::MethodInfo::~MethodInfo()
37 {
38  delete sigE;
39  delete bgdE;
40  delete purS;
41  delete sSig;
42  delete effpurS;
43  if(gROOT->GetListOfCanvases()->FindObject(canvas))
44  delete canvas;
45 }
46 
47 void TMVA::MethodInfo::SetResultHists()
48 {
49  TString pname = "purS_" + methodTitle;
50  TString epname = "effpurS_" + methodTitle;
51  TString ssigname = "significance_" + methodTitle;
52 
53  sigE = (TH1*)origSigE->Clone("sigEffi");
54  bgdE = (TH1*)origBgdE->Clone("bgdEffi");
55 
56  Int_t nbins = sigE->GetNbinsX();
57  Double_t low = sigE->GetBinLowEdge(1);
58  Double_t high = sigE->GetBinLowEdge(nbins+1);
59  purS = new TH1F(pname, pname, nbins, low, high);
60  sSig = new TH1F(ssigname, ssigname, nbins, low, high);
61  effpurS = new TH1F(epname, epname, nbins, low, high);
62 
63  // chop off useless stuff
64  sigE->SetTitle( Form("Cut efficiencies for %s classifier", methodTitle.Data()) );
65 
66  // set the histogram style
67  TMVAGlob::SetSignalAndBackgroundStyle( sigE, bgdE );
68  TMVAGlob::SetSignalAndBackgroundStyle( purS, bgdE );
69  TMVAGlob::SetSignalAndBackgroundStyle( effpurS, bgdE );
70  sigE->SetFillStyle( 0 );
71  bgdE->SetFillStyle( 0 );
72  sSig->SetFillStyle( 0 );
73  sigE->SetLineWidth( 3 );
74  bgdE->SetLineWidth( 3 );
75  sSig->SetLineWidth( 3 );
76 
77  // the purity and quality
78  purS->SetFillStyle( 0 );
79  purS->SetLineWidth( 2 );
80  purS->SetLineStyle( 5 );
81  effpurS->SetFillStyle( 0 );
82  effpurS->SetLineWidth( 2 );
83  effpurS->SetLineStyle( 6 );
84 }
85 
86 void TMVA::StatDialogMVAEffs::SetNSignal()
87 {
88  fNSignal = fSigInput->GetNumber();
89 }
90 
91 void TMVA::StatDialogMVAEffs::SetNBackground()
92 {
93  fNBackground = fBkgInput->GetNumber();
94 }
95 
96 TString TMVA::StatDialogMVAEffs::GetFormula()
97 {
98  // replace all occurrence of S and B but only if neighbours are not alphanumerics
99  auto replace_vars = [](TString & f, char oldLetter, char newLetter ) {
100  auto pos = f.First(oldLetter);
101  while(pos != kNPOS) {
102  if ( ( pos > 0 && !TString(f[pos-1]).IsAlpha() ) ||
103  ( pos < f.Length()-1 && !TString(f[pos+1]).IsAlpha() ) )
104  {
105  f[pos] = newLetter;
106  }
107  int pos2 = pos+1;
108  pos = f.Index(oldLetter,pos2);
109  }
110  };
111 
112  TString formula = fFormula;
113  replace_vars(formula,'S','x');
114  replace_vars(formula,'B','y');
115  // f.ReplaceAll("S","x");
116  // f.ReplaceAll("B","y");
117  return formula;
118 }
119 
120 
121 TString TMVA::StatDialogMVAEffs::GetLatexFormula()
122 {
123  TString f = fFormula;
124  f.ReplaceAll("(","{");
125  f.ReplaceAll(")","}");
126  f.ReplaceAll("sqrt","#sqrt");
127  return f;
128 }
129 
130 void TMVA::StatDialogMVAEffs::Redraw()
131 {
132  UpdateSignificanceHists();
133  UpdateCanvases();
134 }
135 
136 void TMVA::StatDialogMVAEffs::Close()
137 {
138  delete this;
139 }
140 
141 TMVA::StatDialogMVAEffs::~StatDialogMVAEffs()
142 {
143  if (fInfoList) {
144  TIter next(fInfoList);
145  MethodInfo *info(0);
146  while ( (info = (MethodInfo*)next()) ) {
147  delete info;
148  }
149  delete fInfoList;
150  fInfoList=0;
151  }
152 
153 
154  fSigInput->Disconnect();
155  fBkgInput->Disconnect();
156  fDrawButton->Disconnect();
157  fCloseButton->Disconnect();
158 
159  fMain->CloseWindow();
160  fMain->Cleanup();
161  fMain = 0;
162 }
163 
164 TMVA::StatDialogMVAEffs::StatDialogMVAEffs(TString ds,const TGWindow* p, Float_t ns, Float_t nb) :
165  fNSignal(ns),
166  fNBackground(nb),
167  fFormula(""),
168  dataset(ds),
169  fInfoList(0),
170  fSigInput(0),
171  fBkgInput(0),
172  fButtons(0),
173  fDrawButton(0),
174  fCloseButton(0),
175  maxLenTitle(0)
176 {
177  UInt_t totalWidth = 500;
178  UInt_t totalHeight = 300;
179 
180  // main frame
181  fMain = new TGMainFrame(p, totalWidth, totalHeight, kMainFrame | kVerticalFrame);
182 
183  TGLabel *sigLab = new TGLabel(fMain,"Signal events");
184  fMain->AddFrame(sigLab, new TGLayoutHints(kLHintsLeft | kLHintsTop,5,5,5,5));
185 
186  fSigInput = new TGNumberEntry(fMain, (Double_t) fNSignal,5,-1,(TGNumberFormat::EStyle) 5);
187  fSigInput->SetLimits(TGNumberFormat::kNELLimitMin,0,1);
188  fMain->AddFrame(fSigInput, new TGLayoutHints(kLHintsLeft | kLHintsTop,5,5,5,5));
189  fSigInput->Resize(100,24);
190 
191  TGLabel *bkgLab = new TGLabel(fMain, "Background events");
192  fMain->AddFrame(bkgLab, new TGLayoutHints(kLHintsLeft | kLHintsTop,5,5,5,5));
193 
194  fBkgInput = new TGNumberEntry(fMain, (Double_t) fNBackground,5,-1,(TGNumberFormat::EStyle) 5);
195  fBkgInput->SetLimits(TGNumberFormat::kNELLimitMin,0,1);
196  fMain->AddFrame(fBkgInput, new TGLayoutHints(kLHintsLeft | kLHintsTop,5,5,5,5));
197  fBkgInput->Resize(100,24);
198 
199  fButtons = new TGHorizontalFrame(fMain, totalWidth,30);
200 
201  fCloseButton = new TGTextButton(fButtons,"&Close");
202  fButtons->AddFrame(fCloseButton, new TGLayoutHints(kLHintsLeft | kLHintsTop));
203 
204  fDrawButton = new TGTextButton(fButtons,"&Draw");
205  fButtons->AddFrame(fDrawButton, new TGLayoutHints(kLHintsRight | kLHintsTop,15));
206 
207  fMain->AddFrame(fButtons,new TGLayoutHints(kLHintsLeft | kLHintsBottom,5,5,5,5));
208 
209  fMain->SetWindowName("Significance");
210  fMain->SetWMPosition(0,0);
211  fMain->MapSubwindows();
212  fMain->Resize(fMain->GetDefaultSize());
213  fMain->MapWindow();
214 
215  fSigInput->Connect("ValueSet(Long_t)","TMVA::StatDialogMVAEffs",this, "SetNSignal()");
216  fBkgInput->Connect("ValueSet(Long_t)","TMVA::StatDialogMVAEffs",this, "SetNBackground()");
217 
218 // fDrawButton->Connect("Clicked()","TGNumberEntry",fSigInput, "ValueSet(Long_t)");
219 // fDrawButton->Connect("Clicked()","TGNumberEntry",fBkgInput, "ValueSet(Long_t)");
220  fDrawButton->Connect("Clicked()", "TMVA::StatDialogMVAEffs", this, "Redraw()");
221 
222  fCloseButton->Connect("Clicked()", "TMVA::StatDialogMVAEffs", this, "Close()");
223 }
224 
225 void TMVA::StatDialogMVAEffs::UpdateCanvases()
226 {
227  if (fInfoList==0) return;
228  if (fInfoList->First()==0) return;
229  MethodInfo* info = (MethodInfo*)fInfoList->First();
230  if ( info->canvas==0 ) {
231  DrawHistograms();
232  return;
233  }
234  TIter next(fInfoList);
235  while ( (info = (MethodInfo*)next()) ) {
236  info->canvas->Update();
237  info->rightAxis->SetWmax(1.1*info->maxSignificance);
238  info->canvas->Modified(kTRUE);
239  info->canvas->Update();
240  info->canvas->Paint();
241  }
242 }
243 
244 void TMVA::StatDialogMVAEffs::UpdateSignificanceHists()
245 {
246  TFormula f("sigf",GetFormula());
247  TIter next(fInfoList);
248  MethodInfo* info(0);
249  TString cname = "Classifier";
250  if (cname.Length() > maxLenTitle) maxLenTitle = cname.Length();
251  TString str = Form( "%*s ( #signal, #backgr.) Optimal-cut %s NSig NBkg EffSig EffBkg",
252  maxLenTitle, cname.Data(), GetFormulaString().Data() );
253  cout << "--- " << setfill('=') << setw(str.Length()) << "" << setfill(' ') << endl;
254  cout << "--- " << str << endl;
255  cout << "--- " << setfill('-') << setw(str.Length()) << "" << setfill(' ') << endl;
256  Double_t maxSig = -1;
257  Double_t maxSigErr = -1;
258  while ((info = (MethodInfo*)next())) {
259  for (Int_t i=1; i<=info->origSigE->GetNbinsX(); i++) {
260  Float_t eS = info->origSigE->GetBinContent( i );
261  Float_t S = eS * fNSignal;
262  Float_t B = info->origBgdE->GetBinContent( i ) * fNBackground;
263  info->purS->SetBinContent( i, (S+B==0)?0:S/(S+B) );
264 
265  Double_t sig = f.Eval(S,B);
266  if (sig > maxSig) {
267  maxSig = sig;
268  if (GetFormulaString() == "S/sqrt(B)") {
269  maxSigErr = sig * sqrt( 1./S + 1./(2.*B));
270  }
271  }
272  info->sSig->SetBinContent( i, sig );
273  info->effpurS->SetBinContent( i, eS*info->purS->GetBinContent( i ) );
274  }
275 
276  info->maxSignificance = info->sSig->GetMaximum();
277  info->maxSignificanceErr = (maxSigErr > 0) ? maxSigErr : 0;
278  info->sSig->Scale(1/info->maxSignificance);
279 
280  // update the text in the lower left corner
281  PrintResults( info );
282  }
283  cout << "--- " << setfill('-') << setw(str.Length()) << "" << setfill(' ') << endl << endl;
284 }
285 
286 void TMVA::StatDialogMVAEffs::ReadHistograms(TFile* file)
287 {
288  if (fInfoList) {
289  TIter next(fInfoList);
290  MethodInfo *info(0);
291  while ( (info = (MethodInfo*)next()) ) {
292  delete info;
293  }
294  delete fInfoList;
295  fInfoList=0;
296  }
297  fInfoList = new TList;
298 
299  // search for the right histograms in full list of keys
300  TIter next(file->GetDirectory(dataset.Data())->GetListOfKeys());
301  TKey *key(0);
302  while( (key = (TKey*)next()) ) {
303 
304  if (!TString(key->GetName()).BeginsWith("Method_")) continue;
305  if( ! gROOT->GetClass(key->GetClassName())->InheritsFrom("TDirectory") ) continue;
306 
307  cout << "--- Found directory: " << ((TDirectory*)key->ReadObj())->GetName() << endl;
308 
309  TDirectory* mDir = (TDirectory*)key->ReadObj();
310 
311  TIter keyIt(mDir->GetListOfKeys());
312  TKey *titkey;
313  while((titkey = (TKey*)keyIt())) {
314  if( ! gROOT->GetClass(titkey->GetClassName())->InheritsFrom("TDirectory") ) continue;
315 
316  MethodInfo* info = new MethodInfo();
317  TDirectory* titDir = (TDirectory *)titkey->ReadObj();
318 
319  TMVAGlob::GetMethodName(info->methodName,key);
320  TMVAGlob::GetMethodTitle(info->methodTitle,titDir);
321  if (info->methodTitle.Length() > maxLenTitle) maxLenTitle = info->methodTitle.Length();
322  TString hname = "MVA_" + info->methodTitle;
323 
324  cout << "--- Classifier: " << info->methodTitle << endl;
325 
326  info->sig = dynamic_cast<TH1*>(titDir->Get( hname + "_S" ));
327  info->bgd = dynamic_cast<TH1*>(titDir->Get( hname + "_B" ));
328  info->origSigE = dynamic_cast<TH1*>(titDir->Get( hname + "_effS" ));
329  info->origBgdE = dynamic_cast<TH1*>(titDir->Get( hname + "_effB" ));
330  if (info->origSigE==0 || info->origBgdE==0) { delete info; continue; }
331 
332  info->SetResultHists();
333  fInfoList->Add(info);
334  }
335  }
336  return;
337 }
338 
339 void TMVA::StatDialogMVAEffs::DrawHistograms()
340 {
341  // counter variables
342  Int_t countCanvas = 0;
343 
344  // define Canvas layout here!
345  const Int_t width = 600; // size of canvas
346  Int_t signifColor = TColor::GetColor( "#00aa00" );
347 
348  TIter next(fInfoList);
349  MethodInfo* info(0);
350  while ( (info = (MethodInfo*)next()) ) {
351 
352  // create new canvas
353  TCanvas *c = new TCanvas( Form("canvas%d", countCanvas+1),
354  Form("Cut efficiencies for %s classifier",info->methodTitle.Data()),
355  countCanvas*50+200, countCanvas*20, width, Int_t(width*0.78) );
356  info->canvas = c;
357 
358  // draw grid
359  c->SetGrid(1);
360  c->SetTickx(0);
361  c->SetTicky(0);
362 
363  TStyle *TMVAStyle = gROOT->GetStyle("Plain"); // our style is based on Plain
364  TMVAStyle->SetLineStyleString( 5, "[32 22]" );
365  TMVAStyle->SetLineStyleString( 6, "[12 22]" );
366 
367  c->SetTopMargin(.2);
368 
369  // and the signal purity and quality
370  info->effpurS->SetTitle("Cut efficiencies and optimal cut value");
371  if (info->methodTitle.Contains("Cuts")) {
372  info->effpurS->GetXaxis()->SetTitle( "Signal Efficiency" );
373  }
374  else {
375  info->effpurS->GetXaxis()->SetTitle( TString("Cut value applied on ") + info->methodTitle + " output" );
376  }
377  info->effpurS->GetYaxis()->SetTitle( "Efficiency (Purity)" );
378  TMVAGlob::SetFrameStyle( info->effpurS );
379 
380  c->SetTicks(0,0);
381  c->SetRightMargin ( 2.0 );
382 
383  info->effpurS->SetMaximum(1.1);
384  info->effpurS->Draw("histl");
385 
386  info->purS->Draw("samehistl");
387 
388  // overlay signal and background histograms
389  info->sigE->Draw("samehistl");
390  info->bgdE->Draw("samehistl");
391 
392  info->sSig->SetLineColor( signifColor );
393  info->sSig->Draw("samehistl");
394 
395  // redraw axes
396  info->effpurS->Draw( "sameaxis" );
397 
398  // Draw legend
399  TLegend *legend1= new TLegend( c->GetLeftMargin(), 1 - c->GetTopMargin(),
400  c->GetLeftMargin() + 0.4, 1 - c->GetTopMargin() + 0.12 );
401  legend1->SetFillStyle( 1 );
402  legend1->AddEntry(info->sigE,"Signal efficiency","L");
403  legend1->AddEntry(info->bgdE,"Background efficiency","L");
404  legend1->Draw("same");
405  legend1->SetBorderSize(1);
406  legend1->SetMargin( 0.3 );
407 
408  TLegend *legend2= new TLegend( c->GetLeftMargin() + 0.4, 1 - c->GetTopMargin(),
409  1 - c->GetRightMargin(), 1 - c->GetTopMargin() + 0.12 );
410  legend2->SetFillStyle( 1 );
411  legend2->AddEntry(info->purS,"Signal purity","L");
412  legend2->AddEntry(info->effpurS,"Signal efficiency*purity","L");
413  legend2->AddEntry(info->sSig,GetLatexFormula().Data(),"L");
414  legend2->Draw("same");
415  legend2->SetBorderSize(1);
416  legend2->SetMargin( 0.3 );
417 
418  // line to indicate maximum efficiency
419  TLine* effline = new TLine( info->sSig->GetXaxis()->GetXmin(), 1, info->sSig->GetXaxis()->GetXmax(), 1 );
420  effline->SetLineWidth( 1 );
421  effline->SetLineColor( 1 );
422  effline->Draw();
423 
424  // print comments
425  TLatex tl;
426  tl.SetNDC();
427  tl.SetTextSize( 0.033 );
428  Int_t maxbin = info->sSig->GetMaximumBin();
429  info->line1 = tl.DrawLatex( 0.15, 0.23, Form("For %1.0f signal and %1.0f background", fNSignal, fNBackground));
430  tl.DrawLatex( 0.15, 0.19, "events the maximum "+GetLatexFormula()+" is");
431 
432  if (info->maxSignificanceErr > 0) {
433  info->line2 = tl.DrawLatex( 0.15, 0.15, Form("%5.2f +- %4.2f when cutting at %5.2f",
434  info->maxSignificance,
435  info->maxSignificanceErr,
436  info->sSig->GetXaxis()->GetBinCenter(maxbin)) );
437  }
438  else {
439  info->line2 = tl.DrawLatex( 0.15, 0.15, Form("%4.2f when cutting at %5.2f",
440  info->maxSignificance,
441  info->sSig->GetXaxis()->GetBinCenter(maxbin)) );
442  }
443 
444  // add comment for Method cuts
445  if (info->methodTitle.Contains("Cuts")){
446  tl.DrawLatex( 0.13, 0.77, "Method Cuts provides a bundle of cut selections, each tuned to a");
447  tl.DrawLatex(0.13, 0.74, "different signal efficiency. Shown is the purity for each cut selection.");
448  }
449  // save canvas to file
450  c->Update();
451 
452  // Draw second axes
453  info->rightAxis = new TGaxis(c->GetUxmax(), c->GetUymin(),
454  c->GetUxmax(), c->GetUymax(),0,1.1*info->maxSignificance,510,"+L");
455  info->rightAxis->SetLineColor ( signifColor );
456  info->rightAxis->SetLabelColor( signifColor );
457  info->rightAxis->SetTitleColor( signifColor );
458 
459  info->rightAxis->SetTitleSize( info->sSig->GetXaxis()->GetTitleSize() );
460  info->rightAxis->SetTitle( "Significance" );
461  info->rightAxis->Draw();
462 
463  c->Update();
464 
465  // switches
466  const Bool_t Save_Images = kTRUE;
467 
468  if (Save_Images) {
469  TMVAGlob::imgconv( c, Form("%s/plots/mvaeffs_%s",dataset.Data(), info->methodTitle.Data()) );
470  }
471  countCanvas++;
472  }
473 }
474 
475 void TMVA::StatDialogMVAEffs::PrintResults( const MethodInfo* info )
476 {
477  Int_t maxbin = info->sSig->GetMaximumBin();
478  if (info->line1 !=0 )
479  info->line1->SetText( 0.15, 0.23, Form("For %1.0f signal and %1.0f background", fNSignal, fNBackground));
480 
481  if (info->line2 !=0 ) {
482  if (info->maxSignificanceErr > 0) {
483  info->line2->SetText( 0.15, 0.15, Form("%3.2g +- %3.2g when cutting at %3.2g",
484  info->maxSignificance,
485  info->maxSignificanceErr,
486  info->sSig->GetXaxis()->GetBinCenter(maxbin)) );
487  }
488  else {
489  info->line2->SetText( 0.15, 0.15, Form("%3.4f when cutting at %3.4f", info->maxSignificance,
490  info->sSig->GetXaxis()->GetBinCenter(maxbin)) );
491  }
492 
493  }
494 
495  if (info->maxSignificanceErr <= 0) {
496  TString opt = Form( "%%%is: (%%9.8g,%%9.8g) %%9.4f %%10.6g %%8.7g %%8.7g %%8.4g %%8.4g",
497  maxLenTitle );
498  cout << "--- "
499  << Form( opt.Data(),
500  info->methodTitle.Data(), fNSignal, fNBackground,
501  info->sSig->GetXaxis()->GetBinCenter( maxbin ),
502  info->maxSignificance,
503  info->origSigE->GetBinContent( maxbin )*fNSignal,
504  info->origBgdE->GetBinContent( maxbin )*fNBackground,
505  info->origSigE->GetBinContent( maxbin ),
506  info->origBgdE->GetBinContent( maxbin ) )
507  << endl;
508  }
509  else {
510  TString opt = Form( "%%%is: (%%9.8g,%%9.8g) %%9.4f (%%8.3g +-%%6.3g) %%8.7g %%8.7g %%8.4g %%8.4g",
511  maxLenTitle );
512  cout << "--- "
513  << Form( opt.Data(),
514  info->methodTitle.Data(), fNSignal, fNBackground,
515  info->sSig->GetXaxis()->GetBinCenter( maxbin ),
516  info->maxSignificance,
517  info->maxSignificanceErr,
518  info->origSigE->GetBinContent( maxbin )*fNSignal,
519  info->origBgdE->GetBinContent( maxbin )*fNBackground,
520  info->origSigE->GetBinContent( maxbin ),
521  info->origBgdE->GetBinContent( maxbin ) )
522  << endl;
523  }
524 }
525 
526 void TMVA::mvaeffs(TString dataset, TString fin ,
527  Bool_t useTMVAStyle, TString formula )
528 {
529  TMVAGlob::Initialize( useTMVAStyle );
530 
531  TGClient * graphicsClient = TGClient::Instance();
532  if (graphicsClient == nullptr) {
533  // When including mvaeffs in a stand-alone macro, the graphics subsystem
534  // is not initialised and `TGClient::Instance` is a nullptr.
535  graphicsClient = new TGClient();
536  }
537 
538  StatDialogMVAEffs* gGui = new StatDialogMVAEffs(dataset,
539  graphicsClient->GetRoot(), 1000, 1000);
540 
541 
542  TFile* file = TMVAGlob::OpenFile( fin );
543  gGui->ReadHistograms(file);
544  gGui->SetFormula(formula);
545  gGui->UpdateSignificanceHists();
546  gGui->DrawHistograms();
547  gGui->RaiseDialog();
548 }