TMultiGraph SetRangeUser doesn't work in divided canvas


ROOT Version: 6.28/00
Platform: Linux
Compiler: g++ 10.2.1-6


Hello.
I’m trying to set the y-axis of my TMultiGraph, but when the canvas being drawn on is divided, the specified axis with SetRangeUser doesn’t apply. Commenting out c1.cd(2) makes the below code work (but of course, in my actual application, i have something else drawn on pad 1). As indicated by the commented out lines, i tried a few alternatives that showed up by searching the forum, but none had any effect.

/*g++ testmg.C `root-config --cflags --libs` -o testmg*/
#include "TCanvas.h"
#include "TGraph.h"
#include "TMultiGraph.h"
#include "TH1.h"
#include "TSystem.h"
#include "TApplication.h"
#include <vector>

int main(){
	
	TApplication tapp("TApp",0,0,0);
	TCanvas c1;
	c1.Divide(1,2);
	const int size=10;
	
	for(int i=0; i<5; ++i){
		std::vector<double> xs, ys1, ys2;
		
		for(int j=0; j<10; ++j){
			xs.push_back(j);
			ys1.push_back(rand() % 100);
			ys2.push_back(rand() % 100);
		}
		TGraph* g1 = new TGraph(10,xs.data(), ys1.data());
		TGraph* g2 = new TGraph(10,xs.data(), ys2.data());
		TMultiGraph mg;
		mg.Add(g1);
		mg.Add(g2);
		
		c1.cd(2);
		mg.Draw("al");
		mg.GetHistogram()->GetYaxis()->SetRangeUser(-100,200);
//		mg.GetHistogram()->GetYaxis()->SetLimits(-100,200);
//		mg.GetHistogram()->SetMinimum(-100);
//		mg.GetHistogram()->SetMaximum(200);
		
		c1.Modified();
		c1.Update();
		gSystem->ProcessEvents();
		
		gPad->WaitPrimitive();
		
	}
	
	return 0;
}
root [0] .x marc1uk.C
void marc1uk(){

   auto c1 = new TCanvas();
   c1->Divide(1,2);
   const int size=10;

   for (int i=0; i<5; ++i) {
      std::vector<double> xs, ys1, ys2;

      for(int j=0; j<10; ++j){
         xs.push_back(j);
         ys1.push_back(rand() % 100);
         ys2.push_back(rand() % 100);
      }

      auto g1 = new TGraph(10,xs.data(), ys1.data());
      auto g2 = new TGraph(10,xs.data(), ys2.data());
      auto mg = new TMultiGraph ();
      mg->Add(g1);
      mg->Add(g2);

      c1->cd(2);
      mg->Draw("al");
      mg->GetHistogram()->GetYaxis()->SetRangeUser(-100,200);
      gPad->Modified();
      gPad->Update();

   }
}

Thanks couet, it seems that works. The only difference here is using gPad instead of c1. Is there some logic behind this?

As a bonus point, the canvas currently draws the graph with automatic axes first, then adjusts the canvas and re-draws it, resulting in the canvas flickering. As you can see, my code is in a loop and visually it would make it easier to parse (comparing plots between iterations) if it didn’t do this. Is there a way to stop that happening? It seems as though both Modified and Update calls are required to make the graph properly adjust its axes, but i’m not sure how else to ‘freeze’ the canvas until the range is fixed.

You need to update the current pad. Not c1. Gpad points to the current pad. You can also do the following:

     TPad *p = (TPad*)c1->cd(2);
      mg->Draw("al");
      mg->GetHistogram()->GetYaxis()->SetRangeUser(-100,200);
      p->Update();
      p->Modified();

But using gPad is simpler.

I do not see that wit the example you posted.

Not adjust, but display the current state of the plot.

H’mm, ok. I guess I wasn’t clear on when the pad and when the canvas needs updating, but I suppose I can just use pad from now on.

You don’t see this happening? (535.2 KB)

That mp4 does not open for me… even using VLC

hmm, strange. Maybe webm? (721.2 KB)

try:

void marc1uk(){

   auto c1 = new TCanvas();
   c1->Divide(1,2);
   const int size=10;

   for (int i=0; i<5; ++i) {
      std::vector<double> xs, ys1, ys2;

      for(int j=0; j<10; ++j){
         xs.push_back(j);
         ys1.push_back(rand() % 100);
         ys2.push_back(rand() % 100);
      }

      auto g1 = new TGraph(10,xs.data(), ys1.data());
      auto g2 = new TGraph(10,xs.data(), ys2.data());
      auto mg = new TMultiGraph ();
      mg->Add(g1);
      mg->Add(g2);
      mg->GetHistogram()->GetYaxis()->SetRangeUser(-100,200);
      c1->cd(2);
      mg->Draw("al");
      gPad->Modified();
      gPad->Update();
   }
}

That works too! Thanks again couet.
I was under the impression the histogram of a TGraph didn’t exist until it was drawn, so the histogram properties couldn’t be set until that point. Perhaps adding it to the TMultigraph triggers the creation of the histogram as well?

Indeed mg->GetHistogram() does the jobs. If the histogram exists, it returns it, if not it creates it and returns it. As all the GetHistogram() methods in ROOT.

Interesting, I guess i was mistaken (or perhaps this was the case with old versions?)
Thanks for the tip. :smile:

No, it has always been like that.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.