Custom Palettes and TExec trick

Dear all,
I have a macro which draws 2D histograms with different color palettes in the same pad.
They do essentially what is described here:
root.cern.ch/drupal/content/how- … ame-canvas

With the difference that, instead of using just:

TExec *ex1 = new TExec("ex1","gStyle->SetPalette(1);");

It does the trick with a custom class (TMPalette), which handles better the use of new customized palettes in root:

TExec *ex1 = new TExec("ex1","myPalette->cd();");

All my palettes (TMPalette objects) are defined in a separated macro (Palettes.C),
and they are nicely used by the example macro: testPalettes.C.
However, as soon as I try to dynamically create a new palette (not present in Palettes.C) in the same macro which draws the histograms, TExec complains that the new palette “is not defined in the current scope…”

I have attached a tar.gz file with the minimal necessary files to reproduce the problem.
Extract it, go to the directory palettes, do make and run testPalettes.C macro for the good case and testPaletteBad.C macro for the problematic one:
palettes.tar.gz (6.16 KB)

Any help would be highly appreciated. I am stuck with this issue and I really need it.
Thanks!

The pointer used in TExec have to be global. Because the code in Palettes.C is not in a named macro then all the pointers declared there are glocal. To make your “Bad” macro working you new to make the pointer to hot3palette global has shown in the following code:

#include "TMPalette.hh"

TMPalette *hot3Palette = 0;

void testPalettesBad(){
  // Here the Palettes are defined
  gROOT->Macro("Palettes.C");
  
  gStyle->SetOptStat(0);

  TCanvas *c = new TCanvas("c","c",1000,625);
  c->Divide(2,2);
  
  TH2F *h1 = new TH2F("h1","h1",100,-4,4,100,-4,4);
  TH2F *h2 = new TH2F("h2","h2",100,-4,4,100,-4,4);
  TH2F *h3 = new TH2F("h3","h3",100,-4,4,100,-4,4);
  TH2F *h4 = new TH2F("h4","h4",100,-4,4,100,-4,4);
  
  Double_t a,b;
  for (Int_t i=0;i<50000;i++) {
    gRandom->Rannor(a,b);
    h1->Fill(a-1.5,b-1.5);
    h2->Fill(a+1.5,b+1.5);
    h3->Fill(a-1.5,b+1.5);
    h4->Fill(a+1.5,b-1.5);
  }

  hot3Palette = (TMPalette*) gROOT->FindObject("hot3");
  if(!hot3Palette) {
    const Int_t hot3NRGBs = 4;
    const Int_t hot3NCont = 64;
    Double_t hot3Stops[hot3NRGBs] = { 0.00, 0.25, 0.75, 1.00 }; 
    Double_t hot3Red[hot3NRGBs] =   { 0.91, 1.000, 1.000, 0.160 }; 
    Double_t hot3Green[hot3NRGBs] = { 0.91, 0.7, 0.149, 0.160 };
    Double_t hot3Blue[hot3NRGBs] =  { 0.91, 0.000, 0.000, 0.160 };
    hot3Palette = new TMPalette("hot3");
    hot3Palette->CreateGradientColorTable(hot3NRGBs, hot3Stops,hot3Red, hot3Green, hot3Blue, hot3NCont);                                       
  }
  

  TExec *ex1 = new TExec("ex1","electronPalette->cd();");
  TExec *ex2 = new TExec("ex2","hot3Palette->cd();");
  TExec *ex3 = new TExec("ex3","rbowPalette->cd();");
  TExec *ex4 = new TExec("ex4","yellowPalette->cd();");
  
  c->cd(1);
  h1->Draw("axis");
  ex1->Draw();
  h1->Draw("colz same");
  
  c->cd(2);
  h2->Draw("axis");
  ex2->Draw();
  h2->Draw("colz same");
  
  c->cd(3);
  h3->Draw("axis");
  ex3->Draw();
  h3->Draw("colz same");
  
  c->cd(4);
  h4->Draw("axis");
  ex4->Draw();
  h4->Draw("colz same");

  c->Print("./testPalettes.png");
}

BTW, why are you using your own CreateGradientColorTable() method and not the one in TColor ?

Oh! Thanks. Nice explanation! It works good now.
About why using the custom CreateGradientColorTable() method instead of the TColor’s one, I only can say that perhaps the TMPalette class was created by someone before this method exists in TColor. I have inherited this implementation. Any advantages on using the TColors::CreateGradientColorTable() instead of what I have now?

