Quartet methods¶
Toytree
objects can yield quartets, which are 4-sample subtrees that are the minimal information unit in the context of comparative phylogenetics. Being the simplest format of informative unrooted tree, quartets are important for phylogenetic tree reconstruction and are often the main ingredient in optimization algorithms†. The iter_quartets
method provides a fast option to yield quartet subtrees from a larger tree. It includes options for sorting the output and allows the user to return the subtrees as Node
objects, names, or any arvitrary feature of Nodes.
Iter_quartets
yields all quartets (4-sample subtrees) that exist within a larger tree. The set of possible quartets is not affected by tree rooting, but is affected by collapsed edges (polytomies), which reduce the number of quartets. Quartets are returned as a tuple with sets representing the relation among samples: tuple( set{} , set{} ), Quartets can also be collapsed using collapse=True
, which returns an ordered collection of the requested features of Nodes, where e.g. ('a', 'b', 'c', 'd') implies the quartet ab|cd
.
†Alon, Noga, Sagi Snir, and Raphael Yuster. “On the Compatibility of Quartet Trees,” n.d.
Quick example¶
import toytree
#build tree from simple newick string and visualize it
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
tree.draw()
#iteratively return all quartets in phylogenetic tree
for quartet in tree.iter_quartets():
print(quartet)
({'c', 'd'}, {'a', 'e'}) ({'c', 'd'}, {'b', 'e'}) ({'c', 'd'}, {'e', 'f'}) ({'c', 'd'}, {'b', 'a'}) ({'c', 'd'}, {'a', 'f'}) ({'c', 'd'}, {'b', 'f'}) ({'e', 'f'}, {'a', 'd'}) ({'e', 'f'}, {'b', 'a'}) ({'e', 'f'}, {'a', 'c'}) ({'e', 'f'}, {'b', 'd'}) ({'e', 'f'}, {'b', 'c'}) ({'c', 'e'}, {'b', 'a'}) ({'c', 'f'}, {'b', 'a'}) ({'e', 'd'}, {'b', 'a'}) ({'f', 'd'}, {'b', 'a'})
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
#return quartets with nodes being represented by their indices
for quartet in tree.iter_quartets(feature = 'idx'):
print(quartet)
({2, 3}, {0, 4}) ({2, 3}, {1, 4}) ({2, 3}, {4, 5}) ({2, 3}, {0, 1}) ({2, 3}, {0, 5}) ({2, 3}, {1, 5}) ({4, 5}, {0, 3}) ({4, 5}, {0, 1}) ({4, 5}, {0, 2}) ({4, 5}, {1, 3}) ({4, 5}, {1, 2}) ({2, 4}, {0, 1}) ({2, 5}, {0, 1}) ({3, 4}, {0, 1}) ({3, 5}, {0, 1})
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
#(attempt to) collapse the returned quartets
for quartet in tree.iter_quartets(collapse=True):
print(quartet)
⚠️ toytree | quartets:iter_quartets | collapse argument cannot be used with type=set, using collapse=False
({'c', 'd'}, {'a', 'e'}) ({'c', 'd'}, {'b', 'e'}) ({'c', 'd'}, {'e', 'f'}) ({'c', 'd'}, {'b', 'a'}) ({'c', 'd'}, {'a', 'f'}) ({'c', 'd'}, {'b', 'f'}) ({'e', 'f'}, {'a', 'd'}) ({'e', 'f'}, {'b', 'a'}) ({'e', 'f'}, {'a', 'c'}) ({'e', 'f'}, {'b', 'd'}) ({'e', 'f'}, {'b', 'c'}) ({'c', 'e'}, {'b', 'a'}) ({'c', 'f'}, {'b', 'a'}) ({'e', 'd'}, {'b', 'a'}) ({'f', 'd'}, {'b', 'a'})
Note: Since sets are unordered, collapse cannot be used if the quartets are returned as sets (default type=set
) because the relationship information is lost.
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
#collapse the returned quartets to return each as single tuple (order determines split)
for quartet in tree.iter_quartets(type=tuple, collapse=True):
print(quartet)
#(c,d|a,d)
#(c,d|b,e)
# etc.
('c', 'd', 'a', 'e') ('c', 'd', 'b', 'e') ('c', 'd', 'e', 'f') ('c', 'd', 'a', 'b') ('c', 'd', 'a', 'f') ('c', 'd', 'b', 'f') ('e', 'f', 'a', 'd') ('e', 'f', 'a', 'b') ('e', 'f', 'a', 'c') ('e', 'f', 'b', 'd') ('e', 'f', 'b', 'c') ('c', 'e', 'a', 'b') ('c', 'f', 'a', 'b') ('d', 'e', 'a', 'b') ('d', 'f', 'a', 'b')
Sorting¶
The order of the items within each partition of the quartet is not often of interest, but a sort option is included in case it is useful. The order in which the nodes and pairs of a quartet are returned depends on the topology and rooting, and is in Node idx
traversal order, where the first two Nodes are below the edge, and the second two above. This can be changed to a consistent name sorted order for each split partition using sort=True
. If sort=True
, partitions are always sorted alphanumerically within and between partitions (the order in which the quartets themselves are yielded remains the same)
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
#return quartets iteratively as sorted tuples (sorts both within and between)
for quartet in tree.iter_quartets(type=tuple, sort=True):
print(quartet)
(('a', 'e'), ('c', 'd')) (('b', 'e'), ('c', 'd')) (('c', 'd'), ('e', 'f')) (('a', 'b'), ('c', 'd')) (('a', 'f'), ('c', 'd')) (('b', 'f'), ('c', 'd')) (('a', 'd'), ('e', 'f')) (('a', 'b'), ('e', 'f')) (('a', 'c'), ('e', 'f')) (('b', 'd'), ('e', 'f')) (('b', 'c'), ('e', 'f')) (('a', 'b'), ('c', 'e')) (('a', 'b'), ('c', 'f')) (('a', 'b'), ('d', 'e')) (('a', 'b'), ('d', 'f'))
Quadripartite filter¶
If quadripatition=True
, then quartets are only returned that are induced by quadripartitite splits in a the tree. This is a subset of the vquartets induced by bipartitions, since the tip Nodes must comefrom four different clades from each edge/split.
tree = toytree.tree("(a,b,((c,d)CD,(e,f)EF)X)AB;")
tree.draw()
#create a full, sorted list of quartets
no_filter = list(tree.iter_quartets(type=list, sort=True))
#and a sorted list of only quartets induced by quadripartite splits
filter = list(tree.iter_quartets(type=list, sort=True, quadripartitions=True))
print(no_filter)
print("")
print(filter)
[(['a', 'e'], ['c', 'd']), (['b', 'e'], ['c', 'd']), (['c', 'd'], ['e', 'f']), (['a', 'b'], ['c', 'd']), (['a', 'f'], ['c', 'd']), (['b', 'f'], ['c', 'd']), (['a', 'd'], ['e', 'f']), (['a', 'b'], ['e', 'f']), (['a', 'c'], ['e', 'f']), (['b', 'd'], ['e', 'f']), (['b', 'c'], ['e', 'f']), (['a', 'b'], ['c', 'e']), (['a', 'b'], ['c', 'f']), (['a', 'b'], ['d', 'e']), (['a', 'b'], ['d', 'f'])] [(['a', 'e'], ['c', 'd']), (['b', 'e'], ['c', 'd']), (['a', 'f'], ['c', 'd']), (['b', 'f'], ['c', 'd']), (['a', 'd'], ['e', 'f']), (['b', 'd'], ['e', 'f']), (['a', 'c'], ['e', 'f']), (['b', 'c'], ['e', 'f']), (['a', 'b'], ['d', 'e']), (['a', 'b'], ['d', 'f']), (['a', 'b'], ['c', 'e']), (['a', 'b'], ['c', 'f'])]