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 Node 1, Tip and Node 4
5 nodes: [RecursiveNode{OneRoot} 'Node 1', a leaf with an incoming connection (branch 2), RecursiveNode{OneRoot} 'Tip', a leaf with an incoming connection (branch 1), RecursiveNode{OneRoot} 'Internal', an internal node with 1 inbound and 2 outbound connections (branches 3 and [1, 2]), RecursiveNode{OneRoot} 'Node 4', a leaf with an incoming connection (branch 4) and RecursiveNode{OneRoot} 'Root', a root node with 2 outbound connections (branches [3, 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: "Node 1" => Dict{String, Any}() ... "Root" => 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 44, 429, 294, 295, 227, ... [501 omitted] ... and 418
1013 nodes: [RecursiveNode{OneRoot} '44', a leaf with an incoming connection (branch 1008), RecursiveNode{OneRoot} '429', a leaf with an incoming connection (branch 1002), RecursiveNode{OneRoot} '294', a leaf with an incoming connection (branch 1), RecursiveNode{OneRoot} '295', a leaf with an incoming connection (branch 2), RecursiveNode{OneRoot} 'Node 5', an internal node with 1 inbound and 2 outbound connections (branches 4 and [1, 2]) ... 1007 missing ... RecursiveNode{OneRoot} 'Node 1013', a root node with 2 outbound connections (branches [1011, 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: "44" => Dict{String, Any}("length/range" => [0.2935354569691, 13.25043504493], "height/median" => 26.00000000000015, "rate" => 0.0023175365211834218, "rate/95%/HPD" => [0.0006557140561667062, 0.004548632003945957], "rate/median" => 0.002084293354740529, "length/median" => 4.120602200395, "length" => 4.3252483556727395, "height" => 26.000000000000018, "height/95%/HPD" => [25.999999999998415, 26.000000000001833], "length/95%/HPD" => [1.149426096013, 7.673736091046]…) ... "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])
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_AKITA_86_2002, H1N1_A_NORWAY_69_2004, H1N1_A_CAPETOWN_106_2007, H1N1_A_DENMARK_11_2005, H1N1_A_SWITZERLAND_5773_2001, ... [501 omitted] ... and H1N1_A_MIYAGI_3_2000
TREE1: RootedTree with 507 tips and 1 root. Leaf names are H1N1_A_AKITA_86_2002, H1N1_A_NORWAY_69_2004, H1N1_A_CAPETOWN_106_2007, H1N1_A_DENMARK_11_2005, H1N1_A_SWITZERLAND_5773_2001, ... [501 omitted] ... and H1N1_A_MIYAGI_3_2000
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_AKITA_86_2002, H1N1_A_NORWAY_69_2004, H1N1_A_CAPETOWN_106_2007, H1N1_A_DENMARK_11_2005, H1N1_A_SWITZERLAND_5773_2001, ... [501 omitted] ... and H1N1_A_MIYAGI_3_2000
1013 nodes: [RecursiveNode{OneRoot} 'H1N1_A_AKITA_86_2002', a leaf with an incoming connection (branch 616), RecursiveNode{OneRoot} 'H1N1_A_NORWAY_69_2004', a leaf with an incoming connection (branch 657), RecursiveNode{OneRoot} 'H1N1_A_CAPETOWN_106_2007', a leaf with an incoming connection (branch 777), RecursiveNode{OneRoot} 'H1N1_A_DENMARK_11_2005', a leaf with an incoming connection (branch 680), RecursiveNode{OneRoot} 'H1N1_A_SWITZERLAND_5773_2001', a leaf with an incoming connection (branch 85) ... 1007 missing ... RecursiveNode{OneRoot} 'Node 1013', a root node with 2 outbound connections (branches [1011, 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: "H1N1_A_AKITA_86_2002" => Dict{String, Any}("rate_95%_HPD" => [0.0006021252097520666, 0.007002173735735582], "length_median" => 0.6090897602819, "rate" => 0.003232030568588739, "length_range" => [0.02449361059412, 2.268549314258], "height_range" => [6.999999999998764, 7.000000000001592], "length" => 0.6482800164530914, "height" => 7.000000000000023, "rate_median" => 0.0027673965371916008, "rate_range" => [0.0002765801996680506, 0.024321511888174843], "length_95%_HPD" => [0.1022257379351, 1.255366224275]…) ... "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])
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)
RootedTree with 5 tips and 1 root. Leaf names are tip 1, tip 2, tip 3, tip 4 and tip 5
9 nodes: [RecursiveNode{OneRoot} 'tip 1', a leaf with an incoming connection (branch 12), RecursiveNode{OneRoot} 'tip 2', a leaf with an incoming connection (branch 9), RecursiveNode{OneRoot} 'tip 3', a leaf with an incoming connection (branch 10), RecursiveNode{OneRoot} 'tip 4', a leaf with an incoming connection (branch 14), RecursiveNode{OneRoot} 'tip 5', a leaf with an incoming connection (branch 11), RecursiveNode{OneRoot} 'Node 6', an internal node with 1 inbound and 2 outbound connections (branches 13 and [9, 10]), RecursiveNode{OneRoot} 'Node 7', an internal node with 1 inbound and 2 outbound connections (branches 15 and [11, 12]), RecursiveNode{OneRoot} 'Node 8', an internal node with 1 inbound and 2 outbound connections (branches 16 and [13, 14]) and RecursiveNode{OneRoot} 'Node 9', a root node with 2 outbound connections (branches [15, 16])]
8 branches: [RecursiveBranch{OneRoot} 9, from node 'Node 6' to node 'tip 2' (length 1.2448612308517375), RecursiveBranch{OneRoot} 10, from node 'Node 6' to node 'tip 3' (length 0.3102264473574217), RecursiveBranch{OneRoot} 11, from node 'Node 7' to node 'tip 5' (length 1.4124879499779497), RecursiveBranch{OneRoot} 12, from node 'Node 7' to node 'tip 1' (length 0.1394023117070318), RecursiveBranch{OneRoot} 13, from node 'Node 8' to node 'Node 6' (length 0.06034871069889058), RecursiveBranch{OneRoot} 14, from node 'Node 8' to node 'tip 4' (length 0.8172581333164897), RecursiveBranch{OneRoot} 15, from node 'Node 9' to node 'Node 7' (length 0.34173760758669425) and RecursiveBranch{OneRoot} 16, from node 'Node 9' to node 'Node 8' (length 0.09053043007273306)]
Node records: "tip 1" => Dict{String, Any}() ... "Node 9" => Dict{String, Any}()
Or two trees
trees = rand(nu, ["Tree 1", "Tree 2"])
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 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: RootedTree with 5 tips and 1 root. Leaf names are tip 1, tip 2, tip 3, tip 4 and tip 5
Tree 1: RootedTree with 5 tips and 1 root. Leaf names are tip 1, tip 2, tip 3, tip 4 and tip 5
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.parsenewick
— Functionparsenewick(io::IOBuffer, ::Type{TREE}) where TREE <: AbstractTree
Parse an IOBuffer containing a newick tree and convert into a phylogenetic tree of type TREE <: AbstractTree
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
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
parsenewick(inp)
Parse some input containing a newick tree and convert into a phylogenetic tree of type RootedTree
Phylo.parsenexus
— Functionparsenexus(io::IOBuffer, ::Type{TREE}) where TREE <: AbstractTree
Parse an IOBuffer containing a nexus tree and convert into a phylogenetic tree of type TREE <: AbstractTree
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
parsenexus(inp)
Parse some input containing a nexus tree and convert into a phylogenetic tree of type RootedTree
Phylo.Nonultrametric
— TypeNonultrametric{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().
Phylo.Ultrametric
— TypeUltrametric{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().
Phylo.Newick
— TypeNewick{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.
Phylo.Nexus
— TypeNexus
Type to specify nexus format for input or output.