How to zoom subplots together?

Hello,

I stacked multiple pads on top of each other, similar to canvas2.C.

I want to zoom into one axis, but also change the x and y axis.
Is there any method of event listener I could make use to change simultaneously all pads?

In a same row my x axis are the same but y axis are different
In a same line my y axis are the same but x axis are different

Thank you
Marco

This example does that:

TCanvas *C;
TPad *p1, *p2;
TH1F *h1, *h2, *h3;

void globalzoom() {
   int first = h3->GetXaxis()->GetFirst();
   int last  = h3->GetXaxis()->GetLast();

   h1->GetXaxis()->SetRange(first, last);
   h2->GetXaxis()->SetRange(first, last);

   p1->Modified();
   p2->Modified();
}

void zoomdiv() {
   TCanvas *C = new TCanvas("C", "C", 500, 900);
   C->Divide(1,3,0,0);

   h1 = new TH1F("h1", "h1", 100, -5., 5.) ; h1->FillRandom("gaus", 10000);
   h2 = new TH1F("h2", "h2", 100, -5., 5.) ; h2->FillRandom("gaus", 10000);
   h3 = new TH1F("h3", "h3", 100, -5., 5.) ; h3->FillRandom("gaus", 10000);

   TExec *zoom = new TExec("zoom","globalzoom();");

   p1 = (TPad*)C->cd(1); h1->Draw();
   p2 = (TPad*)C->cd(2); h2->Draw();
   C->cd(3); h3->Draw(); zoom->Draw();
}
1 Like

Hi @couet,

Thank you for your useful example. I also had a look at exec1.C introduced in TPad.

As I am looking for a more versatile solution (I have many canvas to draw), I tried to use TCanvas::AddExec() to make it canvas specific, but introducing division breaks the code.
In such case, if I modify pad1,2 or 3 I do no see any execution of the TExec introduced by TCanvas::AddExec() if I modify a subpad. I believe this should be executed, right?

I believe in this situation that subpads make TExec unusable.
I introduced some Propagator to fix that. Is there any better solution in your opinion ?
As there is this hierarchical structure between pad, would it be acceptable to introduce such propagation natively?

TCanvas *C;
TPad *p1, *p2, *p3;
TH1F *h1, *h2, *h3;

void MotherPadPropagator()
{
   if (gPad && gPad->GetMother() != gPad) {
      
      TList *execList = gPad->GetMother()->GetListOfExecs();
      if (execList) {

         for (int i = 0; i < execList->GetSize(); i++) {
            TNamed *exec = (TNamed*)execList->At(i);
            exec->Draw();
         }
      }
   }
}

void GlobalZoom()
{
   if (!gPad) return;
   std::cout << "Selected Pad: " << gPad->GetName() << std::endl;

   Int_t event = gPad->GetEvent();
   int px = gPad->GetEventX();
   int py = gPad->GetEventY();
   TObject *select = gPad->GetSelected();

   if (select && select->InheritsFrom(TAxis::Class())) {

      TAxis *axis = (TAxis*) select;
      double first = axis->GetFirst();
      double last  = axis->GetLast();

      std::cout << "Selected Axis: (" << first << "," << last << ")" << std::endl;
   }
}

void zoomdiv2() {

   TCanvas *C = new TCanvas("C", "C", 500, 900);
   C->Divide(1,3,0,0);

   h1 = new TH1F("h1", "h1", 100, -5., 5.) ; h1->FillRandom("gaus", 10000);
   h2 = new TH1F("h2", "h2", 100, -5., 5.) ; h2->FillRandom("gaus", 10000);
   h3 = new TH1F("h3", "h3", 100, -5., 5.) ; h3->FillRandom("gaus", 10000);


   p1 = (TPad*)C->cd(1); h1->Draw();
   p2 = (TPad*)C->cd(2); h2->Draw();
   p3 = (TPad*)C->cd(3); h3->Draw();

   C->AddExec("GlobalZoom","GlobalZoom();");   
   TExec *exec = new TExec("MotherPadPropagator","MotherPadPropagator();"); 
          exec->Draw();
}

Edit: I noticed that this method is not working for Y axis.

I do not see any AddExec call in your example, should I use the example you sent as strating point ?

Yes I attached a TExec to a canvas C here.

Execution here is propagated to parent using, if TExec is attached to canvas, it is only working if I introduce the following line.

 TExec *exec = new TExec("MotherPadPropagator","MotherPadPropagator();"); 
          exec->Draw();

Here is the latest version I use

TCanvas *C;
TPad *p1, *p2, *p3;
TH1F *h1, *h2, *h3;

void MotherPadPropagator()
{
   if (gPad && gPad->GetMother() != gPad) {
      
      TList *execList = gPad->GetMother()->GetListOfExecs();
      if (execList) {

         for (int i = 0; i < execList->GetSize(); i++) {
            TNamed *exec = (TNamed*)execList->At(i);
            exec->Draw();
         }
      }
   }
}

void GlobalZoom()
{
   if (!gPad) return;
   std::cout << "Selected Pad: " << gPad->GetName() << std::endl;

   Int_t event = gPad->GetEvent();
   int px = gPad->GetEventX();
   int py = gPad->GetEventY();
   TObject *select = gPad->GetSelected();

   if (select && select->InheritsFrom(TAxis::Class())) {

      TAxis *axis = (TAxis*) select;
      double first = axis->GetFirst();
      double last  = axis->GetLast();

      std::cout << "Selected Axis: (" << first << "," << last << ")" << std::endl;

      h1->GetXaxis()->SetRange(first, last);
      h2->GetXaxis()->SetRange(first, last);
      h3->GetXaxis()->SetRange(first, last);

      p1->Modified();
      p2->Modified();
   }
}

void zoomdiv2() {

   TCanvas *C = new TCanvas("C", "C", 500, 900);
   C->Divide(1,3,0,0);

   h1 = new TH1F("h1", "h1", 100, -5., 5.) ; h1->FillRandom("gaus", 10000);
   h2 = new TH1F("h2", "h2", 100, -5., 5.) ; h2->FillRandom("gaus", 10000);
   h3 = new TH1F("h3", "h3", 100, -5., 5.) ; h3->FillRandom("gaus", 10000);


   p1 = (TPad*)C->cd(1); h1->Draw();
   p2 = (TPad*)C->cd(2); h2->Draw();
   p3 = (TPad*)C->cd(3); h3->Draw();

   C->AddExec("GlobalZoom","GlobalZoom();");   
   TExec *exec = new TExec("MotherPadPropagator","MotherPadPropagator();"); 
          exec->Draw();
}

I tried your example zoomdiv2.C. I do not see a real difference compared to the zoomdiv.C example I send you. What is the improvement ?