Reference documentation for deal.II version 8.4.2
table_handler.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2015 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/table_handler.h>
17 #include <deal.II/base/table.h>
18 
19 #include <sstream>
20 #include <iostream>
21 #include <iomanip>
22 
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 
27 /*---------------------------------------------------------------------*/
28 
29 // inline and template functions
30 namespace internal
31 {
33  {}
34 
35 
37  {
38  // we don't quite know the data type in 'value', but
39  // it must be one of the ones in the type list of the
40  // boost::variant. Go through this list and return
41  // the value if this happens to be a number
42  //
43  // first try with int
44  try
45  {
46  return boost::get<int>(value);
47  }
48  catch (...)
49  {}
50 
51 
52  // ... then with unsigned int...
53  try
54  {
55  return boost::get<unsigned int>(value);
56  }
57  catch (...)
58  {}
59 
60  // ...and finally with double precision:
61  try
62  {
63  return boost::get<double>(value);
64  }
65  catch (...)
66  {
67  Assert (false, ExcMessage ("The number stored by this element of the "
68  "table is not a number."))
69  }
70 
71  return 0;
72  }
73 
74  void TableEntry::cache_string(bool scientific, unsigned int precision) const
75  {
76  std::ostringstream ss;
77 
78  ss << std::setprecision(precision);
79 
80  if (scientific)
81  ss.setf(std::ios::scientific, std::ios::floatfield);
82  else
83  ss.setf(std::ios::fixed, std::ios::floatfield);
84 
85  ss << value;
86 
87  cached_value = ss.str();
88  if (cached_value.size()==0)
89  cached_value = "\"\"";
90  }
91 
92  const std::string &TableEntry::get_cached_string() const
93  {
94  return cached_value;
95  }
96 
97 
98  namespace Local
99  {
100  // see which type we can cast to, then use this type to create
101  // a default constructed object
102  struct GetDefaultValue : public boost::static_visitor<>
103  {
104  template <typename T>
105  void operator()( T &operand ) const
106  {
107  operand = T();
108  }
109  };
110  }
111 
113  {
114  TableEntry new_entry = *this;
115  boost::apply_visitor(Local::GetDefaultValue(), new_entry.value);
116 
117  return new_entry;
118  }
119 
120 
121 }
122 
123 /* ------------------------------------------------ */
124 
125 TableHandler::Column::Column(const std::string &tex_caption)
126  :
127  tex_caption(tex_caption),
128  tex_format("c"),
129  precision(4),
130  scientific(0),
131  flag(0),
132  max_length(0)
133 {}
134 
135 
136 
138  :
139  tex_caption(),
140  tex_format("c"),
141  precision(4),
142  scientific(0),
143  flag(0),
144  max_length(0)
145 {}
146 
147 
148 
149 void
150 TableHandler::Column::pad_column_below (const unsigned int size)
151 {
152  // we should never have a column that is completely
153  // empty and that needs to be padded
154  Assert (entries.size() > 0, ExcInternalError());
155 
156  // add as many elements as necessary
157  while (entries.size() < size)
158  {
159  entries.push_back (entries.back().get_default_constructed_copy());
160  internal::TableEntry &entry = entries.back();
162  max_length = std::max(max_length, static_cast<unsigned int>(entry.get_cached_string().length()));
163  }
164 }
165 
166 
167 void
169 {
170  max_length = 0;
171 
172  for (std::vector<::internal::TableEntry>::iterator it=entries.begin(); it!=entries.end(); ++it)
173  {
174  it->cache_string(this->scientific, this->precision);
175  max_length = std::max(max_length, static_cast<unsigned int>(it->get_cached_string().length()));
176  }
177 }
178 
179 
180 /*---------------------------------------------------------------------*/
181 
182 
184  :
185  auto_fill_mode (false)
186 {}
187 
188 
189 
190 void
192 {
193  auto_fill_mode = state;
194 }
195 
196 
197 void TableHandler::add_column_to_supercolumn (const std::string &key,
198  const std::string &superkey)
199 {
200  Assert(columns.count(key), ExcColumnNotExistent(key));
201 
202  if (!supercolumns.count(superkey))
203  {
204  std::pair<std::string, std::vector<std::string> >
205  new_column(superkey, std::vector<std::string>());
206  supercolumns.insert(new_column);
207  // replace key in column_order
208  // by superkey
209  for (unsigned int j=0; j<column_order.size(); ++j)
210  if (column_order[j]==key)
211  {
212  column_order[j]=superkey;
213  break;
214  }
215  }
216  else
217  {
218  // remove key from column_order
219  // for erase we need an iterator
220  for (std::vector<std::string>::iterator order_iter=column_order.begin();
221  order_iter!=column_order.end(); ++order_iter)
222  if (*order_iter==key)
223  {
224  column_order.erase(order_iter);
225  break;
226  }
227  }
228 
229  if (supercolumns.count(superkey))
230  {
231  supercolumns[superkey].push_back(key);
232  // By default set the
233  // tex_supercaption to superkey
234  std::pair<std::string, std::string> new_tex_supercaption(superkey, superkey);
235  tex_supercaptions.insert(new_tex_supercaption);
236  }
237  else
238  Assert(false, ExcInternalError());
239 }
240 
241 
242 
243 void TableHandler::set_column_order (const std::vector<std::string> &new_order)
244 {
245  for (unsigned int j=0; j<new_order.size(); ++j)
246  Assert(supercolumns.count(new_order[j]) || columns.count(new_order[j]),
247  ExcColumnOrSuperColumnNotExistent(new_order[j]));
248 
249  column_order=new_order;
250 }
251 
252 
253 void TableHandler::set_tex_caption (const std::string &key,
254  const std::string &tex_caption)
255 {
256  Assert(columns.count(key), ExcColumnNotExistent(key));
257  columns[key].tex_caption=tex_caption;
258 }
259 
260 
261 
262 void TableHandler::set_tex_table_caption (const std::string &table_caption)
263 {
264  tex_table_caption=table_caption;
265 }
266 
267 
268 
269 void TableHandler::set_tex_table_label (const std::string &table_label)
270 {
271  tex_table_label=table_label;
272 }
273 
274 
275 
276 void TableHandler::set_tex_supercaption (const std::string &superkey,
277  const std::string &tex_supercaption)
278 {
279  Assert(supercolumns.count(superkey), ExcSuperColumnNotExistent(superkey));
280  Assert(tex_supercaptions.count(superkey), ExcInternalError());
281  tex_supercaptions[superkey]=tex_supercaption;
282 }
283 
284 
285 
286 void TableHandler::set_tex_format (const std::string &key,
287  const std::string &tex_format)
288 {
289  Assert(columns.count(key), ExcColumnNotExistent(key));
290  Assert(tex_format=="l" || tex_format=="c" || tex_format=="r",
291  ExcUndefinedTexFormat(tex_format));
292  columns[key].tex_format=tex_format;
293 }
294 
295 
296 
297 void TableHandler::set_precision (const std::string &key,
298  const unsigned int precision)
299 {
300  Assert(columns.count(key), ExcColumnNotExistent(key));
301  if (columns[key].precision!=precision)
302  {
303  columns[key].precision = precision;
304  columns[key].invalidate_cache();
305  }
306 }
307 
308 
309 void TableHandler::set_scientific (const std::string &key,
310  const bool scientific)
311 {
312  Assert(columns.count(key), ExcColumnNotExistent(key));
313  if (columns[key].scientific!=scientific)
314  {
315  columns[key].scientific = scientific;
316  columns[key].invalidate_cache();
317  }
318 }
319 
320 
321 void TableHandler::write_text(std::ostream &out,
322  const TextOutputFormat format) const
323 {
324  AssertThrow (out, ExcIO());
325 
326  // first pad the table from below if necessary
327  if (auto_fill_mode == true)
328  {
329  unsigned int max_rows = 0;
330  for (std::map<std::string, Column>::const_iterator p = columns.begin();
331  p != columns.end(); ++p)
332  max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
333 
334  for (std::map<std::string, Column>::iterator p = columns.begin();
335  p != columns.end(); ++p)
336  p->second.pad_column_below (max_rows);
337  }
338 
339  std::vector<std::string> sel_columns;
340  get_selected_columns(sel_columns);
341 
342  const unsigned int nrows = n_rows();
343  const unsigned int n_cols = sel_columns.size();
344 
345  // cache the columns and compute the widths of each column for alignment
346  std::vector<const Column *> cols;
347  std::vector<unsigned int> column_widths (n_cols, 0);
348  for (unsigned int j=0; j<n_cols; ++j)
349  {
350  std::string key=sel_columns[j];
351  const std::map<std::string, Column>::const_iterator
352  col_iter=columns.find(key);
353  Assert(col_iter!=columns.end(), ExcInternalError());
354  cols.push_back(&(col_iter->second));
355 
356  column_widths[j] = col_iter->second.max_length;
357  }
358 
359  switch (format)
360  {
361  case org_mode_table:
362  {
363  // write the captions
364  out << "| " << std::left;
365  for (unsigned int j=0; j<n_cols; ++j)
366  {
367  const std::string &key = sel_columns[j];
368  column_widths[j] = std::max(column_widths[j],
369  (unsigned int)key.length());
370  out << std::setw(column_widths[j]);
371  out << key << " | ";
372  }
373  out << std::endl;
374 
375  // write the body
376  for (unsigned int i=0; i<nrows; ++i)
377  {
378  out << "| ";
379  for (unsigned int j=0; j<n_cols; ++j)
380  {
381  const Column &column=*(cols[j]);
382 
383  out << std::setw(column_widths[j]);
384  out << column.entries[i].get_cached_string();
385  out << " | ";
386  }
387  out << '\n';
388  }
389 
390  out << std::flush;
391  return;
392  }
393 
394  case simple_table_with_separate_column_description:
395  {
396  // write the captions
397  for (unsigned int j=0; j<n_cols; ++j)
398  {
399  const std::string &key = sel_columns[j];
400  out << "# " << j+1 << ": " << key << '\n';
401  }
402 
403  // write the body
404  for (unsigned int i=0; i<nrows; ++i)
405  {
406  for (unsigned int j=0; j<n_cols; ++j)
407  {
408  const Column &column=*(cols[j]);
409 
410  out << column.entries[i].get_cached_string();
411  out << ' ';
412  }
413  out << '\n';
414  }
415 
416  out << std::flush;
417  return;
418  }
419 
420  case table_with_separate_column_description:
421  {
422  // writing the captions for table_with_separate_column_description
423  // means that we ignore supercolumns and output the column
424  // header for each column. enumerate columns starting with 1
425  for (unsigned int j=0; j<n_cols; ++j)
426  {
427  std::string key=sel_columns[j];
428  out << "# " << j+1 << ": " << key << '\n';
429  }
430  break;
431  }
432 
433  case table_with_headers:
434  {
435  // This format output supercolumn headers and aligns them centered
436  // over all the columns that belong to it.
437  for (unsigned int j=0; j<column_order.size(); ++j)
438  {
439  const std::string &key = column_order[j];
440  unsigned int width=0;
441  {
442  // compute the width of this column or supercolumn
443  const std::map<std::string, std::vector<std::string> >::const_iterator
444  super_iter=supercolumns.find(key);
445  if (super_iter!=supercolumns.end())
446  {
447  const unsigned int n_subcolumns=super_iter->second.size();
448  for (unsigned int k=0; k<n_subcolumns; ++k)
449  {
450  const std::map<std::string, Column>::const_iterator
451  col_iter=columns.find(super_iter->second[k]);
452  Assert(col_iter!=columns.end(), ExcInternalError());
453 
454  width += col_iter->second.max_length;
455  }
456  width += n_subcolumns - 1; // separators between subcolumns
457  }
458  else
459  {
460  const std::map<std::string, Column>::const_iterator
461  col_iter=columns.find(key);
462 
463  width = col_iter->second.max_length;
464  }
465  }
466 
467  // header is longer than the column(s) under it
468  if (width<key.length())
469  {
470  // make the column or the last column in this
471  // supercolumn wide enough
472  std::string colname;
473 
474  const std::map<std::string, std::vector<std::string> >::const_iterator
475  super_iter=supercolumns.find(key);
476  if (super_iter!=supercolumns.end())
477  colname = super_iter->second.back();
478  else
479  colname = key;
480 
481  // find column and change output width
482  for (unsigned int i=0; i<n_cols; ++i)
483  {
484  if (sel_columns[i]==colname)
485  {
486  column_widths[i] += key.length() - width;
487  break;
488  }
489  }
490 
491  width=key.length();
492  }
493 
494  // now write key. try to center it somehow
495  const unsigned int front_padding = (width-key.length())/2,
496  rear_padding = (width-key.length()) -
497  front_padding;
498  for (unsigned int i=0; i<front_padding; ++i)
499  out << ' ';
500  out << key;
501  for (unsigned int i=0; i<rear_padding; ++i)
502  out << ' ';
503 
504  out << ' ';
505  }
506  out << '\n';
507  break;
508  }
509 
510  default:
511  Assert (false, ExcInternalError());
512  }
513 
514 
515  // finally output the data itself for
516  // table_with_headers or table_with_separate_column_description:
517  for (unsigned int i=0; i<nrows; ++i)
518  {
519  for (unsigned int j=0; j<n_cols; ++j)
520  {
521  const Column &column=*(cols[j]);
522  out << std::setw(column_widths[j]);
523  out << column.entries[i].get_cached_string();
524 
525  // pad after this column
526  out << ' ';
527  }
528  out << '\n';
529  }
530  out << std::flush;
531 }
532 
533 
534 void TableHandler::write_tex (std::ostream &out, const bool with_header) const
535 {
536  //TODO[TH]: update code similar to
537  //write_text() to use the cache
538  AssertThrow (out, ExcIO());
539  if (with_header)
540  out << "\\documentclass[10pt]{report}" << std::endl
541  << "\\usepackage{float}" << std::endl << std::endl << std::endl
542  << "\\begin{document}" << std::endl;
543 
544  out << "\\begin{table}[H]" << std::endl
545  << "\\begin{center}" << std::endl
546  << "\\begin{tabular}{|";
547 
548  // first pad the table from below if necessary
549  if (auto_fill_mode == true)
550  {
551  unsigned int max_rows = 0;
552  for (std::map<std::string, Column>::const_iterator p = columns.begin();
553  p != columns.end(); ++p)
554  max_rows = std::max<unsigned int>(max_rows, p->second.entries.size());
555 
556  for (std::map<std::string, Column>::iterator p = columns.begin();
557  p != columns.end(); ++p)
558  p->second.pad_column_below (max_rows);
559  }
560 
561  std::vector<std::string> sel_columns;
562  get_selected_columns(sel_columns);
563 
564  // write the column formats
565  for (unsigned int j=0; j<column_order.size(); ++j)
566  {
567  std::string key=column_order[j];
568  // avoid `supercolumns[key]'
569  const std::map<std::string, std::vector<std::string> >::const_iterator
570  super_iter=supercolumns.find(key);
571 
572  if (super_iter!=supercolumns.end())
573  {
574  const unsigned int n_subcolumns=super_iter->second.size();
575  for (unsigned int k=0; k<n_subcolumns; ++k)
576  {
577  // avoid `columns[supercolumns[key]]'
578  const std::map<std::string, Column>::const_iterator
579  col_iter=columns.find(super_iter->second[k]);
580  Assert(col_iter!=columns.end(), ExcInternalError());
581 
582  out << col_iter->second.tex_format << "|";
583  }
584  }
585  else
586  {
587  // avoid `columns[key]';
588  const std::map<std::string, Column>::const_iterator
589  col_iter=columns.find(key);
590  Assert(col_iter!=columns.end(), ExcInternalError());
591  out << col_iter->second.tex_format << "|";
592  }
593  }
594  out << "} \\hline" << std::endl;
595 
596  // write the caption line of the table
597 
598  for (unsigned int j=0; j<column_order.size(); ++j)
599  {
600  std::string key=column_order[j];
601  const std::map<std::string, std::vector<std::string> >::const_iterator
602  super_iter=supercolumns.find(key);
603 
604  if (super_iter!=supercolumns.end())
605  {
606  const unsigned int n_subcolumns=super_iter->second.size();
607  // avoid use of `tex_supercaptions[key]'
608  std::map<std::string,std::string>::const_iterator
609  tex_super_cap_iter=tex_supercaptions.find(key);
610  out << std::endl << "\\multicolumn{" << n_subcolumns << "}{|c|}{"
611  << tex_super_cap_iter->second << "}";
612  }
613  else
614  {
615  // col_iter->second=columns[col];
616  const std::map<std::string, Column>::const_iterator
617  col_iter=columns.find(key);
618  Assert(col_iter!=columns.end(), ExcInternalError());
619  out << col_iter->second.tex_caption;
620  }
621  if (j<column_order.size()-1)
622  out << " & ";
623  }
624  out << "\\\\ \\hline" << std::endl;
625 
626  // write the n rows
627  const unsigned int nrows=n_rows();
628  for (unsigned int i=0; i<nrows; ++i)
629  {
630  const unsigned int n_cols=sel_columns.size();
631 
632  for (unsigned int j=0; j<n_cols; ++j)
633  {
634  std::string key=sel_columns[j];
635  // avoid `column[key]'
636  const std::map<std::string, Column>::const_iterator
637  col_iter=columns.find(key);
638  Assert(col_iter!=columns.end(), ExcInternalError());
639 
640  const Column &column=col_iter->second;
641 
642  out << std::setprecision(column.precision);
643 
644  if (col_iter->second.scientific)
645  out.setf(std::ios::scientific, std::ios::floatfield);
646  else
647  out.setf(std::ios::fixed, std::ios::floatfield);
648 
649  out << column.entries[i].value;
650 
651  if (j<n_cols-1)
652  out << " & ";
653  }
654  out << "\\\\ \\hline" << std::endl;
655  }
656 
657  out << "\\end{tabular}" << std::endl
658  << "\\end{center}" << std::endl;
659  if (tex_table_caption!="")
660  out << "\\caption{" << tex_table_caption << "}" << std::endl;
661  if (tex_table_label!="")
662  out << "\\label{" << tex_table_label << "}" << std::endl;
663  out << "\\end{table}" << std::endl;
664  if (with_header)
665  out << "\\end{document}" << std::endl;
666 }
667 
668 
670 {
671 
672  columns.clear();
673  supercolumns.clear();
674  column_order.clear();
675  tex_supercaptions.clear();
676 
677  tex_table_label.clear();
678  tex_table_caption.clear();
679 
680 }
681 
682 
683 unsigned int TableHandler::n_rows() const
684 {
685  if (columns.size() == 0)
686  return 0;
687 
688  std::map<std::string, Column>::const_iterator col_iter = columns.begin();
689  unsigned int n = col_iter->second.entries.size();
690  std::string first_name=col_iter->first;
691 
692  for (++col_iter; col_iter!=columns.end(); ++col_iter)
693  Assert(col_iter->second.entries.size()==n,
694  ExcWrongNumberOfDataEntries(col_iter->first,
695  col_iter->second.entries.size(),
696  first_name, n));
697 
698  return n;
699 }
700 
701 
702 void TableHandler::get_selected_columns(std::vector<std::string> &sel_columns) const
703 {
704  sel_columns.clear();
705 
706  for (unsigned int j=0; j<column_order.size(); ++j)
707  {
708  std::string key=column_order[j];
709  const std::map<std::string, std::vector<std::string> >::const_iterator
710  super_iter=supercolumns.find(key);
711 
712  if (super_iter!=supercolumns.end())
713  {
714  // i.e. key is a supercolumn key
715  const unsigned int n_subcolumns=super_iter->second.size();
716  for (unsigned int k=0; k<n_subcolumns; ++k)
717  {
718  const std::string subkey=super_iter->second[k];
719  Assert(columns.count(subkey), ExcInternalError());
720  sel_columns.push_back(subkey);
721  }
722  }
723  else
724  {
725  Assert(columns.count(key), ExcInternalError());
726  // i.e. key is a column key
727  sel_columns.push_back(key);
728  }
729  }
730 }
731 
732 
734 {
735  // Figure out what is the currect (max) length of the columns
736  // so that we "shave" one off.
737  std::vector<internal::TableEntry>::size_type n = 0;
738  for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
739  n = std::max(n, p->second.entries.size());
740 
741  // shave the top most element
742  if (n != 0)
743  for (std::map< std::string, Column >::iterator p = columns.begin(); p != columns.end(); ++p)
744  if (p->second.entries.size() == n)
745  p->second.entries.pop_back();
746 }
747 
748 
749 DEAL_II_NAMESPACE_CLOSE
std::map< std::string, std::string > tex_supercaptions
void set_precision(const std::string &key, const unsigned int precision)
unsigned int max_length
void set_tex_supercaption(const std::string &superkey, const std::string &tex_supercaption)
::ExceptionBase & ExcMessage(std::string arg1)
const std::string & get_cached_string() const
void set_tex_caption(const std::string &key, const std::string &tex_caption)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
void cache_string(bool scientific, unsigned int precision) const
void add_column_to_supercolumn(const std::string &key, const std::string &superkey)
void set_tex_format(const std::string &key, const std::string &format="c")
void get_selected_columns(std::vector< std::string > &sel_columns) const
std::vector< std::string > column_order
std::string tex_format
std::string tex_table_caption
double get_numeric_value() const
TableEntry get_default_constructed_copy() const
void write_text(std::ostream &out, const TextOutputFormat format=table_with_headers) const
std::string cached_value
#define Assert(cond, exc)
Definition: exceptions.h:294
void set_tex_table_label(const std::string &table_label)
unsigned int precision
void write_tex(std::ostream &file, const bool with_header=true) const
void clear_current_row()
void set_column_order(const std::vector< std::string > &new_order)
void set_scientific(const std::string &key, const bool scientific)
void pad_column_below(const unsigned int length)
std::vector< internal::TableEntry > entries
std::map< std::string, Column > columns
unsigned int n_rows() const
std::string tex_caption
void set_tex_table_caption(const std::string &table_caption)
std::map< std::string, std::vector< std::string > > supercolumns
std::string tex_table_label
void set_auto_fill_mode(const bool state)