Code to combine and fit ID spectra (pi/K/p).
[u/mrichter/AliRoot.git] / PWG2 / SPECTRA / Fit / AliLatexTable.cxx
1 // ------------------------------------------------------------------
2 //
3 //                           AliLatexTable
4 //
5 // This class is used to produce tables using latex sintax. It can
6 // than print the table as Latex source code (to be pasted on a paper)
7 // or ASCII.
8 //
9 // The basic idea is that you add columns one after the other with the
10 // SetNextCol method and than you insert this row. The SetNextCol
11 // method comes in different flavours to alow the insertion of
12 // different type of values (numbers with or without errors,
13 // strings...).
14 //
15 // TODO:
16 // 1. Make the class drawable
17 // 2. Implement vertical lines in ascii print
18 // 3. Print output in HTML format
19 //
20 // Author: Michele Floris, CERN
21 // ------------------------------------------------------------------
22
23 #include "AliLatexTable.h"
24 #include "TString.h"
25 #include "TRegexp.h"
26 #include "TObjString.h"
27 #include "TObjArray.h"
28 #include <stdarg.h>
29 #include "snprintf.h"
30 #include "Varargs.h"
31 #include "TPRegexp.h"
32 #include "TMath.h"
33 #include <iostream>
34
35 using namespace std;
36
37 ClassImp(AliLatexTable);
38
39 AliLatexTable::AliLatexTable(Int_t ncol, TString format) : fNcol(0), fFormat(""), fRows(0), fCols(0), fNcolReady(0){
40   // constructor, specify number of cols 
41   fNcol = ncol;
42   fFormat = format;
43   fNcolReady = 0;
44   fRows = new TObjArray;
45   fCols = new TObjArray;
46
47   fRows->SetOwner();
48   fCols->SetOwner();
49 }
50
51
52 AliLatexTable::~AliLatexTable() {
53
54   // dtor
55   if (fRows) delete fRows;
56   if (fCols) delete fCols;
57
58 }
59
60 void AliLatexTable::SetNextCol(Int_t val){
61   // Set next column in current row - integer
62   char col[200];
63   sprintf(col, " %d ", val);
64   SetNextCol(col);
65
66
67
68 void AliLatexTable::SetNextCol(Int_t val, Int_t err){
69
70   // Set next column in current row - int +- int
71   char col[200];
72   sprintf(col, " $%d \\pm %d$ ", val, err);
73   SetNextCol(col);
74
75
76
77 void AliLatexTable::SetNextCol(Double_t val, Int_t scientificNotation){
78
79   // Set next column in current row - double, specify resolution
80
81   char col[200];
82   if(scientificNotation >= 0) {
83     char format[100];
84
85     //    cout << format << endl;    
86     Double_t mantissa, exp;
87     GetMantissaAndExpBase10(val, mantissa, exp);
88     
89     if (exp == 0) {
90       sprintf(format, " $%%%d.%df $", scientificNotation, scientificNotation);
91       sprintf(col, format, mantissa);      
92     }
93     else  {
94       sprintf(format, " $%%%d.%df \\cdot 10^{%%0.0f} $", scientificNotation, scientificNotation);
95       sprintf(col, format, mantissa, exp);
96     }
97
98
99     
100
101     SetNextCol(col);
102
103   } else if (scientificNotation < -1) {
104     char format[100];
105     sprintf(format, " $%%%d.%df $", -scientificNotation,-scientificNotation);    
106     sprintf(col, format , val);
107     SetNextCol(col);
108   } else {
109     sprintf(col, " %f ", val);
110     SetNextCol(col);
111   }
112
113
114 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Int_t scientificNotation){
115
116   // Set next column in current row - double +- double, specify resolution
117
118   // if scientific notation is != -1 is used to determine number of
119   // digits in error 
120
121   //if it is > 0 exp notation is used 
122
123   //if it is < -1 number is truncated to the number of digits after
124   //point dictated by scientificNotation,
125
126   char col[200];
127   if(scientificNotation >=0 ) {
128
129     Double_t mantissa, exp;
130     GetMantissaAndExpBase10(val, mantissa, exp);
131
132     Double_t mantissa_err, exp_err;
133     GetMantissaAndExpBase10(err, mantissa_err, exp_err);
134
135     Int_t nSigDigits =TMath::Nint(exp - exp_err);
136     if(scientificNotation != 0) nSigDigits =  nSigDigits + scientificNotation - 1;
137
138
139     char format[100];
140     if (exp == 0) {
141       sprintf(format, " $%%%d.%df \\pm %%%d.%df $", nSigDigits, nSigDigits, nSigDigits, nSigDigits);
142       sprintf(col, format, mantissa, mantissa_err/TMath::Power(10,exp - exp_err));
143     }
144     else  {
145       sprintf(format, " $%%%d.%df \\pm %%%d.%df \\cdot 10^{%%0.0f}$", nSigDigits, nSigDigits, nSigDigits, nSigDigits);
146       sprintf(col, format, mantissa, mantissa_err/TMath::Power(10,exp - exp_err), exp);
147     }
148
149
150  //cout << format << endl;
151     
152     SetNextCol(col);
153
154   } else if (scientificNotation < -1) {
155     char format[100];
156     sprintf(format, " $%%%d.%df \\pm %%%d.%df $", -scientificNotation,-scientificNotation,-scientificNotation,-scientificNotation);    
157     sprintf(col, format , val, err);
158     SetNextCol(col);
159   }
160   else {
161     sprintf(col, " $%f \\pm %f$ ", val, err);
162     SetNextCol(col);
163   }
164
165
166 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Double_t errSyst, Int_t scientificNotation){
167
168   // Set next column in current row - double +- double +- double, specify resolution
169
170   // if scientific notation is != -1 is used to determine number of
171   // digits in error 
172
173   //if it is > 0 exp notation is used 
174
175   //if it is < -1 number is truncated to the number of digits after
176   //point dictated by scientificNotation,
177
178   char col[200];
179   if(scientificNotation >=0 ) {
180
181     Double_t mantissa, exp;
182     GetMantissaAndExpBase10(val, mantissa, exp);
183
184     Double_t mantissa_err, exp_err;
185     GetMantissaAndExpBase10(err, mantissa_err, exp_err);
186
187     Double_t mantissa_errsyst, exp_errsyst;
188     GetMantissaAndExpBase10(errSyst, mantissa_errsyst, exp_errsyst);
189
190     Int_t nSigDigits =TMath::Nint(exp - exp_err);
191     if(scientificNotation != 0) nSigDigits =  nSigDigits + scientificNotation - 1;
192
193
194     char format[100];
195     if (exp == 0) {
196       sprintf(format, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df $", 
197               nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
198       sprintf(col, format, mantissa, 
199               mantissa_err/TMath::Power(10,exp - exp_err), 
200               mantissa_errsyst/TMath::Power(10,exp - exp_errsyst));
201     }
202     else  {
203       sprintf(format, " $%%%d.%df \\pm %%%d.%df  \\pm %%%d.%df \\cdot 10^{%%0.0f}$", 
204               nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
205       sprintf(col, format, mantissa, 
206               mantissa_err/TMath::Power(10,exp - exp_err), 
207               mantissa_errsyst/TMath::Power(10,exp - exp_errsyst),
208               exp);
209     }
210
211
212  //cout << format << endl;
213     
214     SetNextCol(col);
215
216   } else if (scientificNotation < -1) {
217     char format[100];
218     sprintf(format, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df $", -scientificNotation,-scientificNotation,-scientificNotation,-scientificNotation, -scientificNotation,-scientificNotation);    
219     sprintf(col, format , val, err);
220     SetNextCol(col);
221   } 
222   else {
223     sprintf(col, " $%f \\pm %f  \\pm %f$ ", val, err, errSyst);
224     SetNextCol(col);
225   }
226
227
228 // void AliLatexTable::SetNextColPrintf(const char *va_(fmt), ...){
229
230
231 //   const Int_t buf_size = 1024;  // hope it's long enough
232 //   char colBuffer[buf_size];
233
234 //   va_list ap;
235 //   va_start(ap, va_(fmt));
236 //   Int_t n = vsnprintf(colBuffer, buf_size, fmt, ap);
237
238 //   if (n == -1 || n >= buf_size) {
239 //     Error("SetNextCol", "vsnprintf error!");
240 //   }
241
242 //   va_end(ap);
243      
244 // //   for(int iobj=0; iobj<num; iobj++){   //Loop until all objects are added
245 // //     TH1 * obj = (TH1 *) va_arg(arguments, void *);
246 // //     returnValue = returnValue && AddObject(obj,(char*)fOptMany.Data(), EColor(iobj+1));
247 // //   }
248 //   SetNextCol(colBuffer);
249 // }
250
251
252 void AliLatexTable::SetNextCol(TString val){
253
254   // Set next column in current row - tstring
255
256   fCols->Add(new TObjString(val));
257   fNcolReady++;
258
259
260
261 void AliLatexTable::InsertCustomRow(TString row){
262   // insert a full row from string. Make sure you have all the columns
263   fRows->Add(new TObjString(row));
264 }
265
266
267
268 void AliLatexTable::InsertRow(){
269
270   // Insert the row, based on all the individual columns
271
272   if ( fNcolReady != fNcol) {
273     Warning("InsertRow", "Wrong number of cols: %d (!= %d)", fNcolReady, fNcol); 
274   }
275
276   TString row = "";
277   for(Int_t icol = 0; icol < fNcol; icol++){
278     row = row + ((TObjString*) fCols->At(icol))->String();
279     if(icol != (fNcol-1)) row = row + " & ";
280   }
281   row+="\\\\";
282
283   fRows->Add(new TObjString(row));
284
285   fNcolReady = 0;
286   fCols->Clear();
287
288 }
289
290 void AliLatexTable::InsertHline(){
291
292   // insert an horizontal line
293   fRows->Add(new TObjString("\\hline"));
294   
295
296 }
297
298 Int_t * AliLatexTable::GetColWidths() {
299
300   // Compute the width of columns, for nice ascii printing
301
302   Int_t * col_widths= new Int_t[fNcol];
303   Int_t nrow = fRows->GetEntriesFast();
304
305   for(Int_t icol = 0; icol < fNcol; icol++){
306     col_widths[icol] = 0;
307   }
308   
309
310   for(Int_t irow = 0; irow < nrow; irow++){
311     TString row(((TObjString*) fRows->At(irow))->String());
312     if(row.Contains("\\hline"))continue;
313     
314     StripLatex(row, "ASCII");
315
316     TObjArray * cols = row.Tokenize("&");
317     if(cols->GetEntries() != fNcol) {
318       Error("GetColWidths", "Wrong number of cols in row %s: %d - %d", row.Data(), cols->GetEntries(), fNcol);      
319     }
320     for(Int_t icol = 0; icol < fNcol; icol++){
321       Int_t w = ((TObjString *) cols->At(icol))->String().Length();
322       if (w>col_widths[icol]) col_widths[icol] = w;
323     }
324     
325   }
326
327   return col_widths;
328 }
329
330 void AliLatexTable::PrintTable(Option_t * opt){
331
332   // Print the table on screen. You can specify the format with opt.
333   // Currently supported:
334   // "" -> LaTeX
335   // "ASCII" -> plain ASCII
336   // "HTML"  -> HTML, to be improved
337
338   if(TString(opt) == "ASCII" || TString(opt)=="HTML") {
339     
340     Int_t nrow = fRows->GetEntriesFast();
341
342     Int_t * col_widths = GetColWidths();
343
344     Int_t total_lenght = 0;
345     for(Int_t icol = 0; icol < fNcol; icol++) total_lenght = total_lenght + col_widths[icol] + 2 ;
346     
347
348     for(Int_t irow = 0; irow < nrow; irow++){
349       TString row = ((TObjString*) fRows->At(irow))->String();
350       if (row.Contains("\\hline") ){
351         for(Int_t il = 0; il < total_lenght; il++) printf("-");
352         printf("\n");     
353         continue;
354       }
355       StripLatex(row, opt);
356       TObjArray * cols = row.Tokenize("&");
357       for(Int_t icol = 0; icol < fNcol; icol++){
358         const char * colstr = ((TObjString *) cols->At(icol))->String().Data();
359         char format [200];
360         sprintf(format, "%%%ds", col_widths[icol] + 2); 
361         printf(format, colstr);
362
363       }
364       printf ("\n");
365     }
366     
367
368     return;
369   }
370   
371
372   cout << "\\begin{tabular}{"<<fFormat<<"}"<<endl;
373
374   Int_t nrow = fRows->GetEntriesFast();
375
376   for(Int_t irow = 0; irow < nrow; irow++){
377     cout << ((TObjString*) fRows->At(irow))->String() << endl;
378   }
379   
380   cout << "\\end{tabular}" << endl;
381
382
383 }
384
385 // void AliLatexTable::ParseExponent(TString &expo){
386 // //    TString parseExponent = col;
387 //   TRegexp re = "e[+-][0-9][0-9]";
388 //   //  cout << col << endl;
389   
390 //   if(expo.Contains(re)){
391 //     Int_t index = expo.Index(re);
392 //     TString replacement = "\\cdot 10^{";
393 //     replacement = replacement + expo(index+1, 3) +"}";
394 //     //    cout << replacement <<" --- "<< endl;
395 //     replacement.ReplaceAll("+","");
396 // //     cout << "B: " << expo << endl;      
397 // //     cout << "RE " << expo(re) << endl;
398     
399 //     expo.ReplaceAll(expo(re), replacement);
400 //     //    cout << "A: " << expo << endl;      
401 //     // recursion to parse all exponents
402 //     if (expo.Contains(re)) ParseExponent(expo);
403 //   }
404 //   else Warning("", "Error parsing exponent");
405 // }
406
407 void AliLatexTable::GetMantissaAndExpBase10(Double_t num, Double_t &man, Double_t &exp) {
408
409   // Helper used to get mantissa and exponent
410
411   exp = TMath::Floor(TMath::Log10(TMath::Abs(num)));  
412   man = num / TMath::Power(10, exp);
413
414 //   cout << "" << endl;
415 //   cout << num << " = " << man << " x10^{"<<exp<<"} "   << endl;
416   
417
418 }
419
420 void AliLatexTable::StripLatex(TString &text, TString format) {
421
422   // Strip latex away for ascii and html printing. Replaces latex
423   // command with corresponding text/tags
424
425   text.ReplaceAll("\\cdot", "x");
426   text.ReplaceAll("\\pm", "+-");
427   text.ReplaceAll("$", "");
428   if (format == "ASCII") {
429     text.ReplaceAll("\\right>", ">");
430     text.ReplaceAll("\\left<", "<");
431     text.ReplaceAll("\\rangle", ">");
432     text.ReplaceAll("\\langle", "<");
433   } else if (format == "HTML") {
434     text.ReplaceAll("\\right>", "&rang;");
435     text.ReplaceAll("\\left<",  "&lang;");
436     text.ReplaceAll("\\rangle", "&rang;");
437     text.ReplaceAll("\\langle", "&lang;");
438   } 
439   if(text.Contains("multicolumn")) {
440     //    cout << "col " << text.Data() << endl;
441     // in case of multicol span, replace first column with content and
442     // add n empty cols
443     TObjArray * array = TPRegexp("multicolumn\{(.*)\\}\{.*\\}\{(.*)\\}").MatchS(text); // Added double \\ because gcc 4 triggers hard error on unknown escape sequence. Hope it still works...
444     const TString content = ((TObjString *)array->At(2))->GetString();
445     Int_t nspan   = ((TObjString *)array->At(1))->GetString().Atoi();
446     text = content;
447 //     cout << "ns " << nspan <<  ((TObjString *)array->At(1))->GetString() << endl;
448 //     cout << "t " << text << endl;
449     
450     for(Int_t ispan = 1; ispan < nspan; ispan++){
451       text+=" & ";
452     }
453     //    cout << "t " << text << endl;
454     
455   
456   }
457
458   text.ReplaceAll("\\mathrm", "");
459
460   text.ReplaceAll("\\", "");
461   text.Strip(TString::EStripType(1), ' ');
462
463 }