Ineractive x|y projection of TH2Fs

Dear ROOTers,

I’ve converted René’s DynamicSlice script into a TH2F member function for a quick check on 2d histograms. Feel free to implement this.

Cheers,
Oliver

TH2F.h:

    Bool_t fShowProjectionX;   //! Show projection onto X axis
    Bool_t fShowProjectionY;   //! Show projection onto Y axis

    virtual void ExecuteEvent(Int_t event, Int_t px, Int_t py);
    void SetShowProjectionX(Bool_t ShowProjectionX); // *TOGGLE*
    void SetShowProjectionY(Bool_t ShowProjectionY); // *TOGGLE*
    inline Bool_t GetShowProjectionX() { return fShowProjectionX; }
    inline Bool_t GetShowProjectionY() { return fShowProjectionY; }

TH2F.cxx:

// in ctors
    fShowProjectionX = kFALSE;
    fShowProjectionY = kFALSE;

void TH2F::ExecuteEvent(Int_t event, Int_t px, Int_t py) {
    //
    // Interprete mouse events
    //
    if ( event == kMouseMotion ) {

	if ( fShowProjectionX ) {
	    //
	    // Show projection onto X
	    //
	    gPad->GetCanvas()->FeedbackMode(kTRUE);
	    
	    // Erase old position and draw a line at current position
	    static int pyold = 0;
	    float uxmin = gPad->GetUxmin();
	    float uxmax = gPad->GetUxmax();
	    int pxmin = gPad->XtoAbsPixel(uxmin);
	    int pxmax = gPad->XtoAbsPixel(uxmax);
	    if( pyold ) gVirtualX->DrawLine(pxmin,pyold,pxmax,pyold);
	    gVirtualX->DrawLine(pxmin,py,pxmax,py);
	    pyold = py;
	    Float_t upy = gPad->AbsPixeltoY(py);
	    Float_t y = gPad->PadtoY(upy);

	    // Create or set the new canvas proj x
	    TVirtualPad *padsav = gPad;
	    TCanvas *c = (TCanvas*)gROOT->GetListOfCanvases()
		->FindObject("c_projection_x");
	    if( c != 0 ) {
		c->Clear();
	    } else {
		c = new TCanvas("c_projection_x", "ProjectionX Canvas",
				700, 500);
	    }
	    c->SetGrid();
	    c->cd();

	    // Draw slice corresponding to mouse position
	    Int_t biny = GetYaxis()->FindBin(y);
	    TH1D *hp = ProjectionX("", biny, biny);
	    hp->SetFillColor(38);
	    hp->SetName("ProjectionX");
	    hp->SetTitle(Form("ProjectionX of biny=%d", biny));
	    hp->SetXTitle(GetXaxis()->GetTitle());
	    hp->SetYTitle("Number of Entries");
	    hp->Draw();
	    c->Update();
	    padsav->cd();
	}
	if ( fShowProjectionY ) {
	    //
	    // Show projection onto Y
	    //
	    gPad->GetCanvas()->FeedbackMode(kTRUE);
	    
	    // Erase old position and draw a line at current position
	    static int pxold = 0;
	    float uymin = gPad->GetUymin();
	    float uymax = gPad->GetUymax();
	    int pymin = gPad->YtoAbsPixel(uymin);
	    int pymax = gPad->YtoAbsPixel(uymax);
	    if( pxold ) gVirtualX->DrawLine(pxold,pymin,pxold,pymax);
	    gVirtualX->DrawLine(px,pymin,px,pymax);
	    pxold = px;
	    Float_t upx = gPad->AbsPixeltoX(px);
	    Float_t x = gPad->PadtoX(upx);

	    // Create or set the new canvas proj y
	    TVirtualPad *padsav = gPad;
	    TCanvas *c = (TCanvas*)gROOT->GetListOfCanvases()
		->FindObject("c_projection_y");
	    if( c != 0 ) {
		c->Clear();
	    } else {
		c = new TCanvas("c_projection_y", "ProjectionY Canvas",
				700, 500);
	    }
	    c->SetGrid();
	    c->cd();

	    // Draw slice corresponding to mouse position
	    Int_t binx = GetXaxis()->FindBin(x);
	    TH1D *hp = ProjectionY("", binx, binx);
	    hp->SetFillColor(38);
	    hp->SetName("ProjectionY");
	    hp->SetTitle(Form("ProjectionY of binx=%d", binx));
	    hp->SetXTitle(GetYaxis()->GetTitle());
	    hp->SetYTitle("Number of Entries");
	    hp->Draw();
	    c->Update();
	    padsav->cd();
	}
	
    } else {
	TH1::ExecuteEvent(event, px, py);
    }
}

