Creating phylogenies

Reading phylogenies from disk

Phylo can read newick trees either from strings,

using Phylo
simpletree = parsenewick("((,Tip:1.0)Internal,)Root;")
RootedTree with 3 tips and 1 root. Leaf names are Tip, Node 1 and Node 4

5 nodes: [RecursiveNode{OneRoot} 'Root', a root node with 2 outbound connections (branches [3, 4]), RecursiveNode{OneRoot} 'Internal', an internal node with 1 inbound and 2 outbound connections (branches 3 and [1, 2]), RecursiveNode{OneRoot} 'Tip', a leaf with an incoming connection (branch 1), RecursiveNode{OneRoot} 'Node 1', a leaf with an incoming connection (branch 2) and RecursiveNode{OneRoot} 'Node 4', a leaf with an incoming connection (branch 4)]

4 branches: [RecursiveBranch{OneRoot} 1, from node 'Internal' to node 'Tip' (length 1.0), RecursiveBranch{OneRoot} 2, from node 'Internal' to node 'Node 1', RecursiveBranch{OneRoot} 3, from node 'Root' to node 'Internal' and RecursiveBranch{OneRoot} 4, from node 'Root' to node 'Node 4']

Node records: "Root" => Dict{String, Any}() ... "Node 4" => Dict{String, Any}()

which will result in the following tree:

getbranches(simpletree)
skipmissing(Union{Missing, RecursiveBranch{OneRoot, String, Dict{String, Any}, Dict{String, Any}, PolytomousBranching, Float64}}[RecursiveBranch{OneRoot} 1, from node 'Internal' to node 'Tip' (length 1.0), RecursiveBranch{OneRoot} 2, from node 'Internal' to node 'Node 1', RecursiveBranch{OneRoot} 3, from node 'Root' to node 'Internal', RecursiveBranch{OneRoot} 4, from node 'Root' to node 'Node 4'])

or from files

tree = open(parsenewick, Phylo.path("H1N1.newick"))
RootedTree with 507 tips and 1 root. Leaf names are 227, 294, 295, 110, 390, ... [501 omitted] ... and 418

1013 nodes: [RecursiveNode{OneRoot} 'Node 1013', a root node with 2 outbound connections (branches [1011, 1012]), RecursiveNode{OneRoot} 'Node 1011', an internal node with 1 inbound and 2 outbound connections (branches 1011 and [1009, 1010]), RecursiveNode{OneRoot} 'Node 1009', an internal node with 1 inbound and 2 outbound connections (branches 1009 and [1007, 1008]), RecursiveNode{OneRoot} 'Node 1008', an internal node with 1 inbound and 2 outbound connections (branches 1007 and [1005, 1006]), RecursiveNode{OneRoot} 'Node 1004', an internal node with 1 inbound and 2 outbound connections (branches 1005 and [1001, 1002]) ... 1007 missing ... RecursiveNode{OneRoot} '418', a leaf with an incoming connection (branch 1012)]

1012 branches: [RecursiveBranch{OneRoot} 1, from node 'Node 5' to node '294' (length 0.2559376385188), RecursiveBranch{OneRoot} 2, from node 'Node 5' to node '295' (length 1.255937638519), RecursiveBranch{OneRoot} 3, from node 'Node 7' to node '227' (length 3.093983613629), RecursiveBranch{OneRoot} 4, from node 'Node 7' to node 'Node 5' (length 4.83804597511), RecursiveBranch{OneRoot} 5, from node 'Node 11' to node '104' (length 0.4902870119746) ... 1006 missing ... RecursiveBranch{OneRoot} 1012, from node 'Node 1013' to node '418' (length 13.87884773144)]

Node records: "Node 1013" => Dict{String, Any}("length" => 0.0, "height" => 84.94613266277547, "height/95%/HPD" => [75.00016004016078, 100.9885305644122], "height/median" => 82.87499084796832, "posterior" => 1.0, "height/range" => [75.00016004016078, 151.06404614035887]) ... "418" => Dict{String, Any}("length/range" => [0.000160040160921, 76.06404614036], "height/median" => 75.00000000000021, "rate" => 0.00287656620693594, "rate/95%/HPD" => [0.00032906282418212297, 0.00668807772865533], "rate/median" => 0.002350371083836891, "length/median" => 7.87499084797, "length" => 9.946132662775383, "height" => 74.99999999999999, "height/95%/HPD" => [74.99999999999359, 75.0000000000068], "length/95%/HPD" => [0.000160040160921, 25.98853056441]…)

