taxonomy_tree.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:15k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: taxonomy_tree.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:29:47  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: taxonomy_tree.cpp,v 1000.2 2004/06/01 18:29:47 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      taxonomy tree stuff
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <objects/seq/Seq_descr.hpp>
  47. #include <objects/seq/Seqdesc.hpp>
  48. #include <objects/seqfeat/BioSource.hpp>
  49. #include <objects/seqfeat/Org_ref.hpp>
  50. #ifdef __WXMSW__
  51. #include <windows.h>
  52. #include <wx/msw/winundef.h>
  53. #endif
  54. #include <wx/wx.h>
  55. #include <wx/treectrl.h>
  56. // the application icon (under Windows it is in resources)
  57. #if defined(__WXGTK__) || defined(__WXMAC__)
  58.     #include "cn3d.xpm"
  59. #endif
  60. #include "taxonomy_tree.hpp"
  61. #include "cn3d_tools.hpp"
  62. #include "block_multiple_alignment.hpp"
  63. #include "sequence_set.hpp"
  64. #include "molecule_identifier.hpp"
  65. #include "messenger.hpp"
  66. USING_NCBI_SCOPE;
  67. USING_SCOPE(objects);
  68. BEGIN_SCOPE(Cn3D)
  69. class TaxonomyWindow : public wxFrame
  70. {
  71.     friend class TaxonomyTree;
  72. public:
  73.     TaxonomyWindow(wxFrame *parent, TaxonomyWindow **handle);
  74.     ~TaxonomyWindow(void);
  75. private:
  76.     wxTreeCtrl *tree;
  77.     TaxonomyWindow **handle;
  78.     void OnActivate(wxTreeEvent& event);
  79.     DECLARE_EVENT_TABLE()
  80. };
  81. class NodeData : public wxTreeItemData
  82. {
  83. public:
  84.     NodeData(const Sequence *s) : sequence(s) { }
  85.     const Sequence *sequence;
  86. };
  87. BEGIN_EVENT_TABLE(TaxonomyWindow, wxFrame)
  88.     EVT_TREE_ITEM_ACTIVATED(-1, TaxonomyWindow::OnActivate)
  89. END_EVENT_TABLE()
  90. TaxonomyWindow::TaxonomyWindow(wxFrame *parent, TaxonomyWindow **thisHandle) :
  91.     handle(thisHandle),
  92.     wxFrame(parent, -1, "Taxonomy Tree", wxPoint(75,75), wxSize(400,400),
  93.         wxDEFAULT_FRAME_STYLE
  94. #if defined(__WXMSW__)
  95.                 | wxFRAME_TOOL_WINDOW | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT
  96. #endif
  97.         )
  98. {
  99.     // for now, create simple wx window with the tree
  100.     tree = new wxTreeCtrl(this, -1, wxPoint(0,0), GetClientSize());
  101.     SetIcon(wxICON(cn3d));
  102. }
  103. TaxonomyWindow::~TaxonomyWindow(void)
  104. {
  105.     if (handle) *handle = NULL;
  106. }
  107. static void ExpandAll(wxTreeCtrl& tree, const wxTreeItemId& id, bool shouldExpand, int toLevel)
  108. {
  109.     if (toLevel == 0 || !tree.ItemHasChildren(id)) return;
  110.     // shouldExpand/collapse this node
  111.     bool isExpanded = tree.IsExpanded(id);
  112.     if (shouldExpand && !isExpanded)
  113.         tree.Expand(id);
  114.     else if (!shouldExpand && isExpanded)
  115.         tree.Collapse(id);
  116.     // descend tree and shouldExpand/collapse all children
  117.     long cookie = (long) (&tree);
  118.     for (wxTreeItemId child=tree.GetFirstChild(id, cookie); child.IsOk(); child=tree.GetNextChild(id, cookie))
  119.         ExpandAll(tree, child, shouldExpand, toLevel - 1);
  120. }
  121. void TaxonomyWindow::OnActivate(wxTreeEvent& event)
  122. {
  123.     const wxTreeItemId& itemID = event.GetItem();
  124.     bool keyActivated = (event.GetPoint().x == 0 && event.GetPoint().y == 0);
  125.     bool hasChildren = tree->ItemHasChildren(itemID);
  126.     if (keyActivated && hasChildren) {
  127.         // expand/collapse entire tree at internal node
  128.         ExpandAll(*tree, itemID, !tree->IsExpanded(itemID), -1);
  129.     }
  130.     else if (!keyActivated && !hasChildren) {
  131.         // highlight sequence on double-click
  132.         NodeData *data = dynamic_cast<NodeData*>(tree->GetItemData(itemID));
  133.         if (data)
  134.             GlobalMessenger()->HighlightAndShowSequence(data->sequence);
  135.     }
  136.     event.Skip();
  137. }
  138. TaxonomyTree::TaxonomyTree(void)
  139. {
  140. }
  141. bool TaxonomyTree::Init(void)
  142. {
  143.     if (taxonomyServer.IsAlive()) return true;
  144.     wxBeginBusyCursor();    // sometimes takes a while
  145.     bool status = taxonomyServer.Init();
  146.     wxEndBusyCursor();
  147.     if (status && taxonomyServer.IsAlive())
  148.         INFOMSG("taxonomy server connection initialized");
  149.     else
  150.         ERRORMSG("Unable to initialize taxonomy server!");
  151.     return status;
  152. }
  153. TaxonomyTree::~TaxonomyTree(void)
  154. {
  155.     taxonomyServer.Fini();
  156.     TaxonomyWindowList::iterator w, we = taxonomyWindows.end();
  157.     for (w=taxonomyWindows.begin(); w!=we; ++w) {
  158.         if (**w) {
  159.             (**w)->handle = NULL;
  160.             (**w)->Destroy();
  161.         }
  162.         delete *w;
  163.     }
  164. }
  165. class TaxonomyTreeNode
  166. {
  167. public:
  168.     int taxid, parentTaxid, nDescendentLeaves;
  169.     string name;
  170.     // use maps to ensure uniqueness
  171.     typedef map < int , bool > ChildTaxIDMap;
  172.     ChildTaxIDMap childTaxids;
  173.     // int here is to count occurrences
  174.     typedef map < const Sequence * , int > SequenceMap;
  175.     SequenceMap sequences;
  176.     TaxonomyTreeNode(void) { taxid = parentTaxid = nDescendentLeaves = 0; }
  177. };
  178. // map taxid -> node
  179. typedef map < int , TaxonomyTreeNode > TaxonomyTreeMap;
  180. static void AppendChildrenToTree(wxTreeCtrl *tree, const TaxonomyTreeMap& treeMap,
  181.     const TaxonomyTreeNode& node, const wxTreeItemId id, bool abbreviated)
  182. {
  183.     // add sequence nodes
  184.     if (node.sequences.size() > 0) {
  185.         TaxonomyTreeNode::SequenceMap::const_iterator s, se = node.sequences.end();
  186.         for (s=node.sequences.begin(); s!=se; ++s) {
  187.             wxString name(s->first->identifier->ToString().c_str());
  188.             if (s->second > 1) {
  189.      wxString tmp = name;
  190.                 name.Printf("%s (x%i)", tmp.c_str(), s->second);
  191.     }
  192.             const wxTreeItemId& child = tree->AppendItem(id, name);
  193.             tree->SetItemData(child, new NodeData(s->first));
  194.         }
  195.     }
  196.     // add heirarchy nodes
  197.     if (node.childTaxids.size() > 0) {
  198.         TaxonomyTreeNode::ChildTaxIDMap::const_iterator c, ce = node.childTaxids.end();
  199.         for (c=node.childTaxids.begin(); c!=ce; ++c) {
  200.             const TaxonomyTreeNode *childNode = &(treeMap.find(c->first)->second);
  201.             wxString name = childNode->name.c_str();
  202.             if (abbreviated) {
  203.                 while (childNode->sequences.size() == 0 && childNode->childTaxids.size() == 1 &&
  204.                        treeMap.find(childNode->childTaxids.begin()->first)->second.sequences.size() == 0)
  205.                     childNode = &(treeMap.find(childNode->childTaxids.begin()->first)->second);
  206.                 if (childNode->name != name.c_str())
  207.                     name += wxString(" . . . ") + childNode->name.c_str();
  208.             }
  209.     wxString tmp = name;
  210.             name.Printf("%s (%i)", tmp.c_str(), childNode->nDescendentLeaves);
  211.             wxTreeItemId childId = tree->AppendItem(id, name);
  212.             AppendChildrenToTree(tree, treeMap, *childNode, childId, abbreviated);
  213.         }
  214.     }
  215. }
  216. static void AddNode(TaxonomyTreeMap *taxTree, const Sequence *seq,
  217.     int taxid, const CTaxon2_data *taxData, int parent)
  218. {
  219.     // set info for child node
  220.     TaxonomyTreeNode& node = (*taxTree)[taxid];
  221.     node.taxid = taxid;
  222.     node.parentTaxid = parent;
  223.     node.name = (taxData->IsSetOrg() && taxData->GetOrg().IsSetTaxname()) ?
  224.         taxData->GetOrg().GetTaxname() : string("(error getting node name!)");
  225.     if (seq) {
  226.         ++(node.sequences[seq]);
  227.         ++(node.nDescendentLeaves);
  228.     }
  229.     // set info for parent node
  230.     TaxonomyTreeNode& parentNode = (*taxTree)[parent];
  231.     parentNode.childTaxids[taxid] = true;
  232.     ++(parentNode.nDescendentLeaves);
  233. }
  234. void TaxonomyTree::ShowTreeForAlignment(wxFrame *windowParent,
  235.     const BlockMultipleAlignment *alignment, bool abbreviated)
  236. {
  237.     wxBeginBusyCursor();    // sometimes takes a while
  238.     // holds tree structure
  239.     TaxonomyTreeMap taxTree;
  240.     // build a tree of all sequences with known taxonomy
  241.     int row, taxid, parent;
  242.     const CTaxon2_data *taxData;
  243.     for (row=0; row<alignment->NRows(); ++row) {
  244.         const Sequence *seq = alignment->GetSequenceOfRow(row);
  245.         taxid = GetTaxIDForSequence(seq);
  246.         taxData = (taxid != 0) ? GetTaxInfoForTaxID(taxid) : NULL;
  247.         if (!taxData) continue;
  248.         // add node to tree
  249.         do {
  250.             // find parent
  251.             parent = GetParentTaxID(taxid);
  252.             if (parent == 0) break;
  253.             // add node to tree
  254.             AddNode(&taxTree, seq, taxid, taxData, parent);
  255.             seq = NULL; // only add sequence to first node (leaf)
  256.             // on to next level up
  257.             taxid = parent;
  258.             if (taxid > 1) {    // no tax info for root
  259.                 taxData = GetTaxInfoForTaxID(taxid);
  260.                 if (!taxData) break;
  261.             }
  262.         } while (taxid > 1);    // 1 is root tax node
  263.     }
  264.     taxTree[1].name = "Global Root";
  265.     TRACEMSG("apparent # leaves in tree: " << taxTree[1].nDescendentLeaves);
  266.     TaxonomyTreeNode *node = &(taxTree[1]);
  267.     while (node->childTaxids.size() == 1) node = &(taxTree[node->childTaxids.begin()->first]);
  268.     INFOMSG("deepest node containing all leaves: " << node->name);
  269.     TaxonomyWindow *window;
  270.     TaxonomyWindow **handle = new TaxonomyWindow*;
  271.     *handle = window = new TaxonomyWindow(windowParent, handle);
  272.     wxString name;
  273.     name.Printf("%s (%i)", node->name.c_str(), node->nDescendentLeaves);
  274.     AppendChildrenToTree(window->tree, taxTree, *node, window->tree->AddRoot(name), abbreviated);
  275.     ExpandAll(*(window->tree), window->tree->GetRootItem(), true, 2);
  276.     window->Show(true);
  277.     taxonomyWindows.push_back(handle);
  278.     wxEndBusyCursor();
  279. }
  280. int TaxonomyTree::GetTaxIDForSequence(const Sequence *seq)
  281. {
  282.     // check cache first
  283.     TaxonomyIDMap::const_iterator id = taxonomyIDs.find(seq->identifier);
  284.     if (id != taxonomyIDs.end()) return id->second;
  285.     if (!Init()) return 0;
  286.     int taxid = 0;
  287.     string err = "no gi or source info";
  288.     // try to get "official" tax info from gi
  289.     if (seq->identifier->gi != MoleculeIdentifier::VALUE_NOT_SET) {
  290.         if (!taxonomyServer.GetTaxId4GI(seq->identifier->gi, taxid)) {
  291.             taxid = 0;
  292.             err = taxonomyServer.GetLastError();
  293.         }
  294.     }
  295.     // otherwise, try to get it from org info in Bioseq
  296.     if (taxid == 0 && seq->bioseqASN->IsSetDescr()) {
  297.         CBioseq::TDescr::Tdata::const_iterator d, de = seq->bioseqASN->GetDescr().Get().end();
  298.         for (d=seq->bioseqASN->GetDescr().Get().begin(); d!=de; ++d) {
  299.             const COrg_ref *org = NULL;
  300.             if ((*d)->IsOrg())
  301.                 org = &((*d)->GetOrg());
  302.             else if ((*d)->IsSource())
  303.                 org = &((*d)->GetSource().GetOrg());
  304.             if (org) {
  305.                 if ((taxid=taxonomyServer.GetTaxIdByOrgRef(*org)) != 0)
  306.                     break;
  307.                 else
  308.                     err = taxonomyServer.GetLastError();
  309.             }
  310.         }
  311.     }
  312.     // add taxid to cache
  313.     if (taxid == 0)
  314.         WARNINGMSG("Unable to get taxonomy for " << seq->identifier->ToString()
  315.             << "; reason: " << err);
  316. //    else
  317. //        TESTMSG(seq->identifier->ToString() << " is from taxid " << taxid);
  318.     taxonomyIDs[seq->identifier] = taxid;
  319.     return taxid;
  320. }
  321. const ncbi::objects::CTaxon2_data * TaxonomyTree::GetTaxInfoForTaxID(int taxid)
  322. {
  323.     // check cache first
  324.     TaxonomyInfoMap::const_iterator i = taxonomyInfo.find(taxid);
  325.     if (i != taxonomyInfo.end()) return i->second.GetPointer();
  326.     // if not present, query server
  327.     if (!Init()) return NULL;
  328.     CRef < CTaxon2_data > data = taxonomyServer.GetById(taxid);
  329.     // add to cache
  330.     if (data.Empty())
  331.         WARNINGMSG("Unable to get taxonomy data for taxid " << taxid
  332.             << "; reason: " << taxonomyServer.GetLastError());
  333. //    else if (data->IsSetOrg() && data->GetOrg().IsSetTaxname())
  334. //        TESTMSG("taxid " << taxid << " is " << data->GetOrg().GetTaxname());
  335.     taxonomyInfo[taxid] = data;
  336.     return data.GetPointer();
  337. }
  338. int TaxonomyTree::GetParentTaxID(int taxid)
  339. {
  340.     // check cache first
  341.     TaxonomyParentMap::const_iterator p = taxonomyParents.find(taxid);
  342.     if (p != taxonomyParents.end()) return p->second;
  343.     // if not present, query server
  344.     if (!Init()) return 0;
  345.     int parent = taxonomyServer.GetParent(taxid);
  346.     // add to cache
  347.     if (parent == 0)
  348.         WARNINGMSG("Unable to get parent for taxid " << taxid
  349.             << "; reason: " << taxonomyServer.GetLastError());
  350. //    else
  351. //        TESTMSG("taxid " << parent << " is parent of " << taxid);
  352.     taxonomyParents[taxid] = parent;
  353.     return parent;
  354. }
  355. END_SCOPE(Cn3D)
  356. /*
  357. * ---------------------------------------------------------------------------
  358. * $Log: taxonomy_tree.cpp,v $
  359. * Revision 1000.2  2004/06/01 18:29:47  gouriano
  360. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.13
  361. *
  362. * Revision 1.13  2004/05/21 21:41:40  gorelenk
  363. * Added PCH ncbi_pch.hpp
  364. *
  365. * Revision 1.12  2004/03/15 18:38:52  thiessen
  366. * prefer prefix vs. postfix ++/-- operators
  367. *
  368. * Revision 1.11  2004/02/19 17:05:20  thiessen
  369. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  370. *
  371. * Revision 1.10  2003/02/03 19:20:08  thiessen
  372. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  373. *
  374. * Revision 1.9  2002/12/20 02:43:35  thiessen
  375. * fix Printf to self problems
  376. *
  377. * Revision 1.8  2002/10/10 16:58:56  thiessen
  378. * add const where required
  379. *
  380. * Revision 1.7  2002/10/07 18:51:53  thiessen
  381. * add abbreviated taxonomy tree
  382. *
  383. * Revision 1.6  2002/10/07 13:29:32  thiessen
  384. * add double-click -> show row to taxonomy tree
  385. *
  386. * Revision 1.5  2002/10/04 19:10:35  thiessen
  387. * fix root tax node name
  388. *
  389. * Revision 1.4  2002/10/04 18:45:28  thiessen
  390. * updates to taxonomy viewer
  391. *
  392. * Revision 1.3  2002/09/12 13:09:38  thiessen
  393. * fix windows/wx header problem
  394. *
  395. * Revision 1.2  2002/09/10 17:02:26  thiessen
  396. * show count for repeated sequences
  397. *
  398. * Revision 1.1  2002/09/09 22:51:19  thiessen
  399. * add basic taxonomy tree viewer
  400. *
  401. */