Hi again,
I’ll take the opportunity to ask another question in this respect.
Is there a way to superimpose 2D histograms in such a way they are all visible?
Some kind of transparency in the color palettes…
Here a script to be used within the context of the program I attached in my first post to describe what I mean:testPalettesJoint.C (1.77 KB)

In fact I was asking you the same :slight_smile: … But you replied nicely.

The only advantage of using the TColor one would be that the code is there an you do not needed to add it in your program. To see if one is better than the other a close comparison would need to be done. A priori they are similar.

We have done something recently in that field. I works only for the file output (non on screen yet). I will see how to modified you macro. to see if we can do something. I’ll be back.

You can get it is you print it as a PDF file. (see attachement).
You need to do:

      color = new TColor(highestIndex,
			 Red[g-1] + c * (Red[g] - Red[g-1])/ nColorsGradient,
			 Green[g-1] + c * (Green[g] - Green[g-1])/ nColorsGradient,
			 Blue[g-1] + c * (Blue[g] - Blue[g-1])/ nColorsGradient,
			 Form("%s_%d", GetName(), fNColors),   0.5);

notice the alpha value = 0.5…
testPalettes.pdf (97.4 KB)

Oh I see… Cannot one have transparency also in png output?
And another thing. I have slightly modified the testPaletteJoint.C in such a way that the pointer to the palette created there is deleted and recreated in every iteration of the program.
This is something that may seem silly for this particular example, but it is very important in my real working script. The problem is that I get a segmentation fault at the second - third iteration of the script.
Here the crashing script:
testPalettesJointCrash.C (1.81 KB)

Could you please take a look? I don’t understand the crash, but it seems to be in the constructor of TMPalette.
Thanks in advance!

Speaking with the CINT expert it appears that using global this way in TExec will not fly.
The best would be to make functions defining the palettes and call them in TExec instead of accessing the palettes directly. See TExec help.

Why is not convenient to use globals in such a way?
How would you modify the program to make it work with no crashing?
I don’t understand why using a function will work better.
And, what is TExec help? The documentation here root.cern.ch/root/html530/TExec.html ??
I don’t see anything there related with my problem.
I am still confused and the program is not running when in a loop over data files (they crash after 2 - 3 iterations).

It cannot work that way . CINT does not support it. Sorry .
Do:

#include "TMPalette.hh"

void definehot3()
{
  TMPalette *hot3Palette;
  const Int_t hot3NRGBs = 4;
  const Int_t hot3NCont = 64;
  Double_t hot3Stops[hot3NRGBs] = { 0.00, 0.25, 0.75, 1.00 };
  Double_t hot3Red[hot3NRGBs] =   { 0.91, 1.000, 1.000, 0.160 };
  Double_t hot3Green[hot3NRGBs] = { 0.91, 0.7, 0.149, 0.160 };
  Double_t hot3Blue[hot3NRGBs] =  { 0.91, 0.000, 0.000, 0.160 };
  hot3Palette = new TMPalette("hot3");
  hot3Palette->CreateGradientColorTable(hot3NRGBs, hot3Stops,hot3Red, hot3Green, hot3Blue, hot3NCont);
  hot3Palette->cd();
}

void testPalettesJointCrash(){
  // Here the Palettes are defined
  gROOT->Macro("Palettes.C");

  gStyle->SetOptStat(0);

  TCanvas *c = new TCanvas("c","c",0,700,1000,625);

  TH2F *h1 = new TH2F("h1","h1",100,-4,4,100,-4,4);
  TH2F *h2 = new TH2F("h2","h2",100,-4,4,100,-4,4);
  TH2F *h3 = new TH2F("h3","h3",100,-4,4,100,-4,4);
  TH2F *h4 = new TH2F("h4","h4",100,-4,4,100,-4,4);

  Double_t a,b;
  for (Int_t i=0;i<50000;i++) {
    gRandom->Rannor(a,b);
    h1->Fill(a-1.5,b-1.5);
    h2->Fill(a+1.5,b+1.5);
    h3->Fill(a-1.5,b+1.5);
    h4->Fill(a+1.5,b-1.5);
  }

  TExec *ex1 = new TExec("ex1","electronPalette->cd();");
  TExec *ex2 = new TExec("ex2","definehot3();");
  TExec *ex3 = new TExec("ex3","rbowPalette->cd();");
  TExec *ex4 = new TExec("ex4","yellowPalette->cd();");

  h1->Draw("axis");
  ex1->Draw(); h1->Draw("col same");

  ex2->Draw(); h2->Draw("col same");

  ex3->Draw(); h3->Draw("col same");

  ex4->Draw(); h4->Draw("col same");

  c->Print("./testPalettes.png");
}