It can read nexus trees from files too:

ts = open(parsenexus, Phylo.path("H1N1.trees"))
TreeSet{String, OneRoot, String, RecursiveNode{OneRoot, String, Dict{String, Any}, Dict{String, Any}, PolytomousBranching, Float64}, RecursiveBranch{OneRoot, String, Dict{String, Any}, Dict{String, Any}, PolytomousBranching, Float64}, RootedTree} with 2 tree(s), each with 507 tips.
Tree names are TREE2 and TREE1. Dict("TREE2" => 1013, "TREE1" => 1013) nodes and Dict("TREE2" => 1012, "TREE1" => 1012) branches.

TREE2: RootedTree with 507 tips and 1 root. Leaf names are H1N1_A_BRAZIL_11_1978, H1N1_A_TAHITI_8_1998, H1N1_A_TAIWAN_1_1986, H1N1_A_BAYERN_7_1995, H1N1_A_ENGLAND_45_1998, ... [501 omitted] ... and H1N1_A_PUERTORICO_8_1934
TREE1: RootedTree with 507 tips and 1 root. Leaf names are H1N1_A_BRAZIL_11_1978, H1N1_A_TAHITI_8_1998, H1N1_A_TAIWAN_1_1986, H1N1_A_BAYERN_7_1995, H1N1_A_ENGLAND_45_1998, ... [501 omitted] ... and H1N1_A_PUERTORICO_8_1934

Reading multiple trees from a nexus file returns a TreeSet - index to get the individual trees

gettreeinfo(ts)
Dict{String, Dict{String, Any}} with 2 entries:
  "TREE2" => Dict("lnP"=>-1.0)
  "TREE1" => Dict("lnP"=>1.0)
ts["TREE1"]
RootedTree with 507 tips and 1 root. Leaf names are H1N1_A_BRAZIL_11_1978, H1N1_A_TAHITI_8_1998, H1N1_A_TAIWAN_1_1986, H1N1_A_BAYERN_7_1995, H1N1_A_ENGLAND_45_1998, ... [501 omitted] ... and H1N1_A_PUERTORICO_8_1934

1013 nodes: [RecursiveNode{OneRoot} 'Node 1013', a root node with 2 outbound connections (branches [1011, 1012]), RecursiveNode{OneRoot} 'Node 1012', an internal node with 1 inbound and 2 outbound connections (branches 1011 and [1009, 1010]), RecursiveNode{OneRoot} 'H1N1_A_BRAZIL_11_1978', a leaf with an incoming connection (branch 1009), RecursiveNode{OneRoot} 'Node 1011', an internal node with 1 inbound and 2 outbound connections (branches 1010 and [1007, 1008]), RecursiveNode{OneRoot} 'Node 1010', an internal node with 1 inbound and 2 outbound connections (branches 1007 and [1005, 1006]) ... 1007 missing ... RecursiveNode{OneRoot} 'H1N1_A_PUERTORICO_8_1934', a leaf with an incoming connection (branch 1012)]

1012 branches: [RecursiveBranch{OneRoot} 1, from node 'Node 508' to node 'H1N1_A_MADRID_G793_1998' (length 0.2559376385188), RecursiveBranch{OneRoot} 2, from node 'Node 508' to node 'H1N1_A_MADRID_G930_1999' (length 1.255937638519), RecursiveBranch{OneRoot} 3, from node 'Node 509' to node 'Node 508' (length 4.83804597511), RecursiveBranch{OneRoot} 4, from node 'Node 509' to node 'H1N1_A_JOHANNESBURG_82_1996' (length 3.093983613629), RecursiveBranch{OneRoot} 5, from node 'Node 510' to node 'H1N1_A_ENGLAND_45_1998' (length 0.4902870119746) ... 1006 missing ... RecursiveBranch{OneRoot} 1012, from node 'Node 1013' to node 'H1N1_A_PUERTORICO_8_1934' (length 13.87884773144)]

