A toolkit for working with phylogenetic data.
v0.24.0
tree/drawing/functions.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2020 Lucas Czech and HITS gGmbH
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 
39 
45 
51 
56 
57 #include <fstream>
58 #include <memory>
59 #include <stdexcept>
60 
61 namespace genesis {
62 namespace tree {
63 
64 // =================================================================================================
65 // Newick Functions
66 // =================================================================================================
67 
69  CommonTree const& tree,
70  std::string const& newick_filename
71 ) {
72  CommonTreeNewickWriter().write( tree, utils::to_file( newick_filename ));
73 }
74 
75 // =================================================================================================
76 // Phyloxml Functions
77 // =================================================================================================
78 
80  CommonTree const& tree,
81  std::string const& phyloxml_filename
82 ) {
84  tree, std::vector<utils::Color>{}, phyloxml_filename
85  );
86 }
87 
89  CommonTree const& tree,
90  std::vector<utils::Color> const& color_per_branch,
91  std::string const& phyloxml_filename
92 ) {
93  // We use a normal Phyloxml writer...
94  auto writer = CommonTreePhyloxmlWriter();
95 
96  // ... but also wrap it in a Color Mixin in order to allow for color branches if needed.
97  auto color_plugin = tree::PhyloxmlColorWriterPlugin();
98  if( ! color_per_branch.empty() ) {
99  color_plugin.register_with( writer );
100  color_plugin.edge_colors( color_per_branch );
101  }
102 
103  writer.write( tree, utils::to_file( phyloxml_filename ));
104 }
105 
107  CommonTree const& tree,
108  std::vector<double> const& value_per_branch,
109  utils::ColorMap const& color_map,
110  utils::ColorNormalization const& color_norm,
111  std::string const& phyloxml_filename
112 ) {
114  tree, color_map( color_norm, value_per_branch ), phyloxml_filename
115  );
116 }
117 
118 // =================================================================================================
119 // Nexus Functions
120 // =================================================================================================
121 
123  CommonTree const& tree,
124  std::string const& nexus_filename
125 ) {
127  tree, std::vector<utils::Color>{}, nexus_filename
128  );
129 }
130 
132  CommonTree const& tree,
133  std::vector<utils::Color> const& color_per_branch,
134  std::string const& nexus_filename
135 ) {
136  // We use a normal Newick writer...
137  auto newick_writer = CommonTreeNewickWriter();
138  newick_writer.trailing_new_line( false );
139 
140  // ... but also wrap it in a Color Mixin in order to allow for color branches if needed.
141  auto color_plugin = tree::NewickColorWriterPlugin();
142  if( ! color_per_branch.empty() ) {
143  color_plugin.register_with( newick_writer );
144  color_plugin.edge_colors( color_per_branch );
145  }
146 
147  // Create an (empty) Nexus document.
148  auto nexus_doc = utils::NexusDocument();
149 
150  // Add the taxa of the tree to the document.
151  auto taxa = utils::make_unique<utils::NexusTaxa>();
152  taxa->add_taxa( node_names( tree ));
153  nexus_doc.set_block( std::move( taxa ));
154 
155  // Add the tree itself to the document.
156  auto trees = utils::make_unique<utils::NexusTrees>();
157  trees->add_tree( "tree1", newick_writer.to_string(tree) );
158  nexus_doc.set_block( std::move(trees) );
159 
160  // Write the document to a Nexus file.
161  auto nexus_writer = utils::NexusWriter();
162  nexus_writer.write( nexus_doc, utils::to_file( nexus_filename ));
163 }
164 
166  CommonTree const& tree,
167  std::vector<double> const& value_per_branch,
168  utils::ColorMap const& color_map,
169  utils::ColorNormalization const& color_norm,
170  std::string const& nexus_filename
171 ) {
173  tree, color_map( color_norm, value_per_branch ), nexus_filename
174  );
175 }
176 
177 // =================================================================================================
178 // SVG Functions
179 // =================================================================================================
180 
182  CommonTree const& tree,
183  LayoutParameters const& params,
184  std::vector<utils::Color> const& color_per_branch
185 ) {
186  // Make a layout tree. We need a pointer to it in order to allow for the two different classes
187  // (circular/rectancular) to be returned here. Make it a unique ptr for automatic cleanup.
188  std::unique_ptr<LayoutBase> layout = [&]() -> std::unique_ptr<LayoutBase> {
189  if( params.shape == LayoutShape::kCircular ) {
190  return utils::make_unique<CircularLayout>( tree, params.type, params.ladderize );
191  }
192  if( params.shape == LayoutShape::kRectangular ) {
193  return utils::make_unique<RectangularLayout>( tree, params.type, params.ladderize );
194  }
195  throw std::runtime_error( "Unknown Tree shape parameter." );
196  }();
197 
198  // Set edge colors and strokes.
199  if( ! color_per_branch.empty() ) {
200  std::vector<utils::SvgStroke> strokes;
201  for( auto const& color : color_per_branch ) {
202  auto stroke = params.stroke;
203  stroke.color = color;
204  stroke.line_cap = utils::SvgStroke::LineCap::kRound;
205  strokes.push_back( std::move( stroke ));
206  }
207  layout->set_edge_strokes( strokes );
208  }
209 
210  // Prepare svg doc.
211  auto svg_doc = layout->to_svg_document();
212  svg_doc.margin.left = svg_doc.margin.top = svg_doc.margin.bottom = svg_doc.margin.right = 200;
213  return svg_doc;
214 }
215 
217  CommonTree const& tree,
218  LayoutParameters const& params,
219  std::string const& svg_filename
220 ) {
221  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
222  // purely virtual functiosn and can thus not be instanciated). As the color map however is
223  // empty, the called function will not use the norm.
225  tree, params, std::vector<utils::Color>{},
227  svg_filename
228  );
229 }
230 
232  CommonTree const& tree,
233  LayoutParameters const& params,
234  std::vector<utils::Color> const& color_per_branch,
235  std::string const& svg_filename
236 ) {
237  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
238  // purely virtual functiosn and can thus not be instanciated). As the color map however is
239  // empty, the called function will not use the norm.
241  tree, params, color_per_branch,
243  svg_filename
244  );
245 }
246 
248  CommonTree const& tree,
249  LayoutParameters const& params,
250  std::vector<double> const& value_per_branch,
251  utils::ColorMap const& color_map,
252  utils::ColorNormalization const& color_norm,
253  std::string const& svg_filename
254 ) {
256  tree, params, color_map( color_norm, value_per_branch ), color_map, color_norm, svg_filename
257  );
258 }
259 
261  CommonTree const& tree,
262  LayoutParameters const& params,
263  std::vector<utils::Color> const& color_per_branch,
264  utils::ColorMap const& color_map,
265  utils::ColorNormalization const& color_norm,
266  std::string const& svg_filename
267 ) {
268  // Get the basic svg tree layout.
269  auto svg_doc = get_color_tree_svg_doc_( tree, params, color_per_branch );
270 
271  // Add the color legend / scale.
272  if( ! color_map.empty() ) {
273 
274  // Make the scale with nice sizes.
275  auto svg_pal_settings = utils::SvgColorBarSettings();
276  svg_pal_settings.height = svg_doc.bounding_box().height() / 2.0;
277  svg_pal_settings.width = svg_pal_settings.height / 10.0;
278  svg_pal_settings.text_size = svg_pal_settings.height / 30.0;
279  auto svg_scale = make_svg_color_bar( svg_pal_settings, color_map, color_norm );
280 
281  // Move it to the bottom right corner.
282  if( params.shape == LayoutShape::kCircular ) {
283  svg_scale.second.transform.append( utils::SvgTransform::Translate(
284  1.2 * svg_doc.bounding_box().width() / 2.0, 0.0
285  ));
286  svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() / 2.0 + 2 * svg_pal_settings.width + 200;
287  }
288  if( params.shape == LayoutShape::kRectangular ) {
289  svg_scale.second.transform.append( utils::SvgTransform::Translate(
290  1.2 * svg_doc.bounding_box().width(), svg_pal_settings.height
291  ));
292  svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() + 2 * svg_pal_settings.width + 200;
293  }
294 
295  // Add it to the svg doc.
296  if( ! svg_scale.first.empty() ) {
297  svg_doc.defs.push_back( svg_scale.first );
298  }
299  svg_doc.add( svg_scale.second );
300  }
301 
302  // Write the whole svg doc to file.
303  std::ofstream ofs;
304  utils::file_output_stream( svg_filename, ofs );
305  svg_doc.write( ofs );
306 }
307 
309  CommonTree const& tree,
310  LayoutParameters const& params,
311  std::vector<utils::Color> const& color_per_branch,
312  std::vector<utils::Color> const& color_list,
313  std::vector<std::string> const& color_labels,
314  std::string const& svg_filename
315 ) {
316  // Get the basic svg tree layout.
317  auto svg_doc = get_color_tree_svg_doc_( tree, params, color_per_branch );
318 
319  // Add the color legend / scale.
320 
321  // Make the color list.
322  auto svg_color_list = make_svg_color_list( color_list, color_labels );
323 
324  // Move it to the bottom right corner.
325  if( params.shape == LayoutShape::kCircular ) {
326  svg_color_list.transform.append( utils::SvgTransform::Translate(
327  1.2 * svg_doc.bounding_box().width() / 2.0, 0.0
328  ));
329  // svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() / 2.0 + 2 * svg_pal_settings.width + 200;
330  }
331  if( params.shape == LayoutShape::kRectangular ) {
332  svg_color_list.transform.append( utils::SvgTransform::Translate(
333  1.2 * svg_doc.bounding_box().width(), svg_doc.bounding_box().height() / 2.0
334  ));
335  // svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() + 2 * svg_pal_settings.width + 200;
336  }
337 
338  // Apply a scale factor that scales the box to be half the figure height.
339  // The denominator is the number items in the list times their height (15px, used by make_svg_color_list)
340  auto const sf = ( svg_doc.bounding_box().height() / 2.0 ) / (static_cast<double>( color_list.size() ) * 15.0 );
341  svg_color_list.transform.append( utils::SvgTransform::Scale( sf ));
342 
343  // Add it to the svg doc.
344  svg_doc.add( svg_color_list );
345 
346  // Write the whole svg doc to file.
347  std::ofstream ofs;
348  utils::file_output_stream( svg_filename, ofs );
349  svg_doc.write( ofs );
350 }
351 
352 } // namespace tree
353 } // namespace genesis
std::shared_ptr< BaseOutputTarget > to_file(std::string const &file_name, GzipCompressionLevel compression_level=GzipCompressionLevel::kNoCompression, bool auto_adjust_filename=true)
Obtain an output target for writing to a file.
Default Color normalization, using a sequential linear scaling in the range [ min, max ].
Definition: norm_linear.hpp:59
void file_output_stream(std::string const &filename, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out)
Helper function to obtain an output stream to a file.
Plugin class for PhyloXML output that allows coloring of edges.
Store a list of colors and offer them as a map for values in range [ 0.0, 1.0 ].
Definition: map.hpp:61
void write_color_tree_to_phyloxml_file(CommonTree const &tree, std::vector< utils::Color > const &color_per_branch, std::string const &phyloxml_filename)
CommonTree functions.
utils::SvgDocument to_svg_document() const
SvgGroup make_svg_color_list(ColorMap const &map, std::vector< std::string > const &labels)
Definition: color_bar.cpp:375
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
Write default Newick trees, i.e., trees with names and branch lengths.
Provides some valuable additions to STD.
void write_color_tree_to_svg_file(CommonTree const &tree, LayoutParameters const &params, std::vector< utils::Color > const &color_per_branch, std::string const &svg_filename)
void write_tree_to_svg_file(CommonTree const &tree, LayoutParameters const &params, std::string const &svg_filename)
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
Plugin class for Newick output that allows coloring of edges.
void write(Tree const &tree, std::shared_ptr< utils::BaseOutputTarget > target) const
Write a Tree to an output target, using the Newick format.
void write_tree_to_nexus_file(CommonTree const &tree, std::string const &nexus_filename)
Write a nexus file containing a tree.
void write_tree_to_phyloxml_file(CommonTree const &tree, std::string const &phyloxml_filename)
Write a phyloxml file containing a tree.
void write_tree_to_newick_file(CommonTree const &tree, std::string const &newick_filename)
Write a newick file containing a tree.
void write_color_tree_to_nexus_file(CommonTree const &tree, std::vector< utils::Color > const &color_per_branch, std::string const &nexus_filename)
Provides functions for accessing the file system.
Base class for color normalization.
void set_edge_strokes(utils::SvgStroke const &stroke)
Definition: layout_base.cpp:79
std::pair< SvgGradientLinear, SvgGroup > make_svg_color_bar(SvgColorBarSettings const &settings, ColorMap const &map, ColorNormalization const &norm, std::string const &id)
Definition: color_bar.cpp:324
utils::SvgDocument get_color_tree_svg_doc_(CommonTree const &tree, LayoutParameters const &params, std::vector< utils::Color > const &color_per_branch)
bool empty() const
Return whether the Palette is empty, that is, no colors were set.
Definition: map.hpp:240
std::vector< std::string > node_names(Tree const &tree, bool leaves_only)
Returns a list of all TreeNode names of a Tree.