pad->Divide special case of zero margin

Hi rooters,
the pad->Divided option provides the nice feature -if called with margin 0.0- to have several pads “glued” to each other and only the most left and the bottom one with axis title and labels. Unfortunately in the current implementation the most left pad and the bottom pads have different size than the others. You can easily see it with:
{
gStyle->SetPadTopMargin(0.3);
gStyle->SetPadBottomMargin(0.3);
gStyle->SetPadLeftMargin(0.5);
gStyle->SetPadRightMargin(0.0);
TCanvas* mCanvas = new TCanvas(“kt”,“kt”,500,700);
mCanvas->Divide(5,5,0.0,0.0) ;
mHisto = new TH1D(“Rside”,“Rside”,6,0.01,0.59) ;
for(Int_t i=1 ; i<26>cd(i) ;
mHisto->Draw() ;
}
}
I guess this is not what was intendet, hence I suggest to change the Divide(…) member function in TPad.cxx lines 1063 to something like:

else
{
// special case when xmargin <= 0 || ymargin <= 0
Double_t xl = GetLeftMargin();
Double_t xr = GetRightMargin();
Double_t yb = GetBottomMargin();
Double_t yt = GetTopMargin();

   dx = (1-xl-xr)/nx;
   dy = (1-yb-yt)/ny;
   Int_t number = 0; 
   for (Int_t i=0;i<nx;i++) 
{
  x1 = i*dx+xl;
  x2 = x1 + dx;
  if (i == 0) x1 = 0;
  if (i == nx-1) x2 = 1-xr;
  for (Int_t j=0;j<ny>SetNumber(number);
      pad->SetBorderMode(0);
      pad->SetRightMargin(0);
      pad->SetTopMargin(0);

      if (i == 0) {  pad->SetLeftMargin(xl/(xl+dx)); }
      else        { pad->SetLeftMargin(0); }
      
      if (j == ny-1) { pad->SetBottomMargin(yb/(yb+dy)); }
      else           { pad->SetBottomMargin(0); }

      pad->Draw();
    }
}
 }

It works for me, much better in this way.
Best regards,
d.

I do not see the problem if I do:

{
   TCanvas* mCanvas = new TCanvas("kt","kt",500,700);
   mCanvas->Divide(4,4,0,0);
   mHisto = new TH1D("Rside","Rside",6,0.01,0.59) ;
   for(Int_t i=1 ; i<=16; i++) {
      mCanvas->cd(i) ;
      mHisto->Draw() ;
   }
}

I get the attached picture.


Hi,
you have to set the margins, if I use the values of my example
gStyle->SetPadTopMargin(0.3);
gStyle->SetPadBottomMargin(0.3);
gStyle->SetPadLeftMargin(0.5);
gStyle->SetPadRightMargin(0.0);
I get the attached result. Of course this exaggerates the problem but otherwise it is not well visible. But if you have to produce plots for publications you have to make them look really nice, that’s why I would like to have histograms with exactly the same size.


I do not understand why you want to set the margins if the plot I sent before is what you want …what “margins” do you expect to change with these gStyle extra settings ?

What you want is several histograms with exactly the same size, then you want to have labels and titles on the y axis of the most left pad and on the x axis of the bottom row,
and possibly space above the top row to have titles for the columns.

And you want to be able to increase or decrease the space you need for the axis’s title and labels - exactly what you do with e,g, gSystem->SetPadLeftMargin. I guess that was also intended with the current code - but it is not what you get.

If I still couldn’t make myself clear, I can come up with another example.

Cheers,
d.

I’ve hit the same issue recently, so I would like to revive this discussion. It would be good to have a definite responce from the ROOT Team - if this is a bug that will be fixed, or something like WONTFIX, NOT-A-BUG, etc.

Sorry for the late answer. Writing the correct macro took me some time. I do not think there is a bug in TPad::Divide() in case the margin a equal to 0 but I agree with you that you cannot achieve your goal with this function. I think the following macro does what you want. Let me know.

void div2()
{
   gStyle->SetOptStat(0);
   gStyle->SetPadTopMargin(0.);
   gStyle->SetPadBottomMargin(0.);
   gStyle->SetPadLeftMargin(0.);
   gStyle->SetPadRightMargin(0.);
   TCanvas* mCanvas = new TCanvas("kt","kt",500,700);
   Double_t mlb = 0.3;
   Double_t mrt = 0.1;
   Double_t nx  = 4;
   Double_t ny  = 5;
                                                                                
   DividegPad(nx,ny,mlb,mrt,mrt,mlb);
                                                                                
   mHisto = new TH1D("Rside","Rside",6,0.01,0.59) ;
   for(Int_t i=1 ; i<=nx*ny; i++) {
      mCanvas->cd(i) ;
      mHisto->Draw() ;
   }
}
                                                                                
void DividegPad(Int_t nx, Int_t ny,
                Float_t l, Float_t r, Float_t t, Float_t b)
{
   Int_t ix, iy, n=0;
   Double_t x1, x2, y1, y2;
   Double_t dx = ((1-r)*(1-l))/((1-r)*(1-l)*(nx-2)-r+2-l);
   Double_t dl = dx/(1-l);
   Double_t dy = ((1-t)*(1-b))/((1-t)*(1-b)*(ny-2)-t+2-b);
   Double_t db = dy/(1-b);
   char *name  = new char [strlen(gPad->GetName())+6];
                                                                                
   y1 = 0;
   y2 = db;
   for (iy=0; iy<ny; iy++) {
      x1 = 0;
      x2 = dl;
      for (ix=0;ix<nx;ix++) {
         if (x1 > x2) continue;
         n++;
         sprintf(name,"%s_%d",gPad->GetName(),n);
         pad = new TPad(name,name,x1,y1,x2,y2,0);
         if (ix==0)    pad->SetLeftMargin(l);
         if (ix==nx-1) pad->SetRightMargin(r);
         if (iy==ny-1) pad->SetTopMargin(t);
         if (iy==0)    pad->SetBottomMargin(b);
         x1 = x2;
         if (ix==nx-2) x2 = 1;
         else          x2 = x1+dx;
         pad->SetNumber(n);
         pad->Draw();
      }
      y1 = y2;
      if (iy==ny-2) y2 = 1;
      else          y2 = y1+dy;
   }
}

Thanks, Olivier. I’ve got the idea. I was under impression that TPad::Divide() can do this job of manual TPad placement for me. If not, okay, I’ll stick to your approach.

May be TPad::Divide with 0 margin should be change to the example I sent you… to be discuss…