KAHIBARO
Discord Login Register

12.3 Writing Objects

Saving histograms

Once you have a TFile open, writing a histogram into it is very simple. The general idea is that every ROOT object that inherits from TObject can be written with its Write() method, and histograms such as TH1F, TH1D, TH2F and others all support this.

A typical pattern looks like this, assuming you already created and filled a histogram and opened a file:

cpp
TFile *f = new TFile("results.root", "RECREATE");
TH1F *hEnergy = new TH1F("hEnergy", "Energy spectrum;E [MeV];Counts", 100, 0.0, 10.0);
// ... fill the histogram here ...
hEnergy->Write();   // write to the file
f->Close();         // always close when done

When you call Write() without arguments, ROOT uses the object’s name as the key in the file. In the example, "hEnergy" is both the histogram name and the key name inside results.root. If you want a different key name in the file, you can pass it explicitly:

cpp
hEnergy->Write("energy_spectrum");

You can write several histograms to the same file. They must have unique names within a given directory of the file, because the name is what ROOT uses to retrieve them later with Get() or via the browser. If two objects with the same name are written to the same directory, the later one will overwrite the earlier one in that directory.

You can also use the file method Write() to write everything that is currently “in memory” and owned by that file directory:

cpp
f->Write();  // writes all objects in the current directory to disk

This is useful if you have created many histograms and do not want to call Write() on each one, but it writes all objects in that directory, not only the histograms. For precise control it is often clearer to call Write() on each important object.

Important rule: A histogram is actually written to disk only when you call Write() (on the histogram or on the file) and then close the TFile. Forgetting to close the file can leave it incomplete or empty.

You can control which directory of the file receives the histogram with TDirectory::cd(). For example, to organize histograms into subdirectories inside the file:

cpp
TFile *f = new TFile("results.root", "RECREATE");
f->mkdir("spectra");
f->cd("spectra");
hEnergy->Write();                // stored under /spectra in the file
f->cd();                         // go back to the top directory
TH1F *hTime = new TH1F("hTime", "Time; t [ns]; Counts", 100, 0, 1000);
hTime->Write();                  // stored in the top directory
f->Close();

Later chapters on directories will explain this structure in more detail. For now it is enough to remember that Write() sends the object to the “current directory” of the open file.

Saving graphs

Graphs such as TGraph, TGraphErrors, TGraphAsymmErrors or TMultiGraph are saved to ROOT files in exactly the same way as histograms, since they are also ROOT objects.

Suppose you have created and filled a graph:

cpp
TGraph *gr = new TGraph();
gr->SetName("grCalib");
gr->SetTitle("Calibration curve;Channel;Energy [MeV]");
// ... add points with gr->SetPoint(...) ...

To store this graph in a file:

cpp
TFile *f = new TFile("graphs.root", "RECREATE");
gr->Write();         // uses the name "grCalib"
f->Close();

If the graph has no name yet, you should set one before writing, because that name is how you will later retrieve it with Get():

cpp
gr->SetName("calibration_graph");
gr->Write();

You can write several graphs and histograms in the same file and mix them freely:

cpp
TFile *f = new TFile("analysis.root", "RECREATE");
TH1F *h = new TH1F("h", "Distribution;X;Counts", 100, 0, 1);
// ... fill h ...
TGraphErrors *g = new TGraphErrors();
// ... fill g ...
h->Write();
g->Write();
f->Close();

Because everything is stored as separate objects, you can later open analysis.root, pick out either the histogram or the graph, and draw or further process it. This is one of the main advantages of the ROOT file format over plain image files: you keep the underlying numerical data.

Important rule: When saving graphs, always ensure they have a unique, meaningful GetName(). This is the key you must use to recover them from the file. Two graphs with the same name written to the same directory will conflict, and the last one written will replace the earlier one there.

Saving functions

Analytical functions represented by TF1 (and related classes such as TF2 and TF3) can also be written into ROOT files. When you save a function object, ROOT stores its definition and its current parameter values. This allows you to reuse the same fit function in later ROOT sessions without redefining it.

Assume you created a simple Gaussian function:

cpp
TF1 *fGaus = new TF1("fGaus", "gaus", -5.0, 5.0);
fGaus->SetParameters(1.0, 0.0, 1.0);  // amplitude, mean, sigma

You can write it into a file in the same way as a histogram:

cpp
TFile *f = new TFile("functions.root", "RECREATE");
fGaus->Write();     // stores the TF1
f->Close();

Later, when you open functions.root, you can retrieve the function by name:

cpp
TFile *f = new TFile("functions.root");
TF1 *fGausLoaded = (TF1*)f->Get("fGaus");

If you performed a fit and the function parameters were modified by the fit, writing the function after the fit preserves those fitted parameter values for later reuse. This is especially useful for analysis workflows where you want to apply the same calibrated function to multiple datasets or use it as a starting point for new fits.

You can save several functions into the same file, together with histograms and graphs. For example, to save both a histogram and its fit function:

cpp
TFile *fout = new TFile("peak_fit.root", "RECREATE");
TH1F *hPeak = new TH1F("hPeak", "Peak;X;Counts", 100, -5, 5);
// ... fill and fit hPeak with fGaus ...
hPeak->Write();      // save the histogram
fGaus->Write();      // save the fitted function
fout->Close();

When you load them later, you can draw the histogram and then the function on top, and obtain exactly the same visual result you had at the time of saving.

Important rule: A TF1 must have a valid name and expression in order to be meaningfully stored. When you write a function to a file, ROOT saves the function’s name, its mathematical formula, and its current parameters. If you change the function formula in your code later, the old version in the file remains unchanged.

Because functions, histograms, and graphs all use the same Write() mechanism and live side by side in ROOT files, you can bundle complete analysis results into a single file: the data objects, their visualizations, and the models that describe them. This is the foundation that the following chapters on reading and exploring ROOT files will build upon.

Views: 12

Comments

Please login to add a comment.

Don't have an account? Register now!