SetBinLabel bad_alloc

Hi,

I am trying the following function as part of a bigger code. I copy it here hoping that it has all the necessary information to find the source of the problem. It gets the integral from different histograms (at different cut levels) and produces plots like the attached one. When I try to change the axis label (see the commented line) it crashes with the associated (bad_alloc) comment.

I have done several tests. For example, if I set by hand the label of all minus one bins, it works.

Thanks,
Jonatan

void HistogramReader::Evolution(TFile*  file,
                                TString analysis,
                                TString hname)
{
  TH1D* test_hist = (TH1D*)file->Get(analysis + "/" + hname + "_evolution");

  if (test_hist) return;

  file->cd();

  file->cd(analysis);

  Int_t nbins = 0;

  for (Int_t i=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      nbins++;
    }

  TH1D* hist = new TH1D(hname + "_evolution", "", nbins, -0.5, nbins-0.5);

  for (Int_t i=0, bin=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      TH1D* dummy = (TH1D*)file->Get(scut[i] + "/" + hname);

      hist->SetBinContent(++bin, Yield(dummy));

      // terminate called after throwing an instance of 'std::bad_alloc'                                                                                                             
      // hist->GetXaxis()->SetBinLabel(bin, scut[i].Data());                                                                                                                         
    }

  hist->Write();
}


Try: if (hist && dummy) hist->SetBinContent(++bin, Yield(dummy)); else std::cout << "Error: hist or dummy NOT found." << std::endl;

Thank you Pepe, unfortunately it doesn’t work. I have updated the code this way,

void HistogramReader::Evolution(TFile*  file,
				TString analysis,
				TString hname)
{
  TH1D* test_hist = (TH1D*)file->Get(analysis + "/" + hname + "_evolution");

  if (test_hist) return;

  file->cd();

  file->cd(analysis);

  Int_t nbins = 0;
  
  for (Int_t i=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      nbins++;
    }

  TH1D* hist = new TH1D(hname + "_evolution", "", nbins, -0.5, nbins-0.5);

  for (Int_t i=0, bin=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      TString tok, icut;

      Ssiz_t from = 0;

      while(scut[i].Tokenize(tok, from, "_")) icut = tok;

      TH1D* dummy = (TH1D*)file->Get(scut[i] + "/" + hname);

      if (hist && dummy) {

	hist->SetBinContent(++bin, Yield(dummy));

	if (bin < nbins) hist->GetXaxis()->SetBinLabel(bin, icut);
      }

      else std::cout << " [HistogramReader::Evolution] Error: hist or dummy NOT found." << std::endl;
    }

  hist->Write();
}

which produces the attached plot (notice the non-labelled last bin). But, if I remove the condition below, I get back the bad_alloc crash.

if (bin < nbins)

Thanks, Jonatan


Dear ROOT experts, I have tried to make the code more clear / robust. Unfortunately it continues failing :frowning: Please let me know how can I check / fix this problem.

void HistogramReader::Evolution(TFile*  file,
				TString analysis,
				TString hname)
{
  // Check if the evolution histogram already exists
  TH1D* test_hist = (TH1D*)file->Get(analysis + "/" + hname + "_evolution");

  if (test_hist) return;


  // Get the number of bins
  file->cd(analysis);
  
  Int_t nbins = 0;
  
  for (Int_t i=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      nbins++;
    }


  // Create and fill the evolution histogram
  TH1D* hist = new TH1D(hname + "_evolution", "", nbins, -0.5, nbins-0.5);

  for (Int_t i=0, bin=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      TH1D* dummy = (TH1D*)file->Get(scut[i] + "/" + hname);

      hist->SetBinContent(++bin, Yield(dummy));
    }


  // Change the evolution histogram x-axis labels
  TAxis* xaxis = (TAxis*)hist->GetXaxis();

  for (Int_t i=0, bin=0; i<ncut; i++)
    {
      if (!scut[i].Contains(analysis + "/")) continue;

      TString tok, icut;

      Ssiz_t from = 0;

      while (scut[i].Tokenize(tok, from, "_")) icut = tok;

      if (++bin < nbins) xaxis->SetBinLabel(bin, icut);
      // terminate called after throwing an instance of 'std::bad_alloc'
      // xaxis->SetBinLabel(bin, icut);
    }


  // Write the evolution histogram
  hist->Write();
}

Thanks and best regards,
Jonatan

Hi,

At the end the issue was in a different part of the code. For some reason I was doing:

for (Int_t ibin=0; ibin<=hist->GetNbinsX()+1; ibin++)

Once I have removed the +1 all is good.

Thanks!
Jonatan

ibin=0 is the "underflow bin"
ibin=hist->GetNbinsX()+1 is the "overflow bin"
1<=ibin<=hist->GetNbinsX() are the “normal bins”

There you are! That’s why I was reading the nbin+1 element, to get the overflow bin. Then, as I wrote, if I try to do it with a histogram in which I have changed the label, it crashes :frowning:

I admit that there might be something else going on, but the fact is that not getting the overflow bin (which I should) allows me to read without crash the relabelled histograms.

Thanks,
Jonatan