Axis label offset

Is there a way to ensure that axis labels in different sized pads are always the same absolute distance from the axis? Alternatively, what is the formula used do calculate the absolute pixel-wise offset from the axis. If I know this then hopefully I should be able to derive the appropriate fractional offset from the relevant pad dimensions.

An example is shown in the attached figure. The centre bottom graph has a different absolute offset (presumably because the pad size is different). I would like to be able to calculate the appropriate value for

axis->SetLabelOffset(value)

to have all the bottom axis label offsets match. I managed to get the axis titles to have the same absolute size and offset with the following applied to each sub-pad of the main canvas canv:

[code]TPad * subPad = canv->cd(1);

Int_t marginSize = 80;

Double_t padWidthPix = TMath::Abs(subPad->XtoAbsPixel(subPad->GetX2()) - subPad->XtoAbsPixel(subPad->GetX1()));

Double_t padHeightPix = TMath::Abs(subPad->YtoAbsPixel(subPad->GetY2()) - subPad->YtoAbsPixel(subPad->GetY1()));

if(padWidthPix < padHeightPix){
textSizeFac = 1.0/dynamic_cast<Double_t>(padWidthPix);
}
else{
textSizeFac = 1.0/dynamic_cast<Double_t>(padHeightPix);
}

curGraph->GetXaxis()->SetTitleFont(42);
curGraph->GetYaxis()->SetTitleFont(42);
curGraph->GetYaxis()->SetTitleSize(0.25marginSizetextSizeFac);
curGraph->GetXaxis()->SetTitleSize(0.25marginSizetextSizeFac);
curGraph->GetYaxis()->SetTitleOffset(0.45/(dynamic_cast<Double_t>(marginSize)*textSizeFac));
curGraph->GetXaxis()->SetTitleOffset(0.3/(dynamic_cast<Double_t>(marginSize)*textSizeFac))
[/code]

but the labels seem to behave differently. Any help would be much appreciated.

Regards,

Hugh


Can you sent a running example showing your problem ? the piece of code you sent is not a running macro. Many thanks in advance.

This is the full function required to produce the graph. It’s probably not optimal but it works! It needs a TObjArray of TGraphErrors to be input, and to see the problem you need xDim to be al least 3.

[code]// Function to layout a TObjArray of TGraphErrors* in an N by M array

