]> git.donarmstrong.com Git - mothur.git/blob - designmap.cpp
fixes while testing 1.33.0
[mothur.git] / designmap.cpp
1 //
2 //  designmap.cpp
3 //  Mothur
4 //
5 //  Created by SarahsWork on 6/17/13.
6 //  Copyright (c) 2013 Schloss Lab. All rights reserved.
7 //
8
9 #include "designmap.h"
10
11 /************************************************************/
12 DesignMap::DesignMap(string file) {
13     try {
14         m = MothurOut::getInstance();
15         defaultClass = "not found";
16         read(file);
17     }
18         catch(exception& e) {
19                 m->errorOut(e, "DesignMap", "DesignMap");
20                 exit(1);
21         }
22 }
23 /************************************************************/
24 int DesignMap::read(string file) {
25     try {
26         ifstream in;
27         m->openInputFile(file, in);
28         
29         string headers = m->getline(in); m->gobble(in);
30         vector<string> columnHeaders = m->splitWhiteSpace(headers);
31         
32         namesOfCategories.clear();
33         indexCategoryMap.clear();
34         indexNameMap.clear();
35         designMap.clear();
36         map<int, string> originalGroupIndexes;
37         for (int i = 1; i < columnHeaders.size(); i++) {  namesOfCategories.push_back(columnHeaders[i]);  originalGroupIndexes[i-1] = columnHeaders[i]; }
38         if (columnHeaders.size() > 1) { defaultClass = columnHeaders[1]; }
39         
40         //sort groups to keep consistent with how we store the groups in groupmap
41         sort(namesOfCategories.begin(), namesOfCategories.end());
42         for (int i = 0; i < namesOfCategories.size(); i++) {  indexCategoryMap[namesOfCategories[i]] = i; }
43         int numCategories = namesOfCategories.size();
44         
45         bool error = false;
46         string group;
47         totalCategories.resize(numCategories);
48         int count = 0;
49         while (!in.eof()) {
50             
51             if (m->control_pressed) { break; }
52             
53             in >> group; m->gobble(in); 
54             if (m->debug) { m->mothurOut("[DEBUG]: group = " + group + "\n"); }
55             
56             //if group info, then read it
57             vector<string> categoryValues; categoryValues.resize(numCategories, "not found");
58             for (int i = 0; i < numCategories; i++) {
59                 int thisIndex = indexCategoryMap[originalGroupIndexes[i]]; //find index of this category because we sort the values.
60                 string temp = "not found";
61                 in >> temp; categoryValues[thisIndex] = temp; m->gobble(in);
62                 
63                 if (m->debug) { m->mothurOut("[DEBUG]: value = " + temp + "\n"); }
64                 
65                 //do we have this value for this category already
66                 map<string, int>::iterator it = totalCategories[thisIndex].find(temp);
67                 if (it == totalCategories[thisIndex].end()) { totalCategories[thisIndex][temp] = 1; }
68                 else {  totalCategories[thisIndex][temp]++; }
69             }
70                            
71             
72             map<string, int>::iterator it = indexNameMap.find(group);
73             if (it == indexNameMap.end()) {
74                 indexNameMap[group] = count;
75                 designMap.push_back(categoryValues);
76                 count++;
77             }else {
78                 error = true;
79                 m->mothurOut("[ERROR]: Your design file contains more than 1 group named " + group + ", group names must be unique. Please correct."); m->mothurOutEndLine();
80             }
81         }
82         in.close();
83         
84         //sanity check
85         for (int i = 0; i < totalCategories.size(); i++) {
86             map<string, int>::iterator it = totalCategories[i].find(namesOfCategories[i]);
87             if (it != totalCategories[i].end()) { //we may have an old style design file since category name matches a value
88                 m->mothurOut("\n[WARNING]: Your design file has a category and value for that category named " + namesOfCategories[i] + ". Perhaps you are using an old style design file without headers? If so, please correct."); m->mothurOutEndLine();
89             }
90         }
91         
92         if (error) { m->control_pressed = true; }
93         
94         return 0;
95     }
96         catch(exception& e) {
97                 m->errorOut(e, "DesignMap", "read");
98                 exit(1);
99         }
100 }
101 /************************************************************/
102 ////groupName, returns first categories value. 
103 string DesignMap::get(string groupName) {
104     try {
105         string value = "not found";
106         
107         map<string, int>::iterator it2 = indexNameMap.find(groupName);
108         if (it2 == indexNameMap.end()) {
109             m->mothurOut("[ERROR]: group " + groupName + " is not in your design file. Please correct.\n"); m->control_pressed = true;
110         }else {
111             return designMap[it2->second][0];
112         }
113        
114         return value;
115     }
116         catch(exception& e) {
117                 m->errorOut(e, "DesignMap", "get");
118                 exit(1);
119         }
120 }
121 /************************************************************/
122 ////categoryName, returns category values.
123 vector<string> DesignMap::getValues(string catName) {
124     try {
125         vector<string> values;
126         
127         map<string, int>::iterator it2 = indexCategoryMap.find(catName);
128         if (it2 == indexCategoryMap.end()) {
129             m->mothurOut("[ERROR]: category " + catName + " is not in your design file. Please correct.\n"); m->control_pressed = true;
130         }else {
131             for (map<string, int>::iterator it = totalCategories[it2->second].begin(); it != totalCategories[it2->second].end(); it++) {
132                 values.push_back(it->first);
133             }
134         }
135         
136         return values;
137     }
138         catch(exception& e) {
139                 m->errorOut(e, "DesignMap", "getValues");
140                 exit(1);
141         }
142 }
143
144 /************************************************************/
145 ////groupName, category returns value. example F000132, sex -> male
146 string DesignMap::get(string groupName, string categoryName) {
147     try {
148         string value = "not found";
149         map<string, int>::iterator it = indexCategoryMap.find(categoryName);
150         if (it == indexCategoryMap.end()) {
151             m->mothurOut("[ERROR]: category " + categoryName + " is not in your design file. Please correct.\n"); m->control_pressed = true;
152         }else {
153             map<string, int>::iterator it2 = indexNameMap.find(groupName);
154             if (it2 == indexNameMap.end()) {
155                 m->mothurOut("[ERROR]: group " + groupName + " is not in your design file. Please correct.\n"); m->control_pressed = true;
156             }else {
157                 return designMap[it2->second][it->second];
158             }
159         }
160         return value;
161     }
162         catch(exception& e) {
163                 m->errorOut(e, "DesignMap", "get");
164                 exit(1);
165         }
166 }
167 /************************************************************/
168 //add group, assumes order is correct
169 int DesignMap::push_back(string group, vector<string> values) {
170     try {
171         map<string, int>::iterator it = indexNameMap.find(group);
172         if (it == indexNameMap.end()) {
173             if (values.size() != getNumCategories()) {  m->mothurOut("[ERROR]: Your design file has a " + toString(getNumCategories()) + " categories and " + group + " has " + toString(values.size()) + ", please correct."); m->mothurOutEndLine(); m->control_pressed = true;  return 0; }
174             
175             for (int i = 0; i < values.size(); i++) {
176                 //do we have this value for this category already
177                 map<string, int>::iterator it = totalCategories[i].find(values[i]);
178                 if (it == totalCategories[i].end()) { totalCategories[i][values[i]] = 1; }
179                 else {  totalCategories[i][values[i]]++; }
180             }
181             int count = indexNameMap.size();
182             indexNameMap[group] = count;
183             designMap.push_back(values);
184         }else {
185             m->mothurOut("[ERROR]: Your design file contains more than 1 group named " + group + ", group names must be unique. Please correct."); m->mothurOutEndLine(); m->control_pressed = true;
186         }
187         
188         return 0;
189     }
190         catch(exception& e) {
191                 m->errorOut(e, "DesignMap", "push_back");
192                 exit(1);
193         }
194 }
195 /************************************************************/
196 //set values for group, does not need to set all values. assumes group is in table already
197 int DesignMap::set(string group, map<string, string> values) {
198     try {
199         map<string, int>::iterator it = indexNameMap.find(group);
200         if (it != indexNameMap.end()) {
201             for (map<string, string>::iterator it2 = values.begin(); it2 != values.end(); it2++) {
202                 
203                 map<string, int>::iterator it3 = indexCategoryMap.find(it2->first); //do we have this category
204                 if (it3 == indexCategoryMap.end()) {
205                      m->mothurOut("[ERROR]: Your design file does not contain a category called " + it2->first + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true;
206                 }else {
207                     string oldCategory = designMap[it->second][it3->second];
208                     //adjust totals for old category
209                     int oldCount = totalCategories[it3->second][oldCategory];
210                     if (oldCount == 1) { totalCategories[it3->second].erase(oldCategory); }
211                     else {  totalCategories[it3->second][oldCategory]--; }
212                     
213                     designMap[it->second][it3->second] = it2->second; //reset value
214                     
215                     //adjust totals for new category
216                     map<string, int>::iterator it4 = totalCategories[it3->second].find(it2->second);
217                     if (it4 == totalCategories[it3->second].end()) { totalCategories[it3->second][it2->second] = 1; }
218                     else {  totalCategories[it3->second][it2->second]++; }
219                 }
220             }
221         }else {
222             m->mothurOut("[ERROR]: Your design file does not contain a group named " + group + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true;
223         }
224         
225         return 0;
226     }
227         catch(exception& e) {
228                 m->errorOut(e, "DesignMap", "set");
229                 exit(1);
230         }
231 }
232 /************************************************************/
233 //get number of groups belonging to a category or set of categories, with value or a set of values. Must have all categories and values. Example:
234 //  map<treatment - > early, late>, <sex -> male> would return 1. Only one group is male and from early or late.
235 int DesignMap::getNumUnique(map<string, vector<string> > selected) {
236     try {
237         int num = 0;
238         
239         //get indexes of categories
240         vector<int> indexes;
241         for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) {
242             map<string, int>::iterator it2 = indexCategoryMap.find(it->first);
243             if (it2 == indexCategoryMap.end()) {
244                 m->mothurOut("[ERROR]: Your design file does not contain a category named " + it->first + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return 0;
245             }else { indexes.push_back(it2->second); }
246         }
247         
248         for (int i = 0; i < designMap.size(); i++) {
249             bool hasAll = true; //innocent til proven guilty
250             int count = 0;
251             for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) { //loop through each
252                 //check category to see if this group meets the requirements
253                 if (!m->inUsersGroups(designMap[i][indexes[count]], it->second)) { hasAll = false; it = selected.end(); }
254                 count++;
255             }
256             if (hasAll) { num++; }
257         }
258         
259         return num;
260     }
261         catch(exception& e) {
262                 m->errorOut(e, "DesignMap", "getNumUnique");
263                 exit(1);
264         }
265 }
266 /************************************************************/
267 //get number of groups belonging to a category or set of categories, with value or a set of values. Must have at least one categories and values. Example:
268 //  map<treatment - > early, late>, <sex -> male> would return 3. All three group have are either male or from early or late.
269 int DesignMap::getNumShared(map<string, vector<string> > selected) {
270     try {
271         int num = 0;
272         
273         //get indexes of categories
274         vector<int> indexes;
275         for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) {
276             map<string, int>::iterator it2 = indexCategoryMap.find(it->first);
277             if (it2 == indexCategoryMap.end()) {
278                 m->mothurOut("[ERROR]: Your design file does not contain a category named " + it->first + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return 0;
279             }else { indexes.push_back(it2->second); }
280         }
281         
282         for (int i = 0; i < designMap.size(); i++) {
283             bool hasAny = false; //guilty til proven innocent
284             int count = 0;
285             for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) { //loop through each
286                 //check category to see if this group meets the requirements
287                 if (m->inUsersGroups(designMap[i][indexes[count]], it->second)) { hasAny = true; it = selected.end(); }
288                 count++;
289             }
290             if (hasAny) { num++; }
291         }
292
293         
294         return num;
295     }
296         catch(exception& e) {
297                 m->errorOut(e, "DesignMap", "getNumShared");
298                 exit(1);
299         }
300 }
301
302 /************************************************************/
303 //get names of groups belonging to a category or set of categories, with value or a set of values. Must have all categories and values. Example:
304 //  map<treatment - > early, late>, <sex -> male> would return F000132. F000132 is the only group which is male and from early or late.
305 vector<string> DesignMap::getNamesUnique(map<string, vector<string> > selected) {
306     try {
307         vector<string> names;
308         
309         //get indexes of categories
310         vector<int> indexes;
311         for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) {
312             map<string, int>::iterator it2 = indexCategoryMap.find(it->first);
313             if (it2 == indexCategoryMap.end()) {
314                 m->mothurOut("[ERROR]: Your design file does not contain a category named " + it->first + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return names;
315             }else { indexes.push_back(it2->second); }
316         }
317         
318         //map int to name
319         map<int, string> reverse;
320         for (map<string, int>::iterator it = indexNameMap.begin(); it != indexNameMap.end(); it++) {
321             reverse[it->second] = it->first;
322         }
323         
324         for (int i = 0; i < designMap.size(); i++) {
325             bool hasAll = true; //innocent til proven guilty
326             int count = 0;
327             for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) { //loop through each
328                 //check category to see if this group meets the requirements
329                 if (!m->inUsersGroups(designMap[i][indexes[count]], it->second)) { hasAll = false; it = selected.end(); }
330                 count++;
331             }
332             if (hasAll) {
333                 map<int, string>::iterator it = reverse.find(i);
334                 if (it == reverse.end()) {
335                     m->mothurOut("[ERROR]: should never get here, oops. Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return names;
336                 }else { names.push_back(it->second); }
337             }
338         }
339
340         
341         return names;
342     }
343         catch(exception& e) {
344                 m->errorOut(e, "DesignMap", "getNamesUnique");
345                 exit(1);
346         }
347 }
348 /************************************************************/
349 //get names of groups belonging to a category or set of categories, with value or a set of values. Must have all categories and values. Example:
350 //  map<treatment - > early, late>, <sex -> male> would return F000132. F000132 is the only group which is male and from early or late.
351 vector<string> DesignMap::getNamesShared(map<string, vector<string> > selected) {
352     try {
353         vector<string> names;
354         
355         //get indexes of categories
356         vector<int> indexes;
357         for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) {
358             map<string, int>::iterator it2 = indexCategoryMap.find(it->first);
359             if (it2 == indexCategoryMap.end()) {
360                 m->mothurOut("[ERROR]: Your design file does not contain a category named " + it->first + ". Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return names;
361             }else { indexes.push_back(it2->second); }
362         }
363         
364         //map int to name
365         map<int, string> reverse;
366         for (map<string, int>::iterator it = indexNameMap.begin(); it != indexNameMap.end(); it++) {
367             reverse[it->second] = it->first;
368         }
369         
370         for (int i = 0; i < designMap.size(); i++) {
371             bool hasAny = false; 
372             int count = 0;
373             for (map<string, vector<string> >::iterator it = selected.begin(); it != selected.end(); it++) { //loop through each
374                 //check category to see if this group meets the requirements
375                 if (m->inUsersGroups(designMap[i][indexes[count]], it->second)) { hasAny = true; it = selected.end(); }
376                 count++;
377             }
378             if (hasAny) {
379                 map<int, string>::iterator it = reverse.find(i);
380                 if (it == reverse.end()) {
381                     m->mothurOut("[ERROR]: should never get here, oops. Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return names;
382                 }else { names.push_back(it->second); }
383             }
384         }
385         
386         
387         return names;
388     }
389         catch(exception& e) {
390                 m->errorOut(e, "DesignMap", "getNamesShared");
391                 exit(1);
392         }
393 }
394
395 /************************************************************/
396 //get names of groups belonging to a category or set of categories, with value or a set of values. Must have at least one categories and values. Example:
397 //  map<treatment - > early, late>, <sex -> male> would return F000132, F000142, F000138. All three group have are either male or from early or late.
398
399 vector<string> DesignMap::getNames(string category, string value) {
400     try {
401         vector<string> names;
402         
403         map<string, int>::iterator it = indexCategoryMap.find(category);
404         if (it == indexCategoryMap.end()) {
405             m->mothurOut("[ERROR]: category " + category + " is not in your design file. Please correct.\n"); m->control_pressed = true;
406         }else {
407             int column = it->second;
408             
409             //map int to name
410             map<int, string> reverse;
411             for (map<string, int>::iterator it2 = indexNameMap.begin(); it2 != indexNameMap.end(); it2++) {
412                 reverse[it2->second] = it2->first;
413             }
414             
415             for (int i = 0; i < designMap.size(); i++) {
416                 if (designMap[i][column] == value) {
417                     map<int, string>::iterator it2 = reverse.find(i);
418                     if (it2 == reverse.end()) {
419                         m->mothurOut("[ERROR]: should never get here, oops. Please correct."); m->mothurOutEndLine(); m->control_pressed = true; return names;
420                     }else { names.push_back(it2->second); }
421                 }
422             }
423         }
424         return names;
425         
426     }
427         catch(exception& e) {
428                 m->errorOut(e, "DesignMap", "getNames");
429                 exit(1);
430         }
431 }
432
433 /************************************************************/
434 int DesignMap::print(ofstream& out) {
435     try {
436        
437                 out << "group\t";
438         for (int i = 0; i < namesOfCategories.size(); i++) { out << namesOfCategories[i] << '\t'; }
439         out << endl;
440         
441         map<int, string> reverse; //use this to preserve order
442         for (map<string, int>::iterator it = indexNameMap.begin(); it !=indexNameMap.end(); it++) { reverse[it->second] = it->first;  }
443         
444         for (int i = 0; i < designMap.size(); i++) {
445             map<int, string>::iterator itR = reverse.find(i);
446             
447             if (itR != reverse.end()) { //will equal end if seqs were removed because remove just removes from indexNameMap
448                 out << itR->second  << '\t';
449                 
450                 for (int j = 0; j < namesOfCategories.size(); j++) {
451                     out << designMap[i][j] << '\t';
452                 }
453                 out << endl;
454             }
455         }
456         out.close();
457         
458         return 0;
459     }
460         catch(exception& e) {
461                 m->errorOut(e, "DesignMap", "print");
462                 exit(1);
463         }
464 }
465 /************************************************************/
466 //print specific categories
467 int DesignMap::print(ofstream& out, vector<string> cats) {
468     try {
469         
470                 out << "group\t";
471         for (int i = 0; i < namesOfCategories.size(); i++) { if (m->inUsersGroups(namesOfCategories[i], cats)) { out << namesOfCategories[i] << '\t'; } }
472         out << endl;
473         
474         map<int, string> reverse; //use this to preserve order
475         for (map<string, int>::iterator it = indexNameMap.begin(); it !=indexNameMap.end(); it++) { reverse[it->second] = it->first;  }
476         
477         for (int i = 0; i < designMap.size(); i++) {
478             map<int, string>::iterator itR = reverse.find(i);
479             
480             if (itR != reverse.end()) { //will equal end if seqs were removed because remove just removes from indexNameMap
481                 out << itR->second  << '\t';
482                 
483                 for (int j = 0; j < namesOfCategories.size(); j++) {
484                     if (m->inUsersGroups(namesOfCategories[i], cats)) {
485                         out << designMap[i][j] << '\t';
486                     }
487                 }
488                 out << endl;
489             }
490         }
491         out.close();
492         
493         return 0;
494     }
495         catch(exception& e) {
496                 m->errorOut(e, "DesignMap", "print");
497                 exit(1);
498         }
499 }
500
501 /************************************************************/
502