bpp-phyl  2.2.0
NexusIoTree.cpp
Go to the documentation of this file.
1 //
2 // File: NexusIOTree.cpp
3 // Created by: Julien Dutheil
4 // Created on: Wed May 27 19:06 2009
5 //
6 
7 /*
8 Copyright or © or Copr. CNRS, (November 16, 2004)
9 
10 This software is a computer program whose purpose is to provide classes
11 for phylogenetic data analysis.
12 
13 This software is governed by the CeCILL license under French law and
14 abiding by the rules of distribution of free software. You can use,
15 modify and/ or redistribute the software under the terms of the CeCILL
16 license as circulated by CEA, CNRS and INRIA at the following URL
17 "http://www.cecill.info".
18 
19 As a counterpart to the access to the source code and rights to copy,
20 modify and redistribute granted by the license, users are provided only
21 with a limited warranty and the software's author, the holder of the
22 economic rights, and the successive licensors have only limited
23 liability.
24 
25 In this respect, the user's attention is drawn to the risks associated
26 with loading, using, modifying and/or developing or reproducing the
27 software by the user in light of its specific status of free software,
28 that may mean that it is complicated to manipulate, and that also
29 therefore means that it is reserved for developers and experienced
30 professionals having in-depth computer knowledge. Users are therefore
31 encouraged to load and test the software's suitability as regards their
32 requirements in conditions enabling the security of their systems and/or
33 data to be ensured and, more generally, to use and operate it in the
34 same conditions as regards security.
35 
36 The fact that you are presently reading this means that you have had
37 knowledge of the CeCILL license and that you accept its terms.
38 */
39 
40 #include "NexusIoTree.h"
41 #include "../Tree.h"
42 #include "../TreeTemplate.h"
43 #include "../TreeTemplateTools.h"
44 
45 #include <Bpp/Text/TextTools.h>
46 #include <Bpp/Io/FileTools.h>
47 #include <Bpp/Text/StringTokenizer.h>
48 #include <Bpp/Text/NestedStringTokenizer.h>
49 #include <Bpp/Numeric/VectorTools.h>
50 
51 //From SeqLib:
52 #include <Bpp/Seq/Io/NexusTools.h>
53 
54 using namespace bpp;
55 
56 // From the STL:
57 #include <iostream>
58 #include <fstream>
59 
60 using namespace std;
61 
62 /******************************************************************************/
63 
64 const string NexusIOTree::getFormatName() const { return "Nexus"; }
65 
66 /******************************************************************************/
67 
69 {
70  return string("Nexus format (trees only). ");
71 }
72 
73 /******************************************************************************/
74 
75 #if defined(NO_VIRTUAL_COV)
76  Tree *
77 #else
79 #endif
80 NexusIOTree::read(istream &in) const throw (Exception)
81 {
82  vector<Tree*> trees;
83  read(in, trees);
84  if (trees.size() == 0)
85  throw IOException("NexusIOTree::read(). No tree found in file.");
86  for (size_t i = trees.size() - 1; i > 0; i--)
87  delete trees[i];
88  return dynamic_cast<TreeTemplate<Node>*>(trees[0]);
89 }
90 
91 /******************************************************************************/
92 
93 void NexusIOTree::read(std::istream& in, std::vector<Tree*>& trees) const throw (Exception)
94 {
95  // Checking the existence of specified file
96  if (! in) { throw IOException ("NexusIOTree::read(). Failed to read from stream"); }
97 
98  //Look for the TREES block:
99  string line = "";
100  while (TextTools::toUpper(line) != "BEGIN TREES;")
101  {
102  if (in.eof())
103  throw Exception("NexusIOTree::read(). No trees block was found.");
104  line = TextTools::removeSurroundingWhiteSpaces(FileTools::getNextLine(in));
105  }
106 
107  string cmdName = "", cmdArgs = "";
108  bool cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
109  if (! cmdFound)
110  throw Exception("NexusIOTree::read(). Missing tree command.");
111  cmdName = TextTools::toUpper(cmdName);
112 
113  //Look for the TRANSLATE command:
114  map<string, string> translation;
115  bool hasTranslation = false;
116  if (cmdName == "TRANSLATE")
117  {
118  //Parse translation:
119  StringTokenizer st(cmdArgs, ",");
120  while (st.hasMoreToken())
121  {
122  string tok = TextTools::removeSurroundingWhiteSpaces(st.nextToken());
123  NestedStringTokenizer nst(tok, "'", "'", " \t");
124  if (nst.numberOfRemainingTokens() != 2)
125  throw Exception("NexusIOTree::read(). Unvalid translation description.");
126  string name = nst.nextToken();
127  string tln = nst.nextToken();
128  translation[name] = tln;
129  }
130  hasTranslation = true;
131  cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
132  if (! cmdFound)
133  throw Exception("NexusIOTree::read(). Missing tree command.");
134  else
135  cmdName = TextTools::toUpper(cmdName);
136  }
137 
138  //Now parse the trees:
139  while (cmdFound && cmdName != "END")
140  {
141  if (cmdName != "TREE")
142  throw Exception("NexusIOTree::read(). Unvalid command found: " + cmdName);
143  string::size_type pos = cmdArgs.find("=");
144  if (pos == string::npos)
145  throw Exception("NexusIOTree::read(). unvalid format, should be tree-name=tree-description");
146  string description = cmdArgs.substr(pos + 1);
147  TreeTemplate<Node>* tree = TreeTemplateTools::parenthesisToTree(description + ";", true);
148 
149  //Now translate leaf names if there is a translation:
150  //(we assume that all trees share the same translation! ===> check!)
151  if (hasTranslation)
152  {
153  vector<Node*> leaves = tree->getLeaves();
154  for (size_t i = 0; i < leaves.size(); i++)
155  {
156  string name = leaves[i]->getName();
157  if (translation.find(name) == translation.end())
158  {
159  throw Exception("NexusIOTree::read(). No translation was given for this leaf: " + name);
160  }
161  leaves[i]->setName(translation[name]);
162  }
163  }
164  trees.push_back(tree);
165  cmdFound = NexusTools::getNextCommand(in, cmdName, cmdArgs, false);
166  if (cmdFound) cmdName = TextTools::toUpper(cmdName);
167  }
168 }
169 
170 /******************************************************************************/
171 
172 void NexusIOTree::write_(const Tree& tree, ostream& out) const throw (Exception)
173 {
174  vector<Tree*> trees;
175  trees.push_back(&const_cast<Tree&>(tree));
176  write(trees, out);
177 }
178 
179 /******************************************************************************/
180 
181 template<class N>
182 void NexusIOTree::write_(const TreeTemplate<N>& tree, ostream& out) const throw (Exception)
183 {
184  vector<Tree*> trees;
185  trees.push_back(&const_cast<Tree&>(tree));
186  write(trees, out);
187 }
188 
189 /******************************************************************************/
190 
191 void NexusIOTree::write_(const vector<Tree*>& trees, ostream& out) const throw (Exception)
192 {
193  // Checking the existence of specified file, and possibility to open it in write mode
194  if (! out) { throw IOException ("NexusIOTree::write: failed to write to stream"); }
195 
196  out << "#NEXUS" << endl;
197  out << endl;
198  out << "BEGIN TREES;" << endl;
199 
200  //First, we retrieve all leaf names from all trees:
201  vector<string> names;
202  for (size_t i = 0; i < trees.size(); i++)
203  {
204  names = VectorTools::vectorUnion(names, trees[i]->getLeavesNames());
205  }
206  //... and create a translation map:
207  map<string, size_t> translation;
208  size_t code = 0;
209  for (size_t i = 0; i < names.size(); i++)
210  {
211  translation[names[i]] = code++;
212  }
213 
214  //Second we translate all leaf names to their corresponding code:
215  vector<Tree*> translatedTrees(trees.size());
216  for (size_t i = 0; i < trees.size(); i++)
217  {
218  vector<int> leavesId = trees[i]->getLeavesId();
219  Tree* tree = dynamic_cast<Tree*>(trees[i]->clone());
220  for (size_t j = 0; j < leavesId.size(); j++)
221  {
222  tree->setNodeName(leavesId[j], TextTools::toString(translation[tree->getNodeName(leavesId[j])]));
223  }
224  translatedTrees[i] = tree;
225  }
226 
227  //Third we print the translation command:
228  out << " TRANSLATE";
229  size_t count = 0;
230  for (map<string, size_t>::iterator it = translation.begin(); it != translation.end(); it++)
231  {
232  out << endl << " " << it->second << "\t" << it->first;
233  count++;
234  if (count < translation.size())
235  out << ",";
236  }
237  out << ";";
238 
239  //Finally we print all tree descriptions:
240  for (size_t i = 0; i < trees.size(); i++)
241  {
242  out << endl << " TREE tree" << (i+1) << " = " << TreeTools::treeToParenthesis(*translatedTrees[i]);
243  }
244  out << "END;" << endl;
245 
246  //Clean trees:
247  for (size_t i = 0; i < translatedTrees.size(); i++)
248  {
249  delete translatedTrees[i];
250  }
251 }
252 
253 /******************************************************************************/
254 
255 template<class N>
256 void NexusIOTree::write_(const vector<TreeTemplate<N>*>& trees, ostream& out) const throw (Exception)
257 {
258  // Checking the existence of specified file, and possibility to open it in write mode
259  if (! out) { throw IOException ("NexusIOTree::write: failed to write to stream"); }
260 
261  out << "#NEXUS" << endl;
262  out << endl;
263  out << "BEGIN TREES;" << endl;
264 
265  //First, we retrieve all leaf names from all trees:
266  vector<string> names;
267  for (size_t i = 0; i < trees.size(); i++)
268  {
269  names = VectorTools::vectorUnion(names, trees[i]->getLeavesNames());
270  }
271  //... and create a translation map:
272  map<string, size_t> translation;
273  size_t code = 0;
274  for (size_t i = 0; i < names.size(); i++)
275  {
276  translation[names[i]] = code++;
277  }
278 
279  //Second we translate all leaf names to their corresponding code:
280  vector<Tree*> translatedTrees(trees.size());
281  for (size_t i = 0; i < trees.size(); i++)
282  {
283  vector<int> leavesId = trees[i]->getLeavesId();
284  Tree* tree = dynamic_cast<Tree*>(trees[i]->clone());
285  for (size_t j = 0; j < leavesId.size(); j++)
286  {
287  tree->setNodeName(leavesId[j], TextTools::toString(translation[tree->getNodeName(leavesId[j])]));
288  }
289  translatedTrees[i] = tree;
290  }
291 
292  //Third we print the translation command:
293  out << " TRANSLATE";
294  size_t count = 0;
295  for (map<string, size_t>::iterator it = translation.begin(); it != translation.end(); it++)
296  {
297  out << endl << " " << it->second << "\t" << it->first;
298  count++;
299  if (count < translation.size())
300  out << ",";
301  }
302  out << ";";
303 
304  //Finally we print all tree descriptions:
305  for (size_t i = 0; i < trees.size(); i++)
306  {
307  out << endl << " TREE tree" << (i+1) << " = " << TreeTemplateTools::treeToParenthesis(*translatedTrees[i]);
308  }
309  out << "END;" << endl;
310 
311  //Clean trees:
312  for (size_t i = 0; i < translatedTrees.size(); i++)
313  {
314  delete translatedTrees[i];
315  }
316 }
317 
318 /******************************************************************************/
319 
320 
static std::string treeToParenthesis(const Tree &tree, bool writeId=false)
Get the parenthesis description of a tree.
Definition: TreeTools.cpp:330
const std::string getFormatDescription() const
Definition: NexusIoTree.cpp:68
TreeTemplate< Node > * read(const std::string &path) const
Read a tree from a file.
Definition: NexusIoTree.h:98
STL namespace.
The phylogenetic tree class.
virtual void setNodeName(int nodeId, const std::string &name)=0
Interface for phylogenetic tree objects.
Definition: Tree.h:148
virtual std::vector< const N * > getLeaves() const
Definition: TreeTemplate.h:407
static std::string treeToParenthesis(const TreeTemplate< Node > &tree, bool writeId=false)
Get the parenthesis description of a tree.
const std::string getFormatName() const
Definition: NexusIoTree.cpp:64
static TreeTemplate< Node > * parenthesisToTree(const std::string &description, bool bootstrap=true, const std::string &propertyName=TreeTools::BOOTSTRAP, bool withId=false)
Parse a string in the parenthesis format and convert it to a tree.
void write_(const Tree &tree, std::ostream &out) const
virtual std::string getNodeName(int nodeId) const =0