I came across a strange bug/feature in ROOT. If I create a 2D histogram and assign labels to bins on the x axis, when making a projection, additional “ghost” bins appear in the projection. If no labels are used, no additional bins appear. Here is a minimal code that reproduces the behavior
import ROOT as r
r.gROOT.SetBatch()
hist = r.TH2F("hist", "", 2, 0, 2, 2, 0, 2)
hist.GetXaxis().SetBinLabel(1, "A")
hist.GetXaxis().SetBinLabel(2, "B")
c = r.TCanvas("c", "", 1200,800)
c.cd()
hist_px = hist.ProjectionX().Draw("hist")
hist_px.Draw("hist")
c.SaveAs('histProjectionX.png')
Thanks for the reply. Your suggestion of course works on hist_px since it has two labelled and two unlabelled bins. The problem I am referring to is the fact that the projection results in extra bins (two in this specific case) which are not there in the original 2D histogram.
Yes, of course, this works, as I already said in my previous reply. However, this is just another workaround for the problem. The following code perhaps illustrates the problem more clearly
import ROOT as r
r.gROOT.SetBatch()
hist = r.TH2F("hist", "", 2, 0, 2, 2, 0, 2)
print( "2D x-axis N bins: %d" % hist.GetXaxis().GetNbins() )
hist_px = hist.ProjectionX()
print( "1D N bins: %d" % hist_px.GetXaxis().GetNbins() )
hist.GetXaxis().SetBinLabel(1, "A")
hist.GetXaxis().SetBinLabel(2, "B")
hist_px = hist.ProjectionX()
print( "1D N bins: %d" % hist_px.GetXaxis().GetNbins() )
which returns the following output
2D x-axis N bins: 2
1D N bins: 2
1D N bins: 4
As you can see, the number of bins in the 1D projection changes depending on whether bins are labelled or not. This looks like a bug to me.
I see, my understanding is that the TH1D created from the TH2D in ProjectionX picks the labels from the X TH2D axis and add them just like one would do for a new created labelled TH1D. And in that case the number of labels created is more or less to double of what is needed for performance reasons. In a such case a Deflate is needed when all the labels are in place. Now the question is: Should ProjectionX call Deflate() ? may be yes. I let @moneta answer. The C++ code is:
void dinko() {
auto hist = new TH2F("hist", "", 2, 0, 2, 2, 0, 2);
printf( "2D x-axis N bins: %d \n", hist->GetXaxis()->GetNbins());
TH1D* hist_px = hist->ProjectionX();
printf( "1D N bins: %d \n",hist_px->GetXaxis()->GetNbins());
hist->GetXaxis()->SetBinLabel(1, "A");
hist->GetXaxis()->SetBinLabel(2, "B");
printf( "2D x-axis N bins: %d \n", hist->GetXaxis()->GetNbins());
hist_px = hist->ProjectionX();
printf( "1D N bins: %d \n", hist_px->GetXaxis()->GetNbins() );
hist_px->LabelsDeflate();
printf( "1D N bins: %d \n", hist_px->GetXaxis()->GetNbins() );
}
output:
root [0]
Processing dinko.C...
2D x-axis N bins: 2
1D N bins: 2
2D x-axis N bins: 2
1D N bins: 4
1D N bins: 2
root [1]