AliPhysics  ced2227 (ced2227)
AliLatexTable.cxx
Go to the documentation of this file.
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 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.
15 //
16 // TODO:
17 // 1. Make the class drawable
18 // 2. Implement vertical lines in ascii print
19 // 3. Improve output in HTML format
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>
35 #include <fstream>
36 #include "AliLog.h"
37 
38 using namespace std;
39 
40 ClassImp(AliLatexTable)
41 
42 AliLatexTable::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 
55 AliLatexTable::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 
69 
70  // dtor
71  if (fRows) delete fRows;
72  if (fCols) delete fCols;
73 
74 }
75 
77  // Set next column in current row - integer
78  char col[200];
79  snprintf(col, 200, " %d ", val);
80  SetNextCol(col);
81 
82 }
83 
85 
86  // Set next column in current row - int +- int
87  char col[200];
88  snprintf(col, 200, " $%d \\pm %d$ ", val, err);
89  SetNextCol(col);
90 
91 }
92 
93 void AliLatexTable::SetNextCol(Double_t val, Int_t scientificNotation, Bool_t rounding){
94 
95  // Set next column in current row - double, specify resolution
96 
97  char col[200];
98  if(rounding) {
99  if(scientificNotation >= 0) {
100  char format[100];
101 
102  // cout << format << endl;
103  Double_t mantissa, exp;
104  GetMantissaAndExpBase10(val, mantissa, exp);
105 
106  if (exp == 0) {
107  snprintf(format, 100," $%%%d.%df $", scientificNotation, scientificNotation);
108  snprintf(col, 200, format, mantissa);
109  }
110  else {
111  snprintf(format, 100," $%%%d.%df \\cdot 10^{%%0.0f} $", scientificNotation, scientificNotation);
112  snprintf(col, 200,format, mantissa, exp);
113  }
114 
115 
116 
117 
118  SetNextCol(col);
119 
120  } else {
121  char format[100];
122  snprintf(format, 100," $%%%d.%df $", -scientificNotation,-scientificNotation);
123  snprintf(col, 200, format , TMath::Nint(val*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation));
124  SetNextCol(col);
125  }
126  }else {
127  snprintf(col,200, " %f ", val);
128  SetNextCol(col);
129  }
130 
131 }
132 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Int_t scientificNotation, Bool_t rounding){
133 
134  // Set next column in current row - double +- double, specify resolution
135 
136  // scientific notation is used to determine number of
137  // digits in error
138 
139  //if it is > 0 exp notation is used
140 
141 
142  char col[200];
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) {
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));
160  }
161  else {
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);
164  }
165 
166 
167  //cout << format << endl;
168 
169  SetNextCol(col);
170 
171  } else {
172  char format[100];
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));
175  SetNextCol(col);
176  }
177  }
178  else {
179  snprintf(col, 200, " $%f \\pm %f$ ", val, err);
180  SetNextCol(col);
181  }
182 }
183 
184 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Double_t errSyst, Int_t scientificNotation, Bool_t rounding){
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];
197  if (rounding) {
198  if(scientificNotation >=0 ) {
199 
200  Double_t mantissa, exp;
201  GetMantissaAndExpBase10(val, mantissa, exp);
202 
203  Double_t mantissa_err, exp_err;
204  GetMantissaAndExpBase10(err, mantissa_err, exp_err);
205 
206  Double_t mantissa_errsyst, exp_errsyst;
207  GetMantissaAndExpBase10(errSyst, mantissa_errsyst, exp_errsyst);
208 
209  Int_t nSigDigits =TMath::Nint(exp - exp_err);
210  if(scientificNotation != 0) nSigDigits = nSigDigits + scientificNotation - 1;
211 
212 
213  char format[100];
214  if (exp == 0) {
215  snprintf(format, 100, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df $",
216  nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
217  snprintf(col, 200, format, mantissa,
218  mantissa_err/TMath::Power(10,exp - exp_err),
219  mantissa_errsyst/TMath::Power(10,exp - exp_errsyst));
220  }
221  else {
222  snprintf(format, 100, " $%%%d.%df \\pm %%%d.%df \\pm %%%d.%df \\cdot 10^{%%0.0f}$",
223  nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits, nSigDigits);
224  snprintf(col, 200, format, mantissa,
225  mantissa_err/TMath::Power(10,exp - exp_err),
226  mantissa_errsyst/TMath::Power(10,exp - exp_errsyst),
227  exp);
228  }
229 
230 
231  //cout << format << endl;
232 
233  SetNextCol(col);
234 
235  } else {
236  char format[100];
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));
239  SetNextCol(col);
240  }
241  }
242  else {
243  snprintf(col, 200, " $%f \\pm %f \\pm %f$ ", val, err, errSyst);
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 
273 
274  // Set next column in current row - tstring
275 
276  fCols->Add(new TObjString(val));
277  fNcolReady++;
278 
279 }
280 
282  // insert a full row from string. Make sure you have all the columns
283  fRows->Add(new TObjString(row));
284 }
285 
286 
287 
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  return;
295  } else if (fNcolReady < fNcol) {
296  Warning("InsertRow", "Not enough columns provided, filling with empty cols");
297  for(Int_t icol = fNcolReady; icol < fNcol; icol++){
298  SetNextCol("");
299  }
300 
301  }
302 
303  TString row = "";
304  for(Int_t icol = 0; icol < fNcol; icol++){
305  row = row + ((TObjString*) fCols->At(icol))->String();
306  if(icol != (fNcol-1)) row = row + " & ";
307  }
308  row+="\\\\";
309 
310  fRows->Add(new TObjString(row));
311 
312  fNcolReady = 0;
313  fCols->Clear();
314 
315 }
316 
318 
319  // insert an horizontal line
320  fRows->Add(new TObjString("\\hline"));
321 
322 
323 }
324 
326 
327  // Compute the width of columns, for nice ascii printing
328 
329  Int_t * col_widths= new Int_t[fNcol];
330  Int_t nrow = fRows->GetEntriesFast();
331 
332  for(Int_t icol = 0; icol < fNcol; icol++){
333  col_widths[icol] = 0;
334  }
335 
336 
337  for(Int_t irow = 0; irow < nrow; irow++){
338  TString row(((TObjString*) fRows->At(irow))->String());
339  if(row.Contains("\\hline"))continue;
340 
341  StripLatex(row, "ASCII");
342 
343  TObjArray * cols = row.Tokenize("&");
344  if(cols->GetEntries() != fNcol) {
345  Error("GetColWidths", "Wrong number of cols in row %s: %d - %d", row.Data(), cols->GetEntries(), fNcol);
346  }
347  for(Int_t icol = 0; icol < fNcol; icol++){
348  Int_t w = ((TObjString *) cols->At(icol))->String().Length();
349  if (w>col_widths[icol]) col_widths[icol] = w;
350  }
351  delete cols;
352  }
353 
354  return col_widths;
355 }
356 
358 
359  // Print the table on screen. You can specify the format with opt.
360  // Currently supported:
361  // "" -> LaTeX
362  // "ASCII" -> plain ASCII
363  // "HTML" -> HTML, to be improved
364  // "CSV" -> skips hline, usefult for importing in excell
365  // "TWIKI" -> skips hline, usefult for importing in TWIKI
366  // "MD" -> Print a markdown table
367 
368  if(TString(opt) == "ASCII" || TString(opt)=="HTML" || TString(opt)=="CSV" || TString(opt)=="TWIKI" || TString(opt) == "MD") {
369 
370  Int_t nrow = fRows->GetEntriesFast();
371 
372  Int_t * colWidths = GetColWidths();
373 
374  Int_t total_lenght = 0;
375  for(Int_t icol = 0; icol < fNcol; icol++) total_lenght = total_lenght + colWidths[icol] + 2 ;
376 
377 
378 
379  for(Int_t irow = 0; irow < nrow; irow++){
380  TString row = ((TObjString*) fRows->At(irow))->String();
381  if (row.Contains("\\hline")){
382  if (TString(opt) == "MD") {
383  for(Int_t icol = 0; icol < fNcol; icol++) { // the +2 compensates for the | which are not counted in the column width
384  printf("|");
385  for(Int_t ilen = 0; ilen < (colWidths[icol]+2); ilen++){
386  printf("-");
387  }
388  }
389  printf("|");
390  printf("\n");
391  }
392  else if (TString(opt)!="CSV" && TString(opt)!="TWIKI") {
393  for(Int_t il = 0; il < total_lenght; il++) printf("-");
394  printf("\n");
395  }
396 
397  continue;
398  }
399  StripLatex(row, opt);
400  TObjArray * cols = row.Tokenize("&");
401  for(Int_t icol = 0; icol < fNcol; icol++){
402  if (TString(opt)=="TWIKI" || TString(opt)=="MD") printf("|");
403  TString strTmp = ((TObjString *) cols->At(icol))->String();
404  if(TString(opt)=="TWIKI" || TString(opt)=="HTML"){
405  strTmp.ReplaceAll("AMPER","&");
406  }
407  const char * colstr = strTmp.Data();
408  char format [200];
409  if (TString(opt)!="CSV") {
410  snprintf(format, 200, "%%%ds", colWidths[icol] + 2);
411  } else {
412  snprintf(format, 200, "%%s");
413  }
414  printf(format, colstr);
415  if (TString(opt)=="CSV") printf(", ");
416  if (TString(opt)=="TWIKI") printf(" | ");
417 
418  }
419  if (TString(opt)=="TWIKI" || TString(opt)=="MD") printf("|");
420  printf ("\n");
421  delete cols;
422  }
423 
424  delete [] colWidths;
425  return;
426  }
427 
428 
429  cout << "\\begin{tabular}{"<<fFormat<<"}"<<endl;
430 
431  Int_t nrow = fRows->GetEntriesFast();
432 
433  for(Int_t irow = 0; irow < nrow; irow++){
434  cout << ((TObjString*) fRows->At(irow))->String() << endl;
435  }
436 
437  cout << "\\end{tabular}" << endl;
438 
439 
440 }
441 
442 // void AliLatexTable::ParseExponent(TString &expo){
443 // // TString parseExponent = col;
444 // TRegexp re = "e[+-][0-9][0-9]";
445 // // cout << col << endl;
446 
447 // if(expo.Contains(re)){
448 // Int_t index = expo.Index(re);
449 // TString replacement = "\\cdot 10^{";
450 // replacement = replacement + expo(index+1, 3) +"}";
451 // // cout << replacement <<" --- "<< endl;
452 // replacement.ReplaceAll("+","");
453 // // cout << "B: " << expo << endl;
454 // // cout << "RE " << expo(re) << endl;
455 
456 // expo.ReplaceAll(expo(re), replacement);
457 // // cout << "A: " << expo << endl;
458 // // recursion to parse all exponents
459 // if (expo.Contains(re)) ParseExponent(expo);
460 // }
461 // else Warning("", "Error parsing exponent");
462 // }
463 
465 
466  // Helper used to get mantissa and exponent
467 
468  exp = TMath::Floor(TMath::Log10(TMath::Abs(num)));
469  man = num / TMath::Power(10, exp);
470 
471 // cout << "" << endl;
472 // cout << num << " = " << man << " x10^{"<<exp<<"} " << endl;
473 
474 
475 }
476 
478 
479  // Strip latex away for ascii and html printing. Replaces latex
480  // command with corresponding text/tags
481 
482  text.ReplaceAll("\\cdot", "x");
483  text.ReplaceAll("$", "");
484  if (format == "ASCII" || format == "MD") {
485  text.ReplaceAll("\\right>", ">");
486  text.ReplaceAll("\\left<", "<");
487  text.ReplaceAll("\\rangle", ">");
488  text.ReplaceAll("\\langle", "<");
489  text.ReplaceAll("\\pm", "+-");
490  } else if (format == "HTML" || format == "TWIKI") {
491  // the & is used to tokenize... Have to cheat here
492  text.ReplaceAll("\\right>", "AMPERrang;");
493  text.ReplaceAll("\\left<", "AMPERlang;");
494  text.ReplaceAll("\\rangle", "AMPERrang;");
495  text.ReplaceAll("\\langle", "AMPERlang;");
496  text.ReplaceAll("\\pm", "AMPERplusmn;");
497  }
498  if(text.Contains("multicolumn")) {
499  // cout << "col " << text.Data() << endl;
500  // in case of multicol span, replace first column with content and
501  // add n empty cols
502  TObjArray * array = TPRegexp("multicolumn\\{([^}]*)\\}\\{[^}]*\\}\\{([^]]*)\\}").MatchS(text); // Added double \\ because gcc 4 triggers hard error on unknown escape sequence. Hope it still works...
503  const TString content = ((TObjString *)array->At(2))->GetString();
504  Int_t nspan = ((TObjString *)array->At(1))->GetString().Atoi();
505  text = content;
506  // cout << "ns " << nspan << ((TObjString *)array->At(1))->GetString() << endl;
507  // cout << "t " << text << endl;
508 
509  for(Int_t ispan = 1; ispan < nspan; ispan++){
510  text+=" & ";
511  }
512  // cout << "t " << text << endl;
513 
514 
515  }
516 
517  text.ReplaceAll("\\mathrm", "");
518 
519  text.ReplaceAll("\\", "");
520  text.Strip(TString::EStripType(1), ' ');
521 
522 }
523 
525 
526  // opens a file containing only a latex table and prints it on screen as ASCII
527 
528  ifstream file (filename);
529  if (!file.is_open()) {
530  AliError(Form("Cannot open file %s", filename));
531  }
532  TString line;
533  while (line.ReadLine(file)) {
534  if (line.Contains("begin") && line.Contains("tabular")) {
535  // We need to get and parse the format
536  // TPRegexp re("\\begin\\{tabular\\}\\{([^\\}]*)\\}");
537  TPRegexp re(".*begin{tabular}{(.*)}");
538  TObjArray * arr = re.MatchS(line);
539  if (arr->GetLast() > 0){
540  // cout << "Size: " << arr->GetSize() << " " << arr->GetLast() << endl;
541 
542  TString subStr = ((TObjString *)arr->At(1))->GetString();
543  subStr.ReplaceAll("|","");
544  subStr.ReplaceAll(" ","");
545  subStr.ReplaceAll("\t","");
546  // subStr.ReplaceAll(" ","");
547  // cout << subStr.Data() << " " << subStr.Length()<< endl;
548  fNcol = subStr.Length();
549  delete arr;
550  }
551  }
552 
553  // Skip stuff we don't parse
554  if (line.Contains("begin")) continue;
555  if (line.Contains("end")) continue;
556  if (line.Contains("tabular")) continue;
557  // add line
558  InsertCustomRow(line.Data());
559 
560  }
561  PrintTable("ASCII");
562 }
const char * filename
Definition: TestFCM.C:1
double Double_t
Definition: External.C:58
TString format
file names tag, basically the trigger and calorimeter combination
void LoadTeXFromFileAndPrintASCII(const char *filename)
void PrintTable(Option_t *opt="")
TLatex * text[5]
option to what and if export to output file
TString fFormat
Definition: AliLatexTable.h:63
void SetNextCol(Int_t val)
void InsertCustomRow(TString row)
int Int_t
Definition: External.C:63
TObjArray * fCols
Definition: AliLatexTable.h:66
Int_t * GetColWidths()
void GetMantissaAndExpBase10(Double_t num, Double_t &man, Double_t &exp)
TFile * file
TList with histograms for a given trigger.
const char Option_t
Definition: External.C:48
bool Bool_t
Definition: External.C:53
void StripLatex(TString &row, TString format)
TObjArray * fRows
Definition: AliLatexTable.h:65