/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 2002 ! ! Copyright: MAGIC Software Development, 2000-2007 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // MH3 // // With this histogram you can fill a histogram with up to three // variables from Mars parameter containers in an eventloop. // // In the constructor you can give up to three variables which should be // filled in the histogram. Dependend on the number of given variables // (data members) a TH1D, TH2D or TH3D is created. // Specify the data mamber like the following: // "MHillas.fLength" // Where MHillas is the name of the parameter container in the parameter // list and fLength is the name of the data member which should be filled // in the histogram. Assuming that your MHillas container has a different // name (MyHillas) the name to give would be: // "MyHillas.fLength" // // If you want to use a different unit for histogramming use SetScaleX, // SetScaleY and SetScaleZ. // // // Binning name // ============ // // The axis binning is retrieved from the parameter list, too. Create a // MBinning with the name "Binning" plus the name of your MH3 container // plus the axis name ("X", "Y" or "Z") and add it to the parameter list. // // If the binning should have a different name than the histogram name // the binning name can be added to the name, eg.: // SetName("MyHistName;MyXBins;MyYBins") // Instead of BinningMyHistName[XYZ] the parameter list will be searched // for BinningMyXBinning, BinningMyYBins and BinningMyHistNameZ // // // Axis titles // =========== // // 1) If no other title is given the rule for this axis is used. // 2) If the MBinning used for this axis has a non-default Title // (MBinning::HasTitle) this title is used for the corresponding axis // 3) If the MH3 has a non-default title (MH3::SetTitle called) // this title is set as the histogram title. It can be used to overwrite // the axis titles. For more information see TH1::SetTitle, eg. // SetTitle("MyHist;x[mm];y[cm];Counts"); // // // For example: // MH3 myhist("MHillas.fLength"); // myhist.SetName("MyHist"); // myhist.SetScaleX(geomcam.GetConvMm2Deg()); //convert length to degree // MBinning bins("BinningMyHistX"); // bins.SetEdges(10, 0, 150); // plist.AddToList(&myhist); // plist.AddToList(&bins); // // // Class Version 2: // ---------------- // - MDataChain *fData[3]; // Object from which the data is filled // + MData *fData[3]; // Object from which the data is filled // // Class Version 3: // ---------------- // - Byte_t fStyleBits // ///////////////////////////////////////////////////////////////////////////// #include "MH3.h" #include // tolower #include //#include #include #include #include #include #include #include #include "MLog.h" #include "MLogManip.h" #include "MParList.h" #include "MBinning.h" #include "MDataPhrase.h" ClassImp(MH3); using namespace std; const TString MH3::gsDefName = "MH3"; const TString MH3::gsDefTitle = "Container for a n-D Mars Histogram"; // -------------------------------------------------------------------------- // // Default constructor. // MH3::MH3(const unsigned int dim) : fDimension(dim>3?3:dim), fHist(NULL), fStyleBits(0) { switch (fDimension) { case 1: fHist = new TH1D; fHist->SetYTitle("Counts"); break; case 2: fHist = new TH2D; fHist->SetZTitle("Counts"); break; case 3: fHist = new TH3D; break; } fData[0] = NULL; fData[1] = NULL; fData[2] = NULL; fName = gsDefName; fTitle = gsDefTitle; if (fHist) { fHist->SetDirectory(NULL); fHist->UseCurrentStyle(); } fScale[0] = 1; fScale[1] = 1; fScale[2] = 1; } // -------------------------------------------------------------------------- // // Creates an TH1D. memberx is filled into the X-bins. For a more detailed // description see the class description above. // MH3::MH3(const char *memberx) : fDimension(1), fStyleBits(0) { fHist = new TH1D; fData[0] = new MDataPhrase(memberx); fData[1] = NULL; fData[2] = NULL; fName = gsDefName; fTitle = gsDefTitle; fHist->UseCurrentStyle(); fHist->SetDirectory(NULL); fHist->SetYTitle("Counts"); fScale[0] = 1; fScale[1] = 1; fScale[2] = 1; } MH3::MH3(const TH1 &h1) : fDimension(1), fStyleBits(0) { if (h1.InheritsFrom(TH3::Class())) fDimension = 3; if (h1.InheritsFrom(TH2::Class())) fDimension = 2; fData[0] = NULL; fData[1] = NULL; fData[2] = NULL; switch (fDimension) { case 3: fData[2] = new MDataPhrase(h1.GetZaxis()->GetTitle()); case 2: fData[1] = new MDataPhrase(h1.GetYaxis()->GetTitle()); case 1: fData[0] = new MDataPhrase(h1.GetXaxis()->GetTitle()); } fName = gsDefName; fTitle = gsDefTitle; fHist = (TH1*)h1.Clone(); fHist->SetDirectory(NULL); fScale[0] = 1; fScale[1] = 1; fScale[2] = 1; } // -------------------------------------------------------------------------- // // Creates an TH2D. memberx is filled into the X-bins. membery is filled // into the Y-bins. For a more detailed description see the class // description above. // MH3::MH3(const char *memberx, const char *membery) : fDimension(2), fStyleBits(0) { fHist = new TH2D; fData[0] = new MDataPhrase(memberx); fData[1] = new MDataPhrase(membery); fData[2] = NULL; fName = gsDefName; fTitle = gsDefTitle; fHist->UseCurrentStyle(); fHist->SetDirectory(NULL); fHist->SetZTitle("Counts"); fScale[0] = 1; fScale[1] = 1; fScale[2] = 1; } // -------------------------------------------------------------------------- // // Creates an TH3D. memberx is filled into the X-bins. membery is filled // into the Y-bins. membery is filled into the Z-bins. For a more detailed // description see the class description above. // MH3::MH3(const char *memberx, const char *membery, const char *memberz) : fDimension(3), fStyleBits(0) { fHist = new TH3D; fData[0] = new MDataPhrase(memberx); fData[1] = new MDataPhrase(membery); fData[2] = new MDataPhrase(memberz); fName = gsDefName; fTitle = gsDefTitle; fHist->UseCurrentStyle(); fHist->SetDirectory(NULL); fScale[0] = 1; fScale[1] = 1; fScale[2] = 1; } // -------------------------------------------------------------------------- // // Deletes the histogram // MH3::~MH3() { delete fHist; for (int i=0; i<3; i++) if (fData[i]) delete fData[i]; } // -------------------------------------------------------------------------- // // Return the data members used by the data chain to be used in // MTask::AddBranchToList // TString MH3::GetDataMember() const { TString str=fData[0]->GetDataMember(); if (fData[1]) { str += ";"; str += fData[1]->GetDataMember(); } if (fData[2]) { str += ";"; str += fData[2]->GetDataMember(); } return str; } // -------------------------------------------------------------------------- // // Setup the Binning for the histograms automatically if the correct // instances of MBinning are found in the parameter list // For a more detailed description see class description above. // Bool_t MH3::SetupFill(const MParList *plist) { // reset histogram (necessary if the same eventloop is run more than once) fHist->Reset(); // Tokenize name into name and binnings names TObjArray *tok = fName.Tokenize(";"); const TString name = (*tok)[0] ? (*tok)[0]->GetName() : fName.Data(); TString bx = (*tok)[1] ? (*tok)[1]->GetName() : Form("%sX", name.Data()); TString by = (*tok)[2] ? (*tok)[2]->GetName() : Form("%sY", name.Data()); TString bz = (*tok)[3] ? (*tok)[3]->GetName() : Form("%sZ", name.Data()); bx.Prepend("Binning"); by.Prepend("Binning"); bz.Prepend("Binning"); delete tok; MBinning *binsx = NULL; MBinning *binsy = NULL; MBinning *binsz = NULL; switch (fDimension) { case 3: binsz = (MBinning*)plist->FindObject(bz, "MBinning"); if (!binsz) { *fLog << err << dbginf << "MBinning '" << bz << "' not found... aborting." << endl; return kFALSE; } if (fData[2] && !fData[2]->PreProcess(plist)) return kFALSE; if (fData[2]) fHist->SetZTitle(fData[2]->GetTitle()); if (binsz->HasTitle()) fHist->SetZTitle(binsz->GetTitle()); if (binsz->IsLogarithmic()) fHist->SetBit(kIsLogz); case 2: binsy = (MBinning*)plist->FindObject(by, "MBinning"); if (!binsy) { *fLog << err << dbginf << "MBinning '" << by << "' not found... aborting." << endl; return kFALSE; } if (fData[1] && !fData[1]->PreProcess(plist)) return kFALSE; if (fData[1]) fHist->SetYTitle(fData[1]->GetTitle()); if (binsy->HasTitle()) fHist->SetYTitle(binsy->GetTitle()); if (binsy->IsLogarithmic()) fHist->SetBit(kIsLogy); case 1: binsx = (MBinning*)plist->FindObject(bx, "MBinning"); if (!binsx) { if (fDimension==1) binsx = (MBinning*)plist->FindObject("Binning"+fName, "MBinning"); if (!binsx) { *fLog << err << dbginf << "Neither '" << bx << "' nor '" << binsx << fName << "' found... aborting." << endl; return kFALSE; } } if (fData[0] && !fData[0]->PreProcess(plist)) return kFALSE; if (fData[0]!=NULL) fHist->SetXTitle(fData[0]->GetTitle()); if (binsx->HasTitle()) fHist->SetXTitle(binsx->GetTitle()); if (binsx->IsLogarithmic()) fHist->SetBit(kIsLogx); } TString title("Histogram for "); title += name; title += Form(" (%dD)", fDimension); fHist->SetName(name); fHist->SetTitle(fTitle==gsDefTitle ? title : fTitle); fHist->SetDirectory(0); switch (fDimension) { case 1: SetBinning(fHist, binsx); return kTRUE; case 2: SetBinning((TH2*)fHist, binsx, binsy); return kTRUE; case 3: SetBinning((TH3*)fHist, binsx, binsy, binsz); return kTRUE; } *fLog << err << "ERROR - MH3 has " << fDimension << " dimensions!" << endl; return kFALSE; } // -------------------------------------------------------------------------- // // Set the name of the histogram ant the MH3 container // void MH3::SetName(const char *name) { if (fHist) { if (gPad) { const TString pfx(Form("%sProfX", fHist->GetName())); const TString pfy(Form("%sProfY", fHist->GetName())); TProfile *p = 0; if ((p=dynamic_cast(gPad->FindObject(pfx)))) p->SetName(Form("%sProfX", name)); if ((p=dynamic_cast(gPad->FindObject(pfy)))) p->SetName(Form("%sProfY", name)); } fHist->SetName(name); fHist->SetDirectory(0); } MParContainer::SetName(name); } // -------------------------------------------------------------------------- // // Set the title of the histogram ant the MH3 container // void MH3::SetTitle(const char *title) { if (fHist) fHist->SetTitle(title); MParContainer::SetTitle(title); } // -------------------------------------------------------------------------- // // Fills the one, two or three data members into our histogram // Bool_t MH3::Fill(const MParContainer *par, const Stat_t w) { Double_t x=0; Double_t y=0; Double_t z=0; switch (fDimension) { case 3: z = fData[2]->GetValue()*fScale[2]; case 2: y = fData[1]->GetValue()*fScale[1]; case 1: x = fData[0]->GetValue()*fScale[0]; } switch (fDimension) { case 3: ((TH3*)fHist)->Fill(x, y, z, w); return kTRUE; case 2: ((TH2*)fHist)->Fill(x, y, w); return kTRUE; case 1: fHist->Fill(x, w); return kTRUE; } return kFALSE; } // -------------------------------------------------------------------------- // // If an auto range bit is set the histogram range of the corresponding // axis is set to show only the non-empty bins (with a single empty bin // on both sides) // Bool_t MH3::Finalize() { Bool_t autorangex=TESTBIT(fStyleBits, 0); Bool_t autorangey=TESTBIT(fStyleBits, 1); //Bool_t autorangez=TESTBIT(fStyleBits, 2); Int_t lo, hi; if (autorangex) { GetRangeX(*fHist, lo, hi); cout << "====> " << GetName() << " " << fHist->GetName() << ": " << lo << " " << hi <<" " << fHist->GetNbinsX() << endl; fHist->GetXaxis()->SetRange(lo-2, hi+1); } if (autorangey) { GetRangeY(*fHist, lo, hi); fHist->GetYaxis()->SetRange(lo-2, hi+1); } /* if (autorangez) { GetRangeZ(*fHist, lo, hi); fHist->GetZaxis()->SetRange(lo-2, hi+1); } */ return kTRUE; } // -------------------------------------------------------------------------- // // Setup a inversed deep blue sea palette for the fCenter histogram. // void MH3::SetColors() const { // FIXME: This must be redone each time the canvas is repainted.... gStyle->SetPalette(51, NULL); Int_t c[50]; for (int i=0; i<50; i++) c[49-i] = gStyle->GetColorPalette(i); gStyle->SetPalette(50, c); } void MH3::Paint(Option_t *o) { TProfile *p=0; const TString pfx(Form("%sProfX", fHist->GetName())); if ((p=dynamic_cast(gPad->FindObject(pfx)))) { Int_t col = p->GetLineColor(); p = ((TH2*)fHist)->ProfileX(pfx, -1, -1, "s"); p->SetLineColor(col); } const TString pfy(Form("%sProfY", fHist->GetName())); if ((p=dynamic_cast(gPad->FindObject(pfy)))) { Int_t col = p->GetLineColor(); p = ((TH2*)fHist)->ProfileY(pfy, -1, -1, "s"); p->SetLineColor(col); } /* if (fHist->TestBit(kIsLogx) && fHist->GetEntries()>0) gPad->SetLogx(); if (fHist->TestBit(kIsLogy) && fHist->GetEntries()>0) gPad->SetLogy(); if (fHist->TestBit(kIsLogz) && fHist->GetEntries()>0) gPad->SetLogz(); */ } // -------------------------------------------------------------------------- // // Creates a new canvas and draws the histogram into it. // // Possible options are: // PROFX: Draw a x-profile into the histogram (for 2D histograms only) // PROFY: Draw a y-profile into the histogram (for 2D histograms only) // ONLY: Draw the profile histogram only (for 2D histograms only) // BLUE: Draw the profile in blue color instead of the histograms line color // // If the kIsLog?-Bit is set the axis is displayed lkogarithmically. // eg this is set when applying a logarithmic MBinning // // Be careful: The histogram belongs to this object and won't get deleted // together with the canvas. // void MH3::Draw(Option_t *opt) { TVirtualPad *pad = gPad ? gPad : MakeDefCanvas(fHist); pad->SetBorderMode(0); pad->SetGridx(); pad->SetGridy(); if (fHist->TestBit(kIsLogx)) pad->SetLogx(); if (fHist->TestBit(kIsLogy)) pad->SetLogy(); if (fHist->TestBit(kIsLogz)) pad->SetLogz(); fHist->SetFillStyle(4000); TString str(opt); str.ToLower(); const Bool_t only = str.Contains("only") && fDimension==2; const Bool_t same = str.Contains("same") && fDimension<3; const Bool_t blue = str.Contains("blue") && fDimension==2; const Bool_t profx = str.Contains("profx") && fDimension==2; const Bool_t profy = str.Contains("profy") && fDimension==2; str.ReplaceAll("only", ""); str.ReplaceAll("blue", ""); str.ReplaceAll("profx", ""); str.ReplaceAll("profy", ""); str.ReplaceAll(" ", ""); if (same && fDimension==1) { fHist->SetLineColor(kBlue); fHist->SetMarkerColor(kBlue); } // FIXME: We may have to remove all our own options from str! if (!only) fHist->Draw(str); AppendPad(); TProfile *p=0; if (profx) { const TString pfx(Form("%sProfX", fHist->GetName())); if (same && (p=dynamic_cast(gPad->FindObject(pfx)))) *fLog << warn << "TProfile " << pfx << " already in pad." << endl; p = ((TH2*)fHist)->ProfileX(pfx, -1, -1, "s"); p->UseCurrentStyle(); p->SetLineColor(blue ? kBlue : fHist->GetLineColor()); p->SetBit(kCanDelete); p->SetDirectory(NULL); p->SetXTitle(fHist->GetXaxis()->GetTitle()); p->SetYTitle(fHist->GetYaxis()->GetTitle()); p->Draw(only&&!same?"":"same"); } if (profy) { const TString pfy(Form("%sProfY", fHist->GetName())); if (same && (p=dynamic_cast(gPad->FindObject(pfy)))) *fLog << warn << "TProfile " << pfy << " already in pad." << endl; p = ((TH2*)fHist)->ProfileY(pfy, -1, -1, "s"); p->UseCurrentStyle(); p->SetLineColor(blue ? kBlue : fHist->GetLineColor()); p->SetBit(kCanDelete); p->SetDirectory(NULL); p->SetYTitle(fHist->GetXaxis()->GetTitle()); p->SetXTitle(fHist->GetYaxis()->GetTitle()); p->Draw(only&&!same?"":"same"); } //AppendPad("log"); } // -------------------------------------------------------------------------- // // Implementation of SavePrimitive. Used to write the call to a constructor // to a macro. In the original root implementation it is used to write // gui elements to a macro-file. // void MH3::StreamPrimitive(ostream &out) const { TString name = GetUniqueName(); out << " MH3 " << name << "(\""; out << fData[0]->GetRule() << "\""; if (fDimension>1) out << ", \"" << fData[1]->GetRule() << "\""; if (fDimension>2) out << ", \"" << fData[2]->GetRule() << "\""; out << ");" << endl; if (fName!=gsDefName) out << " " << name << ".SetName(\"" << fName << "\");" << endl; if (fTitle!=gsDefTitle) out << " " << name << ".SetTitle(\"" << fTitle << "\");" << endl; switch (fDimension) { case 3: if (fScale[2]!=1) out << " " << name << ".SetScaleZ(" << fScale[2] << ");" << endl; case 2: if (fScale[1]!=1) out << " " << name << ".SetScaleY(" << fScale[1] << ");" << endl; case 1: if (fScale[0]!=1) out << " " << name << ".SetScaleX(" << fScale[0] << ");" << endl; } } // -------------------------------------------------------------------------- // // Used to rebuild a MH3 object of the same type (data members, // dimension, ...) // MParContainer *MH3::New() const { MH3 *h = NULL; if (fData[0] == NULL) h=new MH3(fDimension); else switch (fDimension) { case 1: h=new MH3(fData[0]->GetRule()); break; case 2: h=new MH3(fData[0]->GetRule(), fData[1]->GetRule()); break; case 3: h=new MH3(fData[0]->GetRule(), fData[1]->GetRule(), fData[2]->GetRule()); break; } switch (fDimension) { case 3: h->SetScaleZ(fScale[2]); case 2: h->SetScaleY(fScale[1]); case 1: h->SetScaleX(fScale[0]); } return h; } TString MH3::GetRule(const Char_t axis) const { switch (tolower(axis)) { case 'x': return fData[0] ? fData[0]->GetRule() : TString(""); case 'y': return fData[1] ? fData[1]->GetRule() : TString(""); case 'z': return fData[2] ? fData[2]->GetRule() : TString(""); default: return ""; } } // -------------------------------------------------------------------------- // // Returns the total number of bins in a histogram (excluding under- and // overflow bins) // Int_t MH3::GetNbins() const { Int_t num = 1; switch (fDimension) { case 3: num *= fHist->GetNbinsZ()+2; case 2: num *= fHist->GetNbinsY()+2; case 1: num *= fHist->GetNbinsX()+2; } return num; } // -------------------------------------------------------------------------- // // Returns the total number of bins in a histogram (excluding under- and // overflow bins) Return -1 if bin is underflow or overflow // Int_t MH3::FindFixBin(Double_t x, Double_t y, Double_t z) const { const TAxis &axex = *fHist->GetXaxis(); const TAxis &axey = *fHist->GetYaxis(); const TAxis &axez = *fHist->GetZaxis(); Int_t binz = 0; Int_t biny = 0; Int_t binx = 0; switch (fDimension) { case 3: binz = axez.FindFixBin(z); if (binz>axez.GetLast() || binzaxey.GetLast() || binyaxex.GetLast()) return -1; } const Int_t nx = fHist->GetNbinsX()+2; const Int_t ny = fHist->GetNbinsY()+2; return binx + nx*(biny +ny*binz); }