SetBatch causes different graphics output for pngs

Here root.cern.ch/root/html604/TCanvas.html one can read:

At creation time, in interactive mode, the canvas size defines the size of the canvas window (including the window manager’s decoration). To define precisely the graphics area size of a canvas, the following four lines of code should be used:

   {
      Double_t w = 600;
      Double_t h = 600;
      TCanvas * c1 = new TCanvas("c", "c", w, h);
      c->SetWindowSize(w + (w - c->GetWw()), h + (h - c->GetWh()));
   }

in batch mode simply do:
c->SetCanvasSize(w,h);

In other words, “c->SetWindowSize(w + (w - c->GetWw()), h + (h - c->GetWh()));” misbehaves in batch mode.
To my surprise, in ROOT 5.34, “c->SetCanvasSize(w,h);” sets the canvas size ALSO in interactive / non-batch mode.

trying to reproduce it it seems to me it is more a matter of pad drawing order.
I did a small reproducer .
seems to me it is a clipping issue not a canvas dimension issue.


Here’s a small reproducer.

{
  gROOT->Reset();
  gROOT->SetBatch();  // comment out to attain a nicer figure
  
  double x[] = {1., 2.};
  double y[] = {2., 4.};
  TGraph g(2, x, y);
  g.SetMarkerStyle(8);
  g.SetMarkerSize(2);


  TCanvas c("c","c",800,600);
  g.Draw("AP");
  c.SaveAs("fig.png");


}

with batch the png is 8kb and without it’s 12kb. I’m running root 6.04.00.

I’m not sure I’m following the discussion. Including c.SetCanvasSize(800,600) in batch mode doesn’t change anything.

I’m afraid TCanvas::SetWindowSize is completely unreliable (it can misbehave even in interactive mode).
When I try (ROOT 5.34 and 6.04.02):

{
  Int_t w = 800;
  Int_t h = 600;
  TCanvas *c;
  gROOT->SetBatch(kFALSE);
  c = new TCanvas("c", "c", w, h); c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  c->SetWindowSize(w + (w - c->GetWw()), h + (h - c->GetWh()));
  c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  delete c;
  c = new TCanvas("c", "c", w, h); c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  c->SetCanvasSize(w, h);
  c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  delete c;
  gROOT->SetBatch(kTRUE);
  c = new TCanvas("c", "c", w, h); c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  c->SetWindowSize(w + (w - c->GetWw()), h + (h - c->GetWh()));
  c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  delete c;
  c = new TCanvas("c", "c", w, h); c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
  c->SetCanvasSize(w, h);
  c->Modified(); c->Update();
  std::cout << c->GetWw() << " " << c->GetWh() << std::endl;
}

I sometimes get:

798 573
800 600 SetWindowSize WORKS in interactive mode
798 573
800 600 SetCanvasSize WORKS in interactive mode
796 572
796 572 !!! SetWindowSize FAILS in batch mode !!!
796 572
800 600 SetCanvasSize WORKS in batch mode

and sometimes:

798 573
798 573 !!! SetWindowSize FAILS in interactive mode !!!
798 573
800 600 SetCanvasSize WORKS in interactive mode
796 572
796 572 !!! SetWindowSize FAILS in batch mode !!!
796 572
800 600 SetCanvasSize WORKS in batch mode

BTW. I can switch from interactive to batch mode, but not the other way (I get “Warning in TCanvas::ResizePad: c width changed from 0 to 10” if I try it).

JIRA: sft.its.cern.ch/jira/browse/ROOT-7552

See what I get with your macro. On the left in batch mode on the right in interactive mode… seems to me it is the same.


Hello,

This is not strictly within the topic, but I think it is somehow related to it.

Working in batch mode with ROOT 5.34/32, I noticed that there is a difference in canvas size given by GetWh() and GetWw(), as well as in produced PDF file, depending on whether I build canvas with this code:

  TCanvas can1("", "", 700, 500);

or that code:

  TCanvas can2;
  can2.SetCanvasSize(700, 500);

From the quoted documentation of TCanvas about difference of graphics area between interactive and batch mode, I understood that in batch mode (that I use) there shouldn’t be difference in outcome of above code snippets.

Did I misunderstood the documentation or is it a bug? A bug possibly related to the topic of discussion?

Regards,
Antoni

See the end of the class description here: root.cern.ch/doc/master/classTCanvas.html

By the end of class description you mean the fragment about window and drawing area size? This is precisely the fragment that I refered to in my post. I asked if I understand that fragment correctly if I work in batch mode only - that in batch mode there should be no difference between the Constructor and the SetCanvasSize.