void GridGraph(TObjArray * inputs, Int_t xDim, Int_t yDim, Int_t graphSize, Int_t marginSize, const char * drawOpt, const char * title = 0){
// set up main canvas

Int_t canvWidth = graphSizexDim + (2marginSize);
Int_t canvHeight = graphSizeyDim + (2marginSize);

TCanvas * canv = new TCanvas(“canv”, title, canvWidth, canvHeight);
canv->SetFixedAspectRatio();

canv->SetTopMargin(0.0);
canv->SetBottomMargin(0.0);
canv->SetLeftMargin(0.0);
canv->SetRightMargin(0.0);

// divide main canvas with no margins
canv->Divide(xDim, yDim, 0., 0.);

// some working variables
Int_t row, col, padLeftPix, padRightPix, padTopPix, padBottomPix;
Double_t padTop, padBottom, padLeft, padRight, curTop, curBottom, curLeft, curRight;
Double_t textSizeFac, offsetFac;
UInt_t padHeightPix, padWidthPix;
TPad * subPad = 0;
TGraphErrors * curGraph = 0;

// determine fraction of enlarged graphs occupied by margin
Double_t marginFactor = dynamic_cast<Double_t>(marginSize)/dynamic_cast<Double_t>(marginSize+graphSize);

// set up sub-pad sizes and margins depending upon position in grid
for(Int_t i = 1; i <= xDimyDim; i++){
subPad = dynamic_cast<TPad
>(canv->cd(i));
subPad->SetVertical(1);

// set all margins to 0, then alter exceptions and set pad sizes

// what row and column are we in?
col = (i-1)%xDim + 1;
row = ((i-col)/xDim)+1;
   
// what are the pad limits?
padLeftPix = (col-1)*graphSize + marginSize;
padRightPix = padLeftPix + graphSize + 1;
padBottomPix = (yDim-row)*graphSize + marginSize;
padTopPix = padBottomPix+graphSize + 1;

padLeft = dynamic_cast<Double_t>(padLeftPix)/dynamic_cast<Double_t>(canvWidth);
padRight = dynamic_cast<Double_t>(padRightPix)/dynamic_cast<Double_t>(canvWidth);
padBottom = dynamic_cast<Double_t>(padBottomPix)/dynamic_cast<Double_t>(canvHeight);
padTop = dynamic_cast<Double_t>(padTopPix)/dynamic_cast<Double_t>(canvHeight);

// set pad limits

// note that for single column or row graphs a graph can be both top and bottom or left and right
subPad->SetPad(padLeft, padBottom, padRight, padTop);
subPad->SetVertical(1);
if(row == yDim && col == 1){ // bottom left corner
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(0.0, 0.0, curRight, curTop);
  subPad->SetLeftMargin(marginFactor);
  subPad->SetBottomMargin(marginFactor);
}
if(row == yDim && col == xDim){ // bottom right corner
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(curLeft, 0.0, 1.0, curTop);
  canv->cd(i)->SetRightMargin(marginFactor);
  subPad->SetBottomMargin(marginFactor);
}
if(row == yDim){ // any other bottom row graphs
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(curLeft, 0.0, curRight, curTop);
  subPad->SetBottomMargin(marginFactor);
}

if(row == 1 && col == 1){ // top left corner
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(0.0, curBottom, curRight, 1.0);
  subPad->SetLeftMargin(marginFactor);
  subPad->SetTopMargin(marginFactor);
}
if(row == 1 && col == xDim){ // top right corner
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(curLeft, curBottom, 1.0, 1.0);
  subPad->SetRightMargin(marginFactor);
  subPad->SetTopMargin(marginFactor);
}
if(row == 1){ // any other top row graphs
  subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
  subPad->SetPad(curLeft, curBottom, curRight, 1.0);
  subPad->SetTopMargin(marginFactor);
}

if(row != 1 && row != yDim){ // not in top or bottom rows
  if(col == 1){ // left hand column
subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
subPad->SetPad(0.0, curBottom, curRight, curTop);
subPad->SetLeftMargin(marginFactor);
  }
  if(col == xDim){ // right hand column
subPad->GetPadPar(curLeft, curBottom, curRight, curTop);
subPad->SetPad(curLeft, curBottom, 1.0, curTop);
subPad->SetRightMargin(marginFactor);
  }

}

// draw the graph after removing title
subPad->cd();
curGraph = dynamic_cast<TGraphErrors*>(inputs->At(i-1));
curGraph->SetTitle("");
curGraph->Draw(drawOpt);

subPad->SetFixedAspectRatio();

// make the labels look nice
// since text sizes are specified as a fraction of the pad width we need to derive a correction factor for the various pads

padWidthPix = TMath::Abs(subPad->XtoAbsPixel(subPad->GetX2()) - subPad->XtoAbsPixel(subPad->GetX1()));
padHeightPix = TMath::Abs(subPad->YtoAbsPixel(subPad->GetY2()) - subPad->YtoAbsPixel(subPad->GetY1()));

offsetFac = dynamic_cast<Double_t>(padWidthPix)/dynamic_cast<Double_t>(canvWidth);

if(padWidthPix < padHeightPix){
  textSizeFac = 1.0/dynamic_cast<Double_t>(padWidthPix);
}
else{
  textSizeFac = 1.0/dynamic_cast<Double_t>(padHeightPix);
}

// The positioning of the axis labels (not titles!) uses a different offset calculation for each axis!

std::cout << padWidthPix << "\t" << padHeightPix << "\t" << canvWidth << "\t" << canvHeight << std::endl; 

curGraph->GetXaxis()->SetTitleFont(42);
curGraph->GetYaxis()->SetTitleFont(42);
curGraph->GetYaxis()->SetTitleSize(0.25*marginSize*textSizeFac);
curGraph->GetXaxis()->SetTitleSize(0.25*marginSize*textSizeFac);
curGraph->GetYaxis()->SetTitleOffset(0.45/(dynamic_cast<Double_t>(marginSize)*textSizeFac));
curGraph->GetXaxis()->SetTitleOffset(0.3/(dynamic_cast<Double_t>(marginSize)*textSizeFac));
curGraph->GetXaxis()->SetLabelFont(42);
curGraph->GetYaxis()->SetLabelFont(42);
curGraph->GetYaxis()->SetLabelSize(0.2*marginSize*textSizeFac);
curGraph->GetXaxis()->SetLabelSize(0.2*marginSize*textSizeFac);

subPad->Modified();

}
canv->Modified();
}
[/code]

Ok, thanks, I was hoping for something simpler ready to run. So, I tried to make a simple one and I do not see the problem. Here it is:

{
   hpx = new TH1F("hpx","hpx",100,-4,4);
   TCanvas * canv = new TCanvas("canv", "canv", 600, 600); 
   canv->Divide(3,3,0,0);
   canv->cd(1); hpx->Draw(); 
   canv->cd(2); hpx->Draw(); 
   canv->cd(3); hpx->Draw(); 
   canv->cd(4); hpx->Draw(); 
   canv->cd(5); hpx->Draw(); 
   canv->cd(6); hpx->Draw(); 
   canv->cd(7); hpx->Draw(); 
   canv->cd(8); hpx->Draw(); 
   canv->cd(9); hpx->Draw();
}

Indeed! Most of my code was completely unnecessary. I should have tried the simple approach first! Many thanks.