24.11. Save the Analysis Results
Table of Contents
Why Saving Results Matters
At the end of an analysis, the most important products are not your temporary histograms on screen, but the reproducible results that others can inspect, re-use, and build upon. In a ROOT-based workflow, saving results is not a single step. It is a small, well-structured set of actions that preserve your numerical outputs, your plots, and enough context to reproduce what you did.
In this chapter you will focus on what to save, how to save it with ROOT, and how to make the saved results useful for later work and for collaborators.
Decide What Needs to Be Saved
Your analysis will usually produce several kinds of outputs:
- Final numerical quantities. For example fitted parameters, mean values in control regions, efficiencies, event counts, or derived physics quantities.
- Final ROOT objects. Histograms, graphs, functions, and possibly TTrees that represent intermediate or final states of the analysis.
- Publication or presentation plots. Static images in formats such as PNG and PDF, as well as vector formats for high-quality rendering.
- Minimal configuration or metadata. Enough information to understand and reproduce which inputs and settings produced the results, without rewriting your entire analysis report.
You do not need to save everything produced in every intermediate step. Focus on what you or someone else will realistically need to re-inspect, combine with new results, or cross-check later. Intermediate steps can be reproduced if your analysis code is under version control and the input datasets are available.
Saving ROOT Objects to Files
The core mechanism for storing ROOT analysis results is the ROOT file. You will typically create one or more .root files to contain your final histograms, graphs, and functions. It is common to have at least one final results file that collects everything you want to preserve for long-term use.
Conceptually, saving objects works in two steps. First, you create or open a TFile in a specific mode. Second, you write objects to it, usually by calling their Write() method.
A typical pattern in a macro looks like this, where the details of object creation are assumed from earlier stages of your project:
TFile *fout = new TFile("final_results.root", "RECREATE");
// Assume these objects already exist and contain your final results
hData->Write();
hMC->Write();
hSignal->Write();
gEfficiency->Write();
fitFunc->Write();
fout->Close();
The file mode controls how ROOT handles an existing file with the same name. For example, "RECREATE" replaces any existing file, while "UPDATE" lets you append or modify entries in an existing ROOT file. Using distinct filenames that include a version tag or date can help you avoid accidental overwriting of important results.
Objects are stored inside the file with the names they already have. If you need multiple histograms with similar content, use descriptive and unique names in your code before writing them, so you can easily retrieve the correct ones later.
If your project naturally separates different groups of results, you can organize them inside directories in the ROOT file, using TDirectory. This lets you group, for instance, all control-region histograms under one directory and all signal-region histograms under another. That can improve clarity when you or others explore the file later.
Always close every TFile that you open for writing, by calling Close() before your macro exits. This ensures that file buffers are flushed and all objects are correctly written to disk.
Saving Numerical Results
Histograms and graphs are convenient to visualize results, but often you also need the underlying numbers. For example, you may have extracted a cross section, an efficiency, or mean values of distributions in specific regions.
In ROOT, if these numbers come from a fit, you can keep both perspectives. First, you retain the fit function object itself in the ROOT file, which contains parameter values and errors. Second, you may export a summary as a human-readable file, such as a plain text table or a CSV file.
Suppose you have a fitted function with three parameters and you want to store their values and uncertainties in a small text table alongside your ROOT file:
std::ofstream out("fit_results.txt");
out << "# Parameter Value Error" << std::endl;
for (int i = 0; i < fitFunc->GetNpar(); ++i) {
out << i << " "
<< fitFunc->GetParameter(i) << " "
<< fitFunc->GetParError(i) << std::endl;
}
out.close();
For more complex final results, such as sets of derived observables per bin of some variable, you may create a TTree that stores these quantities in a structured form. That allows downstream analyses or cross-checks directly from the results file without having to re-run the full event-level analysis. These design decisions belong to your overall analysis plan, but the important point here is that ROOT gives you persistent containers that match both numerical and graphical results.
Try to accompany machine-readable outputs with a simple, separate description file. A few lines of text that explain what each output file contains, which units are used, and what selections were applied can save significant effort later.
Do not rely on plots alone as your only record of key numerical results. Always save the underlying numbers, for example in a ROOT file or a text file, together with your plots.
Saving Plots for Reports and Presentations
Your analysis report and presentations will need static images. ROOT can export canvases, which already display your histograms or graphs with the desired styling, to a variety of formats. You will typically choose at least one raster format, such as PNG, and one vector format, such as PDF or SVG, for publication-quality figures.
Once you have configured and drawn your plots on a TCanvas, you can save the canvas directly:
TCanvas *c1 = new TCanvas("c1", "Final fit", 800, 600);
hData->Draw("E");
fitFunc->Draw("SAME");
// Save in several formats
c1->SaveAs("final_fit.png");
c1->SaveAs("final_fit.pdf");If your analysis produces several standard figures, you can automate this step by writing a small function that takes a canvas pointer and a base name, then saves it in multiple formats. This avoids manual steps and keeps your naming scheme consistent.
For multi-panel canvases, in which you divided the canvas into pads, SaveAs stores the entire layout as it appears on screen. This is particularly useful for summary figures that show multiple distributions or control plots side by side.
When saving for publication or high-quality printing, prefer vector formats such as PDF or SVG. Raster formats are useful for quick sharing, internal notes, and web pages, but they do not scale as well for detailed printouts or zooming.
Organizing Output Files
How you organize the directory structure of your outputs has a direct impact on how easy it is to navigate your results. A typical final project will contain at least your analysis code, your ROOT result files, and your plots.
A simple and effective approach is to keep a dedicated output or results directory inside your project, with subdirectories such as root and plots. For example:
| Directory | Contents |
|---|---|
output/root/ | Final .root files containing histograms and graphs |
output/plots/ | Final PNG/PDF/SVG images for all main figures |
output/text/ | Optional text tables with fit parameters or summaries |
You can create these directories manually or via small helper scripts or macros before running the analysis. In your ROOT code, construct output file names using these directories explicitly, rather than scattering output files in the top-level project directory.
Consistent and descriptive naming helps you and others understand what each file contains without opening it. A pattern that includes the dataset name, the selection, and a version tag usually works well. For example, file names like
results_signalRegion_v1.root
plots_signalRegion_v1.pdf
already communicate more to the reader than generic names such as output.root or plot1.png.
Avoid reusing generic filenames like output.root for different runs of your analysis without versioning or separate directories. Overwriting old results without intention can make it difficult or impossible to trace how your analysis evolved.
Documenting Saved Results
Saving results is only fully useful if someone, including your future self, can quickly understand what those results represent. Documentation for saved results does not need to be long, but it should be clear and co-located with the files.
There are two simple and effective strategies.
First, include minimal metadata inside the ROOT files themselves. For example, you can store small text objects or use titles and axis labels that encode key information such as the selection or observable. While this is not a full metadata system, it can provide immediate clues when browsing the file.
Second, keep a separate text file in your output directory, such as README_results.txt, that lists the main result files and briefly describes what they contain. For instance, you might write which dataset and selection each ROOT file corresponds to, and which plots are considered final for publication. When you later prepare your final report, you can refer to this file and maintain consistency between the report and the stored outputs.
If your analysis uses configuration files or scripts to define selections and constants, it is often helpful to copy the configuration file that was used into the results directory at the time of each run. That way the saved results are always tied to a specific configuration snapshot, even if the main configuration file later changes as the analysis evolves.
By combining structured storage in ROOT files, well-named image exports, and a small amount of focused documentation, you ensure that your final project produces results that are not only correct today, but also reusable and understandable in the future.
Views: 12
KAHIBARO