Hello,

The link to the HowTo on TExec trick to have 2 palettes used in the same canvas doesn’t work. I tried to search again for the information and couldn’t find it.

Is the method to use 2 palettes documented somewhere?

Regards,
Antoni

Hi Antoni,

the example is here: https://root.cern.ch/root/html/tutorials/graphs/multipalette.C.html

Hi yus,

Thanks!

I hoped also for some explanation why the trick is needed in the first place and how it works. Maybe root devs can add some comments to the tutorial. I think it used to be explained somewhere some time ago. When I first stumbled on this, the fact that the following doesn’t work

can->cd(1);
gStyle->SetPalette(1);
h1->Draw("colz");
can->cd(2);
gStyle->SetPalette(51);
h2->Draw("colz");

in the way that the two histograms are drawn with different palettes, was rather surprising.

You can check the original page here: https://web.archive.org/web/20130410182843/http://root.cern.ch/drupal/content/how-have-two-different-color-palettes-same-canvas

It does not, however, answer your question…

Thank you again! While it does not answer the question, it at least has a beginning of the answer “ROOT only has one color palette active at a time.” I think that seeing it I managed to somehow understand what was going on some time ago. The lack of any comments in the current tutorial makes it completely cryptic. Indeed if the text of the old how-to was extended and added to the tutorial, it would be great.

Oh, I see that I was not searching thoroughly enough. Actually TColor’s doxygen documentation already has this information about TExec. Still, it doesn’t go into details - it has roughly the same statement as the old how-to.

Better user a more up today link than this old version of the doc:
https://root.cern/doc/master/multipalette_8C.html

There is nothing really to add than the fact ROOT has only one palette active at a given time. As it is said in the TColor documentation.

Regarding the meaning of “active palette”
My point is that when histogram->Draw(“colz”) is executed, one naively expects that this is the moment, when the currently active palette is used to determine colors in the plot. But in fact, the active palette is used later, when the canvas are saved as “.pdf” (I am mainly working in batch mode). This is why I think that it would be good to add some elaboration on what “active” means in the context of the palette - in what moment the active palette is actually used -> when the canvas are first put to screen in the interactive mode, after clicking on a pad, during SaveAs().

Regarding TExec trick
Once one thinks he understands what it means that only single palette is active, what happens when TExec is used, is still cryptic:

{
   TCanvas *c3  = new TCanvas("c3","C3",0,0,600,400);
   c3->Divide(2,1);
   TF2 *f3 = new TF2("f3","0.1+(1-(x-2)*(x-2))*(1-(y-2)*(y-2))",1,3,1,3);
   f3->SetLineWidth(1);
   f3->SetLineColor(kBlack);
   c3->cd(1);
   f3->Draw("surf1");
   TExec *ex1 = new TExec("ex1","gStyle->SetPalette(1);");
   ex1->Draw();
   f3->Draw("surf1 same");
   c3->cd(2);
   f3->Draw("surf1");
   //TExec *ex2 = new TExec("ex2","gStyle->SetPalette(51);");
   //ex2->Draw();
   f3->Draw("surf1 same");
   gStyle->SetPalette(kBird);
   c3->SaveAs("plot.pdf");
}

When ex2 is commented out, both plots are drawn with palette 1. When ex1 is commented, but ex2 not, the first is drawn with kBird, the second with 51. So it looks like TExec does not have really local effect, but it does not have a global effect (as the line before SaveAs has) as well. It acts on further pads than the one it was drawn in, but it does not work for earlier ones. Furthermore, TF1 has to drawn twice - before and after TExec with “same”. If it is just drawn after TExec, TExec has no effect. This is something that even now I cannot understand. What I do understand now, but what was far from obvious when I first saw the trick, is that it works in the following way:

  • when the pad is actually drawn (= painted?), it goes through its elements in the sequence of Draw calls; for TExec it executes its command - which sets palette globally, so it will set the palette for painting all objects afterwards (including all other pads and their elements).
  • if in the next pad another TExec changes the palette, it doesn’t affect the previous pad which was already painted, but it will affect the current and those painted later.

As I said, I still don’t understand why TF1 has to be drawn twice in the example.