113 THStack::THStack(): TNamed()
125 THStack::THStack(
const char *name,
const char *title)
133 R__LOCKGUARD(gROOTMutex);
134 gROOT->GetListOfCleanups()->Add(
this);
167 THStack::THStack(TH1* hist, Option_t *axis ,
168 const char *name ,
const char *title ,
169 Int_t firstbin , Int_t lastbin ,
170 Int_t firstbin2 , Int_t lastbin2 ,
171 Option_t* proj_option , Option_t* draw_option ): TNamed(name, title) {
178 R__LOCKGUARD(gROOTMutex);
179 gROOT->GetListOfCleanups()->Add(
this);
182 Warning(
"THStack",
"Need an axis.");
186 Warning(
"THStack",
"Need a histogram.");
189 Bool_t isTH2=hist->IsA()->InheritsFrom(TH2::Class());
190 Bool_t isTH3=hist->IsA()->InheritsFrom(TH3::Class());
191 if (!isTH2 && !isTH3) {
192 Warning(
"THStack",
"Need a histogram deriving from TH2 or TH3.");
197 fName=Form(
"%s_stack%s", hist->GetName(), axis);
198 if (!fTitle.Length()) {
199 if (hist->GetTitle() && strlen(hist->GetTitle()))
200 fTitle=Form(
"%s, stack of %s projections", hist->GetTitle(), axis);
202 fTitle=Form(
"stack of %s projections", axis);
206 TH2* hist2=(TH2*) hist;
207 Bool_t useX=(strchr(axis,
'x')) || (strchr(axis,
'X'));
208 Bool_t useY=(strchr(axis,
'y')) || (strchr(axis,
'Y'));
209 if ((!useX && !useY) || (useX && useY)) {
210 Warning(
"THStack",
"Need parameter axis=\"x\" or \"y\" for a TH2, not none or both.");
213 TAxis* haxis= useX ? hist->GetYaxis() : hist->GetXaxis();
215 Warning(
"HStack",
"Histogram axis is NULL");
218 Int_t nbins = haxis->GetNbins();
219 if (firstbin < 0) firstbin = 1;
220 if (lastbin < 0) lastbin = nbins;
221 if (lastbin > nbins+1) lastbin = nbins;
222 for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
224 if (useX) hProj=hist2->ProjectionX(Form(
"%s_px%d",hist2->GetName(), iBin),
225 iBin, iBin, proj_option);
226 else hProj=hist2->ProjectionY(Form(
"%s_py%d",hist2->GetName(), iBin),
227 iBin, iBin, proj_option);
228 Add(hProj, draw_option);
232 TH3* hist3=(TH3*) hist;
235 Int_t dim=3-sAxis.Length();
236 if (dim<1 || dim>2) {
237 Warning(
"THStack",
"Invalid length for parameter axis.");
244 if (sAxis.First(
'x')==kNPOS)
245 haxis=hist->GetXaxis();
246 else if (sAxis.First(
'y')==kNPOS)
247 haxis=hist->GetYaxis();
248 else if (sAxis.First(
'z')==kNPOS)
249 haxis=hist->GetZaxis();
251 Warning(
"HStack",
"Histogram axis is NULL");
255 Int_t nbins = haxis->GetNbins();
256 if (firstbin < 0) firstbin = 1;
257 if (lastbin < 0) lastbin = nbins;
258 if (lastbin > nbins+1) lastbin = nbins;
259 Int_t iFirstOld=haxis->GetFirst();
260 Int_t iLastOld=haxis->GetLast();
261 for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
262 haxis->SetRange(iBin, iBin);
264 TH1* hProj=hist3->Project3D(Form(
"%s_%s%s_%d", hist3->GetName(),
265 axis, proj_option, iBin));
266 Add(hProj, draw_option);
268 haxis->SetRange(iFirstOld, iLastOld);
274 if (sAxis.First(
'x')!=kNPOS) {
275 haxis1=hist->GetYaxis();
276 haxis2=hist->GetZaxis();
277 }
else if (sAxis.First(
'y')!=kNPOS) {
278 haxis1=hist->GetXaxis();
279 haxis2=hist->GetZaxis();
280 }
else if (sAxis.First(
'z')!=kNPOS) {
281 haxis1=hist->GetXaxis();
282 haxis2=hist->GetYaxis();
284 if (!haxis1 || !haxis2) {
285 Warning(
"HStack",
"Histogram axis is NULL");
289 Int_t nbins1 = haxis1->GetNbins();
290 Int_t nbins2 = haxis2->GetNbins();
291 if (firstbin < 0) firstbin = 1;
292 if (lastbin < 0) lastbin = nbins1;
293 if (lastbin > nbins1+1) lastbin = nbins1;
294 if (firstbin2 < 0) firstbin2 = 1;
295 if (lastbin2 < 0) lastbin2 = nbins2;
296 if (lastbin2 > nbins2+1) lastbin2 = nbins2;
297 Int_t iFirstOld1=haxis1->GetFirst();
298 Int_t iLastOld1=haxis1->GetLast();
299 Int_t iFirstOld2=haxis2->GetFirst();
300 Int_t iLastOld2=haxis2->GetLast();
301 for (Int_t iBin=firstbin; iBin<=lastbin; iBin++) {
302 haxis1->SetRange(iBin, iBin);
303 for (Int_t jBin=firstbin2; jBin<=lastbin2; jBin++) {
304 haxis2->SetRange(jBin, jBin);
306 TH1* hProj=hist3->Project3D(Form(
"%s_%s%s_%d", hist3->GetName(),
307 axis, proj_option, iBin));
308 Add(hProj, draw_option);
311 haxis1->SetRange(iFirstOld1, iLastOld1);
312 haxis2->SetRange(iFirstOld2, iLastOld2);
324 R__LOCKGUARD(gROOTMutex);
325 gROOT->GetListOfCleanups()->Remove(
this);
328 fHists->Clear(
"nodelete");
331 if (fStack) {fStack->Delete();
delete fStack;}
339 THStack::THStack(
const THStack &hstack) :
344 fMaximum(hstack.fMaximum),
345 fMinimum(hstack.fMinimum)
347 if (hstack.GetHists()) {
348 TIter next(hstack.GetHists());
350 while ((h=(TH1*)next())) Add(h);
359 void THStack::Add(TH1 *h1, Option_t *option)
362 if (h1->GetDimension() > 2) {
363 Error(
"Add",
"THStack supports only 1-d and 2-d histograms");
366 if (!fHists) fHists =
new TList();
367 fHists->Add(h1,option);
374 void THStack::Browse(TBrowser *b)
376 Draw(b ? b->GetDrawOption() :
"");
384 void THStack::BuildStack()
388 Int_t nhists = fHists->GetSize();
390 fStack =
new TObjArray(nhists);
391 Bool_t add = TH1::AddDirectoryStatus();
392 TH1::AddDirectory(kFALSE);
393 TH1 *h = (TH1*)fHists->At(0)->Clone();
395 for (Int_t i=1;i<nhists;i++) {
396 h = (TH1*)fHists->At(i)->Clone();
397 h->Add((TH1*)fStack->At(i-1));
400 TH1::AddDirectory(add);
407 Int_t THStack::DistancetoPrimitive(Int_t px, Int_t py)
410 const Int_t kMaxDiff = 10;
411 Int_t distance = 9999;
413 distance = fHistogram->DistancetoPrimitive(px,py);
414 if (distance <= 0) {
return distance;}
415 if (distance <= 1) {gPad->SetSelected(fHistogram);
return distance;}
420 if (!fHists)
return distance;
422 const char *doption = GetDrawOption();
423 Int_t nhists = fHists->GetSize();
424 for (Int_t i=0;i<nhists;i++) {
425 h = (TH1*)fHists->At(i);
426 if (fStack && !strstr(doption,
"nostack")) h = (TH1*)fStack->At(i);
427 Int_t dist = h->DistancetoPrimitive(px,py);
428 if (dist <= 0)
return 0;
429 if (dist < kMaxDiff) {
430 gPad->SetSelected(fHists->At(i));
431 gPad->SetCursor(kPointer);
445 void THStack::Draw(Option_t *option)
447 TString opt = option;
450 if (!gPad->IsEditable()) gROOT->MakeDefCanvas();
451 if (!opt.Contains(
"same")) {
454 if (TestBit(kCanDelete)) gPad->GetListOfPrimitives()->Remove(
this);
458 AppendPad(opt.Data());
476 TH1 *THStack::GetHistogram()
const
478 if (fHistogram)
return fHistogram;
482 if (fHistogram)
return fHistogram;
483 TH1 *h1 = (TH1*)gPad->FindObject(
"hframe");
491 Double_t THStack::GetMaximum(Option_t *option)
493 TString opt = option;
495 Bool_t lerr = kFALSE;
496 if (opt.Contains(
"e")) lerr = kTRUE;
497 Double_t them=0, themax = -1e300, c1, e1;
498 if (!fHists)
return 0;
499 Int_t nhists = fHists->GetSize();
503 if (!opt.Contains(
"nostack")) {
505 h = (TH1*)fStack->At(nhists-1);
506 themax = h->GetMaximum();
508 for (Int_t i=0;i<nhists;i++) {
509 h = (TH1*)fHists->At(i);
510 them = h->GetMaximum();
511 if (them > themax) themax = them;
516 for (Int_t i=0;i<nhists;i++) {
517 h = (TH1*)fHists->At(i);
518 first = h->GetXaxis()->GetFirst();
519 last = h->GetXaxis()->GetLast();
520 for (Int_t j=first; j<=last;j++) {
521 e1 = h->GetBinError(j);
522 c1 = h->GetBinContent(j);
523 themax = TMath::Max(themax,c1+e1);
535 Double_t THStack::GetMinimum(Option_t *option)
537 TString opt = option;
539 Bool_t lerr = kFALSE;
540 if (opt.Contains(
"e")) lerr = kTRUE;
541 Double_t them=0, themin = 1e300, c1, e1;
542 if (!fHists)
return 0;
543 Int_t nhists = fHists->GetSize();
547 if (!opt.Contains(
"nostack")) {
549 h = (TH1*)fStack->At(nhists-1);
550 themin = h->GetMinimum();
552 for (Int_t i=0;i<nhists;i++) {
553 h = (TH1*)fHists->At(i);
554 them = h->GetMinimum();
555 if (them <= 0 && gPad && gPad->GetLogy()) them = h->GetMinimum(0);
556 if (them < themin) themin = them;
561 for (Int_t i=0;i<nhists;i++) {
562 h = (TH1*)fHists->At(i);
563 first = h->GetXaxis()->GetFirst();
564 last = h->GetXaxis()->GetLast();
565 for (Int_t j=first; j<=last;j++) {
566 e1 = h->GetBinError(j);
567 c1 = h->GetBinContent(j);
568 themin = TMath::Min(themin,c1-e1);
579 Int_t THStack::GetNhists()
const
581 if (fHists)
return fHists->GetSize();
588 TObjArray *THStack::GetStack()
601 TAxis *THStack::GetXaxis()
const
604 TH1 *h = GetHistogram();
606 return h->GetXaxis();
616 TAxis *THStack::GetYaxis()
const
619 TH1 *h = GetHistogram();
621 return h->GetYaxis();
627 void THStack::ls(Option_t *option)
const
629 TROOT::IndentLevel();
630 std::cout <<IsA()->GetName()
631 <<
" Name= "<<GetName()<<
" Title= "<<GetTitle()<<
" Option="<<option<<std::endl;
632 TROOT::IncreaseDirLevel();
633 if (fHists) fHists->ls(option);
634 TROOT::DecreaseDirLevel();
640 Long64_t THStack::Merge(TCollection* li, TFileMergeInfo * )
642 if (li==0 || li->GetEntries()==0) {
643 return fHists->GetEntries();
647 while (TObject* o = next()) {
648 THStack *stack =
dynamic_cast<THStack*
> (o);
651 "Cannot merge - an object which doesn't inherit from THStack found in the list");
654 histLists.Add(stack->GetHists());
656 fHists->Merge(&histLists);
657 return fHists->GetEntries();
663 void THStack::Modified()
697 void THStack::Paint(Option_t *choptin)
700 if (!fHists->GetSize())
return;
703 strlcpy(option,choptin,128);
706 char *l1 = strstr(option,
"pfc");
707 char *l2 = strstr(option,
"plc");
708 char *l3 = strstr(option,
"pmc");
709 if (l1 || l2 || l3) {
710 TString opt1 = option;
711 if (l1) memcpy(l1,
" ",3);
712 if (l2) memcpy(l2,
" ",3);
713 if (l3) memcpy(l3,
" ",3);
715 if (ws.IsWhitespace()) strncpy(option,
"\0",1);
716 TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
719 Int_t nhists = fHists->GetSize();
721 gPad->IncrementPaletteColor(nhists, opt1);
722 for (Int_t i=0;i<nhists;i++) {
723 ic = gPad->NextPaletteColor();
724 hAti = (TH1F*)(fHists->At(i));
725 if (l1) hAti->SetFillColor(ic);
726 if (l2) hAti->SetLineColor(ic);
727 if (l3) hAti->SetMarkerColor(ic);
729 hsAti = (TH1*)fStack->At(i);
730 if (l1) hsAti->SetFillColor(ic);
731 if (l2) hsAti->SetLineColor(ic);
732 if (l3) hsAti->SetMarkerColor(ic);
734 lnk = (TObjOptLink*)lnk->Next();
738 TString opt = option;
740 opt.ReplaceAll(
" ",
"");
741 Bool_t lsame = kFALSE;
742 if (opt.Contains(
"same")) {
744 opt.ReplaceAll(
"same",
"");
746 Bool_t lclear = kTRUE;
747 if (opt.Contains(
"noclear")) {
749 opt.ReplaceAll(
"noclear",
"");
751 if (opt.Contains(
"pads")) {
752 Int_t npads = fHists->GetSize();
753 TVirtualPad *padsav = gPad;
757 TIter nextp(padsav->GetListOfPrimitives());
758 while ((obj = nextp())) {
759 if (obj->InheritsFrom(TVirtualPad::Class())) nps++;
763 Int_t nx = (Int_t)TMath::Sqrt((Double_t)npads);
764 if (nx*nx < npads) nx++;
766 if (((nx*ny)-nx) >= npads) ny--;
767 padsav->Divide(nx,ny);
771 TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
775 h = (TH1*)lnk->GetObject();
776 h->Draw(lnk->GetOption());
777 lnk = (TObjOptLink*)lnk->Next();
786 Double_t xmin = 1e100;
787 Double_t xmax = -xmin;
788 Double_t ymin = 1e100;
789 Double_t ymax = -xmin;
790 while ((h=(TH1*)next())) {
792 if (h->GetBuffer()) h->BufferEmpty(-1);
793 if (h->GetXaxis()->GetXmin() < xmin) xmin = h->GetXaxis()->GetXmin();
794 if (h->GetXaxis()->GetXmax() > xmax) xmax = h->GetXaxis()->GetXmax();
795 if (h->GetYaxis()->GetXmin() < ymin) ymin = h->GetYaxis()->GetXmin();
796 if (h->GetYaxis()->GetXmax() > ymax) ymax = h->GetYaxis()->GetXmax();
799 TString loption = opt;
800 char *nostack = (
char *)strstr(loption.Data(),
"nostack");
801 char *nostackb = (
char *)strstr(loption.Data(),
"nostackb");
802 char *candle = (
char *)strstr(loption.Data(),
"candle");
803 char *violin = (
char *)strstr(loption.Data(),
"violin");
809 if (!opt.Contains(
"nostack") && (!opt.Contains(
"candle")) && (!opt.Contains(
"violin"))) BuildStack();
811 Double_t themax,themin;
812 if (fMaximum == -1111) themax = GetMaximum(option);
813 else themax = fMaximum;
814 if (fMinimum == -1111) {
815 themin = GetMinimum(option);
816 if (gPad->GetLogy()){
817 if (themin>0) themin *= .9;
818 else themin = themax*1.e-3;
823 else themin = fMinimum;
825 Bool_t add = TH1::AddDirectoryStatus();
826 TH1::AddDirectory(kFALSE);
827 h = (TH1*)fHists->At(0);
828 TAxis *xaxis = h->GetXaxis();
829 TAxis *yaxis = h->GetYaxis();
830 const TArrayD *xbins = xaxis->GetXbins();
831 if (h->GetDimension() > 1) {
832 if (loption.Length()<=0) loption.Form(
"%s",
"lego1");
833 const TArrayD *ybins = yaxis->GetXbins();
834 if (xbins->fN != 0 && ybins->fN != 0) {
835 fHistogram =
new TH2F(GetName(),GetTitle(),
836 xaxis->GetNbins(), xbins->GetArray(),
837 yaxis->GetNbins(), ybins->GetArray());
838 }
else if (xbins->fN != 0 && ybins->fN == 0) {
839 fHistogram =
new TH2F(GetName(),GetTitle(),
840 xaxis->GetNbins(), xbins->GetArray(),
841 yaxis->GetNbins(), ymin, ymax);
842 }
else if (xbins->fN == 0 && ybins->fN != 0) {
843 fHistogram =
new TH2F(GetName(),GetTitle(),
844 xaxis->GetNbins(), xmin, xmax,
845 yaxis->GetNbins(), ybins->GetArray());
847 fHistogram =
new TH2F(GetName(),GetTitle(),
848 xaxis->GetNbins(), xmin, xmax,
849 yaxis->GetNbins(), ymin, ymax);
852 if (xbins->fN != 0) {
853 fHistogram =
new TH1F(GetName(),GetTitle(),
854 xaxis->GetNbins(), xbins->GetArray());
856 fHistogram =
new TH1F(GetName(),GetTitle(),xaxis->GetNbins(),xmin, xmax);
859 fHistogram->SetStats(0);
860 TH1::AddDirectory(add);
862 fHistogram->SetTitle(GetTitle());
865 if (nostack) {*nostack = 0; strncat(nostack,nostack+7,7);}
866 if (nostackb) {*nostackb = 0; strncat(nostackb,nostackb+8,8);}
867 else fHistogram->GetPainter()->SetStack(fHists);
869 if (!fHistogram->TestBit(TH1::kIsZoomed)) {
870 if (nostack && fMaximum != -1111) fHistogram->SetMaximum(fMaximum);
872 if (gPad->GetLogy()) fHistogram->SetMaximum(themax*(1+0.2*TMath::Log10(themax/themin)));
873 else fHistogram->SetMaximum((1+gStyle->GetHistTopMargin())*themax);
875 if (nostack && fMinimum != -1111) fHistogram->SetMinimum(fMinimum);
877 if (gPad->GetLogy()) fHistogram->SetMinimum(themin/(1+0.5*TMath::Log10(themax/themin)));
878 else fHistogram->SetMinimum(themin);
884 TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
885 hfirst = (TH1*)lnk->GetObject();
886 THashList* labels = hfirst->GetXaxis()->GetLabels();
891 while ((lb=(TObjString*)iL())) {
892 fHistogram->GetXaxis()->SetBinLabel(ilab,lb->String().Data());
897 if (!lsame) fHistogram->Paint(loption.Data());
899 if (fHistogram->GetDimension() > 1) SetDrawOption(loption.Data());
900 if (loption.Index(
"lego")>=0)
return;
903 strlcpy(noption,loption.Data(),32);
904 Int_t nhists = fHists->GetSize();
905 if (nostack || candle || violin) {
906 lnk = (TObjOptLink*)fHists->FirstLink();
909 Double_t bw = (1.-(2*bo))/nhists;
910 for (Int_t i=0;i<nhists;i++) {
911 if (strstr(lnk->GetOption(),
"same")) {
912 if (nostackb) loption.Form(
"%s%s b",noption,lnk->GetOption());
913 else loption.Form(
"%s%s",noption,lnk->GetOption());
915 TString indivOpt = lnk->GetOption();
917 if (nostackb) loption.Form(
"%ssame%s b",noption,lnk->GetOption());
918 else if (candle && (indivOpt.Contains(
"candle") || indivOpt.Contains(
"violin"))) loption.Form(
"%ssame",lnk->GetOption());
919 else loption.Form(
"%ssame%s",noption,lnk->GetOption());
921 hAti = (TH1F*)(fHists->At(i));
923 hAti->SetBarWidth(bw);
924 hAti->SetBarOffset(bo);
927 if (candle || violin) {
928 float candleSpace = 1./(nhists*2);
929 float candleOffset = - 1./2 + candleSpace + 2*candleSpace*i;
931 hAti->SetBarWidth(candleSpace);
932 hAti->SetBarOffset(candleOffset);
934 hAti->Paint(loption.Data());
935 lnk = (TObjOptLink*)lnk->Next();
938 lnk = (TObjOptLink*)fHists->LastLink();
941 for (Int_t i=0;i<nhists;i++) {
942 if (strstr(lnk->GetOption(),
"same")) {
943 loption.Form(
"%s%s",noption,lnk->GetOption());
945 loption.Form(
"%ssame%s",noption,lnk->GetOption());
947 h1 = (TH1*)fStack->At(nhists-i-1);
950 h1col = h1->GetFillColor();
951 h1fill = h1->GetFillStyle();
952 h1->SetFillColor(10);
953 h1->SetFillStyle(1001);
954 h1->Paint(loption.Data());
955 static TClassRef clTFrame = TClass::GetClass(
"TFrame",kFALSE);
956 TAttFill *frameFill = (TAttFill*)clTFrame->DynamicCast(TAttFill::Class(),gPad->GetFrame());
958 h1->SetFillColor(frameFill->GetFillColor());
959 h1->SetFillStyle(frameFill->GetFillStyle());
961 h1->Paint(loption.Data());
962 h1->SetFillColor(h1col);
963 h1->SetFillStyle(h1fill);
965 h1->Paint(loption.Data());
966 lnk = (TObjOptLink*)lnk->Prev();
970 opt.ReplaceAll(
"nostack",
"");
971 opt.ReplaceAll(
"candle",
"");
972 if (!lsame && !opt.Contains(
"a")) fHistogram->Paint(
"axissame");
978 void THStack::Print(Option_t *option)
const
983 while ((h = (TH1*) next())) {
992 void THStack::RecursiveRemove(TObject *obj)
995 fHists->RecursiveRemove(obj);
996 while (fHists->IndexOf(obj) >= 0) fHists->Remove(obj);
1002 void THStack::SavePrimitive(std::ostream &out, Option_t *option )
1005 out<<
" "<<std::endl;
1006 if (gROOT->ClassSaved(THStack::Class())) {
1011 out<<GetName()<<
" = new THStack();"<<std::endl;
1012 out<<
" "<<GetName()<<
"->SetName("<<quote<<GetName()<<quote<<
");"<<std::endl;
1013 out<<
" "<<GetName()<<
"->SetTitle("<<quote<<GetTitle()<<quote<<
");"<<std::endl;
1015 if (fMinimum != -1111) {
1016 out<<
" "<<GetName()<<
"->SetMinimum("<<fMinimum<<
");"<<std::endl;
1018 if (fMaximum != -1111) {
1019 out<<
" "<<GetName()<<
"->SetMaximum("<<fMaximum<<
");"<<std::endl;
1022 static Int_t frameNumber = 0;
1025 TString hname = fHistogram->GetName();
1027 hname += frameNumber;
1028 fHistogram->SetName(hname.Data());
1029 fHistogram->SavePrimitive(out,
"nodraw");
1030 out<<
" "<<GetName()<<
"->SetHistogram("<<fHistogram->GetName()<<
");"<<std::endl;
1031 out<<
" "<<std::endl;
1036 TObjOptLink *lnk = (TObjOptLink*)fHists->FirstLink();
1039 h = (TH1*)lnk->GetObject();
1040 TString hname = h->GetName();
1041 hname += Form(
"_stack_%d",++hcount);
1043 h->SavePrimitive(out,
"nodraw");
1044 out<<
" "<<GetName()<<
"->Add("<<h->GetName()<<
","<<quote<<lnk->GetOption()<<quote<<
");"<<std::endl;
1045 lnk = (TObjOptLink*)lnk->Next();
1048 out<<
" "<<GetName()<<
"->Draw("
1049 <<quote<<option<<quote<<
");"<<std::endl;
1055 void THStack::SetMaximum(Double_t maximum)
1058 if (fHistogram) fHistogram->SetMaximum(maximum);
1064 void THStack::SetMinimum(Double_t minimum)
1067 if (fHistogram) fHistogram->SetMinimum(minimum);
1073 TIter THStack::begin()
const
1075 return TIter(fHists);