Skip to content

[hist] Add SetRefPad for consistent axis scaling#20763

Closed
JasMehta08 wants to merge 1 commit intoroot-project:masterfrom
JasMehta08:master
Closed

[hist] Add SetRefPad for consistent axis scaling#20763
JasMehta08 wants to merge 1 commit intoroot-project:masterfrom
JasMehta08:master

Conversation

@JasMehta08
Copy link
Contributor

This Pull request:

Implement opt-in Reference Pad scaling for TAxis (Fixes #20484)

Changes or fixes:

This PR addresses the long-standing issue of inconsistent axis title/label sizing and offsetting between pads of different sizes (e.g., in ratio plots), as described in issue #20484.

The Problem:
When creating canvases with split pads (e.g., 70/30 split), the default behavior scales text sizes relative to the pad height. This results in tiny, unreadable text in the smaller auxiliary pad, requiring users to manually tune SetLabelSize and SetTitleOffset for every axis.

The Solution:
I have implemented an opt-in mechanism that allows an axis to use the dimensions of a "Reference Pad" for scaling calculations.

  • Added TAxis::SetRefPad(TVirtualPad *pad).
  • Implementation:
    • Added a variable fRefLength to TAxis to store the reference height (avoiding unsafe pointer storage).
    • Modified TGaxis::PaintAxis to check if fRefLength > 0.
    • If active, PaintAxis calculates a scaling factor (fRefLength / currentPadHeight) and temporarily applies it to fLabelSize, fTitleSize, fTickSize, fLabelOffset, and fTitleOffset using an AttributeRestorer (RAII) pattern.
    • This ensures proper scaling and prevents titles from overlapping with labels in small pads.

Design Choice:
I chose an opt-in approach (SetRefPad) rather than automatic scaling to preserve backward compatibility.

Note:
I also investigated applying this fix to TPaveStats and TLegend, but due to the complexity of their internal layout logic, those changes are not included in this PR. This PR focuses strictly on fixing the TAxis consistency, which was the core request of the issue.

Verification Code

The following macro demonstrates the fix on a standard ratio plot.
(Please refer to the attached image for the output)

void complete_test() {
   gStyle->SetOptStat(1111);
   gStyle->SetOptFit(0);
   
   auto c = new TCanvas("c", "Axis Scaling Fix - Realistic Ratio Plot", 1200, 600);
   c->Divide(2, 1);
   
   // Create standard histogram template with realistic data
   TH1D *hTemplate = new TH1D("hTemplate", 
      "Invariant Mass;Mass [GeV];Events / 2 GeV", 
      50, 50, 150);
   
   // Use a custom function to fill (Mean=91, Sigma=2.5 - Z peak style)
   TF1 *fRel = new TF1("fRel", "breitwigner", 50, 150);
   fRel->SetParameters(1000, 91.2, 2.5);
   hTemplate->FillRandom("fRel", 10000);
   
   hTemplate->SetLineColor(kBlack);
   hTemplate->SetMarkerStyle(20);
   hTemplate->SetMarkerSize(0.6);
   
   // Standard label sizes
   hTemplate->GetXaxis()->SetLabelSize(0.04);
   hTemplate->GetYaxis()->SetLabelSize(0.04);
   hTemplate->GetXaxis()->SetTitleSize(0.045);
   hTemplate->GetYaxis()->SetTitleSize(0.045);
   
   // Split ratio: Top 70%, Bottom 30%
   Double_t splitPoint = 0.30;
   
   // =============================================
   // LEFT SIDE: BEFORE (Standard Behavior)
   // =============================================
   c->cd(1);
   TPad *leftPad = (TPad*)gPad;
   leftPad->SetName("LeftPad");
   
   // Main Pad (70%)
   TPad *mainL = new TPad("mainL", "Main", 0.0, splitPoint, 1.0, 1.0);
   mainL->SetBottomMargin(0); // Joined pads
   mainL->SetLeftMargin(0.15);
   mainL->Draw();
   mainL->cd();
   
   TH1D *hMainL = (TH1D*)hTemplate->Clone("hMainL");
   hMainL->SetTitle("Original Behavior (Ratio Pad)");
   hMainL->Draw("E1");
   
   // Ratio Pad (30%)
   leftPad->cd();
   TPad *ratioL = new TPad("ratioL", "Ratio", 0.0, 0.0, 1.0, splitPoint);
   ratioL->SetTopMargin(0);
   ratioL->SetBottomMargin(0.35); // Large margin needed for X labels
   ratioL->SetLeftMargin(0.15);
   ratioL->SetGridy();
   ratioL->Draw();
   ratioL->cd();
   
   TH1D *hRatioL = (TH1D*)hTemplate->Clone("hRatioL");
   hRatioL->SetTitle("");
   hRatioL->GetYaxis()->SetTitle("Ratio");
   hRatioL->GetYaxis()->SetNdivisions(505);
   hRatioL->Draw("hist");
   
   // Add Label
   leftPad->cd();
   TLatex *lblL = new TLatex(0.5, 0.95, "Before: Labels too small in ratio pad");
   lblL->SetNDC();
   lblL->SetTextAlign(22);
   lblL->SetTextSize(0.04);
   lblL->Draw();

   // =============================================
   // RIGHT SIDE: AFTER (With SetRefPad)
   // =============================================
   c->cd(2);
   TPad *rightPad = (TPad*)gPad;
   rightPad->SetName("RightPad");
   
   // Main Pad (70%)
   TPad *mainR = new TPad("mainR", "Main", 0.0, splitPoint, 1.0, 1.0);
   mainR->SetBottomMargin(0);
   mainR->SetLeftMargin(0.15);
   mainR->Draw();
   mainR->cd();
   
   TH1D *hMainR = (TH1D*)hTemplate->Clone("hMainR");
   hMainR->SetTitle("With SetRefPad(main)");
   hMainR->Draw("E1");
   
   // Ratio Pad (30%)
   rightPad->cd();
   TPad *ratioR = new TPad("ratioR", "Ratio", 0.0, 0.0, 1.0, splitPoint);
   ratioR->SetTopMargin(0);
   ratioR->SetBottomMargin(0.35); 
   ratioR->SetLeftMargin(0.15);
   ratioR->SetGridy();
   ratioR->Draw();
   ratioR->cd();
   
   TH1D *hRatioR = (TH1D*)hTemplate->Clone("hRatioR");
   hRatioR->SetTitle("");
   hRatioR->GetYaxis()->SetTitle("Ratio");
   hRatioR->GetYaxis()->SetNdivisions(505);
   
   // THE FIX 
   // We tell the ratio plot axes: "Scale yourself as if you were in 'mainR'"
   hRatioR->GetXaxis()->SetRefPad(mainR);
   hRatioR->GetYaxis()->SetRefPad(mainR);
   
   hRatioR->Draw("hist");
   
   // Add Label
   rightPad->cd();
   TLatex *lblR = new TLatex(0.5, 0.95, "After: Consistent text size");
   lblR->SetNDC();
   lblR->SetTextAlign(22);
   lblR->SetTextSize(0.04);
   lblR->SetTextColor(kGreen+2);
   lblR->Draw();

   c->SaveAs("complete_test.png");
}
image

Checklist:

  • tested changes locally
  • updated the docs (if necessary)

This PR fixes #20484

@github-actions
Copy link

Test Results

     6 files       6 suites   1d 2h 16m 50s ⏱️
 4 080 tests  4 077 ✅ 3 💤 0 ❌
19 531 runs  19 531 ✅ 0 💤 0 ❌

Results for commit d1c338c.

@JasMehta08 JasMehta08 closed this Dec 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify axis titles and label sizing and offsetting across a set of pads

1 participant

Comments