TProfile3D::Project3DProfile() setting axis range ignored

Dear ROOTers,

I encountered a following issue: I would like to make a TProfile2D projection out of TProfile3D with only a subset range of third axis (along which I would like to project - let’s called it x). However, this method has no explicit option to set the subset range of x axis, like the one available for (e.g.) TProfile2D::ProfileX(). Therefore the resulting 2D projection is made along whole x axis range.

The documentation offers a tip, how to resolve it:

To select a bin range along an axis, use TAxis::SetRange, eg h3.GetYaxis()->SetRange(23,56);

The problem with this is, that after setting range of x axis, and drawing the resulting projection of yz, the range is ignored, i.e. the resulting TProfile2D is always made from projection over the whole x axis range (I compared the resulting 2D profile with and without setting the x axis range).

Here is the code snippet:
TProfile3D* prof3; // some TProfile3D (in real macro properly loaded)
prof3->GetXaxis()->SetRange(10,20);
TProfile2D* prof3projYZ = prof3->Project3DProfile(“yz”); // projection over x axis

Do you have an idea or hint what could go wrong and the possible way how to solve it?

I looked into this with Vojtech. Turns out there’s some bugs in the code of TProfile3D::DoProjectProfile2D - the axis ranges are not set on intermittent histograms h3dW and h3dN.

Now, the returned histogram of TProfiile3D::ProjectionXYZ will always have the same number of bins in all directions as the full TProfile3D that DoProjectProfile2D - as it should. However, later on, the content of those histograms is projected down to a 2D histogram using TH3::DoProject3D, but since the axis ranges wasn’t set before hand on h3dW and h3dN we will get the full axis range no matter what.

The consequences are slightly different depending on what you do. Let’s start with the example given in the documentation of the class

TProfile3D* p3  = new TProfile3D("p3","",40,-4,4,40,-4,4,40,0,20);
Double_t px, py, pz, pt;
TRandom3 r(0);
for ( Int_t i=0; i<25000; i++) {
   r.Rannor(px,py);
   pz = px*px + py*py;
   pt = r.Landau(0,1);
   p3->Fill(px,py,pz,pt,1);
}

Now suppose I, as Vojtech wants, want to limit the range on the Z axis, and project on the XY plane

p3->GetZaxis()->SetRange(21,40);
TProfile2D* p2z = p3->Project3DProfile("yx"); 

then I get the average over all Z independent of the range setting on the corresponding axis, basically we because the range setting wasn’t copied by TProfile3D::ProjectionXYZ.

Now suppose I want to limit the X range

p3->GetXaxis()->SetRange(21,40);
TProfile2D* p2z = p3->Project3DProfile("yx"); 

In this case, I get an error for the assert in the code

R__ASSERT( h2W->fN == p2->fN );

because the 2D projected histogram does not have the range set according to my choice.

The fix: Copy all range settings of the object on which TProfiile3D::Project3DProfile was called to the two intermittent histograms h3dW and h3dN immediately after calling TProfile3D::ProjectionXYZ.

The conclusion: TProfiile3D::Project3DProfile is not compatible with axis range settings - in the worst case it causes a crash, in the best case it gives back the wrong information.

Yours,

Chritian

1 Like

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