A library for working with phylogenetic and population genetic data.
v0.32.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-2024 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@sund.ku.dk>
20  University of Copenhagen, Globe Institute, Section for GeoGenetics
21  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
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 // Tree to SVG Document
179 // =================================================================================================
180 
182  CommonTree const& tree,
183  LayoutParameters const& params,
184  std::vector<utils::Color> const& color_per_branch,
185  std::vector<utils::SvgGroup> const& node_shapes,
186  std::vector<utils::SvgGroup> const& edge_shapes
187 ) {
188  // Make a layout tree. We need a pointer to it in order to allow for the two different classes
189  // (circular/rectancular) to be returned here. Make it a unique ptr for automatic cleanup.
190  std::unique_ptr<LayoutBase> layout = [&]() -> std::unique_ptr<LayoutBase> {
191  if( params.shape == LayoutShape::kCircular ) {
192  return utils::make_unique<CircularLayout>( tree, params.type, params.ladderize );
193  }
194  if( params.shape == LayoutShape::kRectangular ) {
195  return utils::make_unique<RectangularLayout>( tree, params.type, params.ladderize );
196  }
197  throw std::runtime_error( "Unknown Tree shape parameter." );
198  }();
199 
200  // Set edge colors and strokes.
201  if( ! color_per_branch.empty() ) {
202  std::vector<utils::SvgStroke> strokes;
203  for( auto const& color : color_per_branch ) {
204  auto stroke = params.stroke;
205  stroke.color = color;
206  stroke.line_cap = utils::SvgStroke::LineCap::kRound;
207  strokes.push_back( std::move( stroke ));
208  }
209  layout->set_edge_strokes( strokes );
210  }
211 
212  // Add the edge and node shapes
213  if( ! node_shapes.empty() ) {
214  layout->set_node_shapes( node_shapes );
215  }
216  if( ! edge_shapes.empty() ) {
217  layout->set_edge_shapes( edge_shapes );
218  }
219 
220  // Prepare svg doc.
221  auto svg_doc = layout->to_svg_document();
222  svg_doc.margin.left = svg_doc.margin.top = svg_doc.margin.bottom = svg_doc.margin.right = 200;
223  return svg_doc;
224 }
225 
227  CommonTree const& tree,
228  LayoutParameters const& params
229 ) {
230  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
231  // purely virtual functiosn and can thus not be instanciated). As the color map however is
232  // empty, the called function will not use the norm.
234  tree, params, std::vector<utils::Color>{}, utils::ColorMap{}, utils::ColorNormalizationLinear()
235  );
236 }
237 
239  CommonTree const& tree,
240  LayoutParameters const& params,
241  std::vector<utils::Color> const& color_per_branch
242 ) {
243  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
244  // purely virtual functiosn and can thus not be instanciated). As the color map however is
245  // empty, the called function will not use the norm.
247  tree, params, color_per_branch, utils::ColorMap{}, utils::ColorNormalizationLinear()
248  );
249 }
250 
252  CommonTree const& tree,
253  LayoutParameters const& params,
254  std::vector<double> const& value_per_branch,
255  utils::ColorMap const& color_map,
256  utils::ColorNormalization const& color_norm
257 ) {
259  tree, params, color_map( color_norm, value_per_branch ), color_map, color_norm
260  );
261 }
262 
264  CommonTree const& tree,
265  LayoutParameters const& params,
266  std::vector<utils::Color> const& color_per_branch,
267  utils::ColorMap const& color_map,
268  utils::ColorNormalization const& color_norm
269 ) {
271  tree, params, color_per_branch, color_map, color_norm,
272  std::vector<utils::SvgGroup>{}, std::vector<utils::SvgGroup>{}
273  );
274 }
275 
277  CommonTree const& tree,
278  LayoutParameters const& params,
279  std::vector<utils::Color> const& color_per_branch,
280  utils::ColorMap const& color_map,
281  utils::ColorNormalization const& color_norm,
282  std::vector<utils::SvgGroup> const& node_shapes,
283  std::vector<utils::SvgGroup> const& edge_shapes
284 ) {
285  // Get the basic svg tree layout.
286  auto svg_doc = get_color_tree_svg_doc_(
287  tree, params, color_per_branch, node_shapes, edge_shapes
288  );
289 
290  // Add the color legend / scale.
291  if( ! color_map.empty() ) {
292 
293  // Make the scale with nice sizes.
294  auto svg_pal_settings = utils::SvgColorBarSettings();
295  svg_pal_settings.height = svg_doc.bounding_box().height() / 2.0;
296  svg_pal_settings.width = svg_pal_settings.height / 10.0;
297  svg_pal_settings.line_width = svg_pal_settings.height / 300.0;
298  svg_pal_settings.text_size = svg_pal_settings.height / 30.0;
299  auto svg_scale = make_svg_color_bar( svg_pal_settings, color_map, color_norm );
300 
301  // Move it to the bottom right corner.
302  if( params.shape == LayoutShape::kCircular ) {
303  svg_scale.second.transform.append( utils::SvgTransform::Translate(
304  1.2 * svg_doc.bounding_box().width() / 2.0, 0.0
305  ));
306  svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() / 2.0 + 2 * svg_pal_settings.width + 200;
307  }
308  if( params.shape == LayoutShape::kRectangular ) {
309  svg_scale.second.transform.append( utils::SvgTransform::Translate(
310  1.2 * svg_doc.bounding_box().width(), svg_pal_settings.height
311  ));
312  svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() + 2 * svg_pal_settings.width + 200;
313  }
314 
315  // Add it to the svg doc.
316  if( ! svg_scale.first.empty() ) {
317  svg_doc.defs.push_back( svg_scale.first );
318  }
319  svg_doc.add( svg_scale.second );
320  }
321 
322  return svg_doc;
323 }
324 
326  CommonTree const& tree,
327  LayoutParameters const& params,
328  std::vector<utils::Color> const& color_per_branch,
329  std::vector<utils::Color> const& color_list,
330  std::vector<std::string> const& color_labels
331 ) {
332  // Get the basic svg tree layout.
333  auto svg_doc = get_color_tree_svg_doc_(
334  tree, params, color_per_branch,
335  std::vector<utils::SvgGroup>{}, std::vector<utils::SvgGroup>{}
336  );
337 
338  // Add the color legend / scale.
339 
340  // Make the color list.
341  auto svg_color_list = make_svg_color_list( color_list, color_labels );
342 
343  // Move it to the bottom right corner.
344  if( params.shape == LayoutShape::kCircular ) {
345  svg_color_list.transform.append( utils::SvgTransform::Translate(
346  1.2 * svg_doc.bounding_box().width() / 2.0, 0.0
347  ));
348  // svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() / 2.0 + 2 * svg_pal_settings.width + 200;
349  }
350  if( params.shape == LayoutShape::kRectangular ) {
351  svg_color_list.transform.append( utils::SvgTransform::Translate(
352  1.2 * svg_doc.bounding_box().width(), svg_doc.bounding_box().height() / 2.0
353  ));
354  // svg_doc.margin.right = 0.2 * svg_doc.bounding_box().width() + 2 * svg_pal_settings.width + 200;
355  }
356 
357  // Apply a scale factor that scales the box to be half the figure height.
358  // The denominator is the number items in the list times their height (15px, used by make_svg_color_list)
359  auto const sf = ( svg_doc.bounding_box().height() / 2.0 ) / (static_cast<double>( color_list.size() ) * 15.0 );
360  svg_color_list.transform.append( utils::SvgTransform::Scale( sf ));
361 
362  // Add it to the svg doc.
363  svg_doc.add( svg_color_list );
364  return svg_doc;
365 }
366 
367 // =================================================================================================
368 // Tree to SVG File
369 // =================================================================================================
370 
372  CommonTree const& tree,
373  LayoutParameters const& params,
374  std::string const& svg_filename
375 ) {
376  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
377  // purely virtual functiosn and can thus not be instanciated). As the color map however is
378  // empty, the called function will not use the norm.
380  tree, params, std::vector<utils::Color>{},
382  svg_filename
383  );
384 }
385 
387  CommonTree const& tree,
388  LayoutParameters const& params,
389  std::vector<utils::Color> const& color_per_branch,
390  std::string const& svg_filename
391 ) {
392  // We use a dummy linear norm here, to satisfy the compiler (because the standard norm has
393  // purely virtual functiosn and can thus not be instanciated). As the color map however is
394  // empty, the called function will not use the norm.
396  tree, params, color_per_branch,
398  svg_filename
399  );
400 }
401 
403  CommonTree const& tree,
404  LayoutParameters const& params,
405  std::vector<double> const& value_per_branch,
406  utils::ColorMap const& color_map,
407  utils::ColorNormalization const& color_norm,
408  std::string const& svg_filename
409 ) {
411  tree, params, color_map( color_norm, value_per_branch ), color_map, color_norm, svg_filename
412  );
413 }
414 
416  CommonTree const& tree,
417  LayoutParameters const& params,
418  std::vector<utils::Color> const& color_per_branch,
419  utils::ColorMap const& color_map,
420  utils::ColorNormalization const& color_norm,
421  std::string const& svg_filename
422 ) {
423  // Write the whole svg doc to file.
424  auto const svg_doc = get_color_tree_svg_document(
425  tree, params, color_per_branch, color_map, color_norm
426  );
427  std::ofstream ofs;
428  utils::file_output_stream( svg_filename, ofs );
429  svg_doc.write( ofs );
430 }
431 
433  CommonTree const& tree,
434  LayoutParameters const& params,
435  std::vector<utils::Color> const& color_per_branch,
436  utils::ColorMap const& color_map,
437  utils::ColorNormalization const& color_norm,
438  std::vector<utils::SvgGroup> const& node_shapes,
439  std::vector<utils::SvgGroup> const& edge_shapes,
440  std::string const& svg_filename
441 ){
442  // Write the whole svg doc to file.
443  auto const svg_doc = get_color_tree_svg_document(
444  tree, params, color_per_branch, color_map, color_norm, node_shapes, edge_shapes
445  );
446  std::ofstream ofs;
447  utils::file_output_stream( svg_filename, ofs );
448  svg_doc.write( ofs );
449 }
450 
452  CommonTree const& tree,
453  LayoutParameters const& params,
454  std::vector<utils::Color> const& color_per_branch,
455  std::vector<utils::Color> const& color_list,
456  std::vector<std::string> const& color_labels,
457  std::string const& svg_filename
458 ) {
459  // Write the whole svg doc to file.
460  auto const svg_doc = get_color_tree_svg_document(
461  tree, params, color_per_branch, color_list, color_labels
462  );
463  std::ofstream ofs;
464  utils::file_output_stream( svg_filename, ofs );
465  svg_doc.write( ofs );
466 }
467 
468 } // namespace tree
469 } // namespace genesis
genesis::utils::ColorMap
Store a list of colors and offer them as a map for values in range [ 0.0, 1.0 ].
Definition: map.hpp:61
color_writer_plugin.hpp
genesis::tree::LayoutParameters
Collection of params for simple tree to svg wrapper functions.
Definition: tree/drawing/functions.hpp:126
genesis::tree::LayoutBase::to_svg_document
utils::SvgDocument to_svg_document() const
Definition: layout_base.hpp:158
genesis::utils::SvgStroke::LineCap::kRound
@ kRound
genesis::tree::CommonTreePhyloxmlWriter
Definition: phyloxml_writer.hpp:121
writer.hpp
genesis::tree::LayoutBase::set_edge_shapes
void set_edge_shapes(utils::SvgGroup const &shape)
Definition: layout_base.cpp:203
functions.hpp
CommonTree functions.
genesis::utils::make_svg_color_bar
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:325
circular_layout.hpp
fs.hpp
Provides functions for accessing the file system.
genesis::tree::LayoutBase::set_node_shapes
void set_node_shapes(utils::SvgGroup const &shape)
Definition: layout_base.cpp:227
genesis::utils::NexusDocument
Definition: nexus/document.hpp:54
genesis::utils::SvgDocument::margin
SvgMargin margin
Definition: svg/document.hpp:122
genesis::utils::ColorNormalization
Base class for color normalization.
Definition: normalization.hpp:52
genesis::utils::NexusWriter
Definition: utils/formats/nexus/writer.hpp:55
genesis::tree::node_names
std::vector< std::string > node_names(Tree const &tree, bool leaves_only)
Returns a list of all TreeNode names of a Tree.
Definition: tree/common_tree/functions.cpp:52
output_stream.hpp
block.hpp
genesis::tree::NewickWriter::write
void write(Tree const &tree, std::shared_ptr< utils::BaseOutputTarget > target) const
Write a Tree to an output target, using the Newick format.
Definition: tree/formats/newick/writer.cpp:60
genesis::tree::CommonTreeNewickWriter
Write default Newick trees, i.e., trees with names and branch lengths.
Definition: tree/common_tree/newick_writer.hpp:367
std.hpp
Provides some valuable additions to STD.
genesis::tree::write_tree_to_newick_file
void write_tree_to_newick_file(CommonTree const &tree, std::string const &newick_filename)
Write a newick file containing a tree.
Definition: tree/drawing/functions.cpp:68
genesis::tree::write_color_tree_to_phyloxml_file
void write_color_tree_to_phyloxml_file(CommonTree const &tree, std::vector< utils::Color > const &color_per_branch, std::string const &phyloxml_filename)
Definition: tree/drawing/functions.cpp:88
genesis::tree::LayoutBase::set_edge_strokes
void set_edge_strokes(utils::SvgStroke const &stroke)
Definition: layout_base.cpp:79
trees.hpp
genesis::tree::get_tree_svg_document
utils::SvgDocument get_tree_svg_document(CommonTree const &tree, LayoutParameters const &params)
Definition: tree/drawing/functions.cpp:226
genesis::tree::LayoutParameters::stroke
utils::SvgStroke stroke
Definition: tree/drawing/functions.hpp:131
genesis::tree::Tree
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
genesis::tree::LayoutShape::kCircular
@ kCircular
genesis::tree::write_tree_to_phyloxml_file
void write_tree_to_phyloxml_file(CommonTree const &tree, std::string const &phyloxml_filename)
Write a phyloxml file containing a tree.
Definition: tree/drawing/functions.cpp:79
genesis::tree::LayoutParameters::ladderize
bool ladderize
Definition: tree/drawing/functions.hpp:130
color_writer_plugin.hpp
genesis::utils::SvgTransform::Translate
Definition: attributes.hpp:252
functions.hpp
newick_writer.hpp
genesis::utils::ColorNormalizationLinear
Default Color normalization, using a sequential linear scaling in the range [ min,...
Definition: norm_linear.hpp:59
genesis::utils::SvgTransform::Scale
Definition: attributes.hpp:359
rectangular_layout.hpp
genesis::tree::LayoutShape::kRectangular
@ kRectangular
writer.hpp
genesis::utils::file_output_stream
void file_output_stream(std::string const &file_name, std::ofstream &out_stream, std::ios_base::openmode mode=std::ios_base::out, bool create_dirs=true)
Helper function to obtain an output stream to a file.
Definition: output_stream.hpp:72
genesis::tree::NewickColorWriterPlugin
Plugin class for Newick output that allows coloring of edges.
Definition: newick/color_writer_plugin.hpp:58
writer.hpp
taxa.hpp
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::tree::write_tree_to_nexus_file
void write_tree_to_nexus_file(CommonTree const &tree, std::string const &nexus_filename)
Write a nexus file containing a tree.
Definition: tree/drawing/functions.cpp:122
document.hpp
genesis::tree::get_color_tree_svg_document
utils::SvgDocument get_color_tree_svg_document(CommonTree const &tree, LayoutParameters const &params, std::vector< utils::Color > const &color_per_branch)
Definition: tree/drawing/functions.cpp:238
genesis::utils::SvgColorBarSettings
Definition: color_bar.hpp:59
genesis::utils::to_file
std::shared_ptr< BaseOutputTarget > to_file(std::string const &file_name, GzipCompressionLevel compression_level, bool auto_adjust_filename=true)
Obtain an output target for writing to a file.
Definition: output_target.hpp:81
phyloxml_writer.hpp
genesis::tree::write_color_tree_to_svg_file
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)
Definition: tree/drawing/functions.cpp:386
norm_linear.hpp
genesis::utils::SvgDocument
Definition: svg/document.hpp:50
genesis::tree::PhyloxmlColorWriterPlugin
Plugin class for PhyloXML output that allows coloring of edges.
Definition: phyloxml/color_writer_plugin.hpp:66
genesis::utils::ColorMap::empty
bool empty() const
Return whether the Palette is empty, that is, no colors were set.
Definition: map.hpp:240
genesis::tree::write_tree_to_svg_file
void write_tree_to_svg_file(CommonTree const &tree, LayoutParameters const &params, std::string const &svg_filename)
Definition: tree/drawing/functions.cpp:371
layout_tree.hpp
genesis::tree::write_color_tree_to_nexus_file
void write_color_tree_to_nexus_file(CommonTree const &tree, std::vector< utils::Color > const &color_per_branch, std::string const &nexus_filename)
Definition: tree/drawing/functions.cpp:131
genesis::tree::LayoutParameters::shape
LayoutShape shape
Definition: tree/drawing/functions.hpp:128
genesis::utils::make_svg_color_list
SvgGroup make_svg_color_list(ColorMap const &map, std::vector< std::string > const &labels)
Definition: color_bar.cpp:376
genesis::tree::LayoutParameters::type
LayoutType type
Definition: tree/drawing/functions.hpp:129
genesis::utils::SvgMargin::left
double left
Definition: utils/formats/svg/helper.hpp:120
genesis::tree::get_color_tree_svg_doc_
utils::SvgDocument get_color_tree_svg_doc_(CommonTree const &tree, LayoutParameters const &params, std::vector< utils::Color > const &color_per_branch, std::vector< utils::SvgGroup > const &node_shapes, std::vector< utils::SvgGroup > const &edge_shapes)
Definition: tree/drawing/functions.cpp:181
genesis::utils::SvgStroke::color
Color color
Definition: attributes.hpp:113