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