//____________________________________________________________________

void TH2F::SetShowProjectionX(Bool_t ShowProjectionX) {
    //
    // Set projection onto X
    //
    fShowProjectionX = ShowProjectionX;
    if ( ShowProjectionX == kFALSE ) {
	TCanvas *c = (TCanvas*)gROOT->GetListOfCanvases()
	    ->FindObject("c_projection_x");
	if( c != 0 ) { delete c; c = 0; }   
    }
}

//____________________________________________________________________

void TH2F::SetShowProjectionY(Bool_t ShowProjectionY) {
    //
    // Set projection onto Y
    //
    fShowProjectionY = ShowProjectionY;
    if ( ShowProjectionY == kFALSE ) {
	TCanvas *c = (TCanvas*)gROOT->GetListOfCanvases()
	    ->FindObject("c_projection_y");
	if( c != 0 ) { delete c; c = 0; }   
    }
}

Hi Oliver,

These functions could be an interesting addition, but the implementation
should be in libHistPainter, not in libHist.
libHist should not be depend directly (only via the plugin manager)
on the graphics classes.
The functions in TH2 should call the TVirtualHistPainter implementation.

Rene

Hi Oliver,

see:
root.cern.ch/root/htmldoc//TH2.h … rojectionX
root.cern.ch/root/htmldoc//TH2.h … rojectionY

Now in CVS

Rene

Hi René,

you have been faster than me then. :slight_smile:
Thank you very much. It works perfect.
Oliver

Dear René,

I’ve noticed that the ProjectX|Y() functions always create a new histogram object which in this case is most unwanted. Thus I propose the following change:

czina10/<1>i10a/kind/root/histpainter/src:[133]> cvs diff -u
Index: THistPainter.cxx
===================================================================
RCS file: /user/cvs/root/histpainter/src/THistPainter.cxx,v
retrieving revision 1.249
diff -u -3 -p -u -r1.249 THistPainter.cxx
--- THistPainter.cxx    21 Mar 2006 18:11:33 -0000      1.249
+++ THistPainter.cxx    22 Mar 2006 15:39:57 -0000
@@ -6224,7 +6224,9 @@ void THistPainter::ShowProjectionX(Int_t
 
     // Draw slice corresponding to mouse position
     Int_t biny = fH->GetYaxis()->FindBin(y);
-    TH1D *hp = ((TH2*)fH)->ProjectionX("", biny, biny);
+    static TH1D *hp = 0;
+    if ( hp != 0 ) delete hp;
+    hp = ((TH2*)fH)->ProjectionX("", biny, biny);
     hp->SetFillColor(38);
     hp->SetName("ProjectionX");
     hp->SetTitle(Form("ProjectionX of biny=%d", biny));
@@ -6269,7 +6271,9 @@ void THistPainter::ShowProjectionY(Int_t
 
     // Draw slice corresponding to mouse position
     Int_t binx = fH->GetXaxis()->FindBin(x);
-    TH1D *hp = ((TH2*)fH)->ProjectionY("", binx, binx);
+    static TH1D *hp = 0;
+    if ( hp != 0 ) delete hp;
+    hp = ((TH2*)fH)->ProjectionY("", binx, binx);
     hp->SetFillColor(38);
     hp->SetName("ProjectionY");
     hp->SetTitle(Form("ProjectionY of binx=%d", binx));

Cheers,
Oliver

Oliver,

Thanks to your remark, I have changed THistPainter to optimize
the creation/Reset/Delete of the temporary histograms.
In fact the logic to do this was already in TH2::ProjectionX,Y.
I am just using this facility.
Now in CVS.

Rene

See this app extending this method: