How to correctly scale title size and tick size across pads?

Hello all,
Hope you are well.

I was trying to make a plotting code that does multiple pads but I was having some trouble in scaling the titles and ticks correctly. I may have misunderstood that the sizes scale with the are of the pads themselves. I understand I can do pixel size for the text themselves although not sure if something similar exists for the ticks.

Would appreciate any ideas for the same.
Thank you in advanced.

import ROOT
ROOT.gROOT.SetBatch(True)
ROOT.gStyle.SetOptStat(0)

# Set up three pads (sometimes can be two)
c = ROOT.TCanvas()
pad1 = ROOT.TPad("pad1", "pad1", 0, 0.5, 1, 1)
pad2 = ROOT.TPad("pad2", "pad2", 0, 0.25, 1, 0.5)
pad3 = ROOT.TPad("pad3", "pad3", 0, 0, 1, 0.25)
pad1.SetBottomMargin(0)
pad2.SetTopMargin(0)
pad2.SetBottomMargin(0.3)
pad1.Draw()
pad2.Draw()
pad3.Draw()
c.Draw()

# Setup histograms
# h1, h2 go on pad1
h1 = ROOT.TH1D("h1", "h1", 10, 0, 10)
h2 = ROOT.TH1D("h2", "h2", 10, 0, 10)
h1.FillRandom("gaus", 1000)
h2.FillRandom("gaus", 1000)
# hR goes on pad2
hR = h1.Clone("hR")
hR.Divide(h2)
# hM goes on pad3
hM = h1.Clone("hM")
hM.Add(-1*h2)
hM.Divide(hR)

# Set axis label size correctly...
ylabelSize = 0.05
yTickSize = 0.02
xTickSize = 0.02
h1.GetYaxis().SetTitle("Events")
h1.GetYaxis().SetTitleSize(ylabelSize)
h1.GetYaxis().SetTickSize(yTickSize)
h1.GetXaxis().SetTickSize(xTickSize)

# Scaling Factor for pad2/pad3
pad1Area = pad1.GetWNDC() * pad1.GetHNDC()
pad2Area = pad2.GetWNDC() * pad2.GetHNDC()
pad3Area = pad3.GetWNDC() * pad3.GetHNDC()
pad2ScaleFactor = pad1Area / pad2Area
pad3ScaleFactor = pad1Area / pad3Area

# hR and hM axis label sizes consistent with pad1?
hR.GetYaxis().SetTitle("Ratio")
hR.GetYaxis().SetTitleSize(ylabelSize * pad2ScaleFactor)
hR.GetYaxis().SetTickSize(yTickSize * pad2ScaleFactor)
hR.GetXaxis().SetTickSize(xTickSize * pad2ScaleFactor)

hM.GetYaxis().SetTitle("Difference / Ratio")
hM.GetYaxis().SetTitleSize(ylabelSize * pad3ScaleFactor)
hM.GetYaxis().SetTickSize(yTickSize * pad3ScaleFactor)
hM.GetXaxis().SetTickSize(xTickSize * pad3ScaleFactor)

pad1.cd()
h1.SetLineColor(ROOT.kRed)
h1.Draw("hist")
h2.SetLineColor(ROOT.kBlue)
h2.Draw("hist same")
pad2.cd()
hR.SetLineColor(ROOT.kBlack)
hR.Draw("hist")
pad3.cd()
hM.SetLineColor(ROOT.kGreen)
hM.Draw("hist")

c.SaveAs("test.pdf")

The “size” for the scaling factor is not the area of the pad, but in fact the smaller of height or width. The documentation for this depends on your version of ROOT; for the latest stable (6.36.12), see here:

and the current Master:

Experimenting with your example, like this (I changed the y-axis titles to the same for all, so their positions can be better compared):

import ROOT
ROOT.gROOT.SetBatch(True)
ROOT.gStyle.SetOptStat(0)

# Set up three pads (sometimes can be two)
c = ROOT.TCanvas()
pad1 = ROOT.TPad("pad1", "pad1", 0, 0.5, 1, 1)
pad2 = ROOT.TPad("pad2", "pad2", 0, 0.25, 1, 0.5)
pad3 = ROOT.TPad("pad3", "pad3", 0, 0, 1, 0.25)
pad1.SetBottomMargin(0)
pad2.SetTopMargin(0)
pad2.SetBottomMargin(0.3)
pad1.Draw()
pad2.Draw()
pad3.Draw()
c.Draw()

