1 // ------------------------------------------------------------------
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)
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,
16 // 1. Make the class drawable
17 // 2. Implement vertical lines in ascii print
18 // 3. Print output in HTML format
20 // Author: Michele Floris, CERN
21 // ------------------------------------------------------------------
23 #include "AliLatexTable.h"
26 #include "TObjString.h"
27 #include "TObjArray.h"
39 ClassImp(AliLatexTable)
41 AliLatexTable::AliLatexTable() : fNcol(0), fFormat(""), fRows(0), fCols(0), fNcolReady(0){
42 // default constructor
46 fRows = new TObjArray;
47 fCols = new TObjArray;
54 AliLatexTable::AliLatexTable(Int_t ncol, TString format) : fNcol(0), fFormat(""), fRows(0), fCols(0), fNcolReady(0){
55 // constructor, specify number of cols
59 fRows = new TObjArray;
60 fCols = new TObjArray;
67 AliLatexTable::~AliLatexTable() {
70 if (fRows) delete fRows;
71 if (fCols) delete fCols;
75 void AliLatexTable::SetNextCol(Int_t val){
76 // Set next column in current row - integer
78 sprintf(col, " %d ", val);
83 void AliLatexTable::SetNextCol(Int_t val, Int_t err){
85 // Set next column in current row - int +- int
87 sprintf(col, " $%d \\pm %d$ ", val, err);
92 void AliLatexTable::SetNextCol(Double_t val, Int_t scientificNotation, Bool_t rounding){
94 // Set next column in current row - double, specify resolution
98 if(scientificNotation >= 0) {
101 // cout << format << endl;
102 Double_t mantissa, exp;
103 GetMantissaAndExpBase10(val, mantissa, exp);
106 sprintf(format, " $%%%d.%df $", scientificNotation, scientificNotation);
107 sprintf(col, format, mantissa);
110 sprintf(format, " $%%%d.%df \\cdot 10^{%%0.0f} $", scientificNotation, scientificNotation);
111 sprintf(col, format, mantissa, exp);
121 sprintf(format, " $%%%d.%df $", -scientificNotation,-scientificNotation);
122 sprintf(col, format , TMath::Nint(val*TMath::Power(10,-scientificNotation))/TMath::Power(10,-scientificNotation));
126 sprintf(col, " %f ", val);
131 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Int_t scientificNotation, Bool_t rounding){
133 // Set next column in current row - double +- double, specify resolution
135 // scientific notation is used to determine number of
138 //if it is > 0 exp notation is used
143 if(scientificNotation >=0 ) {
145 Double_t mantissa, exp;
146 GetMantissaAndExpBase10(val, mantissa, exp);
148 Double_t mantissa_err, exp_err;
149 GetMantissaAndExpBase10(err, mantissa_err, exp_err);
151 Int_t nSigDigits =TMath::Nint(exp - exp_err);
152 if(scientificNotation != 0) nSigDigits = nSigDigits + scientificNotation - 1;
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));
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);
166 //cout << format << endl;
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));
178 sprintf(col, " $%f \\pm %f$ ", val, err);
183 void AliLatexTable::SetNextCol(Double_t val, Double_t err, Double_t errSyst, Int_t scientificNotation, Bool_t rounding){
185 // Set next column in current row - double +- double +- double, specify resolution
187 // if scientific notation is != -1 is used to determine number of
190 //if it is > 0 exp notation is used
192 //if it is < -1 number is truncated to the number of digits after
193 //point dictated by scientificNotation,
197 if(scientificNotation >=0 ) {
199 Double_t mantissa, exp;
200 GetMantissaAndExpBase10(val, mantissa, exp);
202 Double_t mantissa_err, exp_err;
203 GetMantissaAndExpBase10(err, mantissa_err, exp_err);
205 Double_t mantissa_errsyst, exp_errsyst;
206 GetMantissaAndExpBase10(errSyst, mantissa_errsyst, exp_errsyst);
208 Int_t nSigDigits =TMath::Nint(exp - exp_err);
209 if(scientificNotation != 0) nSigDigits = nSigDigits + scientificNotation - 1;
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));
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),
230 //cout << format << endl;
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));
242 sprintf(col, " $%f \\pm %f \\pm %f$ ", val, err, errSyst);
247 // void AliLatexTable::SetNextColPrintf(const char *va_(fmt), ...){
250 // const Int_t buf_size = 1024; // hope it's long enough
251 // char colBuffer[buf_size];
254 // va_start(ap, va_(fmt));
255 // Int_t n = vsnprintf(colBuffer, buf_size, fmt, ap);
257 // if (n == -1 || n >= buf_size) {
258 // Error("SetNextCol", "vsnprintf error!");
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));
267 // SetNextCol(colBuffer);
271 void AliLatexTable::SetNextCol(TString val){
273 // Set next column in current row - tstring
275 fCols->Add(new TObjString(val));
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));
287 void AliLatexTable::InsertRow(){
289 // Insert the row, based on all the individual columns
291 if ( fNcolReady != fNcol) {
292 Warning("InsertRow", "Wrong number of cols: %d (!= %d)", fNcolReady, fNcol);
296 for(Int_t icol = 0; icol < fNcol; icol++){
297 row = row + ((TObjString*) fCols->At(icol))->String();
298 if(icol != (fNcol-1)) row = row + " & ";
302 fRows->Add(new TObjString(row));
309 void AliLatexTable::InsertHline(){
311 // insert an horizontal line
312 fRows->Add(new TObjString("\\hline"));
317 Int_t * AliLatexTable::GetColWidths() {
319 // Compute the width of columns, for nice ascii printing
321 Int_t * col_widths= new Int_t[fNcol];
322 Int_t nrow = fRows->GetEntriesFast();
324 for(Int_t icol = 0; icol < fNcol; icol++){
325 col_widths[icol] = 0;
329 for(Int_t irow = 0; irow < nrow; irow++){
330 TString row(((TObjString*) fRows->At(irow))->String());
331 if(row.Contains("\\hline"))continue;
333 StripLatex(row, "ASCII");
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);
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;
349 void AliLatexTable::PrintTable(Option_t * opt){
351 // Print the table on screen. You can specify the format with opt.
352 // Currently supported:
354 // "ASCII" -> plain ASCII
355 // "HTML" -> HTML, to be improved
356 // "CSV" -> skips hline, usefult for importing in excell
358 if(TString(opt) == "ASCII" || TString(opt)=="HTML" || TString(opt)=="CSV") {
360 Int_t nrow = fRows->GetEntriesFast();
362 Int_t * col_widths = GetColWidths();
364 Int_t total_lenght = 0;
365 for(Int_t icol = 0; icol < fNcol; icol++) total_lenght = total_lenght + col_widths[icol] + 2 ;
368 for(Int_t irow = 0; irow < nrow; irow++){
369 TString row = ((TObjString*) fRows->At(irow))->String();
370 if (row.Contains("\\hline")){
371 if (TString(opt)!="CSV") {
372 for(Int_t il = 0; il < total_lenght; il++) printf("-");
377 StripLatex(row, opt);
378 TObjArray * cols = row.Tokenize("&");
379 for(Int_t icol = 0; icol < fNcol; icol++){
380 const char * colstr = ((TObjString *) cols->At(icol))->String().Data();
382 if (TString(opt)!="CSV") {
383 sprintf(format, "%%%ds", col_widths[icol] + 2);
385 sprintf(format, "%%s");
387 printf(format, colstr);
388 if (TString(opt)=="CSV") printf(", ");
399 cout << "\\begin{tabular}{"<<fFormat<<"}"<<endl;
401 Int_t nrow = fRows->GetEntriesFast();
403 for(Int_t irow = 0; irow < nrow; irow++){
404 cout << ((TObjString*) fRows->At(irow))->String() << endl;
407 cout << "\\end{tabular}" << endl;
412 // void AliLatexTable::ParseExponent(TString &expo){
413 // // TString parseExponent = col;
414 // TRegexp re = "e[+-][0-9][0-9]";
415 // // cout << col << endl;
417 // if(expo.Contains(re)){
418 // Int_t index = expo.Index(re);
419 // TString replacement = "\\cdot 10^{";
420 // replacement = replacement + expo(index+1, 3) +"}";
421 // // cout << replacement <<" --- "<< endl;
422 // replacement.ReplaceAll("+","");
423 // // cout << "B: " << expo << endl;
424 // // cout << "RE " << expo(re) << endl;
426 // expo.ReplaceAll(expo(re), replacement);
427 // // cout << "A: " << expo << endl;
428 // // recursion to parse all exponents
429 // if (expo.Contains(re)) ParseExponent(expo);
431 // else Warning("", "Error parsing exponent");
434 void AliLatexTable::GetMantissaAndExpBase10(Double_t num, Double_t &man, Double_t &exp) {
436 // Helper used to get mantissa and exponent
438 exp = TMath::Floor(TMath::Log10(TMath::Abs(num)));
439 man = num / TMath::Power(10, exp);
441 // cout << "" << endl;
442 // cout << num << " = " << man << " x10^{"<<exp<<"} " << endl;
447 void AliLatexTable::StripLatex(TString &text, TString format) {
449 // Strip latex away for ascii and html printing. Replaces latex
450 // command with corresponding text/tags
452 text.ReplaceAll("\\cdot", "x");
453 text.ReplaceAll("\\pm", "+-");
454 text.ReplaceAll("$", "");
455 if (format == "ASCII") {
456 text.ReplaceAll("\\right>", ">");
457 text.ReplaceAll("\\left<", "<");
458 text.ReplaceAll("\\rangle", ">");
459 text.ReplaceAll("\\langle", "<");
460 } else if (format == "HTML") {
461 text.ReplaceAll("\\right>", "⟩");
462 text.ReplaceAll("\\left<", "⟨");
463 text.ReplaceAll("\\rangle", "⟩");
464 text.ReplaceAll("\\langle", "⟨");
466 if(text.Contains("multicolumn")) {
467 // cout << "col " << text.Data() << endl;
468 // in case of multicol span, replace first column with content and
470 TObjArray * array = TPRegexp("multicolumn\\{(.*)\\}\\{.*\\}\\{(.*)\\}").MatchS(text); // Added double \\ because gcc 4 triggers hard error on unknown escape sequence. Hope it still works...
471 const TString content = ((TObjString *)array->At(2))->GetString();
472 Int_t nspan = ((TObjString *)array->At(1))->GetString().Atoi();
474 // cout << "ns " << nspan << ((TObjString *)array->At(1))->GetString() << endl;
475 // cout << "t " << text << endl;
477 for(Int_t ispan = 1; ispan < nspan; ispan++){
480 // cout << "t " << text << endl;
485 text.ReplaceAll("\\mathrm", "");
487 text.ReplaceAll("\\", "");
488 text.Strip(TString::EStripType(1), ' ');
492 void AliLatexTable::LoadTeXFromFileAndPrintASCII(const char * filename) {
494 // opens a file containing only a latex table and prints it on screen as ASCII
496 ifstream file (filename);
497 if (!file.is_open()) {
498 AliError(Form("Cannot open file %s", filename));
501 while (line.ReadLine(file)) {
502 if (line.Contains("begin") && line.Contains("tabular")) {
503 // We need to get and parse the format
504 // TPRegexp re("\\begin\\{tabular\\}\\{([^\\}]*)\\}");
505 TPRegexp re(".*begin{tabular}{(.*)}");
506 TObjArray * arr = re.MatchS(line);
507 if (arr->GetLast() > 0){
508 // cout << "Size: " << arr->GetSize() << " " << arr->GetLast() << endl;
510 TString subStr = ((TObjString *)arr->At(1))->GetString();
511 subStr.ReplaceAll("|","");
512 subStr.ReplaceAll(" ","");
513 subStr.ReplaceAll("\t","");
514 // subStr.ReplaceAll(" ","");
515 // cout << subStr.Data() << " " << subStr.Length()<< endl;
516 fNcol = subStr.Length();
521 // Skip stuff we don't parse
522 if (line.Contains("begin")) continue;
523 if (line.Contains("end")) continue;
524 if (line.Contains("tabular")) continue;
526 InsertCustomRow(line.Data());