diff --git a/hist/hist/inc/TMultiGraph.h b/hist/hist/inc/TMultiGraph.h index 3afb3cbf93d73..a85317db3c754 100644 --- a/hist/hist/inc/TMultiGraph.h +++ b/hist/hist/inc/TMultiGraph.h @@ -73,7 +73,7 @@ class TMultiGraph : public TNamed { TAxis *GetXaxis(); TAxis *GetYaxis(); void Paint(Option_t *chopt = "") override; - void PaintPads(Option_t *chopt = ""); + void PaintPads(Option_t *chopt = "", Int_t nColumn = 0); void PaintPolyLine3D(Option_t *chopt = ""); void PaintReverse(Option_t *chopt = ""); void Print(Option_t *chopt="") const override; diff --git a/hist/hist/src/THStack.cxx b/hist/hist/src/THStack.cxx index f56e7eeaeb155..0debab66221e9 100644 --- a/hist/hist/src/THStack.cxx +++ b/hist/hist/src/THStack.cxx @@ -759,10 +759,18 @@ void THStack::BuildAndPaint(Option_t *choptin, Bool_t paint, Bool_t rebuild_stac lclear = kFALSE; opt.ReplaceAll("noclear",""); } - if (opt.Contains("pads")) { + auto l = strstr(opt.Data(), "pads"); + if (l) { if (!paint) return; + Int_t fnx = 0; + if (sscanf(&l[4], "%d", &fnx) > 0) { + opt.ReplaceAll(TString::Format("pads%d", fnx), ""); + } else { + opt.ReplaceAll("pads", ""); + } + Int_t npads = fHists->GetSize(); TVirtualPad *padsav = gPad; //if pad is not already divided into subpads, divide it @@ -773,12 +781,21 @@ void THStack::BuildAndPaint(Option_t *choptin, Bool_t paint, Bool_t rebuild_stac nps++; } if (nps < npads) { - padsav->Clear(); - Int_t nx = (Int_t)TMath::Sqrt((Double_t)npads); - if (nx*nx < npads) nx++; - Int_t ny = nx; - if (((nx*ny)-nx) >= npads) ny--; - padsav->Divide(nx,ny); + if (fnx <= 0) { + padsav->Clear(); + Int_t nx = (Int_t)TMath::Sqrt((Double_t)npads); + if (nx * nx < npads) + nx++; + Int_t ny = nx; + if (((nx * ny) - nx) >= npads) + ny--; + padsav->Divide(nx, ny); + } else { + Int_t ny = (Int_t)((Double_t)npads / fnx); + if (fnx * ny < npads) + ny++; + padsav->Divide(fnx, ny); + } } Int_t i = 1; diff --git a/hist/hist/src/TMultiGraph.cxx b/hist/hist/src/TMultiGraph.cxx index 16dcc1fb5fcbb..0d2b44125ec06 100644 --- a/hist/hist/src/TMultiGraph.cxx +++ b/hist/hist/src/TMultiGraph.cxx @@ -46,9 +46,10 @@ extern void H1LeastSquareSeqnd(Int_t n, Double_t *a, Int_t idim, Int_t &ifail, I - [Setting drawing options](\ref MG01a) - [Titles setting](\ref MG01b) - [The option \"3D\"](\ref MG01c) - - [Legend drawing](\ref MG01d) - - [Automatic coloring](\ref MG01e) - - [Reverse axis](\ref MG01f) + - [Options \"PADS\" and \"PADSn\"](\ref MG01d) + - [Legend drawing](\ref MG01e) + - [Automatic coloring](\ref MG01f) + - [Reverse axis](\ref MG01g) - [MultiGraphs' fitting](\ref MG02) - [Fit box position](\ref MG02a) - [Axis' limits setting](\ref MG03) @@ -155,6 +156,53 @@ Begin_Macro(source) End_Macro \anchor MG01d +#### Options "PADS" and "PADSn" + +Like for THStack, options `PADS` and `PADSn` to split drawing into individual pads for each graph are also available. + +| Option | Description | +|------------|-----------------------------------------------------------------| +| "PADS" | The current pad/canvas is subdivided into a number of pads equal to the number of graphs in the multigraph and each graph is paint into a separate pad.| +| "PADSn" | Like PADS but the current pad/canvas is subdivided into `n` columns, automatically calculating the number of rows.| + +Begin_Macro(source) +{ +auto c0 = new TCanvas("c1","multigraph L3",200,10,700,500); + +auto mg = new TMultiGraph(); + +auto gr1 = new TGraph(); gr1->SetLineColor(kBlue); +auto gr2 = new TGraph(); gr2->SetLineColor(kRed); +auto gr3 = new TGraph(); gr3->SetLineColor(kGreen); +auto gr4 = new TGraph(); gr4->SetLineColor(kOrange); + +Double_t dx = 6.28/1000; +Double_t x = -3.14; + +for (int i=0; i<=1000; i++) { + x = x+dx; + gr1->SetPoint(i,x,2.*TMath::Sin(x)); + gr2->SetPoint(i,x,TMath::Cos(x)); + gr3->SetPoint(i,x,TMath::Cos(x*x)); + gr4->SetPoint(i,x,TMath::Cos(x*x*x)); + } + + mg->Add(gr4); gr4->SetTitle("Cos(x*x*x)"); gr4->SetLineWidth(3); + mg->Add(gr3); gr3->SetTitle("Cos(x*x)") ; gr3->SetLineWidth(3); + mg->Add(gr2); gr2->SetTitle("Cos(x)") ; gr2->SetLineWidth(3); + mg->Add(gr1); gr1->SetTitle("2*Sin(x)") ; gr1->SetLineWidth(3); + + mg->SetTitle("Multi-graph Title; X-axis Title; Y-axis Title"); + + mg->Draw("a fb l pads3"); + + mg->GetHistogram()->GetXaxis()->SetRangeUser(0.,2.5); + gPad->Modified(); + gPad->Update(); +} +End_Macro + +\anchor MG01e #### Legend drawing The method TPad::BuildLegend is able to extract the graphs inside a @@ -216,7 +264,7 @@ Begin_Macro(source) } End_Macro -\anchor MG01e +\anchor MG01f #### Automatic coloring Automatic coloring according to the current palette is available as shown in the @@ -226,7 +274,7 @@ Begin_Macro(source) ../../../tutorials/visualisation/graphs/gr105_multigraphpalettecolor.C End_Macro -\anchor MG01f +\anchor MG01g #### Reverse axis \since **ROOT version 6.19/02** @@ -1171,8 +1219,13 @@ void TMultiGraph::Paint(Option_t *choptin) l = strstr(chopt.Data(),"PADS"); if (l) { - chopt.ReplaceAll("PADS",""); - PaintPads(chopt.Data()); + Int_t fnx = 0; + if (sscanf(&l[4], "%d", &fnx) > 0) { + chopt.ReplaceAll(TString::Format("PADS%d", fnx), ""); + } else { + chopt.ReplaceAll("PADS", ""); + } + PaintPads(chopt.Data(), fnx); return; } @@ -1372,11 +1425,11 @@ void TMultiGraph::Paint(Option_t *choptin) gfit->PaintStats(fit); } - //////////////////////////////////////////////////////////////////////////////// /// Divides the active pad and draws all Graphs in the Multigraph separately. +/// nColumn parameter larger than 0 enforces number of columns for pad division -void TMultiGraph::PaintPads(Option_t *option) +void TMultiGraph::PaintPads(Option_t *option, Int_t nColumn) { if (!gPad) return; @@ -1392,11 +1445,20 @@ void TMultiGraph::PaintPads(Option_t *option) } if (existingPads < neededPads) { curPad->Clear(); - Int_t nx = (Int_t)TMath::Sqrt((Double_t)neededPads); - if (nx*nx < neededPads) nx++; - Int_t ny = nx; - if (((nx*ny)-nx) >= neededPads) ny--; - curPad->Divide(nx,ny); + if (nColumn <= 0) { + Int_t nx = (Int_t)TMath::Sqrt((Double_t)neededPads); + if (nx * nx < neededPads) + nx++; + Int_t ny = nx; + if (((nx * ny) - nx) >= neededPads) + ny--; + curPad->Divide(nx, ny); + } else { + Int_t ny = (Int_t)((Double_t)neededPads / nColumn); + if (nColumn * ny < neededPads) + ny++; + curPad->Divide(nColumn, ny); + } } Int_t i = 0; diff --git a/hist/histpainter/src/THistPainter.cxx b/hist/histpainter/src/THistPainter.cxx index 866f171e3a348..79a6dd6747d66 100644 --- a/hist/histpainter/src/THistPainter.cxx +++ b/hist/histpainter/src/THistPainter.cxx @@ -355,6 +355,7 @@ using `TH1::GetOption`: | "NOSTACK" | Histograms in the stack are all paint in the same pad as if the option `SAME` had been specified.| | "NOSTACKB" | Histograms are drawn next to each other as bar charts.| | "PADS" | The current pad/canvas is subdivided into a number of pads equal to the number of histograms in the stack and each histogram is paint into a separate pad.| +| "PADSn" | Like PADS but the current pad/canvas is subdivided into a `n` columns, automatically calculating the number of rows.| | "PFC" | Palette Fill Color: stack's fill color is taken in the current palette. | | "PLC" | Palette Line Color: stack's line color is taken in the current palette. | | "PMC" | Palette Marker Color: stack's marker color is taken in the current palette. | @@ -2751,9 +2752,10 @@ the same pad as if the option `SAME` had been specified. This allows to compute X and Y scales common to all the histograms, like `TMultiGraph` does for graphs. -If the option `PADS` is specified, the current pad/canvas is -subdivided into a number of pads equal to the number of histograms and each -histogram is paint into a separate pad. +If the option `PADS` is specified, the current pad/canvas is subdivided into +a number of pads equal to the number of histograms and each histogram is paint +into a separate pad. With `PADSn`, the current pad/canvas is subdivided into +`n` columns, automatically calculating the number of rows. The following example shows various types of stacks (hist023_THStack_simple.C).