Unexpected behaviour in TPad::SetRightMargin

ROOT Version: 6.30.02
Platform: Ubuntu 22.04
Compiler: gcc 11.04


Hello, I’ve encountered a behaviour I’m not sure I understand. I’m drawing a 2d histogram on a canvas with the “COLZ” option to show the palette, but the palette title (which I set through the Z axis of the histogram) is cropped by the canvas. Following some older forum’s posts I tried setting the right margin of the canvas using TPad::SetRightMargin but instead of adding space to the side of the window, the canvas adds space between the histogram and the Palette Axis, is this the correct behaviour? If so how would I be able to show the cropped part?

For instance this is the code in question:

TH2I *hist = new TH2I(...);
  hist->SetZTitle(...);

  TCanvas *canvas = new TCanvas("canvas", nullptr);
  canvas->SetRightMargin(0.2);
  hist->Draw("COLZ");

And this is the result


As you can see the space is added between the palette and the histogram, not between the palette and the canvas right side. Also next to the palette on the upper part there is the axis title cropped…

Hi @andreanicoletti,

I think @couet or @linev will be able to help you on this.

Hi Andrea,

I just tried the following:

$ root -l
root [0] TCanvas *c1 = new TCanvas("c1", "c1", 0, 0, 800, 600);
root [1] c1->SetRightMargin(0.2);
root [2] TH2F* h = new TH2F("h", "my histo;X;Y;Z", 10, 0, 10, 10, 0, 10);
root [3] h->Fill(3, 7, 5);
root [4] h->Draw("colz");

and got

Can you try it and tell us what you see? I’m on root 6.30.02-x86_64-el9-gcc13-opt.

Thank you for your response. I tried running the code in the ROOT command line and I get the expected behaviour (just like in your image). But still running my macro I have the same problem, either if I run the code in the command line or if I run it as a script. The only thing that comes up to my mind which could interfere is that the TH2I histogram is retrieved from a .root file (but I really can’t think in which way that could cause this problem).
Btw the exact ROOT image I’m running is root_v6.32.02.Linux-ubuntu22.04-x86_64-gcc11.4

In that case, may I ask you to share your macro (in a form that I could run) and the input .root file?

Thank you again. I’ve tried to put the histogram generated by your code in a root file, retrieve it and perform on it the same operations I did for my histogram and it works correctly, so I guess the problem lies in the generation of the histogram but I really can’t fathom how…
Anyway I’ve attached a root file with the TH2I histogram inside (its name is “test-histogram”), you can retrieve it and watch the strange behaviour running the following code (in the same directory as the root file obviously):


  TFile *file = TFile::Open("./test-file.root", "READ");
  TH2I *hist = file->Get<TH2I>("test-histogram");
  TCanvas *c = new TCanvas("c", "c");
  c->SetRightMargin(0.2);
  hist->Draw("colz");
  

Thank you!

I don’t see any attached files…

I apologize the file didn’t upload properly. This is the correct one
test-file.root (79.2 KB)

Indeed, the palette does not move with increasing right margin. Weird… It always moves for my histograms (TH2Fs or TH2Is). There must be something unique about this particular test-histogram histogram. Understanding how this histogram was created and written into test-file.root would certainly help.

This seems to happen when the palette’s position was modified before saving the histogram to the file. When the histo is read back from the file, the palette’s position that was saved is remembered and not affected by the new margins. Here’s an example:

{
  TFile *f = new TFile("z.root","recreate");
  auto c = new TCanvas("c","c",600,400);
  c->Divide(1,2);
  auto h0 = new TH2F("h0","h0",40,-4,4,40,-20,20);
  auto h1 = new TH2F("h1","h1",40,-4,4,40,-20,20);
  float px, py;
  for (Int_t i = 0; i < 10000; i++) {
    gRandom->Rannor(px,py);
    h0->Fill(px,5*py);
    h1->Fill(px,5*py);
  }
  c->cd(1);
  h0->Draw("colz");
  //gPad->Update();
  //auto palette = (TPaletteAxis*)h0->GetListOfFunctions()->FindObject("palette");
  //palette->SetX1NDC(0.9);
  h0->Write("h0");

  c->cd(2);
  h1->Draw("colz");
  gPad->Update();
  auto palette = (TPaletteAxis*)h1->GetListOfFunctions()->FindObject("palette");
  palette->SetX1NDC(0.9);
  h1->Write("h1");

  f->Close();
  delete f;

  // Read from file
  TFile *f2 = new TFile("z.root","read");
  auto c0b = new TCanvas("c0b","read from file - 0b",600,400);
  TH2F *h0b = (TH2F*)f2->Get("h0");
  c0b->SetRightMargin(0.2);
  c0b->cd();
  h0b->Draw("colz");

  auto c1b = new TCanvas("c1b","read from file - 1b",600,400);
  TH2F *h1b = (TH2F*)f2->Get("h1");
  c1b->SetRightMargin(0.2);
  c1b->cd();
  h1b->Draw("colz");
}

Note that before writing, the palette is modifed for h1, so when read as h1b it shows the issue you are seeing, while h0 looks as expected.
c0b
c1b

However, also note that if the palette is modifed for h0 instead (swap the un/commented lines above), both histograms show the problem.
The fact that the palette position is remembered when saving, may be a feature, but I think that the last case (modifying one palette affects the behaviour for subsequent histograms) could be a bug.
In any case, it looks like you have to get the palette in your new code (the same way shown above: draw histo, then update, then get the palette) and move it yourself (using SetX1NDC and SetX2NDC for the horizontal, SetY… for vertical).

1 Like

Thank you very much for your help. Yes this is very strange, upon the histogram creation I did not touch the palette axis properties at all. Anyway I will take your advice and manually set the palette position. Can I ask you if by any chance you know how to get the position of the right side of the histogram in NDC (so that I know where to put the palette X1 coord)?

Also, to me it seems a bug that, even if the palette position is persisted in the root file, using TPad::SetRightMargin on the canvas doesn’t give the expected result (that a margin is effectively added to the right of the canvas, not to the right of the histogram before the palette); and if I do not call that method, the palette position is next to the histogram (without any margin), so if the palette axis position is written in the root file, why would this behaviour happen only once I retrieve the file and call canvas->SetRightMargin(…) ?

Try canvas->GetRightMargin() (with whatever pointer you have for the TCanvas), or gPad->GetRightMargin();

The palette is initially positioned based on the canvas’s geometry. If you adjust the margin before drawing the histogram, as shown in the example provided by @yus, the histogram will be positioned accordingly. However, if you modify the margin after plotting, the palette’s position will already be set and won’t change. This is necessary to allow users to adjust the palette’s position as desired. In following example I adjusted the palette’s position after drawing. Also, note that I’ve adjusted the vertical position to avoid covering the power of 10.


   auto file = TFile::Open("test-file.root", "READ");
   TH2I *h = (TH2I*)file->Get("test-histogram");
   h->SetStats(0);
   auto c = new TCanvas("c", "c");
   c->SetRightMargin(0.2);
   h->Draw("colz");
   TPaletteAxis *palette = (TPaletteAxis*)h->GetListOfFunctions()->FindObject("palette");
   palette->SetX1NDC(0.81);
   palette->SetX2NDC(0.85);
   palette->SetY1NDC(0.15);
   c->Modified();
   c->Update();
}