# Setup histograms
# h1, h2 go on pad1
h1 = ROOT.TH1D("h1", "h1", 10, 0, 10)
h2 = ROOT.TH1D("h2", "h2", 10, 0, 10)
h1.FillRandom("gaus", 1000)
h2.FillRandom("gaus", 1000)
# hR goes on pad2
hR = h1.Clone("hR")
hR.Divide(h2)
# hM goes on pad3
hM = h1.Clone("hM")
hM.Add(-1*h2)
hM.Divide(hR)

# Set axis label size correctly...
ylabelSize = 0.05
xlabelSize = 0.2
yTickSize = 0.02
xTickSize = 0.05
yTitleOff = 0.8
h1.GetYaxis().SetTitle("Events")
h1.GetYaxis().SetTitleOffset(yTitleOff)
h1.GetYaxis().SetTitleSize(ylabelSize)
h1.GetYaxis().SetLabelSize(ylabelSize)
h1.GetYaxis().SetTickSize(yTickSize)
h1.GetXaxis().SetLabelSize(xlabelSize)
h2.GetXaxis().SetLabelSize(xlabelSize)
h1.GetXaxis().SetTickSize(xTickSize)

# Scaling Factor for pad2/pad3
pad1H = pad1.GetHNDC()
pad2H = pad2.GetHNDC()
pad3H = pad3.GetHNDC()
pad1W = pad1.GetWNDC()
pad2W = pad2.GetWNDC()
pad3W = pad3.GetWNDC()
pad2hScaleFactor = pad1H / pad2H
pad3hScaleFactor = pad1H / pad3H
pad2wScaleFactor = pad1W / pad2W
pad3wScaleFactor = pad1W / pad3W
print('heights:', pad1H, pad2H, pad3H)
print('widths:', pad1W, pad2W, pad3W)
print('height factors:', pad2hScaleFactor, pad3hScaleFactor)
print('width factors: ', pad2wScaleFactor, pad3wScaleFactor)


# hR and hM axis label sizes consistent with pad1?
hR.GetYaxis().SetTitle("Events") #Ratio
hR.GetYaxis().SetTitleOffset(yTitleOff / pad2hScaleFactor)
hR.GetYaxis().SetTitleSize(ylabelSize * pad2hScaleFactor)
hR.GetYaxis().SetLabelSize(ylabelSize * pad2hScaleFactor)
#hR.GetYaxis().SetTickSize(yTickSize)
hR.GetYaxis().SetTickSize(0.027)
hR.GetXaxis().SetLabelSize(ylabelSize * pad2hScaleFactor)
hR.GetXaxis().SetTickSize(xTickSize * pad2hScaleFactor)

hM.GetYaxis().SetTitle("Events") # "Difference / Ratio"
hM.GetYaxis().SetTitleOffset(yTitleOff / pad3hScaleFactor)
hM.GetYaxis().SetTitleSize(ylabelSize * pad3hScaleFactor)
hM.GetYaxis().SetLabelSize(ylabelSize * pad3hScaleFactor)
#hM.GetYaxis().SetTickSize(yTickSize)
hM.GetYaxis().SetTickSize(0.023)
hM.GetXaxis().SetLabelSize(ylabelSize * pad3hScaleFactor)
hM.GetXaxis().SetTickSize(xTickSize * pad3hScaleFactor)

pad1.cd()
h1.SetLineColor(ROOT.kRed)
h1.Draw("hist")
h2.SetLineColor(ROOT.kBlue)
h2.Draw("hist same")
pad2.cd()
hR.SetLineColor(ROOT.kBlack)
hR.Draw("hist")
pad3.cd()
hM.SetLineColor(ROOT.kGreen)
hM.Draw("hist")

c.SaveAs("test2.pdf")

I get this
test2.pdf (15.1 KB)
which looks ok, but note that:

  • the y-axis ticks needed different scalings (0.027 and 0.023), which don’t seem to come from a direct formula, at least a simple one; notable since both pads have the same scale factors
  • for the y-axis title offsets I had to divide by the factors, not multiply (still, I’m not entirely sure the positions match exactly although they seem very close --and may or may not work well with other pad sizes, etc.)