bpp-phyl3 3.0.0
Nhx.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: The Bio++ Development Group
2//
3// SPDX-License-Identifier: CECILL-2.1
4
5#include "../Tree/PhyloBranch.h"
6#include "../Tree/PhyloBranch.h"
7#include "../Tree/PhyloNode.h"
8#include "../Tree/Tree.h"
9#include "../Tree/TreeTemplate.h"
10#include "Nhx.h"
11
12// From bpp-core:
13#include <Bpp/Text/TextTools.h>
14#include <Bpp/BppString.h>
15#include <Bpp/BppBoolean.h>
16#include <Bpp/Numeric/Number.h>
17
18using namespace bpp;
19
20// From the STL:
21#include <iostream>
22#include <fstream>
23#include <algorithm>
24
25using namespace std;
26
27/******************************************************************************/
28
29Nhx::Nhx(bool useTagsAsPptNames) :
30 supportedProperties_(),
31 useTagsAsPropertyNames_(useTagsAsPptNames),
32 hasIds_(false)
33{
34 registerProperty(Property("Gene name", "GN", false, 0));
35 registerProperty(Property("Sequence accession", "AC", false, 0));
36 registerProperty(Property("Node ID", "ND", false, 0));
38 registerProperty(Property("Event", "Ev", true, 0));
39 registerProperty(Property("EC number", "E", false, 0));
40 registerProperty(Property("Function", "Fu", false, 0));
41 registerProperty(Property("Domain structure", "DS", false, 0));
42 registerProperty(Property("Species name", "S", false, 0));
43 registerProperty(Property("Taxonomy ID", "T", false, 1));
44 registerProperty(Property("Width of parent branch", "W", true, 1));
45 registerProperty(Property("Color of parent branch", "C", true, 0));
46 registerProperty(Property("Collapse", "C", false, 3));
47 registerProperty(Property("Custom", "XB", true, 0));
48 registerProperty(Property("Custom", "XN", false, 0));
49 registerProperty(Property("Orthologous", "O", false, 1));
50 registerProperty(Property("Subtree neighbors", "SN", false, 1));
51 registerProperty(Property("Super orthologous", "SO", false, 1));
52}
53
54/******************************************************************************/
55
56const string Nhx::getFormatName() const { return "Nhx"; }
57
58/******************************************************************************/
59
60const string Nhx::getFormatDescription() const
61{
62 return string("New Hampshire eXtended parenthesis format. ") +
63 "See http://www.phylosoft.org/NHX/ for more info.";
64}
65
66
67/**********************************************************/
68/* INPUT */
69/**********************************************************/
70
71unique_ptr<TreeTemplate<Node>> Nhx::readTreeTemplate(istream& in) const
72{
73 // Checking the existence of specified file
74 if (!in)
75 {
76 throw IOException ("Nhx ::read: failed to read from stream");
77 }
78
79 // We concatenate all line in file till we reach the ending semi colon:
80 string temp, description; // Initialization
81 // Main loop : for all file lines
82 while (!in.eof())
83 {
84 getline(in, temp, '\n'); // Copy current line in temporary string
85 string::size_type index = temp.find(";");
86 if (index != string::npos)
87 {
88 description += temp.substr(0, index + 1);
89 break;
90 }
91 else
92 description += temp;
93 }
94 vector<string> beginnings, endings;
95 beginnings.push_back("[&&NHX:");
96 description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
97 return parenthesisToTree(description);
98}
99
100/******************************************************************************/
101
102unique_ptr<PhyloTree> Nhx::readPhyloTree(istream& in) const
103{
104 // Checking the existence of specified file
105 if (!in)
106 {
107 throw IOException ("Nhx ::read: failed to read from stream");
108 }
109
110 // We concatenate all line in file till we reach the ending semi colon:
111 string temp, description; // Initialization
112 // Main loop : for all file lines
113 while (!in.eof())
114 {
115 getline(in, temp, '\n'); // Copy current line in temporary string
116 string::size_type index = temp.find(";");
117 if (index != string::npos)
118 {
119 description += temp.substr(0, index + 1);
120 break;
121 }
122 else
123 description += temp;
124 }
125 vector<string> beginnings, endings;
126 beginnings.push_back("[&&NHX:");
127 description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
128 return parenthesisToPhyloTree(description);
129}
130
131/******************************************************************************/
132
133void Nhx::readTrees(istream& in, vector<unique_ptr<Tree>>& trees) const
134{
135 // Checking the existence of specified file
136 if (!in)
137 {
138 throw IOException ("Nhx::read: failed to read from stream");
139 }
140
141 // Main loop : for all file lines
142 string temp, description; // Initialization
143 string::size_type index;
144 vector<string> beginnings, endings;
145 beginnings.push_back("[&&NHX:");
146 while (!in.eof())
147 {
148 // We concatenate all line in file till we reach the ending semi colon:
149 while (!in.eof())
150 {
151 getline(in, temp, '\n'); // Copy current line in temporary string
152 index = temp.find(";");
153 if (index != string::npos)
154 {
155 description += temp.substr(0, index + 1);
156 description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
157 trees.push_back(parenthesisToTree(description));
158 description = temp.substr(index + 1);
159 }
160 else
161 description += temp;
162 }
163 }
164}
165
166/******************************************************************************/
167
168void Nhx::readPhyloTrees(istream& in, vector<unique_ptr<PhyloTree>>& trees) const
169{
170 // Checking the existence of specified file
171 if (!in)
172 {
173 throw IOException ("Nhx::read: failed to read from stream");
174 }
175
176 // Main loop : for all file lines
177 string temp, description; // Initialization
178 string::size_type index;
179 vector<string> beginnings, endings;
180 beginnings.push_back("[&&NHX:");
181 while (!in.eof())
182 {
183 // We concatenate all line in file till we reach the ending semi colon:
184 while (!in.eof())
185 {
186 getline(in, temp, '\n'); // Copy current line in temporary string
187 index = temp.find(";");
188 if (index != string::npos)
189 {
190 description += temp.substr(0, index + 1);
191 description = TextTools::removeSubstrings(description, '[', ']', beginnings, endings);
192 trees.push_back(parenthesisToPhyloTree(description));
193 description = temp.substr(index + 1);
194 }
195 else
196 description += temp;
197 }
198 }
199}
200
201/******************************************************************************/
202
203IOTree::Element Nhx::getElement(const string& elt) const
204{
205 IOTree::Element element;
206 element.length = ""; // default
207 element.annotation = ""; // default
208 element.isLeaf = false; // default
209
210 // cout << "ELT=" << elt << endl;
211 size_t lastP = elt.rfind(")"), firstP;
212 size_t beginAnno = string::npos;
213 if (lastP == string::npos)
214 beginAnno = elt.rfind("[&&NHX:");
215 else
216 beginAnno = elt.find("[&&NHX:", lastP + 1);
217 string elementWithoutAnnotation;
218 if (beginAnno != string::npos)
219 {
220 size_t endAnno = elt.find("]", beginAnno + 7);
221 element.annotation = elt.substr(beginAnno + 7, endAnno - beginAnno - 7);
222 elementWithoutAnnotation = elt.substr(0, beginAnno);
223 }
224 else
225 {
226 element.annotation = "";
227 elementWithoutAnnotation = elt;
228 }
229 // cout << "ANNO=" << element.annotation << endl;
230 // cout << "ELT =" << elementWithoutAnnotation << endl;
231
232 size_t colonIndex;
233 bool hasColon = false;
234 for (colonIndex = elementWithoutAnnotation.size() - 1; colonIndex > 0 && elementWithoutAnnotation[colonIndex] != ')' && !hasColon; --colonIndex)
235 {
236 if (elementWithoutAnnotation[colonIndex] == ':')
237 {
238 hasColon = true;
239 }
240 }
241 try
242 {
243 string elt2;
244 if (hasColon)
245 {
246 // this is an element with length:
247 elt2 = elementWithoutAnnotation.substr(0, colonIndex + 1);
248 element.length = elementWithoutAnnotation.substr(colonIndex + 2);
249 }
250 else
251 {
252 // this is an element without length;
253 elt2 = elementWithoutAnnotation;
254 }
255
256 lastP = elt2.rfind(')');
257 firstP = elt2.find('(');
258 if (firstP == string::npos)
259 {
260 // This is a leaf:
261 element.content = elt2;
262 element.isLeaf = true;
263 }
264 else
265 {
266 // This is a node:
267 if (lastP < firstP)
268 throw IOException("Nhx::getElement(). Invalid format: bad closing parenthesis in " + elt2);
269 element.content = elt2.substr(firstP + 1, lastP - firstP - 1);
270 }
271 }
272 catch (exception& e)
273 {
274 throw IOException("Bad tree description: " + elt);
275 }
276 // cout << endl;
277 // cout << "CONTENT:" << endl << element.content << endl;
278 // cout << endl;
279 // cout << "ANNOTATION:" << endl << element.annotation << endl;
280 // cout << endl;
281
282 return element;
283}
284
285/******************************************************************************/
286
287
288Node* Nhx::parenthesisToNode(const string& description) const
289{
290 // cout << "NODE: " << description << endl;
291 Element elt = getElement(description);
292
293 // New node:
294 Node* node = new Node();
295 if (!TextTools::isEmpty(elt.length))
296 {
298 }
300 {
301 bool hasId = setNodeProperties(*node, elt.annotation);
302 hasIds_ |= hasId;
303 if (hasIds_ && !hasId)
304 throw Exception("Nhx::parenthesisToNode. At least one node is missing an id (ND tag).");
305 }
306
307 NestedStringTokenizer nt(elt.content, "(", ")", ",");
308 vector<string> elements;
309 while (nt.hasMoreToken())
310 {
311 elements.push_back(nt.nextToken());
312 }
313 if (elt.isLeaf)
314 {
315 // This is a leaf:
316 string name = TextTools::removeSurroundingWhiteSpaces(elements[0]);
317 node->setName(name);
318 }
319 else
320 {
321 // This is a node:
322 for (size_t i = 0; i < elements.size(); ++i)
323 {
324 // cout << "NODE: SUBNODE: " << i << ", " << elements[i] << endl;
325 Node* son = parenthesisToNode(elements[i]);
326 node->addSon(son);
327 }
328 }
329 return node;
330}
331
332/******************************************************************************/
333
334unique_ptr<TreeTemplate<Node>> Nhx::parenthesisToTree(const string& description) const
335{
336 hasIds_ = false;
337 string::size_type semi = description.rfind(';');
338 if (semi == string::npos)
339 throw Exception("Nhx::parenthesisToTree(). Bad format: no semi-colon found.");
340 string content = description.substr(0, semi);
341 Node* node = parenthesisToNode(content);
342 auto tree = make_unique<TreeTemplate<Node>>();
343 tree->setRootNode(node);
344 if (!hasIds_)
345 {
346 tree->resetNodesId();
347 }
348 return tree;
349}
350
351/******************************************************************************/
352
353std::shared_ptr<PhyloNode> Nhx::parenthesisToNode(PhyloTree& tree, std::shared_ptr<PhyloNode> father, const string& description) const
354{
355 IOTree::Element elt = getElement(description);
356
357 // New node:
358 shared_ptr<PhyloNode> node(new PhyloNode());
359
360 if (father)
361 {
362 shared_ptr<PhyloBranch> branch(new PhyloBranch());
363
364 tree.createNode(father, node, branch);
365
366 if (!TextTools::isEmpty(elt.length))
367 {
368 branch->setLength(TextTools::toDouble(elt.length));
369 }
370 }
371 else
372 tree.createNode(node);
373
375 {
376 bool hasId = setNodeProperties(tree, node, elt.annotation);
377 hasIds_ |= hasId;
378 }
379
380 NestedStringTokenizer nt(elt.content, "(", ")", ",");
381 vector<string> elements;
382 while (nt.hasMoreToken())
383 {
384 elements.push_back(nt.nextToken());
385 }
386
387 if (elt.isLeaf)
388 {
389 // This is a leaf:
390 string name = TextTools::removeSurroundingWhiteSpaces(elements[0]);
391 node->setName(name);
392 }
393 else
394 {
395 // This is a node:
396 for (size_t i = 0; i < elements.size(); ++i)
397 {
398 parenthesisToNode(tree, node, elements[i]);
399 }
400 }
401
402 return node;
403}
404
405/******************************************************************************/
406
407unique_ptr<PhyloTree> Nhx::parenthesisToPhyloTree(const string& description) const
408{
409 hasIds_ = false;
410 string::size_type semi = description.rfind(';');
411 if (semi == string::npos)
412 throw Exception("Nhx::parenthesisToPhyloTree(). Bad format: no semi-colon found.");
413 string content = description.substr(0, semi);
414
415 auto tree = make_unique<PhyloTree>();
416 shared_ptr<PhyloNode> root = parenthesisToNode(*tree, 0, content);
417
418 tree->rootAt(root);
419
420 if (!hasIds_)
421 tree->resetNodesId();
422 else
423 checkNodesId_(*tree);
424
425 Vuint vid = tree->getAllNodesIndexes();
426 return tree;
427}
428
429/******************************************************************************/
430
432{
433 std::unique_ptr<PhyloTree::NodeIterator> nIT = tree.allNodesIterator();
434
435 Vuint nid;
436 vector<shared_ptr<PhyloNode>> vNode;
437
438 for ( ; !nIT->end(); nIT->next())
439 {
440 if (tree.hasNodeIndex(**nIT))
441 nid.push_back(tree.getNodeIndex(**nIT));
442 else
443 vNode.push_back(**nIT);
444 }
445
446 if (nid.size() == tree.getNumberOfNodes())
447 return;
448
449 if (vNode.size() != tree.getNumberOfNodes())
450 ApplicationTools::displayWarning("Warning, missing tree nodes Id automatically filled in NHX.");
451
452 std::sort(nid.begin(), nid.end());
453
454 Vuint::iterator it(nid.begin());
455
456 uint val = *(it++) + 1;
457 while (it != nid.end() && val == *it)
458 {
459 val++;
460 it++;
461 }
462
463 for (auto& node:vNode)
464 {
465 tree.setNodeIndex(node, val);
466 if (tree.hasFather(node))
467 tree.setEdgeIndex(tree.getEdgeToFather(node), val);
468 val++;
469 while (it != nid.end() && val == *it)
470 {
471 val++;
472 it++;
473 }
474 }
475}
476
477/******************************************************************************/
478
479bool Nhx::setNodeProperties(Node& node, const string properties) const
480{
481 string propsDesc = TextTools::removeChar(properties, ']');
482 StringTokenizer st(propsDesc, ":", true, true);
483 map<string, string> props;
484 while (st.hasMoreToken())
485 {
486 string token = st.nextToken();
487 if (TextTools::hasSubstring(token, "="))
488 {
489 StringTokenizer pt(token, "=", true, true);
490 string tag = pt.nextToken();
491 string value = pt.nextToken();
492 props[tag] = value;
493 }
494 }
495
496 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
497 {
498 if (props.find(it->tag) != props.end())
499 {
500 // Property found
501 string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
502 if (it->onBranch)
503 {
504 node.setBranchProperty(ppt, *unique_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
505 }
506 else
507 {
508 node.setNodeProperty(ppt, *unique_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
509 }
510 }
511 }
512
513 // If the ND tag is present and is decimal, we use it has the node id:
514 bool hasId = false;
515
516 if (props.find("ND") != props.end())
517 {
518 string prop = props["ND"];
520 {
521 node.setId(TextTools::toInt(prop));
522 hasId = true;
523 }
524 }
525 return hasId;
526}
527
528/******************************************************************************/
529
530bool Nhx::setNodeProperties(PhyloTree& tree, std::shared_ptr<PhyloNode> node, const string properties) const
531{
532 string propsDesc = TextTools::removeChar(properties, ']');
533 StringTokenizer st(propsDesc, ":", true, true);
534 map<string, string> props;
535 while (st.hasMoreToken())
536 {
537 string token = st.nextToken();
538 if (TextTools::hasSubstring(token, "="))
539 {
540 StringTokenizer pt(token, "=", true, true);
541 string tag = pt.nextToken();
542 string value = pt.nextToken();
543 props[tag] = value;
544 }
545 }
546
547 shared_ptr<PhyloBranch> branch = tree.hasFather(node) ? tree.getEdgeToFather(node) : 0;
548
549 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
550 {
551 if (props.find(it->tag) != props.end())
552 {
553 // Property found
554 string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
555
556 if (it->onBranch)
557 {
558 if (branch)
559 branch->setProperty(ppt, *unique_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
560 }
561 else
562 {
563 node->setProperty(ppt, *unique_ptr<Clonable>(stringToProperty_(props[it->tag], it->type)));
564 }
565 }
566 }
567
568 // If the ND tag is present and is decimal, we use it has the node id:
569 bool hasId = false;
570
571 if (props.find("ND") != props.end())
572 {
573 string prop = props["ND"];
575 {
576 unsigned int id = (unsigned int)TextTools::toInt(prop);
577 tree.setNodeIndex(node, id);
578
579 if (branch)
580 tree.setEdgeIndex(branch, id);
581 hasId = true;
582 }
583 }
584
585 return hasId;
586}
587
588/******************************************************************************/
589
591{
592 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
593 {
594 if (it->onBranch)
595 {
596 if (node.hasBranchProperty(it->tag))
597 {
598 node.setBranchProperty(it->name, *node.getBranchProperty(it->tag));
599 node.deleteBranchProperty(it->tag);
600 }
601 }
602 else
603 {
604 if (node.hasNodeProperty(it->tag))
605 {
606 node.setNodeProperty(it->name, *node.getNodeProperty(it->tag));
607 node.deleteNodeProperty(it->tag);
608 }
609 }
610 }
611 for (unsigned int i = 0; i < node.getNumberOfSons(); ++i)
612 {
613 changeTagsToNames(*node.getSon(i));
614 }
615}
616
617/******************************************************************************/
618
620{
621 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
622 {
623 if (it->onBranch)
624 {
625 if (node.hasBranchProperty(it->name))
626 {
627 node.setBranchProperty(it->tag, *node.getBranchProperty(it->name));
628 node.deleteBranchProperty(it->name);
629 }
630 }
631 else
632 {
633 if (node.hasNodeProperty(it->name))
634 {
635 node.setNodeProperty(it->tag, *node.getNodeProperty(it->name));
636 node.deleteNodeProperty(it->name);
637 }
638 }
639 }
640 for (unsigned int i = 0; i < node.getNumberOfSons(); ++i)
641 {
642 changeNamesToTags(*node.getSon(i));
643 }
644}
645
646/******************************************************************************/
647
648void Nhx::changeTagsToNames(PhyloTree& tree, std::shared_ptr<PhyloNode> node) const
649{
650 shared_ptr<PhyloBranch> branch = tree.hasFather(node) ? tree.getEdgeToFather(node) : 0;
651
652 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
653 {
654 if (it->onBranch)
655 {
656 if (branch)
657 {
658 if (branch->hasProperty(it->tag))
659 {
660 branch->setProperty(it->name, *branch->getProperty(it->tag));
661 branch->deleteProperty(it->tag);
662 }
663 }
664 }
665 else
666 {
667 if (node->hasProperty(it->tag))
668 {
669 node->setProperty(it->name, *node->getProperty(it->tag));
670 node->deleteProperty(it->tag);
671 }
672 }
673 }
674
675 vector<shared_ptr<PhyloNode>> vs = tree.getSons(node);
676
677 for (unsigned int i = 0; i < vs.size(); ++i)
678 {
679 changeTagsToNames(tree, vs[i]);
680 }
681}
682
683/******************************************************************************/
684
685void Nhx::changeNamesToTags(PhyloTree& tree, std::shared_ptr<PhyloNode> node) const
686{
687 shared_ptr<PhyloBranch> branch = tree.hasFather(node) ? tree.getEdgeToFather(node) : 0;
688
689 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
690 {
691 if (it->onBranch)
692 {
693 if (branch)
694 {
695 if (branch->hasProperty(it->name))
696 {
697 branch->setProperty(it->tag, *branch->getProperty(it->name));
698 branch->deleteProperty(it->name);
699 }
700 }
701 }
702 else
703 {
704 if (node->hasProperty(it->name))
705 {
706 node->setProperty(it->tag, *node->getProperty(it->name));
707 node->deleteProperty(it->name);
708 }
709 }
710 }
711
712 vector<shared_ptr<PhyloNode>> vs = tree.getSons(node);
713
714 for (unsigned int i = 0; i < vs.size(); ++i)
715 {
716 changeNamesToTags(tree, vs[i]);
717 }
718}
719
720/**********************************************************/
721/* OUTPUT */
722/**********************************************************/
723
724
725string Nhx::propertiesToParenthesis(const Node& node) const
726{
727 ostringstream s;
728 s << "[&&NHX";
729 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
730 {
731 string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
732 if (it->onBranch)
733 {
734 if (node.hasBranchProperty(ppt))
735 {
736 const Clonable* pptObject = node.getBranchProperty(ppt);
737 s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
738 }
739 }
740 else
741 {
742 if (node.hasNodeProperty(ppt))
743 {
744 const Clonable* pptObject = node.getNodeProperty(ppt);
745 s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
746 }
747 }
748 }
749 // If no special node id is provided, we output the one from the tree:
750 if (!node.hasNodeProperty(useTagsAsPropertyNames_ ? "ND" : "Node ID"))
751 {
752 s << ":ND=" << TextTools::toString(node.getId());
753 }
754 s << "]";
755 return s.str();
756}
757
758
759/******************************************************************************/
760
761string Nhx::propertiesToParenthesis(const PhyloTree& tree, const std::shared_ptr<PhyloNode> node) const
762{
763 ostringstream s;
764 s << "[&&NHX";
765
766 const shared_ptr<PhyloBranch> branch = tree.hasFather(node) ? tree.getEdgeToFather(node) : 0;
767
768 for (set<Property>::iterator it = supportedProperties_.begin(); it != supportedProperties_.end(); ++it)
769 {
770 string ppt = (useTagsAsPropertyNames_ ? it->tag : it->name);
771 if (it->onBranch)
772 {
773 if (branch)
774 {
775 if (branch->hasProperty(ppt))
776 {
777 const Clonable* pptObject = branch->getProperty(ppt);
778 s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
779 }
780 }
781 }
782 else
783 {
784 if (node->hasProperty(ppt))
785 {
786 const Clonable* pptObject = node->getProperty(ppt);
787 s << ":" << it->tag << "=" << propertyToString_(pptObject, it->type);
788 }
789 }
790 }
791 // If no special node id is provided, we output the one from the tree:
792 if (!node->hasProperty(useTagsAsPropertyNames_ ? "ND" : "Node ID"))
793 {
794 s << ":ND=" << TextTools::toString(tree.getNodeIndex(node));
795 }
796 s << "]";
797 return s.str();
798}
799
800/******************************************************************************/
801
802string Nhx::nodeToParenthesis(const Node& node) const
803{
804 ostringstream s;
805 if (node.hasNoSon())
806 {
807 s << node.getName();
808 }
809 else
810 {
811 s << "(";
812 s << nodeToParenthesis(*node[0]);
813 for (int i = 1; i < static_cast<int>(node.getNumberOfSons()); i++)
814 {
815 s << "," << nodeToParenthesis(*node[i]);
816 }
817 s << ")";
818 }
819 if (node.hasDistanceToFather())
820 s << ":" << node.getDistanceToFather();
821 s << propertiesToParenthesis(node);
822 return s.str();
823}
824
825/******************************************************************************/
826
828{
829 ostringstream s;
830 s << "(";
831
832 const Node* node = tree.getRootNode();
833
834 if (node->hasNoSon())
835 {
836 s << node->getName();
837 for (size_t i = 0; i < node->getNumberOfSons(); ++i)
838 {
839 s << "," << nodeToParenthesis(*node->getSon(i));
840 }
841 }
842 else
843 {
844 s << nodeToParenthesis(*node->getSon(0));
845 for (size_t i = 1; i < node->getNumberOfSons(); ++i)
846 {
847 s << "," << nodeToParenthesis(*node->getSon(i));
848 }
849 }
850
851 s << ")";
852 if (node->hasDistanceToFather())
853 s << ":" << node->getDistanceToFather();
854 s << propertiesToParenthesis(*node);
855 s << ";" << endl;
856 return s.str();
857}
858
859/******************************************************************************/
860
861string Nhx::nodeToParenthesis(const PhyloTree& tree, const std::shared_ptr<PhyloNode> node) const
862{
863 ostringstream s;
864 if (tree.getNumberOfSons(node) == 0)
865 {
866 s << node->getName();
867 }
868 else
869 {
870 s << "(";
871
872 vector<shared_ptr<PhyloNode>> vSons = tree.getSons(node);
873
874 for (vector<shared_ptr<PhyloNode>>::const_iterator it = vSons.begin(); it != vSons.end(); it++)
875 {
876 if (it != vSons.begin())
877 s << ",";
878
879 s << nodeToParenthesis(tree, *it);
880 }
881
882 s << ")";
883 }
884
885 const shared_ptr<PhyloBranch> branch = tree.hasFather(node) ? tree.getEdgeToFather(node) : 0;
886
887 if (branch && branch->hasLength())
888 s << ":" << branch->getLength();
889
890 s << propertiesToParenthesis(tree, node);
891 return s.str();
892}
893
894/******************************************************************************/
895
896string Nhx::treeToParenthesis(const PhyloTree& tree) const
897{
898 ostringstream s;
899 s << "(";
900
901 shared_ptr<PhyloNode> root = tree.getRoot();
902 std::vector<shared_ptr<PhyloNode>> rSons = tree.getSons(root);
903
904 if (tree.isRooted())
905 {
906 for (size_t i = 0; i < rSons.size(); ++i)
907 {
908 if (i != 0)
909 s << ",";
910 s << nodeToParenthesis(tree, rSons[i]);
911 }
912 }
913 else
914 {
915 s << root->getName();
916
917 for (size_t i = 0; i < rSons.size(); ++i)
918 {
919 if (i != 0)
920 s << ",";
921 s << nodeToParenthesis(tree, rSons[i]);
922 }
923 }
924
925 s << ")";
926
927 const shared_ptr<PhyloBranch> branch = tree.hasFather(root) ? tree.getEdgeToFather(root) : 0;
928
929 if (branch && branch->hasLength())
930 s << ":" << branch->getLength();
931 s << propertiesToParenthesis(tree, root);
932 s << ";" << endl;
933
934 return s.str();
935}
936
937
938/******************************************************************************/
939
940void Nhx::write_(const Tree& tree, ostream& out) const
941{
942 // Checking the existence of specified file, and possibility to open
943 // it in write mode
944 if (!out)
945 {
946 throw IOException ("Nhx::writeTree: failed to write to stream");
947 }
948 out << treeToParenthesis(*dynamic_cast<const TreeTemplate<Node>* >(&tree));
949}
950
951void Nhx::write_(const PhyloTree& tree, ostream& out) const
952{
953 // Checking the existence of specified file, and possibility to open it in write mode
954 if (!out)
955 {
956 throw IOException ("Nhx::writeTree: failed to write to stream");
957 }
958 out << treeToParenthesis(tree);
959}
960
961/******************************************************************************/
962
963template<class N>
964void Nhx::write_(const TreeTemplate<N>& tree, ostream& out) const
965{
966 // Checking the existence of specified file, and possibility to open it in write mode
967 if (!out)
968 {
969 throw IOException ("Nhx::writeTree: failed to write to stream");
970 }
971 out << treeToParenthesis(tree);
972}
973
974/******************************************************************************/
975
976void Nhx::write_(const vector<const Tree*>& trees, ostream& out) const
977{
978 // Checking the existence of specified file, and possibility to open it in write mode
979 if (!out)
980 {
981 throw IOException ("Nhx::write: failed to write to stream");
982 }
983 for (unsigned int i = 0; i < trees.size(); i++)
984 {
985 if (dynamic_cast<const TreeTemplate<Node>* >(trees[i]))
986 out << treeToParenthesis(*dynamic_cast<const TreeTemplate<Node>* >(trees[i]));
987 }
988}
989
990void Nhx::write_(const vector<const PhyloTree*>& trees, ostream& out) const
991{
992 // Checking the existence of specified file, and possibility to open
993 // it in write mode
994
995 if (!out)
996 {
997 throw IOException ("Nhx::write: failed to write to stream");
998 }
999 for (unsigned int i = 0; i < trees.size(); i++)
1000 {
1001 out << treeToParenthesis(*trees[i]);
1002 }
1003}
1004
1005/******************************************************************************/
1006
1007template<class N>
1008void Nhx::write_(const vector<TreeTemplate<N>*>& trees, ostream& out) const
1009{
1010 // Checking the existence of specified file, and possibility to open
1011 // it in write mode
1012 if (!out)
1013 {
1014 throw IOException ("Nhx::write: failed to write to stream");
1015 }
1016 for (unsigned int i = 0; i < trees.size(); i++)
1017 {
1018 out << treeToParenthesis(*trees[i]);
1019 }
1020}
1021
1022/******************************************************************************/
1023
1024string Nhx::propertyToString_(const Clonable* pptObject, short type)
1025{
1026 if (type == 0)
1027 {
1028 const BppString* castedPptObject = dynamic_cast<const BppString*>(pptObject);
1029 if (castedPptObject)
1030 return castedPptObject->toSTL();
1031 else
1032 throw Exception("Nhx::propertyToString_. Invalid property type, should be of class BppString.");
1033 }
1034 else if (type == 1)
1035 {
1036 const Number<int>* castedPptObject = dynamic_cast<const Number<int>*>(pptObject);
1037 if (castedPptObject)
1038 return TextTools::toString(castedPptObject->getValue());
1039 else
1040 throw Exception("Nhx::propertyToString_. Invalid property type, should be of class Number<int>.");
1041 }
1042 else if (type == 2)
1043 {
1044 const Number<double>* castedPptObject = dynamic_cast<const Number<double>*>(pptObject);
1045 if (castedPptObject)
1046 return TextTools::toString(castedPptObject->getValue());
1047 else
1048 throw Exception("Nhx::propertyToString_. Invalid property type, should be of class Number<double>.");
1049 }
1050 else if (type == 3)
1051 {
1052 const BppBoolean* castedPptObject = dynamic_cast<const BppBoolean*>(pptObject);
1053 if (castedPptObject)
1054 return TextTools::toString(castedPptObject->getValue());
1055 else
1056 throw Exception("Nhx::propertyToString_. Invalid property type, should be of class BppBoolean.");
1057 }
1058 else
1059 {
1060 throw Exception("Nhx::propertyToString_. Unsupported type: " + TextTools::toString(type));
1061 }
1062}
1063
1064/******************************************************************************/
1065
1066Clonable* Nhx::stringToProperty_(const string& pptDesc, short type)
1067{
1068 if (type == 0)
1069 {
1070 return new BppString(pptDesc);
1071 }
1072 else if (type == 1)
1073 {
1074 return new Number<int>(TextTools::toInt(pptDesc));
1075 }
1076 else if (type == 2)
1077 {
1078 return new Number<double>(TextTools::toDouble(pptDesc));
1079 }
1080 else if (type == 3)
1081 {
1082 return new BppBoolean(TextTools::to<bool>(pptDesc));
1083 }
1084 else
1085 {
1086 throw Exception("Nhx::stringToProperty_. Unsupported type: " + TextTools::toString(type));
1087 }
1088}
static void displayWarning(const std::string &text)
virtual NodeIndex setNodeIndex(const std::shared_ptr< N > nodeObject, NodeIndex index)=0
virtual std::shared_ptr< N > getRoot() const=0
virtual bool hasNodeIndex(const std::shared_ptr< N > nodeObject) const=0
virtual EdgeIndex setEdgeIndex(const std::shared_ptr< E > edgeObject, EdgeIndex index)=0
virtual NodeIndex getNodeIndex(const std::shared_ptr< N > nodeObject) const=0
virtual std::unique_ptr< NodeIterator > allNodesIterator()=0
virtual void createNode(std::shared_ptr< N > newNodeObject)=0
std::vector< std::shared_ptr< N > > getSons(const std::shared_ptr< N > node) const
bool hasFather(const std::shared_ptr< N > nodeObject) const
std::shared_ptr< E > getEdgeToFather(const std::shared_ptr< N > nodeObject) const
size_t getNumberOfSons(const std::shared_ptr< N > node) const
const bool getValue() const
const std::string & toSTL() const
const std::string & nextToken()
std::string propertiesToParenthesis(const Node &node) const
Definition: Nhx.cpp:725
void changeNamesToTags(Node &node) const
Convert property names from names to tags.
Definition: Nhx.cpp:619
std::set< Property > supportedProperties_
Definition: Nhx.h:98
std::unique_ptr< PhyloTree > parenthesisToPhyloTree(const std::string &description) const
Definition: Nhx.cpp:407
const std::string getFormatDescription() const override
Definition: Nhx.cpp:60
void readPhyloTrees(std::istream &in, std::vector< std::unique_ptr< PhyloTree > > &trees) const override
Read trees from a stream.
Definition: Nhx.cpp:168
void changeTagsToNames(Node &node) const
Convert property names from tag to names.
Definition: Nhx.cpp:590
std::unique_ptr< TreeTemplate< Node > > parenthesisToTree(const std::string &description) const
Definition: Nhx.cpp:334
static std::string propertyToString_(const Clonable *pptObject, short type)
Definition: Nhx.cpp:1024
const std::string getFormatName() const override
Definition: Nhx.cpp:56
IOTree::Element getElement(const std::string &elt) const override
Definition: Nhx.cpp:203
void registerProperty(const Property &property)
Definition: Nhx.h:201
bool hasIds_
Definition: Nhx.h:100
std::unique_ptr< PhyloTree > readPhyloTree(std::istream &in) const override
Read a tree from a stream.
Definition: Nhx.cpp:102
std::string nodeToParenthesis(const Node &node) const
Definition: Nhx.cpp:802
std::string treeToParenthesis(const TreeTemplate< Node > &tree) const
Definition: Nhx.cpp:827
bool useTagsAsPropertyNames_
Definition: Nhx.h:99
void write_(const Tree &tree, std::ostream &out) const
Definition: Nhx.cpp:940
static Clonable * stringToProperty_(const std::string &pptDesc, short type)
Definition: Nhx.cpp:1066
std::unique_ptr< TreeTemplate< Node > > readTreeTemplate(std::istream &in) const override
Definition: Nhx.cpp:71
bool setNodeProperties(Node &node, const std::string properties) const
Definition: Nhx.cpp:479
void checkNodesId_(PhyloTree &tree) const
check and fill all nodes ids.
Definition: Nhx.cpp:431
void readTrees(std::istream &in, std::vector< std::unique_ptr< Tree > > &trees) const override
Read trees from a stream.
Definition: Nhx.cpp:133
Node * parenthesisToNode(const std::string &description) const
Definition: Nhx.cpp:288
The phylogenetic node class.
Definition: Node.h:59
virtual std::string getName() const
Get the name associated to this node, if there is one, otherwise throw a NodeException.
Definition: Node.h:203
virtual void setDistanceToFather(double distance)
Set or update the distance toward the father node.
Definition: Node.h:266
virtual int getId() const
Get the node's id.
Definition: Node.h:170
virtual bool hasBranchProperty(const std::string &name) const
Definition: Node.h:665
virtual void setId(int id)
Set this node's id.
Definition: Node.h:177
virtual Clonable * getNodeProperty(const std::string &name)
Definition: Node.h:514
virtual Clonable * getBranchProperty(const std::string &name)
Definition: Node.h:604
virtual void addSon(size_t pos, Node *node)
Definition: Node.h:386
virtual void setBranchProperty(const std::string &name, const Clonable &property)
Set/add a branch property.
Definition: Node.h:597
virtual bool hasDistanceToFather() const
Tell is this node has a distance to the father.
Definition: Node.h:288
virtual void setNodeProperty(const std::string &name, const Clonable &property)
Set/add a node property.
Definition: Node.h:507
virtual bool hasNoSon() const
Definition: Node.h:681
virtual const Node * getSon(size_t pos) const
Definition: Node.h:362
virtual void deleteNodeProperty(const std::string &name)
Definition: Node.h:542
virtual void deleteBranchProperty(const std::string &name)
Definition: Node.h:632
virtual void setName(const std::string &name)
Give a name or update the name associated to the node.
Definition: Node.h:214
virtual bool hasNodeProperty(const std::string &name) const
Definition: Node.h:575
virtual double getDistanceToFather() const
Get the distance to the father node is there is one, otherwise throw a NodeException.
Definition: Node.h:250
virtual size_t getNumberOfSons() const
Definition: Node.h:355
int getValue() const
const std::string & nextToken()
The phylogenetic tree class.
Definition: TreeTemplate.h:59
virtual N * getRootNode()
Definition: TreeTemplate.h:389
static const std::string BOOTSTRAP
Bootstrap tag.
Definition: TreeTools.h:684
Interface for phylogenetic tree objects.
Definition: Tree.h:115
int toInt(const std::string &s, char scientificNotation='e')
double toDouble(const std::string &s, char dec='.', char scientificNotation='e')
std::string removeSurroundingWhiteSpaces(const std::string &s)
bool hasSubstring(const std::string &s, const std::string &pattern)
std::string removeSubstrings(const std::string &s, char blockBeginning, char blockEnding)
bool isEmpty(const std::string &s)
std::string removeChar(const std::string &s, char c)
bool isDecimalNumber(char c)
std::string toString(T t)
Defines the basic types of data flow nodes.
std::vector< unsigned int > Vuint
std::string annotation
Definition: IoTree.h:36
std::string length
Definition: IoTree.h:35
std::string content
Definition: IoTree.h:34