Sorry I add not seen you were referring already to that.
Yes i batch mode you need to use SetCanvasSize also:


$ root -b
  *******************************************
  *                                         *
  *        W E L C O M E  to  R O O T       *
  *                                         *
  *   Version   5.34/35    2 October 2015   *
  *                                         *
  *  You are welcome to visit our Web site  *
  *          http://root.cern.ch            *
  *                                         *
  *******************************************

ROOT 5.34/35 (v5-34-34@v5-34-34, Oct 19 2015, 11:21:00 on macosx64)

CINT/ROOT C/C++ Interpreter version 5.18.00, July 2, 2010
Type ? for help. Commands must be C++ statements.
Enclose multiple statements between { }.
root [0]  TCanvas can1("", "", 700, 500);
root [1] can1.GetWh()
(const unsigned int)472
root [2] can1.SetCanvasSize(700, 500);
root [3] can1.GetWh()
(const unsigned int)500
root [4] 

Is this intentional?

If yes, then maybe you can modify the fragment on this in the TCanvas documentation. Namely instead of

better is

or

And then later

Finally, maybe add warning to the documentation of TCanvas::SetCanvasSize() that its parameters ww and wh have different meaning than in constructors (possibly explaining the difference due to window size).

Yes it is an early design decision/mistake…
Thanks for your comments. I have included them in the documentation.

Oh. Ok.
Thank you for updating the documentation.

This is Kubuntu 14.04.5 LTS / x86_64 with gcc 4.8.4 (so, running KDE desktop, if that matters) here.
I tried the macro from my previous post here and I still get the same problem with the newest “v5-34-00-patches” and “6.10.04” (see the second line of every output -> it’s sometimes “800 600” and sometimes “798 573”):

[...] $ for i in {1..10}; do root -l -n -q TestSetWindowSize.cxx; done
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
798 573
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
798 573
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
798 573
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600
root [0] 
Processing TestSetWindowSize.cxx...
798 573
800 600
798 573
800 600
796 572
796 572
796 572
800 600

BTW. Even the newest TCanvas class description does not clearly say what one should expect from the TCanvas::SetWindowSize in batch mode. See the “last line - 2” of every output above -> there’s always “796 572”, so it seems to be completely ignored. Is this a bug or a “feature”?

Dear Wile,

I see also (with the master and 5.34 version on Mac with the X11 backend) that the output varies when I execute the macro in a loop like you. I do not have this issue with the Cocoa backend. But Cocoa does not have the synchronisation mechanism X11 has. I found out that in TRootCanvas::SetWindowSize the synchronisation instructions were not the same one can see in TASimage. Making them the same fixes the issue for me. i.e.: I now get the exact same output when I execute le macro 10 times in a row. I just committed the fix both for the master and 5.34 version. I hope it will fixe the issue for you also.

Cheers,
Olivier

I tried the newest “v5-34-00-patches” code but I still see this problem.

Try to run this “10-times-in-a-row” command several times and see if you always get it right (in my case it’s sometimes better, sometimes worse).

I ran this “10-times-in-a-row” command several times (>30) . And I saw that it was not right 2 or 3 times over 300 (10x30). I did the test with ROOT 6 and ROOT 5.34. I did a change in TRootCanvas to improve this (I increased the Sleep time between the 2 ProcessEvents). After this change both ROOT 6 and ROOT 5.34 gave me a 100% success when I ran the “10-times-in-a-row” command 30 times with the X11 backend. I committed this change for both ROOT 6 and ROOT 5.34. I hope that will be 100% success for you also.

I play with “v5-34-00-patches" only and it seems I was able to “stabilize” it.

The original old source code of “TRootCanvas::SetWindowSize” failed in something like 40% of trials. After adding “gVirtualX->Update(1);”, it failed in something like 33% of trials. After “gSystem->Sleep(100);” modification, it failed in something like 27% of trials. So I tried “gSystem->Sleep(1000);” and it still failed in something like 15% of trials.

So, I decided to play with this myself and I have found a solution which seems to work:

   gVirtualX->Update(1);
   if (!gThreadXAR) {
      gSystem->Sleep(100); // at least 50; 100 is safer                         
      gSystem->ProcessEvents();
      gSystem->Sleep(10); // does not matter at all                             
      gSystem->ProcessEvents();
   }

Thanks for your input. Your X11 server is slower to sync than mine it seems. I verified that this new way of doing it also works for me. It does. I also changed TASImage accordingly for consistency. I committed these change for both ROOT 6 and ROOT 5.34. Thanks for your help in the final tuning.