Skip to content

Commit aa5ddae

Browse files
authored
Add logic to deal with polytomies in input trees (#36)
* Fix for polytomies - Ensure target genome is on top, even with a polytomy in tree - Simplify logic for matching tree topology to desired order * Add logic to double check leaf order is as expected in tree
1 parent 3772ccc commit aa5ddae

2 files changed

Lines changed: 50 additions & 24 deletions

File tree

bin/ntsynt_viz_distance_cladogram.R

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,31 @@ rotate_to_top <- function(tree, target) {
6868

6969
for (node in parent_nodes) {
7070
flipnodes <- child(tree$data, node)$node
71-
tmp_tree <- ggtree::flip(tree, flipnodes[[1]], flipnodes[[2]])
72-
with_rot <- get_clade_position(tmp_tree, which(tmp_tree$data$label == target))$ymin
73-
before <- get_clade_position(tree, which(tree$data$label == target))$ymin
74-
if (with_rot > before ) {
75-
tree <- tmp_tree
71+
# If flipnodes is longer than 2, look for rotation which brings target genome to highest ymin position
72+
if (length(flipnodes) > 2) {
73+
cat(paste("Polytomy detected at node ", node, "\n"), sep="")
74+
# Iterate over each pair of nodes, and store the tree with the target genome in the highest ymin position
75+
curr_tree <- tree
76+
for (i in 1:(length(flipnodes)-1)) {
77+
for (j in (i+1):length(flipnodes)) {
78+
tmp_tree <- ggtree::flip(tree, flipnodes[i], flipnodes[j])
79+
with_rot <- get_clade_position(tmp_tree, which(tmp_tree$data$label == target))$ymin
80+
before <- get_clade_position(tree, which(tree$data$label == target))$ymin
81+
if (with_rot > before ) {
82+
curr_tree <- tmp_tree
83+
}
84+
85+
}
86+
}
87+
tree <- curr_tree
88+
} else {
89+
# Bifurcation case, just flip the two nodes
90+
tmp_tree <- ggtree::flip(tree, flipnodes[[1]], flipnodes[[2]])
91+
with_rot <- get_clade_position(tmp_tree, which(tmp_tree$data$label == target))$ymin
92+
before <- get_clade_position(tree, which(tree$data$label == target))$ymin
93+
if (with_rot > before ) {
94+
tree <- tmp_tree
95+
}
7696
}
7797
}
7898
return(tree)

bin/ntsynt_viz_plot_synteny_blocks_ribbon_plot.R

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env Rscript
22
suppressPackageStartupMessages({
3+
library(ape)
34
library(argparse)
45
library(scales)
56
library(ggtree)
@@ -213,25 +214,28 @@ if (is.null(args$tree)) {
213214
print(ntsynt_tree)
214215

215216
if (!is.null(args$order)) {
216-
ntsynt_ggtree <- ggtree(ntsynt_tree, branch.length = "none") # Initial tree to rotate
217-
orders <- read.csv(args$order, sep = "\t", header = F)
217+
orders <- read.csv(args$order, sep = "\t", header = FALSE)
218218
colnames(orders) <- c("label")
219-
named_order_vector <- setNames(1:length(orders$label), rev(orders$label))
220-
is_tree_right_order <- identical(names(named_order_vector), as.phylo(ntsynt_ggtree)$tip.label)
221-
new_tree <- as.phylo(ntsynt_ggtree)
222-
223-
max_iterations <- 100
224-
iterations <- 0
225-
while (!is_tree_right_order && iterations < max_iterations) {
226-
new_tree <- minRotate(new_tree, named_order_vector)
227-
is_tree_right_order <- identical(names(named_order_vector), new_tree$tip.label)
228-
iterations <- iterations + 1
229-
}
230-
if (!is_tree_right_order) {
231-
stop("Error: Tree could not be reordered within the maximum iterations.")
219+
# reverse to ensure target genome is at the top
220+
desired_order <- rev(orders$label)
221+
222+
# Ensure labels match before rotation - sanity check
223+
if (!all(desired_order %in% as.phylo(ntsynt_tree)$tip.label)) {
224+
stop("Error: Some labels in the order file are not present in the tree.")
232225
}
226+
tree_phylo <- as.phylo(ntsynt_tree)
227+
new_tree <- rotateConstr(tree_phylo, desired_order)
233228
new_tree <- rename_taxa(new_tree, name_conversions)
234229
ntsynt_ggtree <- ggtree(new_tree, branch.length = "none", ladderize = FALSE)
230+
231+
tip_order_plot <- ntsynt_ggtree$data[ntsynt_ggtree$data$isTip, ] %>%
232+
arrange(y) %>%
233+
pull(label)
234+
if (! identical(tip_order_plot, str_replace_all(desired_order, "_", " "))) {
235+
print(tip_order_plot)
236+
print(str_replace_all(desired_order, "_", " "))
237+
stop("Error: Tip order in the plot does not match the new tree after rotation.")
238+
}
235239
} else {
236240
ntsynt_tree <- rename_taxa(ntsynt_tree, name_conversions)
237241
ntsynt_ggtree <- ggtree(ntsynt_tree, branch.length = "none")
@@ -240,10 +244,12 @@ if (is.null(args$tree)) {
240244
# Align the plots properly
241245
synteny_y_range <- ggplot_build(synteny_plot)$layout$panel_params[[1]]$y.range
242246

243-
plots <- ggarrange(ntsynt_ggtree + scale_y_continuous(limits = synteny_y_range, expand = c(0, 0)),
244-
(synteny_plot %>% pick_by_tree(ntsynt_ggtree)),
245-
common.legend = TRUE, align = "hv",
246-
widths = c(1, 10), legend = "bottom")
247+
plots <- ggarrange(
248+
ntsynt_ggtree + scale_y_continuous(limits = synteny_y_range, expand = c(0, 0)),
249+
(synteny_plot %>% pick_by_tree(ntsynt_ggtree)),
250+
common.legend = TRUE, align = "hv",
251+
widths = c(1, 10), legend = "bottom"
252+
)
247253
}
248254

249255
any_rc <- length((sequences %>% filter(relative_orientation != ""))$relative_orientation) > 0

0 commit comments

Comments
 (0)