Home | News | Documentation | Download

Using FitSliceY() for multiple TH2D

Dear ROOTers,

I am trying to fit sliced TH2D graphs. I have something like this,

// 4 systems
TH2D** ratioTH2D;
// 16 TH2D each 10x16 bins
ratioTH2D = new TH2D*[15];
// my fitting function
TF1 *fit1 = new TF1("fit1", "pol1");
// object with all the slices
TObjArray aSlices;
// several canvas
TCanvas* canv_fit[4];
  for(j=0;j<4;j++){
      for(i=0;i<16;i++){
      //for the title of the graphs
      sprintf(tempj, "b1_test %d", j);
      canv_fit[j] = new TCanvas(tempj,tempj);
      canv_fit[j]->Divide(4,4);
      canv_fit[j]->cd(i+1);
      // for the sake of simplycity i try just one graph
      ratioTH2D[i]->FitSlicesY(fit1, 0, -1, 0, "R", &aSlices);  //NOT silent, to see the output in console
      aSlices.Draw();
   }
}
 canv_fit[j]->Write();

This is obvioulsy a pseudo code.
I get 16 fittings in the console, not the 4x16x16=6464 that I would have expected (4 sets of 16 graphs each with x-axis binning of 16, therefore 16 y slices to be fitted linearly).
At the end in my root file (tree), there are 16 chi-square distributions plotted, most of them with no data displayed.
If I call a specific TH2D graph (perhaps ratioTH2D[14]), FitSlicesY is fitting just the first element in the array, i.e. ratioTH2D[0] with 16 console outputs.

Could someone explain to me where is the error or suggesting a strategy to store and plot all these fitted slices?

LG,

Giammarco


ROOT Version: 5.36/34
Platform: Windows 10
Compiler: VS2015


Hi,
I am not sure I have well understood your problem.
For each 2D histogram with nbinsX x nbinsY bins, you will have nbinsX fits when calling TH2::FitSlicesY and nbinsY fits when calling TH2::FitSlicesX.

After fitting you can plot the obtained fit parameters (and their error) in histograms that will be returned in the TObjArray aSlices.
In your case the TObjArray you will contain 3 histograms with nbins=16 (the number of fits = x bins of X axis of 2d histogram).
aSlices[0] will be the histogram for the fitted parameter 0 (i.e. the constant of the polynomial), aSlices[1] will show the fit parameter 1 (the slope) and aSlices[2] will show the resulting Chi2 for each fit.

In your code, I see that the same object array contained the fit slices results will be over-written every time. I would suggest either to have an array for each fit or use DrawClone() to clone the histogram you would like to draw.

Lorenzo

Ciao Lorenzo,

Thank you for your answer. I have 16x4 graphs TH2D already created and plotted. Each of them has nbinX = 16, nbinY = 10. I want to fit linearly each Y distribution for each nbinX slice. I want to plot the distribution of the fitting slopes for each graph (default FitSliceY feature).
As each FitSliceY outputs 3 graphs (p0,p12, chi2), I expect 16x4x3=192 graphs.
These should also be the objects in aSlice.

I implemented the array approach you suggested. but still I don’t get the results I am expecting.
In the console, I can see the 16 minimizing performed every 6 iterations of fit_counter, not all of them.
I the output I can see just chisquare graphs, in apparently random positions on the canvas.

TObjArray* aSlices;
aSlices = new TObjArray[192];

for (int canvas = 0; canvas < 4; canvas) {
		//for the title of the graphs
		sprintf(tempj, "p0, p1=b1, chi2, canvas number %d", canvas);
		canv_fit[canvas] = new TCanvas(tempj, tempj);
		canv_fit[canvas]->Divide(3, 16);
		for (int fit_counter = 0; fit_counter < 16; ) {
			canv_fit[canvas]->cd(fit_counter + int(fit_counter/3)*3 + 1);
			ratioTH2D[fit_counter]->FitSlicesY(fit1, 0, -1, 0, "R", &aSlices[fit_counter + int(fit_counter/3)*3 + canvas*16]);  //NOT silent, to see the output in console
			printf("Fitting graph %d of the ratio %s: DONE! \n \n", fit_counter+1, ratioTH2D[fit_counter]->GetName());	
			sprintf(tempjk, "%s", ratioTH2D[fit_counter]->GetTitle() );
			DrawTextInPad(0.2, 0.93, tempjk, 0.06);
			canv_fit[canvas]->Update();
			aSlices[fit_counter].Draw();
			canv_fit[canvas]->Write();
			printf("Plotted and written %s: DONE! \n \n", tempj);
			fit_counter++;
		}
		canvas++;
	}

Thank you for your patience.

Giammarco

Hi,

It seems to me you are confusing the TObjArray with the histograms. FitSlizeY will fill the TObjArray with the 3 histograms, but you should have one TObjArray per fit.

Your code should be (part from some errors that I cannot check since I cannot run it):

TObjArray* aSlices;
aSlices = new TObjArray[16*4];

