Browse code

parent method

Guangchuang Yu authored on 13/04/2020 09:10:50
Showing 1 changed files
... ...
@@ -2,3 +2,4 @@ nodeid.tbl_tree <- utils::getFromNamespace("nodeid.tbl_tree", "tidytree")
2 2
 rootnode.tbl_tree <- utils::getFromNamespace("rootnode.tbl_tree", "tidytree")
3 3
 offspring.tbl_tree <- utils::getFromNamespace("offspring.tbl_tree", "tidytree")
4 4
 child.tbl_tree <- utils::getFromNamespace("child.tbl_tree", "tidytree")
5
+parent.tbl_tree <- utils::getFromNamespace("parent.tbl_tree", "tidytree")
Browse code

child #287

Guangchuang Yu authored on 13/04/2020 08:50:46
Showing 1 changed files
... ...
@@ -1,3 +1,4 @@
1 1
 nodeid.tbl_tree <- utils::getFromNamespace("nodeid.tbl_tree", "tidytree")
2 2
 rootnode.tbl_tree <- utils::getFromNamespace("rootnode.tbl_tree", "tidytree")
3 3
 offspring.tbl_tree <- utils::getFromNamespace("offspring.tbl_tree", "tidytree")
4
+child.tbl_tree <- utils::getFromNamespace("child.tbl_tree", "tidytree")
Browse code

reexport arrow and unit

Guangchuang Yu authored on 28/09/2019 10:22:18
Showing 1 changed files
... ...
@@ -1,2 +1,3 @@
1 1
 nodeid.tbl_tree <- utils::getFromNamespace("nodeid.tbl_tree", "tidytree")
2
+rootnode.tbl_tree <- utils::getFromNamespace("rootnode.tbl_tree", "tidytree")
2 3
 offspring.tbl_tree <- utils::getFromNamespace("offspring.tbl_tree", "tidytree")
Browse code

offsprint

Guangchuang Yu authored on 06/09/2019 03:37:00
Showing 1 changed files
... ...
@@ -1 +1,2 @@
1 1
 nodeid.tbl_tree <- utils::getFromNamespace("nodeid.tbl_tree", "tidytree")
2
+offspring.tbl_tree <- utils::getFromNamespace("offspring.tbl_tree", "tidytree")
Browse code

geom_strip

Guangchuang Yu authored on 27/08/2019 05:12:46
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+nodeid.tbl_tree <- utils::getFromNamespace("nodeid.tbl_tree", "tidytree")
Browse code

clean up code

