Change binning of histogram

Hi,

how can I change the binning (bin number and/or bin width) of a histogram?
Thanks in advance!

I just noticed that I’m not explicitly creating a histogram in my code… this is what I have:

void MyRunAction::BeginOfRunAction(const G4Run*)
{
G4AnalysisManager *man = G4AnalysisManager::Instance();

man->OpenFile(“output.root”);

man->CreateNtuple(“Hits”, “Hits”);
man->CreateNtupleIColumn(“fEvent”);
man->CreateNtupleDColumn(“fdepEnergy”);
man->CreateNtupleDColumn(“ftotEnergy”);
man->CreateNtupleDColumn(“fX”);
man->CreateNtupleDColumn(“fY”);
man->CreateNtupleDColumn(“fZ”);
man->FinishNtuple(0);

}

void MyRunAction::EndOfRunAction(const G4Run*)
{

G4AnalysisManager *man = G4AnalysisManager::Instance();
man->Write();
man->CloseFile();
}

I’m starting ROOT’s TBrowser then to get a histogram e.g. of “ftotEnergy”. Any advice?

Best,
Ben

When viewing ntuple data with ROOT browser, the bunning is set automatically by ROOT. There are many possibilities how to analyse ROOT trees, see ROOT documentation here:

Below I give a simple macro, plotNtuple2.C, that allows to read the ntuple produced with B4 example and defines two histograms, that are then filled with the ntuple data EAbs and EGap. You can adapt this macro for you use case and set the number of bins that you want.

// ROOT macro file for reading example B4 ntuple
// and plotting selected data
//
// Can be run from ROOT session:
// root[0] .x plotNtuple2.C

{
  std::unique_ptr<TFile> myFile( TFile::Open("B4.root") );
  auto tree = myFile->Get<TTree>("B4");
  
  Double_t eabs;
  Double_t egap;
  tree->SetBranchAddress("Eabs", &eabs);
  tree->SetBranchAddress("Egap", &egap);

  auto hEabs = new TH1D("HEAbs", "Histo Eabs", 100, 0., 100.);
  auto hEgap = new TH1D("HEgap", "Histo Egap", 100, 0., 10.);
  
  for (int iEntry = 0; iEntry < tree->GetEntriesFast(); ++iEntry) {
     // Load the data for the given tree entry
     tree->GetEntry(iEntry);
  
     // Now, `variable` is set to the value of the branch
     // "branchName" in tree entry `iEntry`
     // printf("%d\n", variable);
     hEabs->Fill(eabs);
     hEgap->Fill(egap);
  }

    // Create a canvas and divide it into 2x2 pads
  TCanvas* c1 = new TCanvas("c1", "", 20, 20, 1000, 500);
  c1->Divide(2);

  c1->cd(1);
  hEabs->Draw("HIST");
  c1->cd(2);
  hEgap->Draw("HIST");
}
1 Like

Hi Ivana,

thanks a lot for your help! I changed your code slightly to:

{
std::unique_ptr myFile( TFile::Open(“output.root”));
auto tree = myFile->Get(“toy_ex”);

Double_t partEdep;
Double_t energy;
tree->SetBranchAddress(“partEdep”, &partEdep);
tree->SetBranchAddress(“totEnergy”, &energy);

auto hdepE = new TH1D(“HpartEdep”, “Histo depE”, 100, 0., 100.);
auto htotE = new TH1D(“HtotEnergy”, “Histo totE”, 100, 0., 200.);

for (int iEntry = 0; iEntry < tree->GetEntriesFast(); ++iEntry)
{
// Load the data for the given tree entry
tree->GetEntry(iEntry);

  // Now, `variable` is set to the value of the branch
  // "branchName" in tree entry `iEntry`
  // printf("%d\n", variable);
  HpartEdep->Fill(partEdep);
  HtotEnergy->Fill(energy);

}

// Create a canvas and divide it into 2x2 pads
TCanvas* c1 = new TCanvas(“c1”, “”, 20, 20, 1000, 500);
c1->Divide(2);

c1->cd(1);
hdepE->Draw(“HIST”);
c1->cd(2);
htotE->Draw(“HIST”);
}

