root icon indicating copy to clipboard operation
root copied to clipboard

Issue using TColor and saving canvas to ROOT format

Open ttedeschi opened this issue 1 year ago • 5 comments

Check duplicate issues.

  • [X] Checked for duplicates

Description

It seems that when saving a canvas to a ROOT file (SaveAs("c.root")), colors defined with TColor::GetColor are not preserved whereas builtin colors are. This can be seen saving the canvas to both . png .root formats, then load the .root and save it again as a .png, and compare the two pngs created.

Tagging CMS CAT conveners @lenzip @anigamova and DPROC subconveners @oglez @ttedeschi

Reproducer

Define a save.C macro:

{
  TRandom3 r;
  TH1F h = TH1F("test","Test",100,-1.0,1.0);
  for (int i=0;i<=1000;++i) {
    h.Fill(r.Rndm());
  }

  TCanvas c = TCanvas();
  c.Draw();

  h.SetFillStyle(1001);
  h.SetFillColor(TColor::GetColor("#F5BB54"));

  //h.SetFillColor(kRed);
  h.Draw("HIST");

  c.SaveAs("c.root");
  c.SaveAs("c.png");
}

and a load.C macro:

{
TFile *f = new TFile("c.root");
TH1F *h1 = (TH1F*)f->Get("c1");
h1->Draw();
h1->SaveAs("loaded_c.png")
}

If h.SetFillColor(TColor::GetColor("#F5BB54")); is uncommented and h.SetFillColor(kRed) is commented, c.png and loaded_c.png differ (the latter lacks the color), whereas if h.SetFillColor(TColor::GetColor("#F5BB54")) is commented and h.SetFillColor(kRed) is uncommented, c.png and loaded_c.png are the same (both properly showing the red fill color).

ROOT version

6.32.04

Installation method

Docker image

Operating system

Ubuntu 24.04⁠

Additional context

No response

ttedeschi avatar Sep 30 '24 08:09 ttedeschi

Yes, this is how the colors are implemented. Only the builtins colors are known at saving time in root files. This other formats save the colors (including .C).

couet avatar Sep 30 '24 09:09 couet

One can store all colors in the canvas if call TColor::DefinedColors(1) before. If read such canvas back - all colors (including custom) will be restored.

linev avatar Oct 02 '24 08:10 linev

@ttedeschi

Did you try to call TColor::DefinedColors(1) before storing canvas in ROOT file?

linev avatar Oct 08 '24 07:10 linev

Hi sorry for the late reply, I tried and it works for ROOT 6.32 (I am finally able to see the right color in the loaded canvas), while with ROOT 6.30 I get

/test/./load_new.C:6:18: error: use 'template' keyword to treat 'Get' as a dependent template name
auto cnv = file->Get<TCanvas>("c1");
                 ^
                 template 
/test/./load_new.C:6:1: error: Syntax error
auto cnv = file->Get<TCanvas>("c1");
^
FunctionDecl 0x5af6325fe230 <input_line_8:1:1, /test/./load_new.C:14:1> input_line_8:1:6 __cling_Un1Qu30 'void (void *)'
|-ParmVarDecl 0x5af6325fe178 <col:22, col:28> col:28 vpClingValue 'void *'
|-CompoundStmt 0x5af6326e1a70 <col:42, /test/./load_new.C:14:1>
| |-DeclStmt 0x5af6326de478 <line:3:1, col:35>
| | `-VarDecl 0x5af63264d6a8 <col:1, col:34> col:8 f 'TFile *' cinit
| |   `-CXXNewExpr 0x5af6326de418 <col:12, col:34> 'TFile *' CXXMethod 0x5af6326db188 'operator new' 'void *(size_t)'
| |     `-CXXConstructExpr 0x5af6326ddee0 <col:16, col:34> 'TFile':'TFile' 'void (const char *, Option_t *, const char *, Int_t)'
| |       |-ImplicitCastExpr 0x5af6326dde68 <col:22> 'const char *' <ArrayToPointerDecay>
| |       | `-StringLiteral 0x5af63264d788 <col:22> 'const char[11]' lvalue "c_new.root"
| |       |-CXXDefaultArgExpr 0x5af6326dde80 <<invalid sloc>> 'const char *'
| |       |-CXXDefaultArgExpr 0x5af6326ddea0 <<invalid sloc>> 'const char *'
| |       `-CXXDefaultArgExpr 0x5af6326ddec0 <<invalid sloc>> 'Int_t':'int'
| |-DeclStmt 0x5af6326df820 <line:6:1, col:36>
| | `-VarDecl 0x5af6326de508 <col:1, col:35> col:6 used cnv 'auto' cinit
| |   `-CallExpr 0x5af6326df7c8 <col:12, col:35> '<dependent type>'
| |     |-CXXDependentScopeMemberExpr 0x5af6326df6b0 <col:12, col:29> '<dependent type>' lvalue ->Get
| |     | `-DeclRefExpr 0x5af6326de680 <col:12> '<dependent type>' lvalue Var 0x5af6326de578 'file' '<dependent type>'
| |     `-StringLiteral 0x5af6326df7a8 <col:31> 'const char[3]' lvalue "c1"
| |-CallExpr 0x5af6326df8c0 <line:8:1, col:11> '<dependent type>'
| | `-CXXDependentScopeMemberExpr 0x5af6326df878 <col:1, col:6> '<dependent type>' lvalue ->Draw
| |   `-DeclRefExpr 0x5af6326df838 <col:1> 'auto' lvalue Var 0x5af6326de508 'cnv' 'auto'
| |-CallExpr 0x5af6326e1a40 <line:10:1, col:31> '<dependent type>'
| | |-CXXDependentScopeMemberExpr 0x5af6326df900 <col:1, col:6> '<dependent type>' lvalue ->SaveAs
| | | `-DeclRefExpr 0x5af6326df8e0 <col:1> 'auto' lvalue Var 0x5af6326de508 'cnv' 'auto'
| | `-StringLiteral 0x5af6326e1a18 <col:13> 'const char[17]' lvalue "loaded_c_new.png"
| `-NullStmt 0x5af6326e1a68 <line:13:1>
|-AnnotateAttr 0x5af6326de5e0 <<invalid sloc>> Implicit R"ATTRDUMP(__ResolveAtRuntime)ATTRDUMP"
`-AnnotateAttr 0x5af6326de730 <<invalid sloc>> Implicit R"ATTRDUMP(__ResolveAtRuntime)ATTRDUMP"
<<<NULL>>>

p.s. just for completeness I made a little mistake in the example above, I load the object in the root file as an histogram, but I would have to load it as a canvas object.. anyway if I substitute TH1F *h1 = (TH1F*)f->Get("c1"); with auto cnv = f->Get<TCanvas>("c1"); the issue is exactly the same

ttedeschi avatar Oct 09 '24 14:10 ttedeschi

Looks like you need to use latest ROOT version to get desired functionality.

linev avatar Oct 09 '24 20:10 linev

Hi @couet,

It appears this issue is closed, but wasn't yet added to a project. Please add upcoming versions that will include the fix, or 'not applicable' otherwise.

Sincerely, :robot:

github-actions[bot] avatar Dec 23 '24 06:12 github-actions[bot]

Hi @couet,

It appears this issue is closed, but wasn't yet added to a project. Please add upcoming versions that will include the fix, or 'not applicable' otherwise.

Sincerely, :robot:

github-actions[bot] avatar Dec 24 '24 06:12 github-actions[bot]