Node records: "Node 1013" => Dict{String, Any}("length" => 0.0, "height" => 84.94613266277547, "height_95%_HPD" => [75.00016004016078, 100.9885305644122], "posterior" => 1.0, "height_median" => 82.87499084796832, "height_range" => [75.00016004016078, 151.06404614035887]) ... "H1N1_A_PUERTORICO_8_1934" => Dict{String, Any}("rate_95%_HPD" => [0.00032906282418212297, 0.00668807772865533], "length_median" => 7.87499084797, "rate" => 0.00287656620693594, "length_range" => [0.000160040160921, 76.06404614036], "height_range" => [74.99999999994982, 75.00000000004476], "length" => 9.946132662775383, "height" => 74.99999999999999, "rate_median" => 0.002350371083836891, "rate_range" => [0.0002174783783249233, 0.03749316702012485], "length_95%_HPD" => [0.000160040160921, 25.98853056441]…)

Writing phylogenies to disk

Phylo can write newick trees either to strings,

out = Phylo.outputtree(simpletree, Newick())
"((\"Tip\":1.0,\"Node 1\")\"Internal\",\"Node 4\")\"Root\";"

or to files

Phylo.write("test.newick", simpletree)

It can write nexus trees to files too:

Phylo.write("h1.trees", ts)

It will use newick as the default format for OneTree trees (e.g. a RecursiveTree), and nexus for ManyTrees trees (e.g. a TreeSet). However, you can tell it to use nexus for a OneTree:

Phylo.write("test.trees", simpletree, format = Nexus())

Creating random phylogenies

The package can be used to generate random trees using the framework from Distributions. For instance, to construct a sampler for 5 tip non-ultrametric trees and generate a random tree of that type

using Phylo
nu = Nonultrametric(5);
tree = rand(nu)
LinkTree{OneRoot, String, LinkNode{OneRoot, String, Dict{String, Any}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}, Dict{String, Any}} with 5 tips and 1 root. Leaf names are tip 5, tip 3, tip 1, tip 2 and tip 4

9 nodes: [LinkNode Node 9, a root node with 2 outbound connections (branches 15, 16), LinkNode tip 5, a tip of the tree with an incoming connection (branch 15)., LinkNode Node 8, an internal node with 1 inbound and 2 outbound connections (branches 16 and 13, 14), LinkNode tip 3, a tip of the tree with an incoming connection (branch 13)., LinkNode Node 7, an internal node with 1 inbound and 2 outbound connections (branches 14 and 11, 12), LinkNode Node 6, an internal node with 1 inbound and 2 outbound connections (branches 11 and 9, 10), LinkNode tip 1, a tip of the tree with an incoming connection (branch 9)., LinkNode tip 2, a tip of the tree with an incoming connection (branch 10). and LinkNode tip 4, a tip of the tree with an incoming connection (branch 12).]

8 branches: [LinkBranch 9, from node Node 6 to node tip 1 (length 0.12101678700370899)., LinkBranch 10, from node Node 6 to node tip 2 (length 0.8261694620979034)., LinkBranch 11, from node Node 7 to node Node 6 (length 0.4275760374388495)., LinkBranch 12, from node Node 7 to node tip 4 (length 0.02760134320803661)., LinkBranch 13, from node Node 8 to node tip 3 (length 0.22830747870138596)., LinkBranch 14, from node Node 8 to node Node 7 (length 0.34089639864840676)., LinkBranch 15, from node Node 9 to node tip 5 (length 1.5324455256994456). and LinkBranch 16, from node Node 9 to node Node 8 (length 0.09665453311665001).]

Node records: "Node 9" => Dict{String, Any}() ... "tip 4" => Dict{String, Any}()

Or two trees

trees = rand(nu, ["Tree 1", "Tree 2"])
TreeSet{String, OneRoot, String, LinkNode{OneRoot, String, Dict{String, Any}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}, LinkTree{OneRoot, String, LinkNode{OneRoot, String, Dict{String, Any}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}, Dict{String, Any}}} with 2 tree(s), each with 5 tips.
Tree names are Tree 2 and Tree 1. Dict("Tree 2" => 9, "Tree 1" => 9) nodes and Dict("Tree 2" => 8, "Tree 1" => 8) branches.

Tree 2: LinkTree{OneRoot, String, LinkNode{OneRoot, String, Dict{String, Any}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}, Dict{String, Any}} with 5 tips and 1 root. Leaf names are tip 4, tip 3, tip 1, tip 2 and tip 5
Tree 1: LinkTree{OneRoot, String, LinkNode{OneRoot, String, Dict{String, Any}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}}, LinkBranch{OneRoot, String, Dict{String, Any}, Float64}, Dict{String, Any}} with 5 tips and 1 root. Leaf names are tip 1, tip 2, tip 4, tip 5 and tip 3

