A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
compact.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
35 #include "genesis/tree/tree.hpp"
37 
38 #include <assert.h>
39 #include <sstream>
40 #include <vector>
41 
42 namespace genesis {
43 namespace tree {
44 
45 // =================================================================================================
46 // Print Compact
47 // =================================================================================================
48 
50  std::ostream& out,
51  Tree const& tree,
52  std::function<std::string (
53  TreeNode const& node,
54  TreeEdge const& edge
55  )> const print_line
56 ) {
57  // Stores a count of how many child nodes each node has left for viewing.
58  auto ranks = std::vector<size_t>( tree.node_count(), 0 );
59 
60  // Store the current stack of parents while traversing.
61  auto parents = std::vector<size_t>();
62 
63  for( auto it : preorder(tree) ) {
64  // Index of current and its parent node.
65  size_t cur_idx = it.node().index();
66  size_t par_idx = it.link().outer().node().index();
67 
68  // Set parent stack correctly (including current node), and store current rank.
69  while (!parents.empty() && parents.back() != par_idx) {
70  parents.pop_back();
71  }
72  parents.push_back(cur_idx);
73  ranks[cur_idx] = it.node().rank();
74 
75  // The root node is special: We have to account for one more child, as it does not have a
76  // parent. Also, we do not draw any lines or indention for the root.
77  if (it.is_first_iteration()) {
78  ++ranks[cur_idx];
79  out << print_line( it.node(), it.edge() ) << "\n";
80  continue;
81  }
82 
83  // This point in code is reached for all nodes but the root. Thus, we already have at least
84  // the root and the current node added to the parents stack. Also, the second but last
85  // element will be the parent of the current node, and the last one the node itself.
86  assert( parents.size() >= 2 );
87  assert( parents[ parents.size() - 2 ] == par_idx );
88  assert( parents[ parents.size() - 1 ] == cur_idx );
89 
90  // Draw indention lines for all non-immediate parents of the current node. If their rank
91  // is zero, there will no other children follow, so do not draw a line then.
92  for (size_t i = 0; i < parents.size() - 2; ++i) {
93  if (ranks[parents[i]] > 0) {
94  out << "│ ";
95  } else {
96  out << " ";
97  }
98  }
99 
100  // We are about to draw a child of the parent. Prior to drawing, we need to reduce the
101  // parents rank counter. If it then is zero, the current node is the last child of its
102  // parent (which is drawn differently).
103  // Also assert that it is not zero already, because this would mean that we are currently
104  // processing more children of the parent than its rank indicated.
105  assert(ranks[par_idx] > 0);
106  --ranks[par_idx];
107 
108  // Draw the lines down from the immediate parent of the current node.
109  if (ranks[par_idx] > 0) {
110  out << "├── ";
111  } else {
112  out << "└── ";
113  }
114 
115  // Print the actual information about the current node.
116  out << print_line( it.node(), it.edge() ) << "\n";
117  }
118 }
119 
121  Tree const& tree,
122  std::function<std::string (
123  TreeNode const& node,
124  TreeEdge const& edge
125  )> const print_line
126 ) {
127  std::ostringstream res;
128  print( res, tree, print_line );
129  return res.str();
130 }
131 
132 std::string PrinterCompact::print( Tree const& tree )
133 {
134  auto print_line = [] ( TreeNode const& node, TreeEdge const& edge )
135  {
136  std::string result;
137 
138  auto node_data = node.data_cast<DefaultNodeData>();
139  auto edge_data = edge.data_cast<DefaultEdgeData>();
140 
141  if( node_data ) {
142  result += node_data->name;
143  }
144  if( node_data && edge_data ) {
145  result += ": ";
146  }
147  if( edge_data ) {
148  result += utils::to_string( edge_data->branch_length );
149  }
150  return result;
151  };
152  return print(tree, print_line);
153 }
154 
155 } // namespace tree
156 } // namespace genesis
Default class containing the commonly needed data for tree nodes.
std::string to_string(T const &v)
Return a string representation of a given value.
Definition: string.hpp:300
utils::Range< IteratorPreorder< TreeLink const, TreeNode const, TreeEdge const > > preorder(ElementType const &element)
Default class containing the commonly needed data for tree edges.
size_t node_count() const
Return the number of TreeNodes of the Tree.
Definition: tree/tree.cpp:350
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:95
Provides some commonly used string utility functions.
Header of Tree class.
void print(std::ostream &out, Tree const &tree, std::function< std::string(TreeNode const &node, TreeEdge const &edge)> const print_line)
Print a compact representation of a Tree to an output stream, using a given function for output of th...
Definition: compact.cpp:49
NodeDataType * data_cast()
Definition: node.hpp:120