Excluding lowest pt point for K and p, ratios fit/data are now shown in 3 canvases
[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 #include <fstream>
35 #include "AliLog.h"
36
37 using namespace std;
38
39 ClassImp(AliLatexTable)
40
41 AliLatexTable::AliLatexTable() : fNcol(0), fFormat(""), fRows(0), fCols(0), fNcolReady(0){
42   // default constructor
43   fNcol = 1;
44   fFormat = "c";
45   fNcolReady = 0;
46   fRows = new TObjArray;
47   fCols = new TObjArray;
48
49   fRows->SetOwner();
50   fCols->SetOwner();
51
52 }
53
54 AliLatexTable::AliLatexTable(Int_t ncol, TString format) : fNcol(0), fFormat(""), fRows(0), fCols(0), fNcolReady(0){
55   // constructor, specify number of cols 
56   fNcol = ncol;
57   fFormat = format;
58   fNcolReady = 0;
59   fRows = new TObjArray;
60   fCols = new TObjArray;
61
62   fRows->SetOwner();
63   fCols->SetOwner();
64 }
65
66
67 AliLatexTable::~AliLatexTable() {
68
69   // dtor
70   if (fRows) delete fRows;
71   if (fCols) delete fCols;
72
73 }
74
75 void AliLatexTable::SetNextCol(Int_t val){
76   // Set next column in current row - integer
77   char col[200];
78   sprintf(col, " %d ", val);
79   SetNextCol(col);
80
81
82
83 void AliLatexTable::SetNextCol(Int_t val, Int_t err){
84
85   // Set next column in current row - int +- int
86   char col[200];
87   sprintf(col, " $%d \\pm %d$ ", val, err);
88   SetNextCol(col);
89
90
91
92 void AliLatexTable::SetNextCol(Double_t val, Int_t scientificNotation, Bool_t rounding){
93
94   // Set next column in current row - double, specify resolution
95
96   char col[200];
97   if(rounding) {
98     if(scientificNotation >= 0) {
99       char format[100];
100
101       //    cout << format << endl;    
102       Double_t mantissa, exp;
103       GetMantissaAndExpBase10(val, mantissa, exp);
104     
105       if (exp == 0) {
106         sprintf(format, " $%%%d.%df $", scientificNotation, scientificNotation);
107         sprintf(col, format, mantissa);      
108       }
109       else  {
110         sprintf(format, " $%%%d.%df \\cdot 10^{%%0.0f} $", scientificNotation, scientificNotation);
111         sprintf(col, format, mantissa, exp);
112       }
113
114
115     
116
117       SetNextCol(col);
118
119     } else {
120       char format[100];
121       sprintf(format, " $%%%d.%df $", -scientificNotation,-scientificNotation);    
122       sprintf(col, format , TMath::Nint(val*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation));
123       SetNextCol(col);
124     } 
125   }else {
126     sprintf(col, " %f ", val);
127     SetNextCol(col);
128   }
129
130
131 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Int_t scientificNotation, Bool_t rounding){
132
133   // Set next column in current row - double +- double, specify resolution
134
135   // scientific notation is used to determine number of
136   // digits in error 
137
138   //if it is > 0 exp notation is used 
139
140
141   char col[200];
142   if(rounding) {
143     if(scientificNotation >=0 ) {
144       
145       Double_t mantissa, exp;
146       GetMantissaAndExpBase10(val, mantissa, exp);
147       
148       Double_t mantissa_err, exp_err;
149       GetMantissaAndExpBase10(err, mantissa_err, exp_err);
150
151       Int_t nSigDigits =TMath::Nint(exp - exp_err);
152       if(scientificNotation != 0) nSigDigits =  nSigDigits + scientificNotation - 1;
153
154
155       char format[100];
156       if (exp == 0) {
157         sprintf(format, " $%%%d.%df \\pm %%%d.%df $", nSigDigits, nSigDigits, nSigDigits, nSigDigits);
158         sprintf(col, format, mantissa, mantissa_err/TMath::Power(10,exp - exp_err));
159       }
160       else  {
161         sprintf(format, " $%%%d.%df \\pm %%%d.%df \\cdot 10^{%%0.0f}$", nSigDigits, nSigDigits, nSigDigits, nSigDigits);
162         sprintf(col, format, mantissa, mantissa_err/TMath::Power(10,exp - exp_err), exp);
163       }
164
165
166       //cout << format << endl;
167     
168       SetNextCol(col);
169
170     } else  {
171       char format[100];
172       sprintf(format, " $%%%d.%df \\pm %%%d.%df $", -scientificNotation,-scientificNotation,-scientificNotation,-scientificNotation);    
173       sprintf(col, format , TMath::Nint(val*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation), TMath::Nint(err*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation));
174       SetNextCol(col);
175     }
176   }
177   else {
178     sprintf(col, " $%f \\pm %f$ ", val, err);
179     SetNextCol(col);
180   }
181
182
183 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Double_t errSyst, Int_t scientificNotation, Bool_t rounding){
184
185   // Set next column in current row - double +- double +- double, specify resolution
186
187   // if scientific notation is != -1 is used to determine number of
188   // digits in error 
189
190   //if it is > 0 exp notation is used 
191
192   //if it is < -1 number is truncated to the number of digits after
193   //point dictated by scientificNotation,
194
195   char col[200];
196   if (rounding) {
197     if(scientificNotation >=0 ) {
198
199       Double_t mantissa, exp;
200       GetMantissaAndExpBase10(val, mantissa, exp);
201
202       Double_t mantissa_err, exp_err;
203       GetMantissaAndExpBase10(err, mantissa_err, exp_err);
204
205       Double_t mantissa_errsyst, exp_errsyst;
206       GetMantissaAndExpBase10(errSyst, mantissa_errsyst, exp_errsyst);
207
208       Int_t nSigDigits =TMath::Nint(exp - exp_err);
209       if(scientificNotation != 0) nSigDigits =  nSigDigits + scientificNotation - 1;
210
211
212       char format[100];
213       if (exp == 0) {
214         sprintf(format, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df $", 
215                 nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
216         sprintf(col, format, mantissa, 
217                 mantissa_err/TMath::Power(10,exp - exp_err), 
218                 mantissa_errsyst/TMath::Power(10,exp - exp_errsyst));
219       }
220       else  {
221         sprintf(format, " $%%%d.%df \\pm %%%d.%df  \\pm %%%d.%df \\cdot 10^{%%0.0f}$", 
222                 nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
223         sprintf(col, format, mantissa, 
224                 mantissa_err/TMath::Power(10,exp - exp_err), 
225                 mantissa_errsyst/TMath::Power(10,exp - exp_errsyst),
226                 exp);
227       }
228
229
230       //cout << format << endl;
231     
232       SetNextCol(col);
233
234     } else  {
235       char format[100];
236       sprintf(format, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df $", -scientificNotation,-scientificNotation,-scientificNotation,-scientificNotation, -scientificNotation,-scientificNotation);    
237       sprintf(col, format ,TMath::Nint(val*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation), TMath::Nint(err*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation), TMath::Nint(errSyst*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation));
238       SetNextCol(col);
239     } 
240   }
241   else {
242     sprintf(col, " $%f \\pm %f  \\pm %f$ ", val, err, errSyst);
243     SetNextCol(col);
244   }
245
246
247 // void AliLatexTable::SetNextColPrintf(const char *va_(fmt), ...){
248
249
250 //   const Int_t buf_size = 1024;  // hope it's long enough
251 //   char colBuffer[buf_size];
252
253 //   va_list ap;
254 //   va_start(ap, va_(fmt));
255 //   Int_t n = vsnprintf(colBuffer, buf_size, fmt, ap);
256
257 //   if (n == -1 || n >= buf_size) {
258 //     Error("SetNextCol", "vsnprintf error!");
259 //   }
260
261 //   va_end(ap);
262      
263 // //   for(int iobj=0; iobj<num; iobj++){   //Loop until all objects are added
264 // //     TH1 * obj = (TH1 *) va_arg(arguments, void *);
265 // //     returnValue = returnValue && AddObject(obj,(char*)fOptMany.Data(), EColor(iobj+1));
266 // //   }
267 //   SetNextCol(colBuffer);
268 // }
269
270
271 void AliLatexTable::SetNextCol(TString val){
272
273   // Set next column in current row - tstring
274
275   fCols->Add(new TObjString(val));
276   fNcolReady++;
277
278
279
280 void AliLatexTable::InsertCustomRow(TString row){
281   // insert a full row from string. Make sure you have all the columns
282   fRows->Add(new TObjString(row));
283 }
284
285
286
287 void AliLatexTable::InsertRow(){
288
289   // Insert the row, based on all the individual columns
290
291   if ( fNcolReady != fNcol) {
292     Warning("InsertRow", "Wrong number of cols: %d (!= %d)", fNcolReady, fNcol); 
293   }
294
295   TString row = "";
296   for(Int_t icol = 0; icol < fNcol; icol++){
297     row = row + ((TObjString*) fCols->At(icol))->String();
298     if(icol != (fNcol-1)) row = row + " & ";
299   }
300   row+="\\\\";
301
302   fRows->Add(new TObjString(row));
303
304   fNcolReady = 0;
305   fCols->Clear();
306
307 }
308
309 void AliLatexTable::InsertHline(){
310
311   // insert an horizontal line
312   fRows->Add(new TObjString("\\hline"));
313   
314
315 }
316
317 Int_t * AliLatexTable::GetColWidths() {
318
319   // Compute the width of columns, for nice ascii printing
320
321   Int_t * col_widths= new Int_t[fNcol];
322   Int_t nrow = fRows->GetEntriesFast();
323
324   for(Int_t icol = 0; icol < fNcol; icol++){
325     col_widths[icol] = 0;
326   }
327   
328
329   for(Int_t irow = 0; irow < nrow; irow++){
330     TString row(((TObjString*) fRows->At(irow))->String());
331     if(row.Contains("\\hline"))continue;
332     
333     StripLatex(row, "ASCII");
334
335     TObjArray * cols = row.Tokenize("&");
336     if(cols->GetEntries() != fNcol) {
337       Error("GetColWidths", "Wrong number of cols in row %s: %d - %d", row.Data(), cols->GetEntries(), fNcol);      
338     }
339     for(Int_t icol = 0; icol < fNcol; icol++){
340       Int_t w = ((TObjString *) cols->At(icol))->String().Length();
341       if (w>col_widths[icol]) col_widths[icol] = w;
342     }
343     
344   }
345
346   return col_widths;
347 }
348
349 void AliLatexTable::PrintTable(Option_t * opt){
350
351   // Print the table on screen. You can specify the format with opt.
352   // Currently supported:
353   // "" -> LaTeX
354   // "ASCII" -> plain ASCII
355   // "HTML"  -> HTML, to be improved
356   // "CSV"   -> skips hline, usefult for importing in excell 
357   // "TWIKI" -> skips hline, usefult for importing in TWIKI
358
359   if(TString(opt) == "ASCII" || TString(opt)=="HTML" ||  TString(opt)=="CSV" ||  TString(opt)=="TWIKI") {
360     
361     Int_t nrow = fRows->GetEntriesFast();
362
363     Int_t * col_widths = GetColWidths();
364
365     Int_t total_lenght = 0;
366     for(Int_t icol = 0; icol < fNcol; icol++) total_lenght = total_lenght + col_widths[icol] + 2 ;
367     
368
369     for(Int_t irow = 0; irow < nrow; irow++){
370       TString row = ((TObjString*) fRows->At(irow))->String();
371       if (row.Contains("\\hline")){     
372         if (TString(opt)!="CSV" && TString(opt)!="TWIKI") {
373           for(Int_t il = 0; il < total_lenght; il++) printf("-");
374           printf("\n");   
375         }
376         continue;
377       }
378       StripLatex(row, opt);
379       TObjArray * cols = row.Tokenize("&");
380       if (TString(opt)=="TWIKI") printf(" | ");
381       for(Int_t icol = 0; icol < fNcol; icol++){
382         TString strTmp = ((TObjString *) cols->At(icol))->String();
383         if(TString(opt)=="TWIKI" || TString(opt)=="HTML"){
384           strTmp.ReplaceAll("AMPER","&");
385         }
386         const char * colstr = strTmp.Data();
387         char format [200];
388         if (TString(opt)!="CSV") {
389           sprintf(format, "%%%ds", col_widths[icol] + 2);       
390         } else {
391           sprintf(format, "%%s");       
392         }
393         printf(format, colstr);
394         if (TString(opt)=="CSV") printf(", ");
395         if (TString(opt)=="TWIKI") printf(" | ");
396
397       }
398       printf ("\n");
399     }
400     
401
402     return;
403   }
404   
405
406   cout << "\\begin{tabular}{"<<fFormat<<"}"<<endl;
407
408   Int_t nrow = fRows->GetEntriesFast();
409
410   for(Int_t irow = 0; irow < nrow; irow++){
411     cout << ((TObjString*) fRows->At(irow))->String() << endl;
412   }
413   
414   cout << "\\end{tabular}" << endl;
415
416
417 }
418
419 // void AliLatexTable::ParseExponent(TString &expo){
420 // //    TString parseExponent = col;
421 //   TRegexp re = "e[+-][0-9][0-9]";
422 //   //  cout << col << endl;
423   
424 //   if(expo.Contains(re)){
425 //     Int_t index = expo.Index(re);
426 //     TString replacement = "\\cdot 10^{";
427 //     replacement = replacement + expo(index+1, 3) +"}";
428 //     //    cout << replacement <<" --- "<< endl;
429 //     replacement.ReplaceAll("+","");
430 // //     cout << "B: " << expo << endl;      
431 // //     cout << "RE " << expo(re) << endl;
432     
433 //     expo.ReplaceAll(expo(re), replacement);
434 //     //    cout << "A: " << expo << endl;      
435 //     // recursion to parse all exponents
436 //     if (expo.Contains(re)) ParseExponent(expo);
437 //   }
438 //   else Warning("", "Error parsing exponent");
439 // }
440
441 void AliLatexTable::GetMantissaAndExpBase10(Double_t num, Double_t &man, Double_t &exp) {
442
443   // Helper used to get mantissa and exponent
444
445   exp = TMath::Floor(TMath::Log10(TMath::Abs(num)));  
446   man = num / TMath::Power(10, exp);
447
448 //   cout << "" << endl;
449 //   cout << num << " = " << man << " x10^{"<<exp<<"} "   << endl;
450   
451
452 }
453
454 void AliLatexTable::StripLatex(TString &text, TString format) {
455
456   // Strip latex away for ascii and html printing. Replaces latex
457   // command with corresponding text/tags
458
459   text.ReplaceAll("\\cdot", "x");
460   text.ReplaceAll("$", "");
461   if (format == "ASCII") {
462     text.ReplaceAll("\\right>", ">");
463     text.ReplaceAll("\\left<", "<");
464     text.ReplaceAll("\\rangle", ">");
465     text.ReplaceAll("\\langle", "<");
466     text.ReplaceAll("\\pm", "+-");
467   } else if (format == "HTML" || format == "TWIKI") {
468     // the & is used to tokenize... Have to cheat here
469     text.ReplaceAll("\\right>", "AMPERrang;");
470     text.ReplaceAll("\\left<",  "AMPERlang;");
471     text.ReplaceAll("\\rangle", "AMPERrang;");
472     text.ReplaceAll("\\langle", "AMPERlang;");
473     text.ReplaceAll("\\pm",     "AMPERplusmn;");
474   } 
475   if(text.Contains("multicolumn")) {
476     //    cout << "col " << text.Data() << endl;
477     // in case of multicol span, replace first column with content and
478     // add n empty cols
479     TObjArray * array = TPRegexp("multicolumn\\{(.*)\\}\\{.*\\}\\{(.*)\\}").MatchS(text); // Added double \\ because gcc 4 triggers hard error on unknown escape sequence. Hope it still works...
480     const TString content = ((TObjString *)array->At(2))->GetString();
481     Int_t nspan   = ((TObjString *)array->At(1))->GetString().Atoi();
482     text = content;
483 //     cout << "ns " << nspan <<  ((TObjString *)array->At(1))->GetString() << endl;
484 //     cout << "t " << text << endl;
485     
486     for(Int_t ispan = 1; ispan < nspan; ispan++){
487       text+=" & ";
488     }
489     //    cout << "t " << text << endl;
490     
491   
492   }
493
494   text.ReplaceAll("\\mathrm", "");
495
496   text.ReplaceAll("\\", "");
497   text.Strip(TString::EStripType(1), ' ');
498
499 }
500
501 void AliLatexTable::LoadTeXFromFileAndPrintASCII(const char * filename) {
502
503   // opens a file containing only a latex table and prints it on screen as ASCII
504
505   ifstream file (filename);
506   if (!file.is_open()) {
507     AliError(Form("Cannot open file %s", filename));
508   }
509   TString line;
510   while (line.ReadLine(file)) {
511     if (line.Contains("begin") && line.Contains("tabular")) {
512       // We need to get and parse the format
513       //      TPRegexp re("\\begin\\{tabular\\}\\{([^\\}]*)\\}");
514       TPRegexp re(".*begin{tabular}{(.*)}");
515       TObjArray * arr = re.MatchS(line);
516       if (arr->GetLast() > 0){ 
517         //      cout << "Size: " << arr->GetSize() << " " << arr->GetLast() << endl;
518         
519         TString subStr = ((TObjString *)arr->At(1))->GetString();
520         subStr.ReplaceAll("|","");
521         subStr.ReplaceAll(" ","");
522         subStr.ReplaceAll("\t","");
523         //      subStr.ReplaceAll(" ","");      
524         //      cout << subStr.Data() << " " << subStr.Length()<< endl;
525         fNcol = subStr.Length();
526         delete arr;
527       }
528     }
529
530     // Skip stuff we don't parse
531     if (line.Contains("begin")) continue;
532     if (line.Contains("end")) continue;
533     if (line.Contains("tabular")) continue;
534     // add line
535     InsertCustomRow(line.Data());
536     
537   }
538   PrintTable("ASCII");
539 }