guangchuang yu authored on 14/12/2017 08:47:21
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,1480 +0,0 @@
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-##' @importFrom ape reorder.phylo
11
-layout.unrooted <- function(tree, branch.length="branch.length", layout.method="equal_angle", ...) {
12
-
13
-    df <- switch(layout.method,
14
-                 equal_angle = layoutEqualAngle(tree, branch.length),
15
-                 daylight = layoutDaylight(tree, branch.length)
16
-                 )
17
-
18
-    return(df)
19
-}
20
-
21
-
22
-##' 'Equal-angle layout algorithm for unrooted trees'
23
-##'
24
-##' @references
25
-##' "Inferring Phylogenies" by Joseph Felsenstein.
26
-##'
27
-##' @title layoutEqualAngle
28
-##' @param tree phylo object
29
-##' @param branch.length set to 'none' for edge length of 1. Otherwise the phylogenetic tree edge length is used.
30
-##' @return tree as data.frame with equal angle layout.
31
-layoutEqualAngle <- function(tree, branch.length ){
32
-    root <- getRoot(tree)
33
-    ## Convert Phylo tree to data.frame.
34
-    df <- as.data.frame.phylo_(tree)
35
-
36
-    ## NOTE: Angles (start, end, angle) are in half-rotation units (radians/pi or degrees/180)
37
-
38
-    ## create and assign NA to the following fields.
39
-    df$x <- NA
40
-    df$y <- NA
41
-    df$start <- NA # Start angle of segment of subtree.
42
-    df$end   <- NA # End angle of segment of subtree
43
-    df$angle <- NA # Orthogonal angle to beta for tip labels.
44
-    ## Initialize root node position and angles.
45
-    df[root, "x"] <- 0
46
-    df[root, "y"] <- 0
47
-    df[root, "start"] <- 0 # 0-degrees
48
-    df[root, "end"]   <- 2 # 360-degrees
49
-    df[root, "angle"] <- 0 # Angle label.
50
-
51
-    N <- getNodeNum(tree)
52
-
53
-    ## Get number of tips for each node in tree.
54
-    nb.sp <- sapply(1:N, function(i) length(get.offspring.tip(tree, i)))
55
-    ## Get list of node id's.
56
-    nodes <- getNodes_by_postorder(tree)
57
-
58
-    for(curNode in nodes) {
59
-        ## Get number of tips for current node.
60
-        curNtip <- nb.sp[curNode]
61
-        ## Get array of child node indexes of current node.
62
-        children <- getChild(tree, curNode)
63
-
64
-        ## Get "start" and "end" angles of a segment for current node in the data.frame.
65
-        start <- df[curNode, "start"]
66
-        end <- df[curNode, "end"]
67
-
68
-        if (length(children) == 0) {
69
-            ## is a tip
70
-            next
71
-        }
72
-
73
-        for (i in seq_along(children)) {
74
-            child <- children[i]
75
-            ## Get the number of tips for child node.
76
-            ntip.child <- nb.sp[child]
77
-
78
-            ## Calculated in half radians.
79
-            ## alpha: angle of segment for i-th child with ntips_ij tips.
80
-            ## alpha = (left_angle - right_angle) * (ntips_ij)/(ntips_current)
81
-            alpha <- (end - start) * ntip.child / curNtip
82
-            ## beta = angle of line from parent node to i-th child.
83
-            beta <- start + alpha / 2
84
-
85
-            if (branch.length == "none") {
86
-                length.child <- 1
87
-            } else {
88
-                length.child <- df[child, "length"]
89
-            }
90
-
91
-            ## update geometry of data.frame.
92
-            ## Calculate (x,y) position of the i-th child node from current node.
93
-            df[child, "x"] <- df[curNode, "x"] + cospi(beta) * length.child
94
-            df[child, "y"] <- df[curNode, "y"] + sinpi(beta) * length.child
95
-            ## Calculate orthogonal angle to beta for tip label.
96
-            df[child, "angle"] <- -90 - 180 * beta * sign(beta - 1)
97
-            ## Update the start and end angles of the childs segment.
98
-            df[child, "start"] <- start
99
-            df[child, "end"] <- start + alpha
100
-            start <- start + alpha
101
-        }
102
-
103
-    }
104
-
105
-    return(df)
106
-
107
-}
108
-
109
-##' Equal daylight layout method for unrooted trees.
110
-##'
111
-##' #' @title
112
-##' @param tree phylo object
113
-##' @param branch.length set to 'none' for edge length of 1. Otherwise the phylogenetic tree edge length is used.
114
-##' @return tree as data.frame with equal angle layout.
115
-##' @references
116
-##' The following aglorithm aims to implement the vague description of the "Equal-daylight Algorithm"
117
-##' in "Inferring Phylogenies" pp 582-584 by Joseph Felsenstein.
118
-##'
119
-##' ```
120
-##' Leafs are subtrees with no children
121
-##' Initialise tree using equal angle algorithm
122
-##' tree_df = equal_angle(tree)
123
-##'
124
-##' nodes = get list of nodes in tree_df breadth-first
125
-##' nodes = remove tip nodes.
126
-##'
127
-##' ```
128
-layoutDaylight <- function( tree, branch.length ){
129
-
130
-    ## How to set optimal
131
-    MAX_COUNT <- 5
132
-    MINIMUM_AVERAGE_ANGLE_CHANGE <- 0.05
133
-
134
-
135
-    ## Initialize tree.
136
-    tree_df <- layoutEqualAngle(tree, branch.length)
137
-
138
-    ## nodes = get list of nodes in tree_df
139
-    ## Get list of node id's.
140
-    ## nodes <- getNodes_by_postorder(tree)
141
-    ## nodes <- getSubtree.df(tree_df, root)
142
-
143
-    ## Get list of internal nodes
144
-    ## nodes <- tree_df[tree_df$IsTip != TRUE]$nodes
145
-
146
-    nodes <- getNodesBreadthFirst.df(tree_df)
147
-    ## select only internal nodes
148
-    internal_nodes <- tree_df[!tree_df$isTip,]$node
149
-    ## Remove tips from nodes list, but keeping order.
150
-    nodes <- intersect(nodes, internal_nodes)
151
-
152
-    i <- 1
153
-    ave_change <- 1.0
154
-    while( i <= MAX_COUNT & ave_change > MINIMUM_AVERAGE_ANGLE_CHANGE ){
155
-        message('Iteration: ', i)
156
-
157
-        ## Reset max_change after iterating over tree.
158
-        total_max <- 0.0
159
-
160
-        ## for node in nodes {
161
-        for( j in seq_along(nodes)){
162
-            currentNode_id <- nodes[j]
163
-
164
-            result <- applyLayoutDaylight(tree_df, currentNode_id)
165
-            tree_df <- result$tree
166
-            total_max <- total_max + result$max_change
167
-
168
-        }
169
-        # Calculate the running average of angle changes.
170
-        ave_change <- total_max / length(nodes) * length(i)
171
-
172
-        cat('Average angle change [',i,']', ave_change,'\n')
173
-
174
-        i <- i + 1
175
-    }
176
-
177
-    return(tree_df)
178
-
179
-}
180
-
181
-##' Apply the daylight alorithm to adjust the spacing between the subtrees and tips of the
182
-##' specified node.
183
-##'
184
-##' @title applyLayoutDaylight
185
-##' @param df tree data.frame
186
-##' @param node_id is id of the node from which daylight is measured to the other subtrees.
187
-##' @return list with tree data.frame with updated layout using daylight algorithm and max_change angle.
188
-##
189
-##
190
-## ```
191
-## for node in nodes {
192
-##   if node is a leaf {
193
-##     next
194
-##   }
195
-##
196
-##   subtrees = get subtrees of node
197
-##
198
-##   for i-th subtree in subtrees {
199
-##     [end, start] = get left and right angles of tree from node id.
200
-##     angle_list[i, 'left'] = end
201
-##     angle_list[i, 'beta'] = start - end  # subtree arc angle
202
-##     angle_list[i, 'index'] = i-th # index of subtree/leaf
203
-##   }
204
-##
205
-##   sort angle_list by 'left' column in ascending order.
206
-##
207
-##   D = 360 - sum( angle_list['beta'] ) # total daylight angle
208
-##   d = D / |subtrees| # equal daylight angle.
209
-##
210
-##   new_L = left angle of first subtree.
211
-##
212
-##   for n-th row in angle_list{
213
-##     # Calculate angle to rotate subtree/leaf to create correct daylight angle.
214
-##     new_left_angle = new_left_angle + d + angle_list[n, 'beta']
215
-##     Calculate the difference between the old and new left angles.
216
-##     adjust_angle = new_left_angle - angle_list[n, 'left']
217
-##
218
-##     index = angle_list['index']
219
-##     rotate subtree[index] wrt n-th node by adjust_angle
220
-##     }
221
-##   }
222
-## }
223
-## ```
224
-applyLayoutDaylight <- function(df, node_id){
225
-
226
-  max_change <- 0.0
227
-
228
-  # Get lists of node ids for each subtree, including  rest of unrooted tree.
229
-  subtrees <- getSubtreeUnrooted.df(df, node_id)
230
-  angle_list <- data.frame(left=numeric(0), beta=numeric(0), subtree_id=integer(0) )
231
-
232
-  # Return tree if only 2 or less subtrees to adjust.
233
-  if(length(subtrees) <= 2){
234
-    return( list(tree = df, max_change = max_change) )
235
-  }
236
-
237
-  # Find start and end angles for each subtree.
238
-  #   subtrees = get subtrees of node
239
-  #   for i-th subtree in subtrees {
240
-  for (i in seq_along(subtrees) ) {
241
-    subtree <- subtrees[[i]]
242
-    # [end, start] = get start and end angles of tree.
243
-
244
-    angles <- getTreeArcAngles(df, node_id, subtree)
245
-    angle_list[ i, 'subtree_id'] <- i
246
-    angle_list[ i, 'left'] <- angles['left']
247
-    angle_list[ i, 'beta'] <- angles['left'] - angles['right'] # subtree arc angle
248
-    # If subtree arc angle is -ve, then + 2 (360).
249
-    if(angle_list[ i, 'beta'] < 0 ){
250
-      angle_list[ i, 'beta'] <- angle_list[ i, 'beta'] + 2
251
-    }
252
-  }
253
-  #   sort angle_list by 'left angle' column in ascending order.
254
-  angle_list <- angle_list[with(angle_list, order(left)), ]
255
-  #   D = 360 - sum( angle_list['beta'] ) # total day
256
-  #   d = D / |subtrees| # equal daylight angle.
257
-  total_daylight <- 2 - colSums(angle_list['beta'])
258
-  d <- total_daylight / length(subtrees)
259
-
260
-  # Initialise new left-angle as first subtree left-angle.
261
-  new_left_angle <- angle_list[1, 'left']
262
-
263
-  # Adjust angles of subtrees and tips connected to current node.
264
-  # for n-th row in angle_list{
265
-  # Skip the first subtree as it is not adjusted.
266
-  for (i in 2:nrow(angle_list) ) {
267
-    # Calculate angle to rotate subtree/leaf to create correct daylight angle.
268
-    new_left_angle <- new_left_angle + d + angle_list[i, 'beta']
269
-    # Calculate the difference between the old and new left angles.
270
-    adjust_angle <- new_left_angle - angle_list[i, 'left']
271
-
272
-    max_change <- max(max_change, abs(adjust_angle))
273
-    #cat('Adjust angle:', abs(adjust_angle), ' Max change:', max_change ,'\n')
274
-
275
-    # rotate subtree[index] wrt current node
276
-    subtree_id <- angle_list[i, 'subtree_id']
277
-    subtree_nodes <- subtrees[[subtree_id]]$subtree
278
-    # update tree_df for all subtrees with rotated points.
279
-    df <- rotateTreePoints.df(df, node_id, subtree_nodes, adjust_angle)
280
-  }
281
-
282
-  return( list(tree = df, max_change = max_change) )
283
-
284
-}
285
-
286
-
287
-##' Find the right (clockwise rotation, angle from +ve x-axis to furthest subtree nodes) and
288
-##' left (anti-clockwise angle from +ve x-axis to subtree) Returning arc angle in [0, 2] (0 to 360) domain.
289
-##'
290
-##' @title getTreeArcAngles
291
-##' @param df tree data.frame
292
-##' @param origin_id node id from which to calculate left and right hand angles of subtree.
293
-##' @param subtree named list of root id of subtree (node) and list of node ids for given subtree (subtree).
294
-##' @return named list with right and left angles in range [0,2] i.e 1 = 180 degrees, 1.5 = 270 degrees.
295
-getTreeArcAngles <- function(df, origin_id, subtree) {
296
-  # Initialise variables
297
-  theta_child <- 0.0
298
-  subtree_root_id <- subtree$node
299
-  subtree_node_ids <- subtree$subtree
300
-
301
-  # Initialise angle from origin node to parent node.
302
-  # If subtree_root_id is child of origin_id
303
-  if( any(subtree_root_id == getChild.df(df, origin_id)) ){
304
-    # get angle from original node to parent of subtree.
305
-    theta_left <- getNodeAngle.df(df, origin_id, subtree_root_id)
306
-    theta_right <- theta_left
307
-  }else if( subtree_root_id == origin_id){
308
-    # Special case.
309
-    # get angle from parent of subtree to children
310
-    children_ids <- getChild.df(df, subtree_root_id)
311
-
312
-    if(length(children_ids) == 2){
313
-      # get angles from parent to it's two children.
314
-      theta1 <- getNodeAngle.df(df, origin_id, children_ids[1])
315
-      theta2 <- getNodeAngle.df(df, origin_id, children_ids[2])
316
-
317
-      delta <- theta1 - theta2
318
-
319
-
320
-      # correct delta for points crossing 180/-180 quadrant.
321
-      if(delta > 1){
322
-        delta_adj = delta - 2
323
-      }else if(delta < -1){
324
-        delta_adj = delta + 2
325
-      }else{
326
-        delta_adj <- delta
327
-      }
328
-
329
-      if(delta_adj >= 0){
330
-        theta_left = theta1
331
-        theta_right = theta2
332
-      }else if(delta_adj < 0){
333
-        theta_left = theta2
334
-        theta_right = theta1
335
-      }
336
-    }else{
337
-      # subtree only has one child node.
338
-      theta_left <- getNodeAngle.df(df, origin_id, children_ids[1])
339
-      theta_right <- theta_left
340
-    }
341
-
342
-  }else{
343
-    # get the real root of df tree to initialise left and right angles.
344
-    tree_root <- getRoot.df(df)
345
-    if( !is.na(tree_root) & is.numeric(tree_root) ){
346
-      theta_left <- getNodeAngle.df(df, origin_id, tree_root)
347
-      theta_right <- theta_left
348
-    }else{
349
-      print('ERROR: no root found!')
350
-      theta_left <- NA
351
-    }
352
-
353
-  }
354
-
355
-  # no parent angle found.
356
-  if (is.na(theta_left) ){
357
-    return(0)
358
-  }
359
-
360
-
361
-  # create vector with named columns
362
-  # left-hand and right-hand angles between origin node and the extremities of the tree nodes.
363
-  arc <- c('left' = theta_left, 'right' = theta_right)
364
-
365
-  # Subtree has to have 1 or more nodes to compare.
366
-  if (length(subtree_node_ids) == 0 ){
367
-    return(0)
368
-  }
369
-
370
-
371
-  # Remove tips from nodes list, but keeping order.
372
-  # internal_nodes <- df[!df$isTip,]$node
373
-  # subtree_node_ids <- intersect(subtree_node_ids, internal_nodes)
374
-
375
-
376
-  # Calculate the angle from the origin node to each child node.
377
-  # Moving from parent to children in depth-first traversal.
378
-  for( i in seq_along(subtree_node_ids) ){
379
-    parent_id <- subtree_node_ids[i]
380
-    # Get angle from origin node to parent node.
381
-    # Skip if parent_id is a tip or parent and child node are the same.
382
-    if(origin_id == parent_id | isTip.df(df, parent_id) ){
383
-      next
384
-    }
385
-
386
-    theta_parent <- getNodeAngle.df(df, origin_id, parent_id)
387
-
388
-    children_ids <- getChild.df(df, parent_id)
389
-
390
-    for( j in seq_along(children_ids)){
391
-      #delta_x <- df[subtree_node_id, 'x'] - df[origin_id, 'x']
392
-      #delta_y <- df[subtree_node_id, 'y'] - df[origin_id, 'y']
393
-      #angles[i] <- atan2(delta_y, delta_x) / pi
394
-      child_id <- children_ids[j]
395
-      # Skip if child is parent node of subtree.
396
-      if( child_id == origin_id ){
397
-        next
398
-      }
399
-
400
-      theta_child <- getNodeAngle.df(df, origin_id, child_id)
401
-
402
-      # Skip if child node is already inside arc.
403
-      # if left < right angle (arc crosses 180/-180 quadrant) and child node is not inside arc of tree.
404
-      # OR if left > right angle (arc crosses 0/360 quadrant) and child node is inside gap
405
-      if ( (arc['left'] < arc['right'] & !( theta_child > arc['left'] & theta_child < arc['right'])) |
406
-        (arc['left'] > arc['right'] & ( theta_child < arc['left'] & theta_child > arc['right'])) ){
407
-        # child node inside arc.
408
-        next
409
-      }
410
-
411
-
412
-      delta <- theta_child - theta_parent
413
-      delta_adj <- delta
414
-      # Correct the delta if parent and child angles cross the 180/-180 half of circle.
415
-      # If delta > 180
416
-      if( delta > 1){ # Edge between parent and child cross upper and lower quadrants of cirlce on 180/-180 side.
417
-        delta_adj <- delta - 2 # delta' = delta - 360
418
-      # If delta < -180
419
-      }else if( delta < -1){ # Edge between parent and child cross upper and lower quadrants of cirlce
420
-        delta_adj <- delta + 2 # delta' = delta - 360
421
-      }
422
-
423
-      theta_child_adj <- theta_child
424
-
425
-      # If angle change from parent to node is positive (anti-clockwise), check left angle
426
-      if(delta_adj > 0){
427
-        # If child/parent edges cross the -180/180 quadrant (angle between them is > 180),
428
-        # check if right angle and child angle are different signs and adjust if needed.
429
-        if( abs(delta) > 1){
430
-          if( arc['left'] > 0 & theta_child < 0){
431
-            theta_child_adj <- theta_child + 2
432
-          }else if (arc['left'] < 0 & theta_child > 0){
433
-            theta_child_adj <- theta_child - 2
434
-          }
435
-        }
436
-
437
-          # check if left angle of arc is less than angle of child. Update if true.
438
-        if( arc['left'] < theta_child_adj ){
439
-          arc['left'] <- theta_child
440
-        }
441
-      # If angle change from parent to node is negative (clockwise), check right angle
442
-      }else if(delta_adj < 0){
443
-        # If child/parent edges cross the -180/180 quadrant (angle between them is > 180),
444
-        # check if right angle and child angle are different signs and adjust if needed.
445
-        if( abs(delta) > 1){
446
-          # Else change in angle from parent to child is negative, then adjust child angle if right angle is a different sign.
447
-          if( arc['right'] > 0 & theta_child < 0){
448
-            theta_child_adj <- theta_child + 2
449
-          }else if (arc['right'] < 0 & theta_child > 0){
450
-            theta_child_adj <- theta_child - 2
451
-          }
452
-        }
453
-        # check if right angle of arc is greater than angle of child. Update if true.
454
-        if( arc['right'] > theta_child_adj  ){
455
-          arc['right'] <- theta_child
456
-        }
457
-
458
-      }
459
-    }
460
-
461
-  }
462
-  # Convert arc angles of [1, -1] to [2,0] domain.
463
-  arc[arc<0] <- arc[arc<0] + 2
464
-  return(arc)
465
-
466
-}
467
-
468
-##' Rotate the points in a tree data.frame around a pivot node by the angle specified.
469
-##'
470
-##' @title rotateTreePoints.data.fram
471
-##' @param df tree data.frame
472
-##' @param pivot_node is the id of the pivot node.
473
-##' @param nodes list of node numbers that are to be rotated by angle around the pivot_node
474
-##' @param angle in range [0,2], ie degrees/180, radians/pi
475
-##' @return updated tree data.frame with points rotated by angle
476
-rotateTreePoints.df <- function(df, pivot_node, nodes, angle){
477
-  # Rotate nodes around pivot_node.
478
-  # x' = cos(angle)*delta_x - sin(angle)*delta_y + delta_x
479
-  # y' = sin(angle)*delta_x + cos(angle)*delta_y + delta_y
480
-
481
-  cospitheta <- cospi(angle)
482
-  sinpitheta <- sinpi(angle)
483
-  for(node in nodes){
484
-    # Update (x,y) of node
485
-    delta_x <- df[node, 'x'] - df[pivot_node, 'x']
486
-    delta_y <- df[node, 'y'] - df[pivot_node, 'y']
487
-    df[node, 'x'] <- cospitheta * delta_x - sinpitheta * delta_y + df[pivot_node, 'x']
488
-    df[node, 'y'] <- sinpitheta * delta_x + cospitheta * delta_y + df[pivot_node, 'y']
489
-
490
-  }
491
-
492
-  # Now update tip labels of rotated tree.
493
-  # angle is in range [0, 360]
494
-  for(node in nodes){
495
-    # Update label angle of tipnode if not root node.
496
-    if( isTip.df(df, node) ){
497
-      # get parent
498
-      parent_id <- getParent.df(df, node)
499
-      # if 'node' is not root, then update label angle.
500
-      if( parent_id != 0 ){
501
-        theta_parent_child <- getNodeAngle.df(df, parent_id, node)
502
-        if(!is.na(theta_parent_child)){
503
-          # Update tip label angle, that is parallel to edge.
504
-          #df[node, 'angle'] <- -90 - 180 * theta_parent_child * sign(theta_parent_child - 1)
505
-          if(theta_parent_child > 0 ){
506
-            df[node, 'angle'] <- 180 * theta_parent_child
507
-          }else if(theta_parent_child < 0 ){
508
-            df[node, 'angle'] <- 180 * ( theta_parent_child + 2 )
509
-          }
510
-
511
-        }
512
-      }
513
-    }
514
-  }
515
-
516
-
517
-  return(df)
518
-}
519
-
520
-##' Get the angle between the two nodes specified.
521
-##'
522
-##' @title getNodeAngle.df
523
-##' @param df tree data.frame
524
-##' @param origin_node_id origin node id number
525
-##' @param node_id end node id number
526
-##' @return angle in range [-1, 1], i.e. degrees/180, radians/pi
527
-getNodeAngle.df <- function(df, origin_node_id, node_id){
528
-  if( (origin_node_id != node_id) & any(origin_node_id %in% df$node) & any(node_id %in% df$node) ){
529
-    delta_x <- df[node_id, 'x'] - df[origin_node_id, 'x']
530
-    delta_y <- df[node_id, 'y'] - df[origin_node_id, 'y']
531
-    angle <- atan2(delta_y, delta_x) / pi
532
-    return( angle )
533
-  }else{
534
-    return(NA)
535
-  }
536
-}
537
-
538
-euc.dist <- function(x1, x2) sqrt(sum((x1 - x2) ^ 2))
539
-
540
-## Get the distances from the node to all other nodes in data.frame (including itself if in df)
541
-getNodeEuclDistances <- function(df, node){
542
-  # https://stackoverflow.com/questions/24746892/how-to-calculate-euclidian-distance-between-two-points-defined-by-matrix-contain#24747155
543
-  dist <- NULL
544
-  for(i in 1:nrow(df)) dist[i] <- euc.dist(df[df$node==node, c('x', 'y')], df[i, c('x', 'y')])
545
-  return(dist)
546
-}
547
-
548
-
549
-##' Get all children of node from tree, including start_node.
550
-##'
551
-##' @title getSubtree
552
-##' @param tree ape phylo tree object
553
-##' @param node is the tree node id from which the tree is derived.
554
-##' @return list of all child node id's from starting node.
555
-getSubtree <- function(tree, node){
556
-
557
-  subtree <- c(node)
558
-  i <- 1
559
-  while( i <= length(subtree)){
560
-    subtree <- c(subtree, getChild(tree, subtree[i]))
561
-    # remove any '0' root nodes
562
-    subtree <- subtree[subtree != 0]
563
-    i <- i + 1
564
-  }
565
-  return(subtree)
566
-}
567
-
568
-##' Get all children of node from df tree using breath-first.
569
-##'
570
-##' @title getSubtree.df
571
-##' @param df tree data.frame
572
-##' @param node id of starting node.
573
-##' @return list of all child node id's from starting node.
574
-getSubtree.df <- function(df, node){
575
-  subtree <- c(node)
576
-  subtree <- subtree[subtree != 0]
577
-  i <- 1
578
-  while( i <= length(subtree)){
579
-    subtree <- c(subtree, getChild.df(df, subtree[i]))
580
-    # remove any '0' root nodes
581
-    subtree <- subtree[subtree != 0]
582
-    i <- i + 1
583
-  }
584
-  return(subtree)
585
-}
586
-
587
-##' Get all subtrees of specified node. This includes all ancestors and relatives of node and
588
-##' return named list of subtrees.
589
-##'
590
-##' @title getSubtreeUnrooted
591
-##' @param tree ape phylo tree object
592
-##' @param node is the tree node id from which the subtrees are derived.
593
-##' @return named list of subtrees with the root id of subtree and list of node id's making up subtree.
594
-getSubtreeUnrooted <- function(tree, node){
595
-  # if node leaf, return nothing.
596
-  if( isTip(tree, node) ){
597
-    # return NA
598
-    return(NA)
599
-  }
600
-
601
-  subtrees <- list()
602
-
603
-  # get subtree for each child node.
604
-  children_ids <- getChild(tree, node)
605
-
606
-  remaining_nodes <- getNodes_by_postorder(tree)
607
-  # Remove current node from remaining_nodes list.
608
-  remaining_nodes <- setdiff(remaining_nodes, node)
609
-
610
-
611
-  for( child in children_ids ){
612
-    # Append subtree nodes to list if not 0 (root).
613
-    subtree <- getSubtree(tree, child)
614
-    subtrees[[length(subtrees)+1]] <- list( node = child, subtree = subtree)
615
-    # remove subtree nodes from remaining nodes.
616
-    remaining_nodes <- setdiff(remaining_nodes, as.integer(unlist(subtrees[[length(subtrees)]]['subtree']) ))
617
-  }
618
-
619
-  # The remaining nodes that are not found in the child subtrees are the remaining subtree nodes.
620
-  # ie, parent node and all other nodes. We don't care how they are connect, just their ids.
621
-  parent_id <- getParent(tree, node)
622
-  # If node is not root, add remainder of tree nodes as subtree.
623
-  if( parent_id != 0 & length(remaining_nodes) >= 1){
624
-    subtrees[[length(subtrees)+1]] <- list( node = parent_id, subtree = remaining_nodes)
625
-  }
626
-
627
-  return(subtrees)
628
-}
629
-
630
-
631
-##' Get all subtrees of node, as well as remaining branches of parent (ie, rest of tree structure as subtree)
632
-##' return named list of subtrees with list name as starting node id.
633
-##' @title getSubtreeUnrooted
634
-##' @param df tree data.frame
635
-##' @param node is the tree node id from which the subtrees are derived.
636
-##' @return named list of subtrees with the root id of subtree and list of node id's making up subtree.
637
-getSubtreeUnrooted.df <- function(df, node){
638
-  # if node leaf, return nothing.
639
-  if( isTip.df(df, node) ){
640
-    return(NA)
641
-  }
642
-
643
-  subtrees <- list()
644
-
645
-  # get subtree for each child node.
646
-  children_ids <- getChild.df(df, node)
647
-
648
-  # remaining_nodes <- getNodes_by_postorder(tree)
649
-  remaining_nodes <- df$node
650
-
651
-  # Remove current node from remaining_nodes list.
652
-  remaining_nodes <- setdiff(remaining_nodes, node)
653
-
654
-  for( child in children_ids ){
655
-    subtree <- getSubtree.df(df, child)
656
-    # Append subtree nodes to list if more than 1 node in subtree (i.e. not a tip)
657
-    #if(length(subtree) >= 2){
658
-      subtrees[[length(subtrees)+1]] <- list( node = child, subtree = subtree)
659
-      # remove subtree nodes from remaining nodes.
660
-      remaining_nodes <- setdiff(remaining_nodes, as.integer(unlist(subtrees[[length(subtrees)]]['subtree']) ))
661
-    #}else{
662
-      # remove remaining nodes
663
-    #  remaining_nodes <- setdiff(remaining_nodes, subtree)
664
-    #}
665
-  }
666
-
667
-  # The remaining nodes that are not found in the child subtrees are the remaining subtree nodes.
668
-  # ie, parent node and all other nodes. We don't care how they are connected, just their id.
669
-  parent_id <- getParent.df(df, node)
670
-  # If node is not root.
671
-  if( parent_id != 0 & length(remaining_nodes) >= 1){
672
-    subtrees[[length(subtrees)+1]] <- list( node = parent_id, subtree = remaining_nodes)
673
-  }
674
-
675
-  return(subtrees)
676
-}
677
-
678
-
679
-getRoot.df <- function(df, node){
680
-
681
-  root <- which(is.na(df$parent))
682
-  # Check if root was found.
683
-  if(length(root) == 0){
684
-    # Alternatively, root can self reference, eg node = 10, parent = 10
685
-    root <- unlist(apply(df, 1, function(x){ if(x['node'] == x['parent']){ x['node'] } }))
686
-  }
687
-  return(root)
688
-}
689
-
690
-
691
-
692
-
693
-
694
-
695
-
696
-
697
-isTip <- function(tr, node) {
698
-  children_ids <- getChild(tr, node)
699
-  #length(children_ids) == 0 ## getChild returns 0 if nothing found.
700
-  if( length(children_ids) == 0 | any(children_ids == 0) ){
701
-    return(TRUE)
702
-  }
703
-  return(FALSE)
704
-
705
-}
706
-
707
-isTip.df <- function(df, node) {
708
-  # df may not have the isTip structure.
709
-  # return(df[node, 'isTip'])
710
-  # Tip has no children.
711
-  children_ids <- getChild.df(df, node)
712
-  if( length(children_ids) == 0 | any(children_ids == 0) ){
713
-    return(TRUE)
714
-  }
715
-  return(FALSE)
716
-}
717
-
718
-
719
-
720
-##' Get the nodes of tree from root in breadth-first order.
721
-##'
722
-##' @title getNodesBreadthFirst.df
723
-##' @param df tree data.frame
724
-##' @return list of node id's in breadth-first order.
725
-getNodesBreadthFirst.df <- function(df){
726
-
727
-  root <- getRoot.df(df)
728
-  if(isTip.df(df, root)){
729
-    return(root)
730
-  }
731
-
732
-  tree_size <- nrow(df)
733
-  # initialise list of nodes
734
-  res <- root
735
-
736
-  i <- 1
737
-  while(length(res) < tree_size){
738
-    parent <- res[i]
739
-    i <- i + 1
740
-
741
-    # Skip if parent is a tip.
742
-    if(isTip.df(df, parent)){
743
-      next
744
-    }
745
-
746
-    # get children of current parent.
747
-    children <- getChild.df(df,parent)
748
-
749
-    # add children to result
750
-    res <- c(res, children)
751
-
752
-  }
753
-
754
-  return(res)
755
-
756
-}
757
-
758
-
759
-
760
-
761
-
762
-
763
-
764
-
765
-
766
-
767
-##' convert tip or node label(s) to internal node number
768
-##'
769
-##'
770
-##' @title nodeid
771
-##' @param x tree object or graphic object return by ggtree
772
-##' @param label tip or node label(s)
773
-##' @return internal node number
774
-##' @importFrom methods is
775
-##' @export
776
-##' @author Guangchuang Yu
777
-nodeid <- function(x, label) {
778
-    if (is(x, "gg"))
779
-        return(nodeid.gg(x, label))
780
-
781
-    nodeid.tree(x, label)
782
-}
783
-
784
-nodeid.tree <- function(tree, label) {
785
-    tr <- get.tree(tree)
786
-    lab <- c(tr$tip.label, tr$node.label)
787
-    match(label, lab)
788
-}
789
-
790
-nodeid.gg <- function(p, label) {
791
-    p$data$node[match(label, p$data$label)]
792
-}
793
-
794
-
795
-reroot_node_mapping <- function(tree, tree2) {
796
-    root <- getRoot(tree)
797
-
798
-    node_map <- data.frame(from=1:getNodeNum(tree), to=NA, visited=FALSE)
799
-    node_map[1:Ntip(tree), 2] <- match(tree$tip.label, tree2$tip.label)
800
-    node_map[1:Ntip(tree), 3] <- TRUE
801
-
802
-    node_map[root, 2] <- root
803
-    node_map[root, 3] <- TRUE
804
-
805
-    node <- rev(tree$edge[,2])
806
-    for (k in node) {
807
-        ip <- getParent(tree, k)
808
-        if (node_map[ip, "visited"])
809
-            next
810
-
811
-        cc <- getChild(tree, ip)
812
-        node2 <- node_map[cc,2]
813
-        if (anyNA(node2)) {
814
-            node <- c(node, k)
815
-            next
816
-        }
817
-
818
-        to <- unique(sapply(node2, getParent, tr=tree2))
819
-        to <- to[! to %in% node_map[,2]]
820
-        node_map[ip, 2] <- to
821
-        node_map[ip, 3] <- TRUE
822
-    }
823
-    node_map <- node_map[, -3]
824
-    return(node_map)
825
-}
826
-
827
-
828
-
829
-##' Get parent node id of child node.
830
-##'
831
-##' @title getParent.df
832
-##' @param df tree data.frame
833
-##' @param node is the node id of child in tree.
834
-##' @return integer node id of parent
835
-getParent.df <- function(df, node) {
836
-    i <- which(df$node == node)
837
-    parent_id <- df$parent[i]
838
-    if (parent_id == node | is.na(parent_id)) {
839
-        ## root node
840
-        return(0)
841
-    }
842
-    return(parent_id)
843
-}
844
-
845
-
846
-getAncestor.df <- function(df, node) {
847
-    anc <- getParent.df(df, node)
848
-    anc <- anc[anc != 0]
849
-    if (length(anc) == 0) {
850
-        # stop("selected node is root...")
851
-      return(0)
852
-    }
853
-    i <- 1
854
-    while(i<= length(anc)) {
855
-        anc <- c(anc, getParent.df(df, anc[i]))
856
-        anc <- anc[anc != 0]
857
-        i <- i+1
858
-    }
859
-    return(anc)
860
-}
861
-
862
-
863
-
864
-##' Get list of child node id numbers of parent node
865
-##'
866
-##' @title getChild.df
867
-##' @param df tree data.frame
868
-##' @param node is the node id of child in tree.
869
-##' @return list of child node ids of parent
870
-getChild.df <- function(df, node) {
871
-    i <- which(df$parent == node)
872