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 
18 using namespace bpp;
19 
20 // From the STL:
21 #include <iostream>
22 #include <fstream>
23 #include <algorithm>
24 
25 using namespace std;
26 
27 /******************************************************************************/
28 
29 Nhx::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 
56 const string Nhx::getFormatName() const { return "Nhx"; }
57 
58 /******************************************************************************/
59 
60 const 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 
71 unique_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 
102 unique_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 
133 void 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 
168 void 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 
203 IOTree::Element Nhx::getElement(const string& elt) const
204 {
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 
288 Node* 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  }
299  if (!TextTools::isEmpty(elt.annotation))
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 
334 unique_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 
353 std::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 
374  if (!TextTools::isEmpty(elt.annotation))
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 
407 unique_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 
431 void Nhx::checkNodesId_(PhyloTree& tree) const
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 
479 bool 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"];
519  if (TextTools::isDecimalNumber(prop))
520  {
521  node.setId(TextTools::toInt(prop));
522  hasId = true;
523  }
524  }
525  return hasId;
526 }
527 
528 /******************************************************************************/
529 
530 bool 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"];
574  if (TextTools::isDecimalNumber(prop))
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 
590 void Nhx::changeTagsToNames(Node& node) const
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 
619 void Nhx::changeNamesToTags(Node& node) const
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 
648 void 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 
685 void 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 
725 string 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 
761 string 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 
802 string 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 
861 string 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 
896 string 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 
940 void 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 
951 void 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 
963 template<class N>
964 void 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 
976 void 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 
990 void 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 
1007 template<class N>
1008 void 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 
1024 string 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 
1066 Clonable* 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 }
return element
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()
Nhx(bool useTagsAsPptNames=true)
Build a new Nhx reader/writer.
Definition: Nhx.cpp:29
virtual std::unique_ptr< TreeTemplate< Node > > readTreeTemplate(std::istream &in) const=0
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
virtual void readPhyloTrees(std::istream &in, std::vector< std::unique_ptr< PhyloTree >> &trees) const override=0
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 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::string nodeToParenthesis(const Node &node) const
Definition: Nhx.cpp:802
std::string treeToParenthesis(const TreeTemplate< Node > &tree) const
Definition: Nhx.cpp:827
std::unique_ptr< PhyloTree > readPhyloTree(std::istream &in) const override=0
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
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
virtual void readTrees(std::istream &in, std::vector< std::unique_ptr< Tree >> &trees) const override=0
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 Clonable * getNodeProperty(const std::string &name)
Definition: Node.h:502
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:653
virtual void setId(int id)
Set this node's id.
Definition: Node.h:177
virtual void addSon(size_t pos, Node *node)
Definition: Node.h:374
virtual const Node * getSon(size_t pos) const
Definition: Node.h:362
virtual void setBranchProperty(const std::string &name, const Clonable &property)
Set/add a branch property.
Definition: Node.h:585
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:495
virtual bool hasNoSon() const
Definition: Node.h:669
virtual void deleteNodeProperty(const std::string &name)
Definition: Node.h:530
virtual Clonable * getBranchProperty(const std::string &name)
Definition: Node.h:592
virtual void deleteBranchProperty(const std::string &name)
Definition: Node.h:620
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:563
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