I believe I only changed the names. When I run the macro via

root -l
.x plot.C

I’m receiving only this response:

C:\geant4\sim>
C:\geant4\sim>root -l
root [0] .x plot.C

==========================================
=============== STACKTRACE ===============

================ Thread 0 ================
libCling!cling::runtime::internal::EvaluateDynamicExpression()
libCling!cling_runtime_internal_throwIfInvalidPointer()
0x23e43d116be ??
0x23e504ea3a0 ??

================ Thread 1 ================
ntdll!ZwWaitForWorkViaWorkerFactory()
ntdll!TpReleaseCleanupGroupMembers()
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

================ Thread 2 ================
ntdll!ZwWaitForWorkViaWorkerFactory()
ntdll!TpReleaseCleanupGroupMembers()
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

================ Thread 3 ================
ntdll!ZwWaitForWorkViaWorkerFactory()
ntdll!TpReleaseCleanupGroupMembers()
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

================ Thread 4 ================
ntdll!NtDelayExecution()
KERNELBASE!SleepEx()
libCore!TWinNTSystem::TimerThread()
libCore!TWinNTSystem::ThreadStub()
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

================ Thread 5 ================
win32u!NtUserGetMessage()
USER32!GetMessageA()
libCore!TWinNTSystem::FreeDirectory()
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

================ Thread 6 ================
ntdll!ZwWaitForMultipleObjects()
KERNELBASE!WaitForMultipleObjectsEx()
KERNELBASE!WaitForMultipleObjects()
tmmon64!??
tmmon64!??
tmmon64!??
KERNEL32!BaseThreadInitThunk()
ntdll!RtlUserThreadStart()

==========================================
============= END STACKTRACE =============

C:\geant4\sim>

but no plot, window or the like pops up. Could you tell me whether I’m doing things correctly?

So far, I only notice that at the beginning of your code the line

auto tree = myFile->Get<TTree>("B4");

seems suspicious to me. In my simulation there is no TTree created but this line tries to read a TTree stored in the output file, or?

Got something working via the one file in B4:

{
gROOT->Reset();
gROOT->SetStyle(“Plain”);

// Draw histos filled by Geant4 simulation
//

// Open file filled by Geant4 simulation
TFile f(“output.root”);

// Create a canvas and divide it into 2x2 pads
TCanvas* c1 = new TCanvas(“c1”, “”, 20, 20, 1000, 1000);
c1->Divide(1,2);

// Get ntuple
TNtuple* ntuple = (TNtuple*)f.Get(“Hits”);

// Draw Eabs histogram in the pad 1
c1->cd(1);
ntuple->Draw(“fdepEnergy”);

// Draw Labs histogram in the pad 2
c1->cd(2);
ntuple->Draw(“ftotEnergy”);

}

Hits

is the name of the NTuple created in the run()-file as follows:

man->CreateNtuple(Hits, Hits);
man->CreateNtupleIColumn(fEvent);
man->CreateNtupleDColumn(fdepEnergy);
man->CreateNtupleDColumn(ftotEnergy);
man->CreateNtupleDColumn(fX);
man->CreateNtupleDColumn(fY);
man->CreateNtupleDColumn(fZ);

Though, I realized this is better as I can rebin within the Browser then but I guess it’s not quite exactly what’s needed, or?

Btw, I could also save it in a different format other than NTuple, or not? Just depends on what is easier to proceed from.

You defined the histograms as hdepE and htotE.

To debug your macro, the best is to process in line by line interactively (in the ROOT shell). Instead of the loop which spans on more than one line, you can process the lines with replacing iEntry with 0:

  tree->GetEntry(0);
  hdepE->Fill(partEdep);
  htotE->Fill(energy);
1 Like

ntuple->Draw(“fdepEnergy”); will result in the same histogram as when you double click on fdepEnergy in your browser, with the binning defined automatically by ROOT.

Though, I realized this is better as I can rebin within the Browser

A histogram already displayed in the browser cannot be rebinned. That’s why I gave you the macro above.

1 Like

ah god, thanks for pointing out… didn’t see that but it works now!

Thanks a lot for your support!

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