NCBI C++ ToolKit
phylo_tree_ds.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: phylo_tree_ds.cpp 47464 2023-04-20 00:19:10Z evgeniev $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Bob Falk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
34 
36 
43 #include <objects/biotree/Node.hpp>
46 
47 #include <util/xregexp/regexp.hpp>
48 
49 
51 
52 
54 {
55  if (uo.HasField("view-label") &&
56  uo.GetField("view-label").GetData().IsObject()) {
57 
58  const CUser_field::C_Data::TObject& label_obj = uo.GetField("view-label").GetData().GetObject();
59 
60  if (label_obj.HasField("label") &&
61  label_obj.GetField("label").GetData().IsStr()) {
62  m_Label = label_obj.GetField("label").GetData().GetStr();
63  }
64 
65  if (label_obj.HasField("font-name") &&
66  label_obj.GetField("font-name").GetData().IsStr()) {
67  m_FontName = label_obj.GetField("font-name").GetData().GetStr();
68  }
69 
70  if (label_obj.HasField("font-size") &&
71  label_obj.GetField("font-size").GetData().IsInt()) {
72  m_FontSize = label_obj.GetField("font-size").GetData().GetInt();
73  }
74 
75  if (label_obj.HasField("posx") &&
76  label_obj.GetField("posx").GetData().IsInt()) {
77  m_XPos = label_obj.GetField("posx").GetData().GetInt();
78  }
79 
80  if (label_obj.HasField("posy") &&
81  label_obj.GetField("posy").GetData().IsInt()) {
82  m_YPos = label_obj.GetField("posy").GetData().GetInt();
83  }
84 
85  if (label_obj.HasField("color") &&
86  label_obj.GetField("color").GetData().IsStr()) {
87  m_Color.FromString(label_obj.GetField("color").GetData().GetStr());
88  }
89  }
90 }
91 
93 {
95 
96  if (uo.HasField("view-label") &&
97  uo.GetField("view-label").GetData().IsObject()) {
98  label_object.Reset(&(uo.SetField("view-label").SetData().SetObject()));
99  }
100  else {
101  CUser_object* label_uo = new CUser_object();
102  CRef<CObject_id> uo_id;
103  uo_id.Reset(new CObject_id());
104  uo_id->SetStr("label-parameters");
105  label_uo->SetType(*uo_id);
106 
107  label_object.Reset(label_uo);
108  uo.AddField("view-label", *label_uo);
109  }
110 
111  if (label_object->HasField("label") &&
112  label_object->GetField("label").GetData().IsStr()) {
113  label_object->SetField("label").SetData().SetStr(m_Label);
114  }
115  else {
116  label_object->AddField("label", m_Label);
117  }
118 
119  if (label_object->HasField("font-name") &&
120  label_object->GetField("font-name").GetData().IsStr()) {
121  label_object->SetField("font-name").SetData().SetStr(m_FontName);
122  }
123  else {
124  label_object->AddField("font-name", m_FontName);
125  }
126 
127  if (label_object->HasField("font-size") &&
128  label_object->GetField("font-size").GetData().IsInt()) {
129  label_object->SetField("font-size").SetData().SetInt(m_FontSize);
130  }
131  else {
132  label_object->AddField("font-size", m_FontSize);
133  }
134 
135  if (label_object->HasField("posx") &&
136  label_object->GetField("posx").GetData().IsInt()) {
137  label_object->SetField("posx").SetData().SetInt(m_XPos);
138  }
139  else {
140  label_object->AddField("posx", m_XPos);
141  }
142 
143  if (label_object->HasField("posy") &&
144  label_object->GetField("posy").GetData().IsInt()) {
145  label_object->SetField("posy").SetData().SetInt(m_YPos);
146  }
147  else {
148  label_object->AddField("posy", m_YPos);
149  }
150 
151  if (label_object->HasField("color") &&
152  label_object->GetField("color").GetData().IsStr()) {
153  label_object->SetField("color").SetData().SetStr(m_Color.ToString());
154  }
155  else {
156  label_object->AddField("color", m_Color.ToString());
157  }
158 }
159 
161 
162 //////////////////////////////////////////////////////////////////////
163 //
164 //////////////////////////////////////////////////////////////////////
165 CPhyloTreeDataSource::CPhyloTreeDataSource(const objects::CBioTreeContainer& tree,
166  objects::CScope& scope,
167  bool expand_all)
168 : m_Calc(NULL)
169 {
170  Init(tree, scope, expand_all);
171 }
172 
174 {
175  delete m_Calc;
176  m_Calc = NULL;
177 }
178 
179 void CPhyloTreeDataSource::Init(const objects::CBioTreeContainer& tree,
180  objects::CScope& scope,
181  bool expand_all)
182 {
183  // Make sure we have a valid container - it can't be empty.
184  if (tree.GetNodeCount() == 0 ) {
185  NCBI_THROW(CException, eUnknown, "Cannot initialize CPhyloTreeDataSource with an empty tree");
186  }
187 
188  if (!m_TreeModel.IsNull())
189  m_TreeModel->Clear();
190  else
192 
193 
194  m_Scope.Reset(&scope);
195 
198 
199  if (tree.IsSetUser()) {
200  const CBioTreeContainer_Base::TUser& uo = tree.GetUser();
202 
205  }
206 
209 
210  MeasureTree();
211  m_Calc->DumpStats();
212 }
213 
215 {
216  m_TreeModel->Clear();
217 
219 }
220 
222 {
223  if (scheme != NULL)
225 
227 }
228 
230 {
231  size_t idx = (size_t)(pct*float(m_LenDistribution.size()));
232  return m_LenDistribution[std::min(idx, m_LenDistribution.size() - 1)];
233 }
234 
236 {
237  if (!m_Calc)
241 
242  // Force lengths to be recomputed if tree changed (but do not compute by
243  // default since they are not always needed).
244  m_LenDistribution.clear();
245 }
246 
248 {
249  // Can't compute lengths without distance parameter.
250  if (!m_TreeModel->GetFeatureDict().HasFeature("dist"))
251  return;
252 
253  // The array is only needed for visualization based on edge length of
254  // large trees. Only compute if needed. If tree changes, MeasureTree()
255  // clears the array so we know its needed.
256  if (m_LenDistribution.size() != 0)
257  return;
258 
259  CPhyloTreeMaxChildDist child_dist =
263 
264  float min_dist = child_dist.GetMinDist();
265  float max_dist = child_dist.GetMaxDist();
266 
267  float dist_scaler = 1.0f / (max_dist - min_dist);
268  m_LenDistribution.swap(child_dist.GetDistances());
269  for (size_t i = 0; i<m_LenDistribution.size(); ++i) {
270  m_LenDistribution[i] = (m_LenDistribution[i] - min_dist)*dist_scaler;
271  m_TreeModel->GetNode(i)->SetEdgeScore(m_LenDistribution[i]);
272  }
273 
275 }
276 
278 {
280 }
281 
283 {
284  string ttf = "";
285 
286  if (!m_TreeModel.IsNull()) {
288 
290  string sName = it->second;
291  string sKey = "$(" + it->second + ")";
292 
293  ttf += ttf.empty()?"" : "\n";
294  ttf += (sName + ": " + sKey);
295  }
296  }
297 
298  return ttf.empty()?"Tree Node":ttf;
299 }
300 
301 
303  CPhyloTreeScheme* scheme,
304  const string& labelfmt)
305 {
307  m_Calc->SetAttrTable(attrs);
308  if (!labelfmt.empty())
309  m_Calc->SetLabelFormat(labelfmt);
312 
313 
314 
315  // Update all colors in the color table (scheme colors, colors attached to nodes
316  // and cluster colors)
318 
320 
321  Clusterize(scheme);
322 }
323 
324 // clusters check
326 {
327  return (m_Calc != NULL && !m_Calc->GetClusters().empty());
328 }
329 
330 
331 // clusterizing with colors
333 {
334  if (!m_Calc)
335  return;
336 
337  // seed color
338  CRgbaColor color(204, 153, 102);
339  CRgbaColor white(255,255,255,255);
340 
341  size_t color_idx;
342  if (!m_TreeModel->GetColorTable()->FindColor(color, color_idx)) {
343  color_idx = m_TreeModel->GetColorTable()->AddColor(color);
344  }
345 
346  m_ClusterToColorMap.clear();
347 
348  // COLOR 'STEP'
349  int nmbClusters = static_cast<int>(m_Calc->GetClusters().size());
350  float colorStep = nmbClusters? (180.0 / nmbClusters): 0;
351  //unsigned contrast = 1;
352  // for narrow color angle we will try an alternative color assignment
353  bool narrow_angle = colorStep < 5.0;
354 
355  // Get cluster ids from selection sets -these have their own assigned colors so
356  // we should not generate them. Only active (selected) selection sets need to
357  // be considered here.
358  map<int, size_t> cluster_id_to_selection_map = m_TreeModel->GetSelectionSets().GetClusterToSelectionMap();
359 
360 
361  // Find colors for each cluster
363  int cluster_id = cl->first;
364 
365  // Get color from table of selected node sets OR generate it for the cluster.
366  // We generate a new color each time though the loop even if not all are used
367  // because we want to not change cluster colors when selection changes. (disconcerting
368  // for user)
369  CRgbaColor cluster_color = color;
370  if (cluster_id_to_selection_map.find(cluster_id) != cluster_id_to_selection_map.end()) {
371  size_t select_set_idx = cluster_id_to_selection_map[cluster_id];
372  cluster_color = m_TreeModel->GetSelectionSets().GetSets()[select_set_idx].GetColor();
373  }
374  else {
375  // This code is to protect us from colors too bright (almost white)
376  float c_dist = CRgbaColor::ColorDistance(white, cluster_color);
377  while (c_dist < 0.2f) {
378  cluster_color.Darken(0.15f);
379  c_dist = CRgbaColor::ColorDistance(white, cluster_color);
380  }
381  }
382 
383  if (!m_TreeModel->GetColorTable()->FindColor(cluster_color, color_idx)) {
384  size_t closest_idx;
385  float dist = m_TreeModel->GetColorTable()->FindClosestColor(cluster_color, closest_idx);
386 
387  if (dist > 0.01f) {
388  // Add a new color to the color table
389  color_idx = m_TreeModel->GetColorTable()->AddColor(cluster_color);
390  }
391  else {
392  // Use an existing color (to avoid letting the table get large - since it's stored in a texture
393  // max size may be 4096 or 8192.
394  color_idx = closest_idx;
395  }
396  }
397 
398  m_ClusterToColorMap[cluster_id] = color_idx;
399 
400  float rotate_angle = colorStep + (narrow_angle ? 90.0 : 180.0);
401  color = CRgbaColor::RotateColor(color, rotate_angle);
402  } // ITERATE
403 
404 
405  // propagate colors
406  const CPhyloTreeCalculator::TClusterHash& cluster_map = m_Calc->GetClusters();
407  ITERATE(CPhyloTreeCalculator::TClusterHash, cl, cluster_map) {
408  // getting min x of each cluster
409  int minX = m_Calc->GetWidth();
410 
411  ITERATE (vector<TTreeIdx>, node_iter, cl->second) {
412  if ((*m_TreeModel)[*node_iter].HasParent()) {
413  CPhyloTreeNode& parent = m_TreeModel->GetParent((*m_TreeModel)[*node_iter]);
414 
415  if ((*parent).IDX().first < minX) {
416  minX = (*parent).IDX().first;
417  }
418  }
419  }
420 
421  color_idx = m_ClusterToColorMap[cl->first];
422  bool selection_cluster = (cluster_id_to_selection_map.find(cl->first) != cluster_id_to_selection_map.end());
423 
424  // Selection clusters propogate all the way to the root. Standard clusters
425  // (cluster-id property) propogate to nearest common ancester. Also standard clusters
426  // are only seen when coloration mode is 'cluster'
427  if (selection_cluster)
428  minX = 0;
429  else if (scheme->GetColoration()!=CPhyloTreeScheme::eClusters)
430  continue;
431 
432  ITERATE (vector<TTreeIdx>, node_iter, cl->second) {
433  TTreeIdx parent_idx = *node_iter;
434 
435  // if it is not lowest common node, mark parents
436  for (; (*m_TreeModel)[parent_idx].HasParent();
437  parent_idx = (*m_TreeModel)[parent_idx].GetParent()) {
438 
439  CPhyloTreeNode& cursor = ((*m_TreeModel)[parent_idx]);
440  if ((*cursor).IDX().first > minX) {
441 
442  // If its the primary cluster-id, update cluster colors.
443  // If there are multiple cluster id's in the node add a marker
444  // if were are visiting parents for > 1 time... ignore. Only multi-mark
445  // the selected nodes themselves, and only visit parents of dominant
446  // color. (first sel color or, if none, cluster-id).
447  int primary_cluster_id = (*cursor).GetPrimaryCluster();
448  if (parent_idx == *node_iter) {
449  if (primary_cluster_id == cl->first) {
450  (*cursor).SetClusterColorIdx(color_idx);
451  }
452  if (cursor.IsLeaf() && (*cursor).GetNumClusters() > 1) {
453  // only include selection colors in the set of colors for
454  // markers, and only apply markers to leaf nodes.
455  if (selection_cluster) {
456  // Marker size is a multiple of node size, so just use 2 here (double node size):
457  (*cursor).SetMarkerSize(2.0f);
458  (*cursor).GetMarkerColors().push_back(
459  m_TreeModel->GetColorTable()->GetColor(color_idx));
460  }
461  }
462  }
463  else {
464  (*cursor).SetClusterColorIdx(color_idx);
465  }
466  }
467  else {
468  break;
469  }
470  }
471  }
472  }
473 
474  SetColorIndices(scheme);
475 }
476 
478 {
479  m_TreeModel->ReRoot(root_idx);
480 
481  // root node has 0 distance since it has no parent (and distance stored in a node is
482  // the node's distance from it's parent)
483  m_TreeModel->GetNode(root_idx).GetValue().SetDistance(0.0f);
486 }
487 
489 {
490  // We can still re-root if there is not distance attribute. But
491  // if there is, we need to update it and split the distance 50%
492  // on either side of the new node.
493  float dist = 0.0f;
494  if (m_TreeModel->GetFeatureDict().HasFeature("dist"))
495  dist = m_TreeModel->GetNode(edge_child_node).GetValue().GetDistance();
496 
497  // Create the new node to be the root:
498  m_TreeModel->SetCurrentNode(edge_child_node);
499  TTreeIdx new_node_idx = NewNode(false);
500 
501  // If there is a distance attribute, allocate 1/2 the distance from the child
502  // to the new node, and the other half from the new node to the child's parent
503  if (m_TreeModel->GetFeatureDict().HasFeature("dist")) {
504  m_TreeModel->GetNode(new_node_idx).GetValue().SetDistance(dist/2.0f);
506  m_TreeModel->GetNode(edge_child_node).GetValue().SetDistance(dist/2.0f);
507  m_TreeModel->GetNode(edge_child_node).GetValue().Sync(m_TreeModel->GetFeatureDict());
508  }
509  ReRoot(new_node_idx);
511 }
512 
514 {
515  if (!m_TreeModel->GetFeatureDict().HasFeature("dist"))
516  return;
517 
522 
526  child_dist.GetDistances(),
527  child_dist.GetMaxDistNode()));
528 
529  float dist;
530  std::vector<CPhyloTree::TTreeIdx> path;
531 
532  midpoint_dist.GetLongest(path, dist);
533  float midpoint = dist / 2.0f;
534  float d = 0.0f;
535 
536  if (path.size() > 1) {
537  TTreeIdx midpoint_parent = CPhyloTree::Null();
538  TTreeIdx midpoint_child = CPhyloTree::Null();
539  float dist_from_parent = 0.0f;
540  float dist_from_child = 0.0f;
541 
542  for (size_t i=0; i < path.size(); ++i) {
543  TNodeType& node = m_TreeModel->GetNode(path[i]);
544 
545  // Find middle of path, based on distances. Distances are stored in the child node as distance
546  // to the parent, so we have to check at each node along the path which is parent and which is
547  // child since it switches at the least common ancestor - the highest node in the tree that
548  // the two leaves at either end of 'path' have in common. Once we identify the midpoint,
549  // we may stop this loop. (but we run to the end to highlight nodes for debugging)
550  if (i < path.size() - 1 && midpoint_child == CPhyloTree::Null()) {
551 
552  TNodeType& next_node = m_TreeModel->GetNode(path[i + 1]);
553 
554  // If next node is parent of this node, distance is in this node.
555  if (node.GetParent() == path[i + 1]) {
556  d += node.GetValue().GetDistance();
557 
558  if (d >= midpoint) {
559  midpoint_child = path[i];
560  midpoint_parent = path[i + 1];
561 
562  float base_distance = d - node.GetValue().GetDistance();
563  dist_from_parent = d - midpoint;
564  dist_from_child = midpoint - base_distance;
565  }
566  }
567  // If this node is parent of the next node, distance is in the next node
568  else if (next_node.GetParent() == path[i]) {
569  d += next_node.GetValue().GetDistance();
570 
571  if (d >= midpoint) {
572  midpoint_parent = path[i];
573  midpoint_child = path[i + 1];
574 
575  float base_distance = d - next_node.GetValue().GetDistance();
576  dist_from_parent = midpoint - base_distance;
577  dist_from_child = d - midpoint;
578  }
579  }
580  else {
581  /// Error - either one or the other is a parent
582  _ASSERT(0);
583  }
584  }
585 
586  /* For debugging: highlight the path we found
587  node.GetValue().SetFeature(
588  m_TreeModel->GetFeatureDict(), "$NODE_COLOR", "[255 0 0 255]");
589  node.GetValue().InitFeatures(
590  m_TreeModel->GetFeatureDict(), m_TreeModel->GetColorTable());
591  */
592  }
593 
594 
595  if (midpoint_child != CPhyloTree::Null()) {
596  // It is possible the tree is already mid-point rooted. If the
597  // midpoint is 'close' to an existing node, make
598  // that the root if it is not already (and write info message)
599  // Now that node has at least 2 children by definition. If it
600  // has more I think we accept that - it is possible to have
601  // the midpoint lie at an n-node intersection
602 
603  // What is a 'close'? Let's say 1/100 of average edge length.
604  // Since we now know the maximum distance between 2 leaves and the
605  // number of edges between them, we could set 'close' to be 1/100
606  // of the length of an average edge, i.e. given 10 edges in the path
607  // and the total path length of 0.7, 'small' is < (0.7/10)/100
608  float close = (dist/float(path.size() - 1))/100.0f;
609  TTreeIdx close_idx = CPhyloTree::Null();
610  if (dist_from_parent <= close)
611  close_idx = midpoint_parent;
612  else if (dist_from_child <= close)
613  close_idx = midpoint_child;
614 
615  if (close_idx != CPhyloTree::Null()) {
616  TNodeType& midpoint = m_TreeModel->GetNode(close_idx);
617  if (!midpoint.HasParent()) {
618  LOG_POST(Info << "Tree already rooted at midpoint");
619  return;
620  }
621  else {
622  ReRoot(close_idx);
623  LOG_POST(Info << "Re-rooted tree at existing midpoint");
624  return;
625  }
626  }
627  else {
628  // Set current node to child node (midpoint child)
629  // Call newnode with false to insert between parent and child
630  // set new nodes distance to dist_from_parent
631  // set midpoint_child's distance to dist_from_child
632  // Re-root tree at new node.
633  m_TreeModel->SetCurrentNode(midpoint_child);
634  TTreeIdx new_node_idx = NewNode(false);
635  m_TreeModel->GetNode(new_node_idx).GetValue().SetDistance(dist_from_parent);
637  m_TreeModel->GetNode(midpoint_child).GetValue().SetDistance(dist_from_child);
638  // This also can be done via CPhyloNodeData::Sync(feature_dict) but we don't want to sync the
639  // label which may or may not be initialized at this point
640  string str_dist;
641  NStr::DoubleToString(str_dist, dist_from_child);
642  m_TreeModel->GetNode(midpoint_child).GetValue().SetFeature(m_TreeModel->GetFeatureDict(), "dist", str_dist);
643  ReRoot(new_node_idx);
645  }
646  }
647  }
648 
649 }
650 
651 /// Collapse, based on distance, enough nodes in the tree to get the total
652 /// number of leaves down to the requested number. (or just over if exact
653 /// match is not possible). We do not expand nodes that may already be
654 /// collapsed.
656 CPhyloTreeDataSource::CollapseByDistance(int leaf_count_target, SCollapsable* collapse_func)
657 {
658  set<CPhyloNodeData::TID> collapsed_nodes;
659 
660  if (!m_TreeModel->GetFeatureDict().HasFeature("dist"))
661  return collapsed_nodes;
662 
663  // Get distance of each node from root to determine which should be collapsed.
664  // distance here is max distance of any direct child of the node from root
665  CPhyloTreeMaxDirectChildDist child_dist =
669 
670  vector<SChildMaxDist> distances = child_dist.GetDistances();
671 
672  // sort by distance (least to greatest)
673  std::sort(distances.begin(), distances.end());
674  int current_leaf_count = m_TreeModel->GetRoot()->GetNumLeavesEx();
675 
676  //
677  while (current_leaf_count > leaf_count_target) {
678  vector<SChildMaxDist>::reverse_iterator riter = distances.rbegin();
679 
680  // pick the node with the most distant direct child (exclude any nodes
681  // with subtrees).
682  for (; riter != distances.rend(); ++riter) {
683  TNodeType& n = m_TreeModel->GetNode((*riter).m_NodeIdx);
684 
685  bool has_subtree = false;
686  // make sure node only has direct children (leaf nodes or collapsed nodes)
687  // and do not include the root node.
688  for (size_t i = 0; i < n.GetChildren().size(); ++i) {
689  TNodeType& child_node = m_TreeModel->GetNode(n.GetChildren()[i]);
690  if (child_node.IsLeafEx())
691  continue;
692  else if (collapsed_nodes.find(child_node->GetId()) == collapsed_nodes.end()) {
693  has_subtree = true;
694  break;
695  }
696  }
697  if (!has_subtree)
698  break;
699  }
700 
701  if (riter == distances.rend())
702  break;
703 
704  TNodeType& n = m_TreeModel->GetNode((*riter).m_NodeIdx);
705 
706  // Collapse nodes in order of most distant to least. Distance is based on
707  // the maximum distance of any of the nodes immediate children (whether or
708  // not they are leaves). Using this approach, we should never collapse
709  // a node that has a non-leaf child that is not already collapsed.
710  if (n.CanExpandCollapse(CPhyloNodeData::eHideChildren)) {
711  // We only want to show top-level nodes as collapsed, so remove
712  // from the set of collapsed nodes any children of the node
713  // we have chosen to collapse.
714  for (size_t i = 0; i < n.GetChildren().size(); ++i) {
715  TNodeType& child_node = m_TreeModel->GetNode(n.GetChildren()[i]);
716 
718  iter = collapsed_nodes.find(child_node->GetId());
719  if (iter != collapsed_nodes.end()) {
720  collapsed_nodes.erase(iter);
721  }
722  }
723 
724  collapsed_nodes.insert(n->GetId());
725 
726  // When you collapse a node that only has leaves or collapsed nodes as children,
727  // You reduce the number of leaves by the number of its leaves-1 because it
728  // is now a leaf.
729  current_leaf_count -= n.GetChildren().size() - 1;
730  }
731 
732  distances.erase(--riter.base());
733  }
734 
735  return collapsed_nodes;
736 }
737 
739  string labelFmt)
740 {
742  m_Calc->SetLabelFormat(labelFmt);
745 
746  Clusterize(scheme);
747 
748  int max_children = std::max(10, m_Calc->GetHeight() / 2);
749  scheme->SetMaxNumChildren(GLdouble(max_children));
751 }
752 
753 void CPhyloTreeDataSource::Sort(bool ascending)
754 {
757  CPhyloTreeSorter(m_TreeModel.GetPointer(), ascending));
758 
759  MeasureTree();
760 }
761 
762 void CPhyloTreeDataSource::SortDist(bool ascending)
763 {
764  if (!m_TreeModel->GetFeatureDict().HasFeature("dist"))
765  return;
766 
767  CPhyloTreeMaxChildDist child_dist =
771 
775 
776  MeasureTree();
777 }
778 
780 {
784 
785  MeasureTree();
786 }
787 
789 {
790  CPhyloTreeLabelRange label_ranges =
794 
797  CPhyloTreeSorterLabelRange(m_TreeModel.GetNCPointer(), label_ranges.GetLabelRanges(), ascending));
798 
799  MeasureTree();
800 }
801 
803 {
804  // rectangle calculator
806  rect_calc.Init();
807  rect_calc = TreeDepthFirst(m_TreeModel.GetNCObject(), m_TreeModel->GetRootIdx(), rect_calc);
808  return rect_calc.GetRect();
809 }
810 
812 {
813  // Convert to biocontainer to get user data
814  CRef<objects::CBioTreeContainer> btc(new objects::CBioTreeContainer());
816  TreeConvert2Container(*new_container, *GetTree());
817 
818  // Now convert tree datastructure to biotreecontainer, skipping over any
819  // single child nodes
820  TreeConvertNonSingleChild2Container(*btc, *GetTree(), GetTree()->GetRootIdx());
821 
822  // Add user data to new biotreecontainer
823  if (new_container->IsSetUser()) {
824  btc->SetUser().Assign(new_container->GetUser());
825  }
826 
827  // Initialize tree with new biotreecontainer
828  Init(*btc, *m_Scope, false);
830 }
831 
833 {
834  // not currently hooked up to UI (and would have problems - needs to fix child pointers..)
837 
838  MeasureTree();
839 }
840 
841 
843 {
844  // not currently hooked up to UI (and would have problems - needs to fix child pointers..)
847 
848  MeasureTree();
849 }
850 
851 
852 
853 string CPhyloTreeDataSource::GetColumnLabel(size_t col) const
854 {
858 
859  size_t count = 0;
860  for (fiter=fdict.begin(); fiter != fdict.end(); ++fiter, ++count) {
861  if (count == col) {
862  return (*fiter).second;
863  }
864  }
865 
866  return "";
867 }
868 
870 {
872 }
873 
875 {
876  CTreeQueryExec* qexec = new CTreeQueryExec(&(this->GetDictionary()));
877 
878  qexec->SetTree(this->GetTree());
879 
880  // Logical operators:
882  new CQueryFuncPromoteAndOr());
884  new CQueryFuncPromoteAndOr());
886  new CQueryFuncPromoteLogic());
888  new CQueryFuncPromoteLogic());
890  new CQueryFuncPromoteLogic());
891 
892  // Constants:
894  new CQueryFuncPromoteValue());
896  new CQueryFuncPromoteValue());
898  new CQueryFuncPromoteValue());
900  new CQueryFuncPromoteValue());
901 
902  NStr::ECase cs = casesensitive ? NStr::eCase : NStr::eNocase;
903 
904  // Comparison operators:
906  new CQueryFuncPromoteEq(cs, matching));
916  new CQueryFuncPromoteIn(cs, matching));
918  new CQueryFuncPromoteBetween(cs));
920  new CQueryFuncLike(cs));
921 
922  // Functions
924  new CQueryFuncFunction());
927  // Unusual mapping: Run time vars -> CQueryParseNode::eSelect
928  // This is done to preserve CQueryParseNode from modification.
929  qexec->AddFunc(CQueryParseNode::eSelect, // RT Variable
930  new CQueryFuncRTVar());
931  qexec->AddFunc(CQueryParseNode::eFrom, // Assignment operator
932  new CQueryFuncAssignment());
933 
934  return qexec;
935 }
936 
938 {
939  CTreeQueryExec *e = dynamic_cast<CTreeQueryExec*>(q);
940 
943  m_TreeModel->SetSelection(e->GetTreeSelected(), false, true);
944 }
945 
947 {
949 }
950 
952  size_t& num_selected,
953  size_t& num_queried,
954  CStringMatching::EStringMatching string_matching,
955  NStr::ECase use_case)
956 {
957  // Re-run the query if options that can change query results have changed
959  num_queried = 0;
960  num_selected = 0;
961 
962  m_StringQueryIDs.clear();
963 
964  // simple string queries are completed synchronously since
965  // they can never get hung up in network access.
966  if (query != "") {
967  vector<TTreeIdx> sel = FindNodes(query, num_queried, string_matching, use_case);
969 
970  // Because of selecting parents this can lose the fact that some
971  // non leaf nodes were selected.
972  m_TreeModel->SetSelection(sel, false, true);
973  num_selected = sel.size();
974 
975  // Be a bit more efficient to get these during query if we decide we have to keep this.
976  m_StringQueryIDs.reserve(sel.size());
977  for (auto iter=sel.begin(); iter!=sel.end(); ++iter) {
978  m_StringQueryIDs.push_back(m_TreeModel->GetNode(*iter).GetValue().GetId());
979  }
980 
981  LOG_POST(Info << "String Query: " << query << " Num selected: " << sel.size());
982  }
983 }
984 
986 {
987 public:
989 
990 public:
991  visitor_stringmatch_query(CStringMatching &stringMatching, vector<TTreeIdx> &selNodes, size_t &numQueried) :
992  m_StringMatching(stringMatching),
993  m_SelNodes(selNodes),
994  m_NumQueried(numQueried)
995  {}
997  TTreeIdx node, int delta)
998  {
999  if (delta==1 || delta==0){
1000  ++m_NumQueried;
1002  tree[node]->GetBioTreeFeatureList().GetFeatureList();
1003 
1004 
1006  if (m_StringMatching.MatchString(it->value)) {
1007  m_SelNodes.push_back(node);
1008  break;
1009  }
1010  }
1011  }
1012  return eTreeTraverse;
1013  }
1014 
1015 private:
1017  vector<TTreeIdx> &m_SelNodes;
1018  size_t &m_NumQueried;
1019 };
1020 
1021 vector<CPhyloTree::TTreeIdx>
1022 CPhyloTreeDataSource::FindNodes(const string &query, size_t& num_queried, CStringMatching::EStringMatching string_matching, NStr::ECase use_case) const
1023 {
1024  vector<TTreeIdx> selNodes;
1025  CStringMatching stringMatching(query, string_matching, use_case);
1026  visitor_stringmatch_query finder(stringMatching, selNodes, num_queried);
1028  return selNodes;
1029 }
1030 
1031 // This sorts nodes by their position (depth-first order) in the tree using
1032 // the node index which represents the position of the node relative to other
1033 // nodes.
1034 struct NodeIdxSort {
1037  const CPhyloTree::TNodeType& n1 = m_Tree[lhs];
1038  const CPhyloTree::TNodeType& n2 = m_Tree[rhs];
1039 
1040  if (n1.GetValue().IDX().second < n2.GetValue().IDX().second)
1041  return true;
1042  else if (n1.GetValue().IDX().second > n2.GetValue().IDX().second)
1043  return false;
1044  // first value was equal:
1045  else if (n1.GetValue().IDX().first < n2.GetValue().IDX().first)
1046  return true;
1047  else return false;
1048  }
1049 
1050 protected:
1052 };
1053 
1055 CPhyloTreeDataSource::IterateOverSelNodes(int direction, bool highlight)
1056 {
1057  // highlight
1059  return CPhyloTree::Null();
1060 
1061  // Get all nodes user 'explicitly' selected - so either the user clicked on
1062  // them directly (does not count if they are the child of a selected node) or
1063  // the node was directly selected by a query
1064  vector<TTreeIdx> search_cache;
1066 
1067  // Sort the nodes into depth-first order
1068  std::sort(search_cache.begin(), search_cache.end(), NodeIdxSort(m_TreeModel.GetObject()));
1069 
1070  if (search_cache.empty())
1071  return CPhyloTree::Null();
1072 
1073  // cursor
1074  if (direction==0) {
1076  m_SearchCurrentNode = (*search_cache.begin());
1077  }
1078  }
1079  else if (direction>0) {
1081  m_SearchCurrentNode = (*search_cache.begin());
1082  }
1083  else {
1084  vector<TTreeIdx>::iterator itt =
1085  find(search_cache.begin(), search_cache.end(), m_SearchCurrentNode);
1086 
1087  // If not found (unexpected) set cursor to beginning.
1088  if (itt == search_cache.end()) {
1089  m_SearchCurrentNode = (*search_cache.begin());
1090  }
1091  // else increment unless we are already at the end.
1092  else {
1093  ++itt;
1094  if (itt != search_cache.end())
1095  m_SearchCurrentNode = *itt;
1096  else // wrap around to the beginning
1097  m_SearchCurrentNode = (*search_cache.begin());
1098  }
1099  }
1100  }
1101  else {
1103  m_SearchCurrentNode = *(search_cache.begin() + (search_cache.size() - 1));
1104  }
1105  else {
1106  vector<TTreeIdx>::iterator itt =
1107  find(search_cache.begin(), search_cache.end(), m_SearchCurrentNode);
1108 
1109  // If not found (unexpected) set cursor to the end
1110  if (itt == search_cache.end()) {
1111  m_SearchCurrentNode = *(search_cache.begin() + (search_cache.size() - 1));
1112  }
1113  // else decrement cursor if not already at the beginning
1114  else {
1115  if (itt != search_cache.begin())
1116  m_SearchCurrentNode = *(--itt);
1117  else // wrap around to the end
1118  m_SearchCurrentNode = search_cache[search_cache.size() - 1];
1119  }
1120  }
1121  }
1122 
1123  // Make the node we have iterated to the current node -this will give it
1124  // a small visual marker (square) around the node so user knows where they are.
1125  if (m_SearchCurrentNode)
1127 
1128  return m_SearchCurrentNode;
1129 }
1130 
1132 {
1133  // renumber selection cluster IDs in set to make sure the selection cluster IDs
1134  // don't overlap regular cluster IDs:
1135  // pick cluster id larger than existing ids:
1136  CPhyloTree::TClusterID max_id =
1138  // set ids, first highest then lower.
1140 
1142  MeasureTree();
1143 
1144  // Check max-id one more time. We do this because MeasureTree() updates the value
1145  // returned by GetMaxClusterID() and there is a small chance that this value has
1146  // increased since the tree was created. (change would be via editing of node properties)
1147  if (GetMaxClusterID() >= max_id - TClusterID(m_TreeModel->GetSelectionSets().GetSets().size())) {
1148  GetSelectionSets().RenumberClusterIDs(GetMaxClusterID() + 500 + static_cast<int>(m_TreeModel->GetSelectionSets().GetSets().size()));
1150  MeasureTree();
1151  }
1152 
1153  Clusterize(scheme);
1154 }
1155 
1157 {
1158 public:
1161  {
1162  if (delta==1 || delta==0){
1163  tree[node].GetValue().SetId(CPhyloNodeData::TID(-1));
1164  }
1165  return eTreeTraverse;
1166  }
1167 };
1168 
1170 {
1171 public:
1175 
1176 public:
1178  : m_Target(target)
1179  {
1180  m_Target.GetFeatureDict() = tree.GetFeatureDict();
1181  m_Target.SetRootIdx(0);
1182  }
1184  CPhyloTree::TTreeIdx node_idx,
1185  int delta)
1186  {
1187  if (delta < 0) {
1188  return eTreeTraverse;
1189  }
1190 
1191  TNodeType& node = tree[node_idx];
1192  CPhyloNodeData::TID id = node.GetValue().GetId();
1193 
1194  // Make sure not already in tree (but traversal should guarantee)
1195  TTreeIdx idx = m_Target.FindNodeById(id);
1196  if (idx != CPhyloTreeNode::Null()) {
1197  return eTreeTraverse;
1198  }
1199 
1200  // Adds a copy of node. Need to update indices to match the target tree
1201  TTreeIdx new_node_idx = m_Target.AddNode(node);
1202  TNodeType& new_node = m_Target[new_node_idx];
1203  new_node.ClearConnections();
1204 
1205  // Look up the parent index of the new node using the
1206  // node id
1207  CPhyloNodeData::TID parent_id = tree[node.GetParent()]->GetId();
1208  TTreeIdx parent_idx = m_Target.FindNodeById(parent_id);
1209 
1210  // This will only happen for the top (first) node of the
1211  // subtree being cut since its parent won't be in the subtree
1212  if (parent_idx == CPhyloTreeNode::Null()) {
1213  return eTreeTraverse;
1214  }
1215  m_Target.AddChild(parent_idx, new_node_idx);
1216 
1217  return eTreeTraverse;
1218  }
1219 
1221 };
1222 
1224 {
1225 public:
1229 
1230 public:
1232  : m_Target(target)
1233  , m_Source(source)
1234  , m_TargetIdx(target_idx)
1235  {
1237  next_id = TreeDepthFirst(m_Target, next_id);
1238  m_TargetMaxId = next_id.GetMaxId();
1239  }
1240  // This is iterating over the source tree adding each
1241  // element to the target tree (m_Target)
1243  CPhyloTree::TTreeIdx node_idx,
1244  int delta)
1245  {
1246  if (delta < 0) {
1247  return eTreeTraverse;
1248  }
1249 
1250  // Node from source tree (the tree we are copying into the target tree)
1251  TNodeType& node = tree[node_idx];
1252  CPhyloNodeData::TID source_id = node.GetValue().GetId();
1253 
1254  // Adds a copy of node. Need to update indices to match the target tree
1255  TTreeIdx new_node_idx = m_Target.AddNode(node);
1256  TNodeType& new_node = m_Target[new_node_idx];
1257  new_node.ClearConnections();
1258 
1259  CPhyloNodeData::TID target_id = ++m_TargetMaxId;
1260  m_IdMap[source_id] = target_id;
1261 
1262  new_node->SetId(target_id);
1264 
1265  // Add any features in in dictionary of source but not target to target.
1266  // Get the id for the name each time too since ids between the two
1267  // trees may not match.
1269  node->GetBioTreeFeatureList().GetFeatureList()) {
1270  // Use the id for the feature to get the feature name
1271  string feature_name = m_Source.GetFeatureDict().GetName(it->id);
1272  TBioTreeFeatureId id = m_Target.GetFeatureDict().Register(feature_name);
1273  new_node.GetValue().GetBioTreeFeatureList().SetFeature(id, it->value);
1274  }
1275 
1276  // If this is the root of the source tree, attach it to the node
1277  // m_TargetIdx in the target tree. Otherwise attach it to the
1278  // corresponding node copied from the source tree using the id-to-id map
1279  if (node.GetParent() == CPhyloTreeNode::Null()) {
1280  m_Target.AddChild(m_TargetIdx, new_node_idx);
1281  }
1282  else {
1283  CPhyloNodeData::TID parent_id = tree[node.GetParent()]->GetId();
1284  CPhyloNodeData::TID target_tree_parent_id = m_IdMap[parent_id];
1285  TTreeIdx parent_idx = m_Target.FindNodeById(target_tree_parent_id);
1286 
1287  if (parent_idx != CPhyloTreeNode::Null()) {
1288  m_Target.AddChild(parent_idx, new_node_idx);
1289  }
1290  else {
1291  LOG_POST(Info << "Error - did not find parent node as expected.");
1292  }
1293  }
1294 
1295  return eTreeTraverse;
1296  }
1297 
1301 
1302  /// mapping from Ids in source tree to target tree
1304 
1306 };
1307 
1308 
1309 
1311 {
1312  TTreeIdx node_idx = m_TreeModel->GetCurrentNodeIdx();
1313 
1314  if (node_idx == CPhyloTree::Null()) {
1315  _TRACE("CPhyloTreeDataSource::Cut - Nothing is selected");
1316  return;
1317  }
1318 
1319  if (node_idx == m_TreeModel->GetRootIdx()) {
1320  _TRACE("CPhyloTreeDataSource::Cut - Removing root item is illegal");
1321  return;
1322  }
1323 
1325 
1327 
1328  m_TreeModel->SetSelection(n.GetParent(), true, true);
1329 
1330  TreeDepthFirst(m_TreeModel.GetNCObject(), node_idx,
1332 
1334  m_TreeModel->RemoveChild(n.GetParent(), node_idx);
1335 
1337  MeasureTree();
1338 }
1339 
1341 {
1342  TTreeIdx node_idx = m_TreeModel->GetCurrentNodeIdx();
1343 
1344  if (node_idx == CPhyloTree::Null()) {
1345  _TRACE("CPhyloTreeDataSource::Paste - Nothing is selected");
1346  return;
1347  }
1348 
1350  _TRACE("CPhyloTreeDataSource::Paste - Clipboard is empty");
1351  return;
1352  }
1353 
1356 
1358  MeasureTree();
1359 }
1360 
1362 {
1363  TTreeIdx current_node_idx = m_TreeModel->GetCurrentNodeIdx();
1364 
1365  if (current_node_idx == CPhyloTree::Null()) {
1366  _TRACE("CPhyloTreeDataSource::NewNode - Nothing is selected");
1367  return CPhyloTree::Null();
1368  }
1369 
1370  TTreeIdx parent_node_idx = m_TreeModel->GetNode(current_node_idx).GetParent();
1371 
1372  if (!after && parent_node_idx == CPhyloTree::Null()) {
1373  _TRACE("CPhyloTreeDataSource::NewNode - New root cannot be added");
1374  return CPhyloTree::Null();
1375  }
1376 
1377  TTreeIdx new_node_idx = m_TreeModel->AddNode();
1378  TNodeType& new_node = m_TreeModel->GetNode(new_node_idx);
1379 
1380  // Set node id to current maximim node id value +1. IDs needed during export.
1382  next_id = TreeDepthFirst(m_TreeModel.GetNCObject(), next_id);
1383  new_node->SetId(next_id.GetMaxId() + 1);
1384 
1385  if (after) { // insert as a child
1386  TNodeType& current_node = m_TreeModel->GetCurrentNode();
1387  current_node.GetChildren().insert(current_node.SubNodeBegin(), new_node_idx);
1389  }
1390  else {
1391  m_TreeModel->RemoveChild(parent_node_idx, current_node_idx);
1392  m_TreeModel->AddChild(parent_node_idx, new_node_idx);
1393  m_TreeModel->AddChild(new_node_idx, current_node_idx);
1394  }
1395 
1396  // Set dictionary and a blank feature table with all values from dictionary.
1397  //new_node.GetValue().SetDictionaryPtr(&(m_TreeModel->GetFeatureDict()));
1398  // Do we need this - I don't see why... maybe dist?
1401  new_node.GetValue().SetFeature(m_TreeModel->GetFeatureDict(), it->second, "");
1402  }
1403 
1404  new_node->Init(m_TreeModel->GetFeatureDict(), m_TreeModel->GetColorTable());
1405 
1407  MeasureTree();
1408 
1409  return new_node_idx;
1410 }
1411 
1412 
1414 {
1415  TTreeIdx current_node_idx = m_TreeModel->GetCurrentNodeIdx();
1416  if (current_node_idx == CPhyloTree::Null()) {
1417  _TRACE("CPhyloTreeDataSource::Remove - Nothing is selected");
1418  return;
1419  }
1420 
1421  TTreeIdx parent_node_idx = m_TreeModel->GetNode(current_node_idx).GetParent();
1422  if (parent_node_idx == CPhyloTree::Null()) {
1423  _TRACE("CPhyloTreeDataSource::Remove - The root node can't be removed");
1424  return;
1425  }
1426 
1428 
1429  if (subtree) {
1430  // Remove the node and all it's subnodes
1432  m_TreeModel->RemoveChild(parent_node_idx, current_node_idx);
1433  }
1434  else {
1435  // Remove the node and add all its children to its parent
1436  TNodeType& current_node = m_TreeModel->GetNode(current_node_idx);
1437 
1438  for(TNodeType::TNodeList_I it = current_node.SubNodeBegin();
1439  it != current_node.SubNodeEnd(); it++ ) {
1440  m_TreeModel->AddChild(parent_node_idx, *it);
1441  }
1442 
1443  current_node.ClearConnections();
1444  m_TreeModel->RemoveChild(parent_node_idx, current_node_idx);
1445  current_node.GetValue().SetId(CPhyloNodeData::TID(-1));
1446  }
1447 
1449  MeasureTree();
1450 }
1451 
1453 {
1454  vector<CPhyloNodeData::TID> sel;
1456 
1457  if (sel.size() == 0) {
1458  _TRACE("CPhyloTreeDataSource::RemoveSelected() - Nothing is selected");
1459  return;
1460  }
1461 
1462  // Make sure root node is not selected
1463  for (size_t i = 0; i < sel.size(); ++i) {
1464  CPhyloTree::TTreeIdx node_idx = m_TreeModel->FindNodeById(sel[i]);
1465  if (node_idx != CPhyloTree::Null()) {
1466  TTreeIdx parent_node_idx = m_TreeModel->GetNode(node_idx).GetParent();
1467  if (parent_node_idx == CPhyloTree::Null()) {
1468  _TRACE("CPhyloTreeDataSource::Remove - The root node can't be removed");
1469  return;
1470  }
1471  }
1472  }
1473 
1475 
1476  // Delete nodes one at a time based on ID since indices may change in deletion
1477  // process. Also, a node may disappear if it is the child of a node that has
1478  // already been deleted.
1479  for (size_t i = 0; i < sel.size(); ++i)
1480  {
1481  CPhyloTree::TTreeIdx node_idx = m_TreeModel->FindNodeById(sel[i]);
1482  if (node_idx != CPhyloTree::Null()) {
1483  TTreeIdx parent_node_idx = m_TreeModel->GetNode(node_idx).GetParent();
1485  m_TreeModel->RemoveChild(parent_node_idx, node_idx);
1486  }
1487  }
1488 
1490  MeasureTree();
1491 }
1492 
1494 {
1495  /* We update labels for nodes being collapsed only if the tree
1496  * support the $PRIORITY (integer) parameter. In this case, we find the
1497  * subnode with the highest $PRIORITY value and assign its label to
1498  * the collapsed node. In the case that multiple sub-nodes have the same
1499  * (highest) value for $PRIORITY, we pick the label of the subnode
1500  * closest to the center of the subtree (center being the middle leaf node)
1501  */
1502  if (!m_TreeModel->GetFeatureDict().HasFeature("$PRIORITY") ||
1503  !m_TreeModel->GetFeatureDict().HasFeature("label"))
1504  return;
1505 
1506  if (idx != CPhyloTree::Null()) {
1507  CPhyloTree::TNodeType& current = m_TreeModel->GetNode(idx);
1508 
1510  CBioTreeFeatureList& features = (*current).GetBioTreeFeatureList();
1511  TBioTreeFeatureId label_feat_id = m_TreeModel->GetFeatureDict().GetId("label");
1512  // We do not update labels here. Only set the label if it is not already set
1513  if (features.GetFeatureValue(label_feat_id) != "")
1514  return;
1515 
1516  CPhyloTreePriorityNode pnode(m_TreeModel, idx);
1517  pnode = TreeDepthFirst(*m_TreeModel, idx, pnode);
1518  if (pnode.GetMaxPriorityNode() != CPhyloTree::Null())
1519  {
1520  CBioTreeFeatureList& priority_node_features =
1521  m_TreeModel->GetNode(pnode.GetMaxPriorityNode())->GetBioTreeFeatureList();
1522 
1523  string priority_label = priority_node_features.GetFeatureValue(label_feat_id);
1524  current->SetLabel(priority_label);
1525 
1526  if (m_TreeModel->GetFeatureDict().HasFeature("label")) {
1527  features.SetFeature(label_feat_id, priority_label);
1528  }
1529  }
1530  }
1531  }
1532 }
1533 
1534 void CPhyloTreeDataSource::SetCollapsedLabels(const vector<CPhyloNodeData::TID>& node_ids)
1535 {
1536  for (size_t i = 0; i < node_ids.size(); ++i) {
1537  CPhyloTree::TTreeIdx idx = m_TreeModel->FindNodeById(node_ids[i]);
1538  if (idx != CPhyloTree::Null()) {
1539  CPhyloTree::TNodeType& current =
1540  m_TreeModel->GetNode(idx);
1541 
1543  SetCollapsedLabel(idx);
1544  }
1545  }
1546  }
1547 }
1548 
1550 {
1551  vector<TTreeIdx> sel;
1553  TTreeIdx root_idx = m_TreeModel->GetRootIdx();
1554 
1555  if (sel.size() == 0) {
1556  _TRACE("CPhyloTreeDataSource::RemoveSelected() - Nothing is selected");
1557  return;
1558  }
1559 
1560  // Collapse all selected nodes. Do not collapse nodes if they
1561  // have a collapsed parent or a parent in 'sel' which is also going to be
1562  // collapsed.
1563  for (size_t i = 0; i < sel.size(); ++i)
1564  {
1565  CPhyloTree::TTreeIdx node_idx = sel[i];
1566  bool collapse_node = true;
1567 
1569  TTreeIdx parent_node_idx = m_TreeModel->GetNode(node_idx).GetParent();
1570  while (parent_node_idx != root_idx) {
1571  // If parent node is already collapsed:
1573  collapse_node = false;
1574  break;
1575  }
1576 
1577  // if parent node is also in the list, sel, of nodes to be collapsed:
1578  if (std::find(sel.begin(), sel.end(), parent_node_idx) != sel.end()) {
1579  collapse_node = false;
1580  break;
1581  }
1582 
1583  parent_node_idx = m_TreeModel->GetNode(parent_node_idx).GetParent();
1584  }
1585 
1586  // no parent nodes were already collapsed, so this node can be collapsed:
1587  if (collapse_node) {
1588  SetCollapsedLabel(node_idx);
1591  }
1592  }
1593  }
1594 
1595  MeasureTree();
1596 }
1597 
1599 {
1600  TTreeIdx current_node_idx = m_TreeModel->GetCurrentNodeIdx();
1601 
1602  if (current_node_idx == CPhyloTree::Null()) {
1603  _TRACE("CPhyloTreeDataSource::MoveNode - Nothing is selected");
1604  return;
1605  }
1606 
1607  TTreeIdx parent_node_idx = m_TreeModel->GetNode(current_node_idx).GetParent();
1608 
1609  if (parent_node_idx == CPhyloTree::Null()) {
1610  _TRACE("CPhyloTreeDataSource::MoveNode - The root node can't be moved");
1611  return;
1612  }
1613 
1614  TNodeType& parent = m_TreeModel->GetNode(parent_node_idx);
1615 
1616  for(TNodeType::TNodeList_I it = parent.SubNodeBegin();
1617  it != parent.SubNodeEnd(); it++ ) {
1618  if (*it == current_node_idx) {
1619  if (up && (it!=parent.SubNodeBegin())) {
1620  TNodeType::TNodeList_I pre = it--;
1621  swap(*pre, *it);
1622  break;
1623  }
1624  else {
1626  if (it != last) {
1627  TNodeType::TNodeList_I pst = it++;
1628  swap(*pst, *it);
1629  break;
1630  }
1631  }
1632  }
1633  }
1634 }
1635 
1636 
1637 
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
Feature dictionary.
Definition: bio_tree.hpp:176
Features storage for the bio tree node.
Definition: bio_tree.hpp:101
class CMacroQueryExec
Template class to create a table with custom row-column access.
Definition: ncbi_table.hpp:66
void Sync(CBioTreeFeatureDictionary &dict)
void SetDistance(TDistance x_dist)
void SetId(TID x_id)
CBioTreeFeatureList & GetBioTreeFeatureList()
objects::CNode::TId TID
TDistance GetDistance() const
void SetFeature(CBioTreeFeatureDictionary &dict, const string &name, const string &value)
void InitFromUserObject(CPhyloTree *tree_model, const objects::CBioTreeContainer_Base::TUser &uo)
vector< CPhyloSelectionSet > & GetSets()
void SetSelectionSetProperty(CPhyloTree *tree_model)
void RenumberClusterIDs(int start_id)
Update all cluster ids using the starting-id as the lowest value.
map< int, size_t > GetClusterToSelectionMap()
void SetLabelFormat(string labelFmt)
void SetAttrTable(const TAttrTable &attr)
const TClusterHash & GetClusters()
void Init(CRgbaGradColorTable *ct)
void SortDist(bool ascending)
vector< CPhyloTree::TID > m_StringQueryIDs
Temporary storage for string query results to get ID's back to caller.
virtual string GetColumnLabel(size_t col) const
get number and names of columns in data source
void Init(const objects::CBioTreeContainer &tree, objects::CScope &scope, bool expand_all=false)
Throws exception if tree is empty - at least 1 node is required.
void ReRootMidpoint()
Re-root tree using midpoint-method.
TTreeIdx IterateOverSelNodes(int direction, bool highlight)
virtual CMacroQueryExec * GetQueryExec(bool casesensitive, CStringMatching::EStringMatching matching)
Create an appropriate instance of a subclass of CQueryExec for that will be used to execute a query o...
void FilterDistances(double x_dist)
void Clusterize(CPhyloTreeScheme *scheme)
CPhyloTree * GetTree()
void ComputeLengthsFromRoot()
Create sorted array of distances of nodes from the parent (the m_LenDistribution array)
void SortLabel(bool ascending)
CRef< objects::CScope > m_Scope
void UpdateSelectionSets(CPhyloTreeScheme *scheme)
virtual void ClearQueryResults()
Clear any current results from previous queries.
void ApplyAttributes(CBioTreeAttrReader::TAttrTable &attrs, CPhyloTreeScheme *scheme, const string &labelfmt="")
CPhyloTree::TClusterID TClusterID
virtual void ExecuteStringQuery(const string &query, size_t &num_selected, size_t &num_queried, CStringMatching::EStringMatching string_matching=CStringMatching::ePlainSearch, NStr::ECase use_case=NStr::eCase)
Execute a string-matching query on the underlying data.
virtual void SetQueryResults(CMacroQueryExec *q)
Set selection results to be whatever elements are selected in 'q'.
TClusterID GetMaxClusterID()
void ReRootEdge(TTreeIdx edge_child_node)
Re-root on the edge between the selected node and its parent.
void Relabel(CPhyloTreeScheme *scheme, string labelFmt)
void ReRoot(TTreeIdx root_idx)
Set the root node of the tree to the node at root_idx.
TTreeIdx NewNode(bool after=true)
vector< TTreeIdx > FindNodes(const string &query, size_t &num_queried, CStringMatching::EStringMatching string_matching, NStr::ECase use_case) const
search for nodes via the specified text matching algorithm
CRef< CPhyloTree > m_TreeModel
void Remove(bool subtree=true)
void Sort(bool ascending)
CPhyloSelectionSetMgr & GetSelectionSets()
static CPhyloTree m_sTreeClipboard
static (to allow copying between trees)
float GetClosestLen(float pct) const
Look in vector of sorted distances of nodes from the root and given a pct (0..1), return the distance...
CPhyloTreeCalculator * m_Calc
CPhyloTree::TTreeIdx TTreeIdx
void SetColorIndices(CPhyloTreeScheme *scheme)
virtual size_t GetColsCount() const
set< CPhyloNodeData::TID > CollapseByDistance(int leaf_count_target, SCollapsable *collapse_func)
Collapse, based on distance, enough nodes in the tree to get the total number of leaves down to the r...
void SetCollapsedLabels(const vector< CPhyloNodeData::TID > &node_ids)
Collapse all nodes in node_ids, doing relabeling if needed.
std::vector< float > m_LenDistribution
CPhyloTreeDataSource(const objects::CBioTreeContainer &tree, objects::CScope &scope, bool expand_all=false)
Throws exception if tree is empty - at least 1 node is required.
void SortLabelRange(bool ascending)
const CBioTreeFeatureDictionary & GetDictionary() const
CTreeGraphicsModel & GetModel()
Get model for rendering.
TModelRect GetBoundRect()
TClusterToColorMap m_ClusterToColorMap
void SetCollapsedLabel(CPhyloTree::TTreeIdx idx)
Collapse single node, do any relabeling if needed.
vector< float > & GetDistances()
vector< pair< string, string > > & GetLabelRanges()
For each node, this returns the maximum distances of any of its children (recursively searched) from ...
vector< float > & GetDistances()
For each node this finds the maximum distance of any of its immediate (not recursively searched) chil...
vector< SChildMaxDist > & GetDistances()
CPhyloNodeData::TID GetMaxId() const
void GetLongest(vector< TTreeIdx > &path, float &length)
void ExpandCollapse(CBioTreeFeatureDictionary &dict, CPhyloNodeData::TDisplayChildren chds)
Set this node to be expanded/collapsed.
bool CanExpandCollapse(CPhyloNodeData::TDisplayChildren chds)
Return true if node can have its expand/collapsed state changed to chds.
void SetLabel(CBioTreeFeatureDictionary &dict, const string &label)
Set label string and synch value to the feature list for this ndoe.
bool IsLeafEx() const
Return true if node is a leaf or is collapsed.
TTreeIdx GetMaxPriorityNode() const
const TModelRect & GetRect() const
void SetMaxBranchDist(GLdouble bd)
void SetMaxNumChildren(GLdouble max_num_children)
void UpdateColorTable(CRgbaGradColorTable *color_table)
Make sure all current colors used by the scheme are in 'color_table' and add the ones that are not.
const TColoration & GetColoration(void) const
Tree subclass also has functions and data needed for rendering and selection.
Definition: phylo_tree.hpp:52
void ClearSelection()
Sets selection state of all nodes to eNotSelected and clears m_Selected.
Definition: phylo_tree.cpp:242
void Clear()
Clear the tree nodes, graphics model and selected nodes.
Definition: phylo_tree.cpp:48
void UpdateNodesMapping()
Definition: phylo_tree.cpp:535
CPhyloNodeData::TClusterID TClusterID
Definition: phylo_tree.hpp:54
CPhyloSelectionSetMgr & GetSelectionSets()
Definition: phylo_tree.hpp:326
void SetCurrentNode(TTreeIdx node_idx)
Set the index of the currently active node.
Definition: phylo_tree.cpp:415
void SetSelection(TTreeIdx idx, bool sel, bool sel_children=true, bool sel_parents=true)
Select or deselect the node at the specified index and, optionally, its parents and children as well.
Definition: phylo_tree.cpp:577
TTreeIdx GetCurrentNodeIdx() const
Return the index of the currently active node (may be Null()).
Definition: phylo_tree.hpp:268
void GetExplicitlySelectedAndNotCollapsed(vector< TTreeIdx > &esel) const
Returns only indices of nodes explicitly selected, but when a node is underneath a collapsed node,...
Definition: phylo_tree.cpp:279
CPhyloTreeNode & GetCurrentNode()
Get reference to currently active node. Throws exception if it's Null()
Definition: phylo_tree.cpp:434
CRgbaGradColorTable * GetColorTable()
Definition: phylo_tree.cpp:64
void GetExplicitlySelectedIDs(vector< TID > &esel) const
Returns only ids of nodes explicitly selected, not their parents or children, i.e.
Definition: phylo_tree.cpp:313
TTreeIdx FindNodeById(TID id) const
Return index of the node with the given id or Null().
Definition: phylo_tree.hpp:307
void GetExplicitlySelected(vector< TTreeIdx > &esel) const
Returns only indices of nodes explicitly selected, not their parents or children, i....
Definition: phylo_tree.cpp:273
CBioTreeFeatureDictionary & GetFeatureDict()
Return feature dictionary.
Definition: phylo_tree.hpp:323
Query execution function for assignment operator.
class CQueryFuncFunction
class CQueryFuncLike
class CQueryFuncPromoteAndOr
class CQueryFuncPromoteBetween
class CQueryFuncPromoteEq
class CQueryFuncPromoteGtLt
class CQueryFuncPromoteIdentifier
class CQueryFuncPromoteIn
class CQueryFuncPromoteLogic
class CQueryFuncPromoteValue
Query execution function for run-time variables.
CRef –.
Definition: ncbiobj.hpp:618
class CRgbaColor provides a simple abstraction for managing colors.
Definition: rgba_color.hpp:58
class CTextSearch
EStringMatching
String matching algorithms.
bool MatchString(const CTempString &str)
Matches a string to a pattern, using the specified string matching algorithm.
CTreeCollisionModel2D & GetCollisionData()
string m_FontName
CRgbaColor m_Color
void InitializeFromUserObject(const CBioTreeContainer_Base::TUser &uo)
void SaveToUserObject(CBioTreeContainer_Base::TUser &uo)
TTreeIdx GetParent() const
Get node's parent.
Definition: tree_model.hpp:82
void ClearConnections()
Remove connections to parent and children of this node.
Definition: tree_model.hpp:154
TNodeList_CI SubNodeEnd() const
Return const iterator to end of subnode list.
Definition: tree_model.hpp:136
TNodeList & GetChildren()
Return the indices of this node's child nodes.
Definition: tree_model.hpp:126
TNodeList::iterator TNodeList_I
Definition: tree_model.hpp:63
void SetParent(TTreeIdx parent_idx)
Set index of nodes parent.
Definition: tree_model.hpp:77
TData & GetValue()
Return the value object for the node.
Definition: tree_model.hpp:159
bool HasParent() const
Check if the node has a parent.
Definition: tree_model.hpp:90
bool IsLeaf() const
Report whether this is a leaf node.
Definition: tree_model.hpp:121
static TTreeIdx Null()
Static function that returns the null value.
Definition: tree_model.hpp:636
TNodeList_CI SubNodeBegin() const
Return const iterator to first subnode index.
Definition: tree_model.hpp:130
void ReRoot(TTreeIdx idx)
Sets the root idx to be 'idx' and updates the tree so that all nodes above the new root become childr...
Definition: tree_model.hpp:722
TNodeType & GetParent(TNodeType &node)
Return a reference to the parent node of the given node.
Definition: tree_model.hpp:690
static TTreeIdx Null()
Return the index value that represents a NULL node.
Definition: tree_model.hpp:678
void SetNumNodes(int count)
Set the number of displayed nodes in current tree layout.
Definition: tree_model.hpp:229
TNodeType & GetNode(TTreeIdx idx)
Return a reference to the node at the given index.
Definition: tree_model.hpp:207
TNodeType & GetRoot()
Return a reference to the root node of the tree.
Definition: tree_model.hpp:254
void AddChild(TTreeIdx parent_idx, TTreeIdx child_idx)
Add the node at 'child_idx' to the children 'parent_idx'.
Definition: tree_model.hpp:715
TTreeIdx GetRootIdx() const
Return the index of the root node.
Definition: tree_model.hpp:267
TTreeIdx AddNode()
Add a new default node to the tree and return its index.
Definition: tree_model.hpp:749
void RemoveChild(TTreeIdx parent_idx, TTreeIdx child_idx)
Remove the node at 'child_idx' from its parent 'parent_idx' Nothing is done if the node 'child_idx' i...
Definition: tree_model.hpp:708
void SetRootIdx(TTreeIdx idx)
Set the index of the root node of the tree.
Definition: tree_model.hpp:262
class CTreeQueryExec
void SetTree(CPhyloTree *t)
Set current node for query execution.
std::vector< TTreeIdx > GetTreeSelected() const
bool HasField(const string &str, const string &delim=".", NStr::ECase use_case=NStr::eCase) const
Verify that a named field exists.
CUser_object & AddField(const string &label, const string &value, EParseField parse=eParse_String)
add a data field to the user object that holds a given value
CUser_field & SetField(const string &str, const string &delim=".", const string &obj_subtype=kEmptyStr, NStr::ECase use_case=NStr::eCase)
Access a named field in this user object.
const CUser_field & GetField(const string &str, const string &delim=".", NStr::ECase use_case=NStr::eCase) const
Access a named field in this user object.
Definition: User_object.cpp:71
size_type size() const
Definition: map.hpp:148
const_iterator begin() const
Definition: map.hpp:151
const_iterator end() const
Definition: map.hpp:152
bool empty() const
Definition: map.hpp:149
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: set.hpp:45
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
parent_type::iterator iterator
Definition: set.hpp:80
const_iterator find(const key_type &key) const
Definition: set.hpp:137
void erase(iterator pos)
Definition: set.hpp:151
const_iterator end() const
Definition: set.hpp:136
visitor_copy_subtree(CPhyloTree &tree, CPhyloTree &target)
CPhyloTree::TNodeType TNodeType
ETreeTraverseCode operator()(CPhyloTree &tree, CPhyloTree::TTreeIdx node_idx, int delta)
CPhyloTree::TTreeIdx TTreeIdx
ETreeTraverseCode operator()(CPhyloTree &tree, CPhyloTree::TTreeIdx node, int delta)
CPhyloTree::TTreeIdx TTreeIdx
map< CPhyloNodeData::TID, CPhyloNodeData::TID > m_IdMap
mapping from Ids in source tree to target tree
CPhyloTree::TNodeType TNodeType
CPhyloNodeData::TID m_TargetMaxId
visitor_paste_subtree(CPhyloTree &source, CPhyloTree &target, TTreeIdx target_idx)
ETreeTraverseCode operator()(CPhyloTree &tree, CPhyloTree::TTreeIdx node_idx, int delta)
visitor_stringmatch_query(CStringMatching &stringMatching, vector< TTreeIdx > &selNodes, size_t &numQueried)
ETreeTraverseCode operator()(CPhyloTree &tree, TTreeIdx node, int delta)
vector< TTreeIdx > & m_SelNodes
CPhyloTree::TTreeIdx TTreeIdx
CStringMatching & m_StringMatching
int close(int fd)
Definition: connection.cpp:45
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
size_t AddColor(const CRgbaColor &c)
Add a single color to the table.
float FindClosestColor(const CRgbaColor &c, size_t &idx) const
Return index of color with minimum color disance (as defined in CRgbaColor) from c.
bool FindColor(const CRgbaColor &c, size_t &idx) const
On exact match, returns true with index in idx, false otherwise.
void LoadTexture(int alpha_levels=8)
OpenGL parameters and operations to allow color table to (also) be stored as a 1D texture.
void ClearColors()
Empty color table.
CRgbaColor & GetColor(size_t i)
static CRgbaColor RotateColor(const CRgbaColor &c, float degrees)
Rotate the hue of the color by degrees.
string ToString(bool printAlpha=true, bool uchars=true) const
Return a string representation of the current color.
Definition: rgba_color.cpp:309
void Darken(float scale)
Definition: rgba_color.cpp:472
static float ColorDistance(const CRgbaColor &c1, const CRgbaColor &c2)
returns the distance in the RGB color cube between the two colors, scaled to a range [0,...
void FromString(const string &str)
Assign color values encoded in a string.
Definition: rgba_color.cpp:363
TObjectType * GetNCPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1174
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
bool IsNull(void) const THROWS_NONE
Check if pointer is null – same effect as Empty().
Definition: ncbiobj.hpp:735
TObjectType & GetObject(void)
Get object.
Definition: ncbiobj.hpp:1011
TObjectType & GetNCObject(void) const
Get object.
Definition: ncbiobj.hpp:1187
void AddFunc(CQueryParseNode::EType func_type, CQueryFunctionBase *func)
Register function implementation.
Definition: query_exec.cpp:96
@ eFunction
Function.
Definition: query_parse.hpp:91
@ eIdentifier
Identifier like db.field (Org, Fld12, etc.)
Definition: query_parse.hpp:86
@ eFloatConst
Floating point const.
Definition: query_parse.hpp:88
@ eIntConst
Integer const.
Definition: query_parse.hpp:87
@ eBoolConst
Boolean (TRUE or FALSE)
Definition: query_parse.hpp:89
@ eString
String ("free text")
Definition: query_parse.hpp:90
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static string DoubleToString(double value, int precision=-1, TNumToStringFlags flags=0)
Convert double to string.
Definition: ncbistr.hpp:5181
ECase
Which type of string comparison.
Definition: ncbistr.hpp:1204
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
@ eCase
Case sensitive compare.
Definition: ncbistr.hpp:1205
string GetName(TBioTreeFeatureId id) const
Return the featue name given the id, or "" if not found.
Definition: bio_tree.cpp:218
ETreeTraverseCode
Tree traverse code returned by the traverse predicate function.
Definition: ncbi_tree.hpp:51
unsigned int TBioTreeFeatureId
Feature Id.
Definition: bio_tree.hpp:60
void SetFeature(TBioTreeFeatureId id, const string &value)
Set feature value, feature if exists replaced, if not added.
Definition: bio_tree.cpp:56
TBioTreeFeatureId GetId(const string &feature_name) const
If feature is already registered returns its id by name.
Definition: bio_tree.cpp:209
TBioTreeFeatureId Register(const string &feature_name)
Register new feature, return its id.
Definition: bio_tree.cpp:160
const string & GetFeatureValue(TBioTreeFeatureId id) const
Get feature value by id.
Definition: bio_tree.cpp:69
bool HasFeature(const string &feature_name) const
Check if feature is listed in the dictionary.
Definition: bio_tree.cpp:146
const TFeatureDict & GetFeatureDict() const
Get reference on the internal map.
Definition: bio_tree.hpp:219
vector< CBioTreeFeaturePair > TFeatureList
Definition: bio_tree.hpp:103
@ eTreeTraverse
Keep traversal.
Definition: ncbi_tree.hpp:52
const TData & GetData(void) const
Get the Data member data.
TStr & SetStr(void)
Select the variant.
Definition: Object_id_.hpp:304
const TObject & GetObject(void) const
Get the variant data.
void SetType(TType &value)
Assign a value to Type data member.
void SetData(TData &value)
Assign a value to Data data member.
bool IsObject(void) const
Check if variant Object is selected.
n background color
int i
yy_size_t n
constexpr auto sort(_Init &&init)
const struct ncbi::grid::netcache::search::fields::SIZE size
const CharType(& source)[N]
Definition: pointer.h:1149
EIPRangeType t
Definition: ncbi_localip.c:101
T max(T x_, T y_)
T min(T x_, T y_)
Int4 delta(size_t dimension_, const Int4 *score_)
#define count
void TreeConvertNonSingleChild2Container(TBioTreeContainer &tree_container, TPhyloTree &phylo_tree, typename TPhyloTree::TTreeIdx node_idx=TPhyloTree::Null())
Convert selected nodes from tree to ASN.1 BioTree container.
void TreeConvert2Container(TBioTreeContainer &tree_container, TPhyloTree &phylo_tree, typename TPhyloTree::TTreeIdx node_idx=TPhyloTree::Null())
Convert tree to ASN.1 BioTree container.
void BioTreeConvertContainer2Tree(TPhyloTree &phylo_tree, const TBioTreeContainer &tree_container, CBioTreeFeatureDictionary *dictionary, bool preserve_node_ids=true, bool expand_all=false)
Convert ASN.1 BioTree container to phylo tree.
bool operator()(CPhyloTree::TTreeIdx lhs, CPhyloTree::TTreeIdx rhs) const
const CPhyloTree & m_Tree
NodeIdxSort(const CPhyloTree &t)
static string query
#define _ASSERT
Fun TreeDepthFirst(TTreeModel &tree_model, typename TTreeModel::TTreeIdx node_idx, Fun func)
Depth-first tree traversal algorithm.
Definition: tree_model.hpp:355
Fun TreeDepthFirstInvarient(TTreeModel &tree_model, typename TTreeModel::TTreeIdx node_idx, Fun func)
Definition: tree_model.hpp:463
C++ wrappers for the Perl-compatible regular expression (PCRE) library.
Modified on Fri Sep 20 14:57:29 2024 by modify_doxy.py rev. 669887