1 |
/*************************************************
|
2 |
Automatically plots histograms from two or more
|
3 |
files onto the same plot and saves them.
|
4 |
|
5 |
This first looks for ALL histograms in the first
|
6 |
file then and plots the corresponding histograms
|
7 |
from the rest of the files onto the sample plot.
|
8 |
|
9 |
Images are saved into a directory structure
|
10 |
that copies the structure of the root files.
|
11 |
|
12 |
Can be run from a bash prompt as well:
|
13 |
root -b -l -q "plotCorrespondingHists.C(\"fileA.root\",\"fileB.root\")"
|
14 |
root -b -l -q "plotCorrespondingHists.C(\"fileA.root\",\"fileB.root\",\"fileC.root\")"
|
15 |
|
16 |
Michael B. Anderson
|
17 |
Sept 29, 2009
|
18 |
*************************************************/
|
19 |
|
20 |
|
21 |
|
22 |
// *******************************************
|
23 |
// Variables
|
24 |
TString imageType = "gif";
|
25 |
TString outputFolder = "HistogramsTogether/";
|
26 |
int plotWidth = 480;
|
27 |
int plotHeight = 360;
|
28 |
bool plotLogY = false;
|
29 |
bool areaNormalize = true;
|
30 |
// Turn off stats box
|
31 |
gStyle->SetOptStat(0);
|
32 |
// End of Variables
|
33 |
// *******************************************
|
34 |
|
35 |
void plotCorrespondingHists(TString fileName1, TString fileName2) {
|
36 |
vector<TString> fileNames;
|
37 |
fileNames.push_back( fileName1 ) ;
|
38 |
fileNames.push_back( fileName2 ) ;
|
39 |
plotCorrespondingHists( fileNames );
|
40 |
}
|
41 |
|
42 |
void plotCorrespondingHists(TString fileName1, TString fileName2, TString fileName3) {
|
43 |
vector<TString> fileNames;
|
44 |
fileNames.push_back( fileName1 ) ;
|
45 |
fileNames.push_back( fileName2 ) ;
|
46 |
fileNames.push_back( fileName3 ) ;
|
47 |
plotCorrespondingHists( fileNames );
|
48 |
}
|
49 |
|
50 |
void plotCorrespondingHists(TString fileName1, TString fileName2, TString fileName3, TString fileName4) {
|
51 |
vector<TString> fileNames;
|
52 |
fileNames.push_back( fileName1 ) ;
|
53 |
fileNames.push_back( fileName2 ) ;
|
54 |
fileNames.push_back( fileName3 ) ;
|
55 |
fileNames.push_back( fileName4 ) ;
|
56 |
plotCorrespondingHists( fileNames );
|
57 |
}
|
58 |
|
59 |
void plotCorrespondingHists(vector<TString> fileName) {
|
60 |
|
61 |
TString firstFileName = fileName[0];
|
62 |
|
63 |
if (firstFileName == "" ) return;
|
64 |
|
65 |
// Open all the files & create a list of Labels
|
66 |
TList *fileList = new TList();
|
67 |
TList *listOfLabels = new TList();
|
68 |
for (int i=0; i<fileName.size(); i++) {
|
69 |
cout << "Opening " << fileName[i] << " ..." << endl;
|
70 |
TFile *tempFile = new TFile(fileName[i], "READ");
|
71 |
if ( tempFile->IsZombie() ) {
|
72 |
cout << "Error opening " << fileName[i] << endl;
|
73 |
return;
|
74 |
}
|
75 |
fileList->Add( tempFile );
|
76 |
listOfLabels->Add( new TObjString(fileName[i].ReplaceAll(".root","")) );
|
77 |
}
|
78 |
|
79 |
// Create a list of all the histograms in the file
|
80 |
TList *listOfHistograms = new TList();
|
81 |
TFile *firstFile = (TFile*)fileList->First();
|
82 |
gSystem->MakeDirectory(outputFolder);
|
83 |
recurseOverKeys( firstFile, listOfHistograms );
|
84 |
|
85 |
cout << "Found " << listOfHistograms->GetSize() << " histograms in " << firstFileName << endl;
|
86 |
|
87 |
// Loop over histograms, then loop over files
|
88 |
// plot the same histogram from all the files together
|
89 |
// save the canvas
|
90 |
TCanvas *c1 = new TCanvas("c1", "c1",0,0,plotWidth,plotHeight);
|
91 |
TObjString *currentHistString = (TObjString*)listOfHistograms->First();
|
92 |
for (int i_hist=0; i_hist<listOfHistograms->GetSize(); i_hist++) {
|
93 |
TFile *current_file = (TFile*)fileList->First();
|
94 |
|
95 |
// Loop over the files, building list of histograms
|
96 |
TList *listOfHistsToPlot = new TList();
|
97 |
for (int i_file=0; i_file<fileName.size(); i_file++) {
|
98 |
TH1* htemp;
|
99 |
//cout << currentHistString->GetString() << endl;
|
100 |
TString currentHistName = currentHistString->GetString();
|
101 |
if (currentHistName[0] == '/') {
|
102 |
currentHistName = currentHistName(1,currentHistName.Length());
|
103 |
}
|
104 |
current_file->GetObject(currentHistName, htemp);
|
105 |
|
106 |
if ( !htemp ) {
|
107 |
cout << "Error getting " << currentHistString->GetString() << " from " << current_file->GetName() << endl;
|
108 |
return;
|
109 |
}
|
110 |
|
111 |
listOfHistsToPlot->Add(htemp);
|
112 |
current_file = (TFile*)fileList->After( current_file );
|
113 |
}
|
114 |
|
115 |
// Created a list of histograms to plot, now plot and save file
|
116 |
plotHists(listOfHistsToPlot, listOfLabels, c1);
|
117 |
c1->SaveAs(outputFolder+currentHistString->GetString()+"."+imageType);
|
118 |
|
119 |
currentHistString = (TObjString*)listOfHistograms->After(currentHistString);
|
120 |
}
|
121 |
|
122 |
// Close all the files
|
123 |
TFile *current_file = (TFile*)fileList->First();
|
124 |
for (int i=0; i<fileName.size(); i++) {
|
125 |
cout << "Closing " << fileName[i] << " ..." << endl;
|
126 |
current_file->Close();
|
127 |
current_file = (TFile*)fileList->After( current_file );
|
128 |
}
|
129 |
}
|
130 |
|
131 |
void recurseOverKeys( const TDirectory *target, TList *listOfHistograms) {
|
132 |
|
133 |
// Figure out where we are
|
134 |
TString path( (char*)strstr( target->GetPath(), ":" ) );
|
135 |
path.Remove( 0, 2 );
|
136 |
|
137 |
TDirectory *current_sourcedir = gDirectory;
|
138 |
|
139 |
TKey *key;
|
140 |
TIter nextkey(current_sourcedir->GetListOfKeys());
|
141 |
|
142 |
while (key = (TKey*)nextkey()) {
|
143 |
|
144 |
obj = key->ReadObj();
|
145 |
|
146 |
// Check if this is a 1D histogram or a directory
|
147 |
if (obj->IsA()->InheritsFrom("TH1F")) {
|
148 |
|
149 |
TH1F *htemp = (TH1F*)obj;
|
150 |
TString histName = htemp->GetName();
|
151 |
TObjString *histToAdd = new TObjString(path+"/"+histName);
|
152 |
listOfHistograms->Add(histToAdd);
|
153 |
|
154 |
} else if ( obj->IsA()->InheritsFrom( "TDirectory" ) ) {
|
155 |
// it's a subdirectory
|
156 |
|
157 |
const TDirectory *tempDir = (TDirectory*)obj;
|
158 |
current_sourcedir->cd ( tempDir->GetName() );
|
159 |
|
160 |
gSystem->MakeDirectory(outputFolder+path+"/"+tempDir->GetName());
|
161 |
|
162 |
// obj still knows its depth within the target file via
|
163 |
// GetPath(), so we can still figure out where we are in the recursion
|
164 |
recurseOverKeys( tempDir , listOfHistograms );
|
165 |
|
166 |
} // end of IF a TDriectory
|
167 |
}
|
168 |
}
|
169 |
|
170 |
void plotHists(TList *histogramsToPlot,
|
171 |
TList *histogramLabels,
|
172 |
TCanvas *c1) {
|
173 |
|
174 |
|
175 |
//*************************************************
|
176 |
// Variables
|
177 |
vector<int> histColors;
|
178 |
histColors.push_back(kBlack); // change colors as you like
|
179 |
histColors.push_back(kBlue);
|
180 |
histColors.push_back(kRed);
|
181 |
histColors.push_back(kGreen-1);
|
182 |
|
183 |
float histLineWidth = 2.0;
|
184 |
|
185 |
bool useMarkers = false; // search online for TAttMarker
|
186 |
vector<int> histMarkerStyles; // to see all available markers
|
187 |
histMarkerStyles.push_back( 20 );
|
188 |
histMarkerStyles.push_back( 22 );
|
189 |
histMarkerStyles.push_back( 21 );
|
190 |
histMarkerStyles.push_back( 23 );
|
191 |
float histMarkerSize = 0.9;
|
192 |
|
193 |
// END of Variables
|
194 |
//*************************************************
|
195 |
|
196 |
// Create copies of histograms provided
|
197 |
// and area normalize, if requested
|
198 |
TList *hists = new TList();
|
199 |
TH1* currentHistogram = (TH1*)histogramsToPlot->First();
|
200 |
for (int i=0; i<histogramsToPlot->GetSize(); i++) {
|
201 |
TH1* tempCurrentClone = (TH1*)currentHistogram->Clone();
|
202 |
hists->Add( tempCurrentClone );
|
203 |
if (areaNormalize) {
|
204 |
Double_t integral = tempCurrentClone->Integral();
|
205 |
if (integral>0.0) tempCurrentClone->Scale(1/integral);
|
206 |
}
|
207 |
currentHistogram = (TH1*)histogramsToPlot->After( currentHistogram );
|
208 |
}
|
209 |
|
210 |
|
211 |
// Set histogram plotting variables
|
212 |
// and add them to the histogram stack & legend
|
213 |
THStack *tempStack = new THStack();
|
214 |
TLegend *infoBox = new TLegend(0.75, 0.83, 0.99, 0.99, "");
|
215 |
currentHistogram = (TH1*)hists->First();
|
216 |
TObjString *currentHistString = (TObjString*)histogramLabels->First();
|
217 |
for (int i=0; i<histogramsToPlot->GetSize(); i++) {
|
218 |
|
219 |
currentHistogram->SetLineColor(histColors[i]);
|
220 |
currentHistogram->SetLineWidth(histLineWidth);
|
221 |
|
222 |
if (useMarkers) {
|
223 |
currentHistogram->SetMarkerStyle(histMarkerStyles[i]);
|
224 |
currentHistogram->SetMarkerColor(histColors[i]);
|
225 |
currentHistogram->SetMarkerSize(histMarkerSize);
|
226 |
}
|
227 |
|
228 |
infoBox->AddEntry(currentHistogram,currentHistString->GetString(),"LP");
|
229 |
currentHistString = (TObjString*)histogramLabels->After( currentHistString);
|
230 |
|
231 |
tempStack->Add(currentHistogram);
|
232 |
|
233 |
currentHistogram = (TH1*)hists->After( currentHistogram );
|
234 |
}
|
235 |
|
236 |
// Draw the stack of histograms
|
237 |
tempStack->Draw("nostack");
|
238 |
|
239 |
// Set title/label sizes and offsets
|
240 |
tempStack->GetXaxis()->SetTitleOffset(0.9);
|
241 |
tempStack->GetYaxis()->SetTitleOffset(1.2);
|
242 |
tempStack->GetXaxis()->SetLabelSize(0.04);
|
243 |
tempStack->GetYaxis()->SetLabelSize(0.05);
|
244 |
tempStack->GetXaxis()->SetTitleSize(0.06);
|
245 |
tempStack->GetYaxis()->SetTitleSize(0.05);
|
246 |
|
247 |
// Set axis titles
|
248 |
TString title = ((TH1*)hists->First())->GetTitle();
|
249 |
TString xTitle = ((TH1*)hists->First())->GetXaxis()->GetTitle();
|
250 |
TString yTitle = ((TH1*)hists->First())->GetYaxis()->GetTitle();
|
251 |
tempStack->SetTitle(title+";"+xTitle+";"+yTitle);
|
252 |
|
253 |
// Draw legend
|
254 |
infoBox->SetShadowColor(0); // 0 = transparent
|
255 |
//infoBox->SetLineColor(0);
|
256 |
infoBox->SetFillColor(kWhite);
|
257 |
//infoBox->SetFillStyle(0);
|
258 |
infoBox->Draw();
|
259 |
|
260 |
c1->SetLogy(plotLogY);
|
261 |
}
|