Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tree with root node #103

Closed
KlausVigo opened this issue Nov 16, 2023 · 5 comments
Closed

tree with root node #103

KlausVigo opened this issue Nov 16, 2023 · 5 comments
Labels
bug Something isn't working enhancement New feature or request

Comments

@KlausVigo
Copy link
Contributor

Hi @emmanuelparadis,

I got a bug report which contained this tree

tree1 <- ape::read.tree(text = "(((((t1:1,t2:1)n5:1,(((t3:1,t4:1)n8:1,(t5:1,t6:1)n9:1)n7:1,(t7:1,(t8:1,t9:1)n11:1)n10:1)n6:1,(t10:1,t11:1,((t12:1,t13:1,t14:1)n14:1,(t15:1,t16:1,t17:1,t18:1)n15:1)n13:1)n12:1)n4:1,(((t19:1,(t20:1,(t21:1,t22:1)n20:1)n19:1)n18:1,t23:1)n17:1,(t24:1,(t25:1,t26:1)n22:1,(t27:1,t28:1,t29:1,t30:1)n23:1)n21:1)n16:1,(t31:1)n24:1,(t32:1,t33:1,t34:1)n25:1)n3:1,t35:1)n2:1)n1;")

If you plot this tree

plot(tree1, show.node.label=TRUE)

you will see that the tree has a root node (n1 to n2) and I quite like that it is possible to plot a tree like that.
I think the tree is stored quite elegant, but one need to check for the root edge and in many wants cases remove it.
However this tree comes with side effects and can cause problems afterwards.

> tree2 <- unroot(tree1)
> is.rooted(tree2)
[1] TRUE
> plot(tree2, show.node.label = TRUE)

As you can see unroot removes the root edge, but leaves the tree rooted. So one would have to call unroot twice to unroot the tree.

collapse.singles removes the singleton (node n24) and also the root node and solved the bug.
So these kind of edges can cause quite some problems and the behaviour is often random.
There might be even cases where one want to treat the root (with an root edge) as tip after unrooting.

Cheers,
Klaus

@emmanuelparadis
Copy link
Owner

Hi @KlausVigo,

Thanks a lot for reporting this since, I think, it can help to clarify a point on the structure and manipulation of "phylo" objects.

The $root.edge element can be confusing because it stores an edge length separately from the other edges, but it makes possible to distinguish the 3 following trees:

((a:1,b:1):1);
(a:1,b:1):1;
(a:1,b:1, :1);

When plotted, they look identical (unless the internal nodes are visualized explicitly). Only the 2nd one has a $root.edge element. Your tree1 is similar to the 1st one: I can reproduce the bug with it:

R> mytree <- read.tree(text = "((a:1,b:1):1);")
R> is.rooted(unroot(mytree))
[1] TRUE

So these kind of edges can cause quite some problems and the behaviour is often random.

Correct! Let's take a more extreme example:

R> mytree2 <- read.tree(text = "((((((((((a:1,b:1))))))))));")
R> is.rooted(unroot(unroot(unroot(unroot(unroot(mytree2))))))
[1] TRUE

You can call unroot() multiple times but:

R> mytree3 <- mytree2 # keep the original tree
R> while (is.rooted(mytree3)) mytree3 <- unroot(mytree3)
Erreur dans .unroot_ape(phy, length(phy$tip.label)) :
  cannot unroot a tree with less than three edges.

Same thing if you call collapse.singles().

There might be even cases where one want to treat the root (with an root edge) as tip after unrooting.

That seems a very good idea which will require a new option to unroot(). drop.tip() has a similar option (root.edge = 0) doing actually the opposite operation (taking internal edges to build a root edge).

To summarize, the changes needed are:

  1. The new option could be root.edge.as.terminal = 0.
  2. Find a fix to avoid calling unroot repeatedly. collapse.singles() does the work but maybe there is a more efficient solution directly within the function.

Cheers,
Emmanuel

@KlausVigo
Copy link
Contributor Author

Hi @emmanuelparadis,
nice examples. Just some weird behaviour of the axisPhylo.

mytree2 <- read.tree(text = "((((((((((a:1,b:1))))))))));")
mytree2$edge.length <- runif(11)
mytree3 <- collapse.singles(mytree2, TRUE)
# fine
plot(mytree2)
axisPhylo()
# weird
plot(mytree3, root.edge=TRUE)
axisPhylo()

Might worth fixing, too.

Cheers,
Klaus

@emmanuelparadis
Copy link
Owner

Hi @KlausVigo,

I've pushed a new version with an improved version of unroot(). There are two new options:

  1. collapse.singles = FALSE
  2. keep.root.edge = FALSE

The first one needs to be switched to TRUE to have a completely unrooted tree. I prefer to keep the default FALSE to agree with the current behaviour of the function.

More tests welcome!

Cheers,
Emmanuel

@KlausVigo
Copy link
Contributor Author

Hi @emmanuelparadis,
the new unroot function needs some small improvements.
unroot.multiPhylo fails if trees are compressed.

> trees <- rmtree(10, 10)
> trees <- .compressTipLabel(trees)
> unroot(trees)
Fehler in FUN(X[[i]], ...) : 
  cannot unroot a tree where all nodes are singleton

ape:::.unroot_ape and degree.phylo assume that there is slot $tip.label.

Regards,
Klaus

@emmanuelparadis
Copy link
Owner

Hi Klaus,
I've just pushed the fix.
Regards,
Emmanuel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants