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