Importing phylogenies from R

Phylo allows transferring trees from R's ape package directly via RCall. This allows any existing R library functions to be carried out on julia trees. Naturally the medium-term plan is to make this package feature-complete with existing functionality in R, and as a result the R interface is not built into the package, avoiding having RCall (and R) a dependency. Instead, if you want to use the R interface you need to do it manually, as below:

julia> using RCall

julia> include(Phylo.path("rcall.jl", dir = "src"));

R> library(ape)

You can then translate back and forth using rcopy on R phylo objects, and RObject constructors on julia NamedTree types to keep them in Julia or @rput to move the object into R:

julia> rt = rcall(:rtree, 10)
RCall.RObject{RCall.VecSxp}

Phylogenetic tree with 10 tips and 9 internal nodes.

Tip labels:
  t10, t8, t1, t2, t6, t5, ...

Rooted; includes branch lengths.

julia> jt = rcopy(NamedTree, rt)
NamedTree with 10 tips, 19 nodes and 18 branches.
Leaf names are t8, t3, t7, t9, t6, ... [4 omitted] ... and t1

julia> rjt = RObject(jt); # manually translate it back to R

R> if (all.equal($rjt, $rt)) "no damage in translation"
[1] "no damage in translation"

julia> @rput rt; # Or use macros to pass R object back to R

julia> @rput jt; # And automatically translate jt back to R

R> jt

Phylogenetic tree with 10 tips and 9 internal nodes.

Tip labels:
  t10, t8, t1, t2, t6, t5, ...

Rooted; includes branch lengths.

R> if (all.equal(rt, jt)) "no damage in translation"
[1] "no damage in translation"
Phylo.parsenewickFunction
parsenewick(io::IOBuffer, ::Type{TREE}) where TREE <: AbstractTree

Parse an IOBuffer containing a newick tree and convert into a phylogenetic tree of type TREE <: AbstractTree

source
parsenewick(io::String, ::Type{TREE}) where TREE <: AbstractTree

Parse a String containing a newick tree and convert into a phylogenetic tree of type TREE <: AbstractTree

source
parsenewick(io::IOStream, ::Type{TREE}) where TREE <: AbstractTree

Parse an IOStream containing a newick tree and convert into a phylogenetic tree of type TREE <: AbstractTree

source
parsenewick(inp)

Parse some input containing a newick tree and convert into a phylogenetic tree of type RootedTree

source
Phylo.parsenexusFunction
parsenexus(io::IOBuffer, ::Type{TREE}) where TREE <: AbstractTree

Parse an IOBuffer containing a nexus tree and convert into a phylogenetic tree of type TREE <: AbstractTree

source
parsenexus(io::IOStream, ::Type{TREE}) where TREE <: AbstractTree

Parse an IOStream containing a nexus tree and convert into a phylogenetic tree of type TREE <: AbstractTree

source
parsenexus(inp)

Parse some input containing a nexus tree and convert into a phylogenetic tree of type RootedTree

source
Phylo.NonultrametricType
Nonultrametric{T <: AbstractTree,
               SAMP <: Sampleable}(n::Int,
                                   sampleable::SAMP = Exponential())
Nonultrametric{T <: AbstractTree,
               SAMP <: Sampleable}(tiplabels::Vector{String},
                                   sampleable::SAMP = Exponential())

The sampler for non-ultrametric phylogenetic trees of size n or with tip labels tiplabels. Generate random trees by calling rand().

source
Phylo.UltrametricType
Ultrametric{T <: AbstractTree,
            SAMP <: Sampleable,
            LenUnits <: Number}(n::Int,
                                sampleable::SAMP = Exponential())
Ultrametric{T <: AbstractTree,
            SAMP <: Sampleable,
            LenUnits <: Number}(tiplabels::Vector{String},
                                sampleable::SAMP = Exponential())

The sampler for ultrametric phylogenetic trees of size n or with tip labels tiplabels. Generate random trees by calling rand().

source
Phylo.NewickType
Newick{T}

Type to specify newick format for input or output. Parameterised optionally (default Nothing) by T to allow a dictionary to specify which nodes to export and how to map their names during export.

source