for (int canvas = 0; canvas < 4; canvas) {
		//for the title of the graphs
		sprintf(tempj, "p0, p1=b1, chi2, canvas number %d", canvas);
		canv_fit[canvas] = new TCanvas(tempj, tempj);
		canv_fit[canvas]->Divide(3, 16);
		for (int fit_counter = 0; fit_counter < 16; ) {
			// for the sake of simplycity i try just one graph
			ratioTH2D[fit_counter]->FitSlicesY(fit1, 0, -1, 0, "R", &aSlices[fit_counter + canvas*16]);  //NOT silent, to see the output in console
			printf("Fitting graph %d of the ratio %s: DONE! \n \n", fit_counter+1, ratioTH2D[fit_counter]->GetName());	
			sprintf(tempjk, "%s", ratioTH2D[fit_counter]->GetTitle() );
			DrawTextInPad(0.2, 0.93, tempjk, 0.06);
			canv_fit[canvas]->Update();
                        canv_fit[canvas]->cd(fit_counter*3 + 1);
			aSlices[fit_counter+canvas*16][0].Draw();  // draw p0 histogram
                        canv_fit[canvas]->cd(fit_counter*3 + 2);
                        aSlices[fit_counter+canvas*16][1].Draw();  // draw p1 histogram
                        canv_fit[canvas]->cd(fit_counter*3 + 3);
                        aSlices[fit_counter+canvas*16][2].Draw();  // draw chi2 histogram
			canv_fit[canvas]->Write();
			printf("Plotted and written %s: DONE! \n \n", tempj);
			fit_counter++;
		}
		canvas++;
	}

Lorenzo

Thank you, I have understood the structure now. The correct syntax is something like this

aSlices[fit_counter+canvas*16][1]->Draw();

Nevertheless, all p0, p1 and chi2 have zero entries. I will try to have a look what’s happening. Maybe it doesn’t like the type of TH2D I am asking to slice.

Cheers,

Hi Lorenzo,

I simplified the code to see an output. I get the three graphs in the expected arrangement, but there are no entries displayed. Could you see a way around it?

I tried with DrawClone() too, but it draws just the last Chi2 graph with the size of the actual canvas (i.e. Divide(n,m) is not respected).

        TObjArray aSlices1;
	aSlices1.SetOwner(kTRUE);
	sprintf(tempj, "p0, p1=b1, chi2, canvas number 1");
	canv_fit[0] = new TCanvas(tempj, tempj);
	canv_fit[0]->Divide(3, 1);
	canv_fit[0]->Update();
	ratioTH2D_b1[1]->FitSlicesY(0, 0, -1, 0, "R", &aSlices1);  //NOT silent, to see the output in console
	printf("Fiting of graph %d of the ratio %s: DONE! \n \n", 1, ratioTH2D[1]->GetName());	
	sprintf(tempjk, "%s", ratioTH2D[1]->GetTitle() );
	DrawTextInPad(0.2, 0.93, tempjk, 0.06);
	canv_fit[0]->cd(1);
	aSlices1[0]->Draw();  // draw p0 histogram
	canv_fit[0]->cd(2);
	aSlices1[1]->Draw();  // draw p1 histogram
	canv_fit[0]->cd(3);
	aSlices1[2]->Draw();  // draw chi2 histogram
	canv_fit[0]->Update();
	canv_fit[0]->Write();
	printf("Plot and write canv_fit %s: DONE! \n \n", tempj);

Bests

Hi

Are you sure the fit worked fine ? Also are you seeing empty pad (i.e. all blank) or an histogram with 0 entries ?
In the first case, it means th histograms it has been deleted. But you should see it in the written canvas

Lorenzo

Hi Lorenzo,
Thank you for you patience for this mental problem.
I see 16 calls of a linear fit in console, therefore I assume the fit worked.
I don’t see empty pads, but just a pad with the right three graphs (title, axis, ranges, all correct), but no entries (reported too in the statistics legend).

Cheers,

Hi Lorenzo,
I have tried some variation, but nothing happened. I am without ideas!
With the following piece of code, the fitting is not displayed in the console. I tried to draw the TH2D ratioTH2D_b1[1] and it is working, therefore the problem is on aSlices or to my fitting function. I am quite stuck.

	TH2D** ratioTH2D_b1;
	ratioTH2D_b1 = new TH2D*[15];
	//Fitting
	TF1 *fit1 = new TF1("fit1", "[0]+[1]*x");
	//TF1 *fit1 = new TF1("fit1", "pol1");
        TObjArray* aSlices1;
	aSlices1 = new TObjArray();
	aSlices1->SetOwner(kTRUE);
	sprintf(tempj, "p0, p1=b1, chi2, canvas number 1");
	canv_fit[0] = new TCanvas(tempj, tempj);
	canv_fit[0]->Divide(3, 1);
	canv_fit[0]->Update();
	ratioTH2D_b1[1]->FitSlicesY(fit1, 0, -1, 0, "R", aSlices1);  //NOT silent, to see the output in console
	printf("Fiting of graph %d of the ratio %s: DONE! \n \n", 1, ratioTH2D[1]->GetName());	
	sprintf(tempjk, "%s", ratioTH2D[1]->GetTitle() );
	DrawTextInPad(0.2, 0.93, tempjk, 0.06);
	canv_fit[0]->cd(1);
	aSlices1[0].Draw();  // draw p0 histogram
	canv_fit[0]->cd(2);
	aSlices1[1].Draw();  // draw p1 histogram
	canv_fit[0]->cd(3);
	aSlices1[2].Draw();  // draw chi2 histogram
	canv_fit[0]->Update();
	canv_fit[0]->Write();
	printf("Plot and write canv_fit %s: DONE! \n \n", tempj);

Do you have any idea?

Bests,

Hi ,
Can you please upload a running macro with an histogram file, so I can reproduce this problem.
Thank you

Lorenzo