def test_ignores_non_sample_leaves(self): nodes = io.StringIO("""\ id is_sample time population individual metadata 0 1 0.000000 0 -1 1 0 0.000000 0 -1 2 1 0.000000 0 -1 3 0 0.000000 0 -1 4 1 0.000000 0 -1 5 0 1.000000 0 -1 6 0 1.000000 0 -1 7 0 2.000000 0 -1 8 0 3.000000 0 -1 """) edges = io.StringIO("""\ left right parent child 0.000000 1.000000 5 0 0.000000 1.000000 5 1 0.000000 1.000000 6 2 0.000000 1.000000 6 3 0.000000 1.000000 7 5 0.000000 1.000000 7 6 0.000000 1.000000 8 4 0.000000 1.000000 8 7 """) ts = tskit.load_text(nodes, edges, sequence_length=1, strict=False, base64_metadata=False) sample_sets = [[0], [2], [4]] expected = comb.TopologyCounter() expected[0] = collections.Counter({(0, 0): 1}) expected[1] = collections.Counter({(0, 0): 1}) expected[2] = collections.Counter({(0, 0): 1}) expected[0, 1] = collections.Counter({(0, 0): 1}) expected[0, 2] = collections.Counter({(0, 0): 1}) expected[1, 2] = collections.Counter({(0, 0): 1}) expected[0, 1, 2] = collections.Counter({(1, 2): 1}) tree_topologies = ts.first().count_topologies(sample_sets) treeseq_topologies = list(ts.count_topologies(sample_sets)) assert tree_topologies == expected assert treeseq_topologies == [expected]
def test_three_populations(self): nodes = io.StringIO( """\ id is_sample time population individual metadata 0 1 0.000000 0 -1 1 1 0.000000 1 -1 2 1 0.000000 1 -1 3 1 0.000000 2 -1 4 1 0.000000 2 -1 5 1 0.000000 0 -1 6 0 1.000000 0 -1 7 0 2.000000 0 -1 8 0 2.000000 0 -1 9 0 3.000000 0 -1 10 0 4.000000 0 -1 """ ) edges = io.StringIO( """\ left right parent child 0.000000 1.000000 6 4 0.000000 1.000000 6 5 0.000000 1.000000 7 1 0.000000 1.000000 7 2 0.000000 1.000000 8 3 0.000000 1.000000 8 6 0.000000 1.000000 9 7 0.000000 1.000000 9 8 0.000000 1.000000 10 0 0.000000 1.000000 10 9 """ ) ts = tskit.load_text( nodes, edges, sequence_length=1, strict=False, base64_metadata=False ) expected = comb.TopologyCounter() expected[0] = collections.Counter({(0, 0): 2}) expected[1] = collections.Counter({(0, 0): 2}) expected[2] = collections.Counter({(0, 0): 2}) expected[0, 1] = collections.Counter({(0, 0): 4}) expected[0, 2] = collections.Counter({(0, 0): 4}) expected[1, 2] = collections.Counter({(0, 0): 4}) expected[0, 1, 2] = collections.Counter({(1, 0): 4, (1, 1): 4}) self.verify_topologies(ts, expected=[expected])
def single_tree_ts_n2(): r""" Simple case where we have n = 2 and one tree. 2 / \ 0 1 """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 0 1 """) edges = io.StringIO("""\ left right parent child 0 1 2 0,1 """) return(tskit.load_text(nodes=nodes, edges=edges, strict=False))
def ts(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 1 3 1 1 4 0 2 5 0 2 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 3 1 0 1 4 2 0 1 5 3 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def test_simple_tree_long_label(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 2 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 2 1 """) tree = ( "ABCDEF\n" "┏┻┓ \n" "0 1 \n") ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) drawn = t.draw_text(node_labels={0: "0", 1: "1", 2: "ABCDEF"}) self.verify_text_rendering(drawn, tree) tree = ( "0┓ \n" " ┣ABCDEF\n" "1┛ \n") drawn = t.draw_text( node_labels={0: "0", 1: "1", 2: "ABCDEF"}, orientation="right") self.verify_text_rendering(drawn, tree) drawn = t.draw_text( node_labels={0: "ABCDEF", 1: "1", 2: "2"}, orientation="right") tree = ( "ABCDEF┓ \n" " ┣2\n" "1━━━━━┛ \n") self.verify_text_rendering(drawn, tree) tree = ( " ┏0\n" "ABCDEF┫ \n" " ┗1\n") drawn = t.draw_text( node_labels={0: "0", 1: "1", 2: "ABCDEF"}, orientation="left") self.verify_text_rendering(drawn, tree)
def test_trident_tree(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 2 """) edges = io.StringIO("""\ left right parent child 0 1 3 0 0 1 3 1 0 1 3 2 """) tree = (" 3 \n" "┏━╋━┓\n" "0 1 2\n") ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree)
def test_simple_example_internal_focal_node(self): ts = tskit.load_text(nodes=io.StringIO(self.small_tree_ex_nodes), edges=io.StringIO(self.small_tree_ex_edges), strict=False) focal = [7] # An internal node reference_sets = [[4, 0, 1], [2, 3]] GNN = naive_genealogical_nearest_neighbours(ts, focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([1.0, 0.0]))) GNN = tsutil.genealogical_nearest_neighbours(ts, focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([1.0, 0.0]))) GNN = ts.genealogical_nearest_neighbours(focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([1.0, 0.0]))) focal = [8] # The root GNN = naive_genealogical_nearest_neighbours(ts, focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([0.6, 0.4]))) GNN = tsutil.genealogical_nearest_neighbours(ts, focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([0.6, 0.4]))) GNN = ts.genealogical_nearest_neighbours(focal, reference_sets) self.assertTrue(np.allclose(GNN[0], np.array([0.6, 0.4])))
def test_max_tree_height(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 4 0 2 5 0 3 """) edges = io.StringIO("""\ left right parent child 0 1 5 2 0 1 5 3 1 2 4 2 1 2 4 3 0 2 3 0 0 2 3 1 """) ts = tskit.load_text(nodes, edges, strict=False) svg1 = ts.at_index(0).draw() svg2 = ts.at_index(1).draw() # if not scaled to ts, node 3 is at a different height in both trees, because the # root is at a different height. We expect a label looking something like # <text x="10.0" y="XXXX">3</text> where XXXX is different str_pos = svg1.find('>3<') snippet1 = svg1[svg1.rfind("<", 0, str_pos):str_pos] str_pos = svg2.find('>3<') snippet2 = svg2[svg2.rfind("<", 0, str_pos):str_pos] self.assertNotEqual(snippet1, snippet2) svg1 = ts.at_index(0).draw(max_tree_height="ts") svg2 = ts.at_index(1).draw(max_tree_height="ts") # when scaled, node 3 should be at the *same* height in both trees, so the label # should be the same self.verify_basic_svg(svg1) self.verify_basic_svg(svg2) str_pos = svg1.find('>3<') snippet1 = svg1[svg1.rfind("<", 0, str_pos):str_pos] str_pos = svg2.find('>3<') snippet2 = svg2[svg2.rfind("<", 0, str_pos):str_pos] self.assertEqual(snippet1, snippet2)
def polytomy_tree_ts(): r""" Simple case where we have n = 3 and a polytomy. 3 /|\ 0 1 2 """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 """) edges = io.StringIO("""\ left right parent child 0 1 3 0,1,2 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def test_pitchfork_tree(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 0 4 1 2 """) edges = io.StringIO("""\ left right parent child 0 1 4 0 0 1 4 1 0 1 4 2 0 1 4 3 """) ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) tree = (" 4 \n" "┏━┳┻┳━┓\n" "0 1 2 3\n") drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(), tree) # No labels tree = (" ┃ \n" "┏━┳┻┳━┓\n" "┃ ┃ ┃ ┃\n") drawn = t.draw(format="unicode", node_labels={}) self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(node_labels={}), tree) # Some labels tree = (" ┃ \n" "┏━┳┻┳━┓\n" "0 ┃ ┃ 3\n") labels = {0: "0", 3: "3"} drawn = t.draw(format="unicode", node_labels=labels) self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(node_labels=labels), tree) tree = (" ┏0\n" " ┃\n" " ┣1\n" "4┫\n" " ┣2\n" " ┃\n" " ┗3\n") drawn = t.draw_text(orientation="left") self.verify_text_rendering(drawn, tree) tree = ("0┓\n" " ┃\n" "1┫\n" " ┣4\n" "2┫\n" " ┃\n" "3┛\n") drawn = t.draw_text(orientation="right") self.verify_text_rendering(drawn, tree)
def test_simple_tree(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 2 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 2 1 """) tree = ( " 2 \n" "┏┻┓\n" "0 1") ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree) drawn = t.draw_text() self.verify_text_rendering(drawn, tree) tree = ( " 2 \n" "+++\n" "0 1\n") drawn = t.draw_text(use_ascii=True) self.verify_text_rendering(drawn, tree) tree = ( " ┏0\n" "2┫ \n" " ┗1\n") drawn = t.draw_text(orientation="left") self.verify_text_rendering(drawn, tree) tree = ( " +0\n" "2+ \n" " +1\n") drawn = t.draw_text(orientation="left", use_ascii=True) self.verify_text_rendering(drawn, tree)
class TestIbdDifferentPaths2: # # 5 | # / \ | # / 4 | 4 # / / \ | / \ # / / \ | / \ # / / \ | 3 \ # / / \ | / \ \ # 0 1 2 | 0 2 1 # | # 0.2 nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 4 0 2.5 5 0 3.5 """) edges = io.StringIO("""\ left right parent child 0.2 1.0 3 0 0.2 1.0 3 2 0.0 1.0 4 1 0.0 0.2 4 2 0.2 1.0 4 3 0.0 0.2 5 0 0.0 0.2 5 4 """) ts = tskit.load_text(nodes=nodes, edges=edges, strict=False) def test_defaults(self): ibd_segs = find_ibd(self.ts, sample_pairs=[(1, 2)]) true_segs = { (1, 2): [ibd.Segment(0.0, 0.2, 4), ibd.Segment(0.2, 1.0, 4)], } assert ibd_is_equal(ibd_segs, true_segs)
class TestIbdUnrelatedSamples(unittest.TestCase): # # 2 3 # | | # 0 1 nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 0 1 3 0 1 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 3 1 """) ts = tskit.load_text(nodes=nodes, edges=edges, strict=False) def test_basic(self): ibd_f = ibd.IbdFinder(self.ts) ibd_segs = ibd_f.find_ibd_segments() ibd_segs = convert_dict_of_segmentlists(ibd_segs) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs) def test_time(self): ibd_f = ibd.IbdFinder(self.ts, max_time=1.2) ibd_segs = ibd_f.find_ibd_segments() ibd_segs = convert_dict_of_segmentlists(ibd_segs) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs) def test_length(self): ibd_f = ibd.IbdFinder(self.ts, min_length=0.2) ibd_segs = ibd_f.find_ibd_segments() ibd_segs = convert_dict_of_segmentlists(ibd_segs) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs)
def ts(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 0 4 0 2.5 5 0 3.5 """) edges = io.StringIO("""\ left right parent child 0.0 1.0 4 0 0.0 1.0 4 1 0.0 0.3 4 2 0.3 1.0 4 3 0.3 1.0 5 2 0.0 0.3 5 3 0.0 1.0 5 4 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def ts(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 0 1 3 0 1.5 4 0 2.5 """) edges = io.StringIO("""\ left right parent child 0.2 0.7 2 0 0.2 0.7 3 1 0.0 0.2 4 0 0.0 0.2 4 1 0.7 1.0 4 0 0.7 1.0 4 1 0.2 0.7 4 2 0.2 0.7 4 3 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def test_stick_tree(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 1 2 1 2 """) edges = io.StringIO("""\ left right parent child 0 1 1 0 0 1 2 1 """) tree = ( "2\n" "┃\n" "1\n" "┃\n" "0\n") ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(), tree) tree = ( "0\n" "┃\n" "1\n" "┃\n" "2\n") drawn = t.draw_text(orientation="bottom") self.verify_text_rendering(drawn, tree) tree = "2━1━0\n" drawn = t.draw_text(orientation="left") self.verify_text_rendering(drawn, tree) tree = "0━1━2\n" drawn = t.draw_text(orientation="right") self.verify_text_rendering(drawn, tree)
def loopy_tree(): r""" Simple case where we have n = 3, 2 trees, three mutations. . 7 . / \ . / | . / | 6 . / 6 / \ . / / \ / 5 . / / | / / \ . / / | | / \ . | | | | | \ . | | | | 4 | . | 4 | | / \ | . | / \ | 0 1 2 3 . 0 1 2 3 """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 0 4 0 1 5 0 2 6 0 3 7 0 4 """) edges = io.StringIO("""\ left right parent child 0 1 4 0,1 0 0.2 5 2,4 0 0.2 6 5 0 1 6 3 0.2 1 6 4 0.2 1 7 2 0.2 1 7 6 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def ts(self): # # 2 4 # / \ # 1 3 \ # / \ \ # 0 0 1 2 print("evaluating ts") nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 4 0 2 """) edges = io.StringIO("""\ left right parent child 0 1 3 0,1 0 1 4 2,3 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def test_no_samples(self): # # 2 # / \ # / \ # / \ # (0) (1) nodes = io.StringIO("""\ id is_sample time 0 0 0 1 0 0 2 0 1 3 0 1 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 3 1 """) ts = tskit.load_text(nodes=nodes, edges=edges, strict=False) with pytest.raises(ValueError): ibd.IbdFinder(ts, sample_pairs=[(0, 1)])
def test_odd_num_children_tree(self): nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 1 2 1 2 3 1 1 4 1 4 5 1 5 """) edges = io.StringIO("""\ left right parent child 0 1 5 0 0 1 5 1 0 1 5 2 0 1 5 3 0 1 5 4 """) ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) text = t.draw(format=self.drawing_format) self.verify_basic_text(text)
def single_tree_ts_n3(): r""" Simple case where we have n = 3 and one tree. 4 / \ 3 \ / \ \ 0 1 2 """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 4 0 2 """) edges = io.StringIO("""\ left right parent child 0 1 3 0,1 0 1 4 2,3 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def single_tree_ts_2mutations_n3(): r""" Simple case where we have n = 3 and one tree. Site has two mutations with different times. 4 x \ 3 \ / x \ [0] [1] [2] """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 0 1 4 0 2 """) edges = io.StringIO("""\ left right parent child 0 1 3 0,1 0 1 4 2,3 """) sites = io.StringIO("""\ position ancestral_state 0.5 0 """) mutations = io.StringIO("""\ site node derived_state 0 3 1 0 1 0 """) return tskit.load_text(nodes=nodes, edges=edges, sites=sites, mutations=mutations, strict=False)
class TestIbdUnrelatedSamples: # # 2 3 # | | # 0 1 nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 0 1 3 0 1 """) edges = io.StringIO("""\ left right parent child 0 1 2 0 0 1 3 1 """) ts = tskit.load_text(nodes=nodes, edges=edges, strict=False) def test_basic(self): ibd_segs = find_ibd(self.ts, sample_pairs=[(0, 1)]) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs) def test_time(self): ibd_segs = find_ibd(self.ts, sample_pairs=[(0, 1)], max_time=1.2) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs) def test_length(self): ibd_segs = find_ibd(self.ts, sample_pairs=[(0, 1)], min_length=0.2) true_segs = {(0, 1): []} assert ibd_is_equal(ibd_segs, true_segs)
def two_tree_two_mrcas(): r""" Simple case where we have n = 4, 2 trees. 6 | / \ | 7 / \ | / \ / \ | / \ / \ | / \ / \ | / \ 4 5 | 4 5 / \ / \ | / \ / \ / \ / \ | / \ / \ | | | | | | | | | 0 1 2 3 | 0 1 2 3 """ nodes = io.StringIO("""\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 0 4 1 1 5 0 1 6 0 3 7 0 2 """) edges = io.StringIO("""\ left right parent child 0 1 4 0,1 0 1 5 2,3 0 0.3 6 4 0 0.3 6 5 0.3 1 7 4 0.3 1 7 5 """) return tskit.load_text(nodes=nodes, edges=edges, strict=False)
def tree_structure(): def write_table(tree): fmt = "{:<12}" heading = [ "node", "parent", "left_child", "right_child", "left_sib", "right_sib", ] line = "".join(fmt.format(s) for s in heading) col_def = " ".join(["=" * 11] * 6) print(col_def) print(line) print(col_def) for u in range(ts.num_nodes): line = "".join( fmt.format(v) for v in [ u, tree.parent(u), tree.left_child(u), tree.right_child(u), tree.left_sib(u), tree.right_sib(u), ]) print(line) print(col_def) nodes = """\ id is_sample time 0 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 0 1 6 0 2 7 0 3 """ edges = """\ left right parent child 0 1 5 0,1,2 0 1 6 3,4 0 1 7 5,6 """ ts = tskit.load_text(nodes=io.StringIO(nodes), edges=io.StringIO(edges), strict=False) tree = ts.first() write_table(tree) print(tree.draw_text()) tree.draw_svg("_static/tree_structure1.svg", tree_height_scale="rank") edges = """\ left right parent child 0 1 5 0,1,2 0 1 6 3,4 0 1 7 5 """ ts = tskit.load_text(nodes=io.StringIO(nodes), edges=io.StringIO(edges), strict=False) tree = ts.first() write_table(tree) print(tree.draw_text()) tree.draw_svg("_static/tree_structure2.svg", tree_height_scale="rank")
class TestParsimonyExamples(TestParsimonyBase): """ Some examples on a given tree. """ # # 8 # / \ # / \ # / \ # 7 \ # / \ 6 # / 5 / \ # / / \ / \ # 4 0 1 2 3 small_tree_ex_nodes = """\ id is_sample population time 0 1 0 0.00000000000000 1 1 0 0.00000000000000 2 1 0 0.00000000000000 3 1 0 0.00000000000000 4 1 0 0.00000000000000 5 0 0 0.14567111023387 6 0 0 0.21385545626353 7 0 0 0.43508024345063 8 0 0 1.60156352971203 """ small_tree_ex_edges = """\ id left right parent child 0 0.00000000 1.00000000 5 0,1 1 0.00000000 1.00000000 6 2,3 2 0.00000000 1.00000000 7 4,5 3 0.00000000 1.00000000 8 6,7 """ tree = tskit.load_text(nodes=io.StringIO(small_tree_ex_nodes), edges=io.StringIO(small_tree_ex_edges), strict=False).first() def test_mutation_over_0(self): genotypes = [1, 0, 0, 0, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=0, parent=-1, derived_state="1")) def test_mutation_over_5(self): genotypes = [1, 1, 0, 0, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=5, parent=-1, derived_state="1")) def test_mutation_over_7(self): genotypes = [1, 1, 0, 0, 1] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=7, parent=-1, derived_state="1")) def test_mutation_over_7_0(self): genotypes = [2, 1, 0, 0, 1] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 2) self.assertEqual(transitions[0], tskit.Mutation(node=7, parent=-1, derived_state="1")) self.assertEqual(transitions[1], tskit.Mutation(node=0, parent=0, derived_state="2")) def test_mutation_over_7_0_alleles(self): genotypes = [2, 1, 0, 0, 1] alleles = ["ANC", "ONE", "TWO"] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes, alleles) self.assertEqual(ancestral_state, "ANC") self.assertEqual(len(transitions), 2) self.assertEqual( transitions[0], tskit.Mutation(node=7, parent=-1, derived_state="ONE")) self.assertEqual(transitions[1], tskit.Mutation(node=0, parent=0, derived_state="TWO")) def test_mutation_over_7_missing_data_0(self): genotypes = [-1, 1, 0, 0, 1] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=7, parent=-1, derived_state="1")) def test_mutation_over_leaf_sibling_missing(self): genotypes = [0, 0, 1, -1, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) # We assume that the mutation is over the parent of 2 and the missing data # so we impute that 3 also has allele 1. This suprising behaviour to me: # I would have thought it was more parsimonious to assume that the missing # data had the ancestral state. However, the number of *state changes* # is the same, which is what the algorithm is minimising. self.assertEqual(transitions[0], tskit.Mutation(node=6, parent=-1, derived_state="1")) # Reverse is the same genotypes = [0, 0, -1, 1, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=6, parent=-1, derived_state="1")) def test_mutation_over_6_missing_data_0(self): genotypes = [-1, 0, 1, 1, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=6, parent=-1, derived_state="1")) def test_mutation_over_0_missing_data_4(self): genotypes = [1, 0, 0, 0, -1] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 1) self.assertEqual(transitions[0], tskit.Mutation(node=0, parent=-1, derived_state="1")) def test_multi_mutation_missing_data(self): genotypes = [1, 2, -1, 0, 0] ancestral_state, transitions = self.do_map_mutations( self.tree, genotypes) self.assertEqual(ancestral_state, "0") self.assertEqual(len(transitions), 2) self.assertEqual(transitions[0], tskit.Mutation(node=5, parent=-1, derived_state="1")) self.assertEqual(transitions[1], tskit.Mutation(node=1, parent=0, derived_state="2"))
def test_max_tree_height(self): nodes = io.StringIO("""\ id is_sample population individual time metadata 0 1 0 -1 0.00000000000000 1 1 0 -1 0.00000000000000 2 1 0 -1 0.00000000000000 3 1 0 -1 0.00000000000000 4 0 0 -1 0.02445014598813 5 0 0 -1 0.11067965364865 6 0 0 -1 1.75005250750382 7 0 0 -1 2.31067154311640 8 0 0 -1 3.57331354884652 9 0 0 -1 9.08308317451295 """) edges = io.StringIO("""\ id left right parent child 0 0.00000000 1.00000000 4 0 1 0.00000000 1.00000000 4 1 2 0.00000000 1.00000000 5 2 3 0.00000000 1.00000000 5 3 4 0.79258618 0.90634460 6 4 5 0.79258618 0.90634460 6 5 6 0.05975243 0.79258618 7 4 7 0.90634460 0.91029435 7 4 8 0.05975243 0.79258618 7 5 9 0.90634460 0.91029435 7 5 10 0.91029435 1.00000000 8 4 11 0.91029435 1.00000000 8 5 12 0.00000000 0.05975243 9 4 13 0.00000000 0.05975243 9 5 """) ts = tskit.load_text(nodes, edges, strict=False) tree = ( " 9 \n" " ┏━┻━┓ \n" " ┃ ┃ \n" " ┃ ┃ \n" " ┃ ┃ \n" " ┃ ┃ \n" " ┃ ┃ \n" " ┃ ┃ \n" " ┃ 5 \n" " ┃ ┏┻┓\n" " 4 ┃ ┃\n" "┏┻┓ ┃ ┃\n" "0 1 2 3\n") t = ts.first() self.verify_text_rendering(t.draw_text(max_tree_height="ts"), tree) tree = ( " 9 \n" " ┏━┻━┓ \n" " ┃ 5 \n" " ┃ ┏┻┓\n" " 4 ┃ ┃\n" "┏┻┓ ┃ ┃\n" "0 1 2 3\n") t = ts.first() self.verify_text_rendering(t.draw_text(max_tree_height="tree"), tree) for bad_max_tree_height in [1, "sdfr", ""]: with self.assertRaises(ValueError): t.draw_text(max_tree_height=bad_max_tree_height)
def test_simple_tree_sequence(self): nodes = io.StringIO("""\ id is_sample population individual time metadata 0 1 0 -1 0.00000000000000 1 1 0 -1 0.00000000000000 2 1 0 -1 0.00000000000000 3 1 0 -1 0.00000000000000 4 0 0 -1 0.02445014598813 5 0 0 -1 0.11067965364865 6 0 0 -1 1.75005250750382 7 0 0 -1 2.31067154311640 8 0 0 -1 3.57331354884652 9 0 0 -1 9.08308317451295 """) edges = io.StringIO("""\ id left right parent child 0 0.00000000 1.00000000 4 0 1 0.00000000 1.00000000 4 1 2 0.00000000 1.00000000 5 2 3 0.00000000 1.00000000 5 3 4 0.79258618 0.90634460 6 4 5 0.79258618 0.90634460 6 5 6 0.05975243 0.79258618 7 4 7 0.90634460 0.91029435 7 4 8 0.05975243 0.79258618 7 5 9 0.90634460 0.91029435 7 5 10 0.91029435 1.00000000 8 4 11 0.91029435 1.00000000 8 5 12 0.00000000 0.05975243 9 4 13 0.00000000 0.05975243 9 5 """) ts = tskit.load_text(nodes, edges, strict=False) ts_drawing = ( "9.08┊ 9 ┊ ┊ ┊ ┊ ┊\n" " ┊ ┏━┻━┓ ┊ ┊ ┊ ┊ ┊\n" "3.57┊ ┃ ┃ ┊ ┊ ┊ ┊ 8 ┊\n" " ┊ ┃ ┃ ┊ ┊ ┊ ┊ ┏━┻━┓ ┊\n" "2.31┊ ┃ ┃ ┊ 7 ┊ ┊ 7 ┊ ┃ ┃ ┊\n" " ┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊\n" "1.75┊ ┃ ┃ ┊ ┃ ┃ ┊ 6 ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" " ┊ ┃ ┃ ┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" "0.11┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊\n" " ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊\n" "0.02┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊\n" " ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊\n" "0.00┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊\n" " 0.00 0.06 0.79 0.91 0.91 1.00\n") self.verify_text_rendering(ts.draw_text(), ts_drawing) ts_drawing = ( "9.08| 9 | | | | |\n" " | +-+-+ | | | | |\n" "3.57| | | | | | | 8 |\n" " | | | | | | | +-+-+ |\n" "2.31| | | | 7 | | 7 | | | |\n" " | | | | +-+-+ | | +-+-+ | | | |\n" "1.75| | | | | | | 6 | | | | | | |\n" " | | | | | | | +-+-+ | | | | | | |\n" "0.11| | 5 | | 5 | | 5 | | 5 | | 5 |\n" " | | +++ | | +++ | | +++ | | +++ | | +++ |\n" "0.02| 4 | | | 4 | | | 4 | | | 4 | | | 4 | | |\n" " | +++ | | | +++ | | | +++ | | | +++ | | | +++ | | |\n" "0.00| 0 1 2 3 | 0 1 2 3 | 0 1 2 3 | 0 1 2 3 | 0 1 2 3 |\n" " 0.00 0.06 0.79 0.91 0.91 1.00\n") self.verify_text_rendering(ts.draw_text(use_ascii=True), ts_drawing) ts_drawing = ( "┊ 9 ┊ ┊ ┊ ┊ ┊\n" "┊ ┏━┻━┓ ┊ ┊ ┊ ┊ ┊\n" "┊ ┃ ┃ ┊ ┊ ┊ ┊ 8 ┊\n" "┊ ┃ ┃ ┊ ┊ ┊ ┊ ┏━┻━┓ ┊\n" "┊ ┃ ┃ ┊ 7 ┊ ┊ 7 ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┃ ┃ ┊ 6 ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" "┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊\n" "┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊\n" "┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊\n" "┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊\n" "┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊\n" "0.00 0.06 0.79 0.91 0.91 1.00\n") self.verify_text_rendering(ts.draw_text(time_label_format=""), ts_drawing) ts_drawing = ( "┊ 9 ┊ ┊ ┊ ┊ ┊\n" "┊ ┏━┻━┓ ┊ ┊ ┊ ┊ ┊\n" "┊ ┃ ┃ ┊ ┊ ┊ ┊ 8 ┊\n" "┊ ┃ ┃ ┊ ┊ ┊ ┊ ┏━┻━┓ ┊\n" "┊ ┃ ┃ ┊ 7 ┊ ┊ 7 ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┃ ┃ ┊ 6 ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" "┊ ┃ ┃ ┊ ┃ ┃ ┊ ┏━┻━┓ ┊ ┃ ┃ ┊ ┃ ┃ ┊\n" "┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊ ┃ 5 ┊\n" "┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊ ┃ ┏┻┓ ┊\n" "┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊ 4 ┃ ┃ ┊\n" "┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊ ┏┻┓ ┃ ┃ ┊\n" "┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊ 0 1 2 3 ┊\n" "┊ ┊ ┊ ┊ ┊ ┊\n") self.verify_text_rendering( ts.draw_text(time_label_format="", position_label_format=""), ts_drawing)
def test_draw_forky_tree(self): tree = ( " 14 \n" " ┏━━━━┻━━━━┓ \n" " ┃ 13 \n" " ┃ ┏━┳━┳━╋━┳━━┓ \n" " ┃ ┃ ┃ ┃ ┃ ┃ 12 \n" " ┃ ┃ ┃ ┃ ┃ ┃ ┏┻┓ \n" " 11 ┃ ┃ ┃ ┃ ┃ ┃ ┃ \n" "┏━┻┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ \n" "┃ 10 ┃ ┃ ┃ ┃ ┃ ┃ ┃ \n" "┃ ┏┻┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃ \n" "8 0 3 2 4 5 6 9 1 7 \n") nodes = io.StringIO("""\ id is_sample population individual time metadata 0 1 0 -1 0.00000000000000 1 1 0 -1 0.00000000000000 2 1 0 -1 0.00000000000000 3 1 0 -1 0.00000000000000 4 1 0 -1 0.00000000000000 5 1 0 -1 0.00000000000000 6 1 0 -1 0.00000000000000 7 1 0 -1 0.00000000000000 8 1 0 -1 0.00000000000000 9 1 0 -1 0.00000000000000 10 0 0 -1 0.02398248117831 11 0 0 -1 0.17378680550869 12 0 0 -1 0.19950200178411 13 0 0 -1 0.20000000000000 14 0 0 -1 5.68339203134457 """) edges = io.StringIO("""\ left right parent child 0.00000000 1.00000000 10 0 0.00000000 1.00000000 10 3 0.00000000 1.00000000 11 8 0.00000000 1.00000000 11 10 0.00000000 1.00000000 12 1 0.00000000 1.00000000 12 7 0.00000000 1.00000000 13 2 0.00000000 1.00000000 13 4 0.00000000 1.00000000 13 5 0.00000000 1.00000000 13 6 0.00000000 1.00000000 13 9 0.00000000 1.00000000 13 12 0.00000000 1.00000000 14 11 0.00000000 1.00000000 14 13 """) ts = tskit.load_text(nodes, edges, strict=False) t = next(ts.trees()) drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(), tree) tree = ( " 14 \n" " ┏━━━━━━┻━━━━━━┓ \n" " ┃ 13 \n" " ┃ ┏━┳━┳┻┳━┳━━┓ \n" " ┃ ┃ ┃ ┃ ┃ ┃ 12 \n" " ┃ ┃ ┃ ┃ ┃ ┃ ┏┻┓\n" "x11xxxxxxx ┃ ┃ ┃ ┃ ┃ ┃ ┃\n" "┏━┻┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃\n" "┃ 10 ┃ ┃ ┃ ┃ ┃ ┃ ┃\n" "┃ ┏┻┓ ┃ ┃ ┃ ┃ ┃ ┃ ┃\n" "8 0 3 2 4 5 6 9 1 7\n") labels = {u: str(u) for u in t.nodes()} labels[11] = "x11xxxxxxx" self.verify_text_rendering(t.draw_text(node_labels=labels), tree)
def test_four_leaves(self): nodes = io.StringIO("""\ id is_sample population individual time metadata 0 1 0 -1 0.00000000000000 1 1 0 -1 0.00000000000000 2 1 0 -1 0.00000000000000 3 1 0 -1 0.00000000000000 4 0 0 -1 0.26676079696421 5 0 0 -1 1.48826948286480 6 0 0 -1 2.91835007758007 """) edges = io.StringIO("""\ left right parent child 0.00000000 1.00000000 4 0 0.00000000 1.00000000 4 3 0.00000000 1.00000000 5 2 0.00000000 1.00000000 5 4 0.00000000 1.00000000 6 1 0.00000000 1.00000000 6 5 """) tree = ( " 6 \n" "┏━┻━┓ \n" "┃ 5 \n" "┃ ┏━┻┓ \n" "┃ ┃ 4 \n" "┃ ┃ ┏┻┓ \n" "1 2 0 3 \n") ts = tskit.load_text(nodes, edges, strict=False) t = ts.first() drawn = t.draw(format="unicode") self.verify_text_rendering(drawn, tree) self.verify_text_rendering(t.draw_text(), tree) drawn = t.draw_text(orientation="bottom") tree = ( "1 2 0 3\n" "┃ ┃ ┗┳┛\n" "┃ ┃ 4 \n" "┃ ┗━┳┛ \n" "┃ 5 \n" "┗━┳━┛ \n" " 6 \n") self.verify_text_rendering(drawn, tree) tree = ( " ┏━━━━1\n" " ┃ \n" "6┫ ┏━━2\n" " ┃ ┃ \n" " ┗5┫ ┏0\n" " ┗4┫ \n" " ┗3\n") self.verify_text_rendering(t.draw_text(orientation="left"), tree) tree = ( "2.92┊ 6 ┊\n" " ┊ ┏━┻━┓ ┊\n" "1.49┊ ┃ 5 ┊\n" " ┊ ┃ ┏━┻┓ ┊\n" "0.27┊ ┃ ┃ 4 ┊\n" " ┊ ┃ ┃ ┏┻┓ ┊\n" "0.00┊ 1 2 0 3 ┊\n" " 0.00 1.00\n") self.verify_text_rendering(ts.draw_text(), tree) tree = ( " 6 \n" "+-+-+ \n" "| 5 \n" "| +-++ \n" "| | 4 \n" "| | +++\n" "1 2 0 3\n") drawn = t.draw(format="ascii") self.verify_text_rendering(drawn, tree) tree = ( " 6 \n" "┏━┻━┓ \n" "┃xxxxxxxxxx\n" "┃ ┏━┻┓ \n" "┃ ┃ 4 \n" "┃ ┃ ┏┻┓ \n" "1 2 0 3 \n") labels = {u: str(u) for u in t.nodes()} labels[5] = "xxxxxxxxxx" drawn = t.draw_text(node_labels=labels) self.verify_text_rendering(drawn, tree) tree = ( " ┏━━━━━━━━━━━━━1\n" " ┃ \n" "6┫ ┏━━2\n" " ┃ ┃ \n" " ┗xxxxxxxxxx┫ ┏0\n" " ┗4┫ \n" " ┗3\n") drawn = t.draw_text(node_labels=labels, orientation="left") self.verify_text_rendering(drawn, tree) tree = ( "2.92┊ 6 ┊\n" " ┊ ┏━┻━┓ ┊\n" "1.49┊ ┃xxxxxxxxxx ┊\n" " ┊ ┃ ┏━┻┓ ┊\n" "0.27┊ ┃ ┃ 4 ┊\n" " ┊ ┃ ┃ ┏┻┓ ┊\n" "0.00┊ 1 2 0 3 ┊\n" " 0.00 1.00\n") drawn = ts.draw_text(node_labels=labels) self.verify_text_rendering(drawn, tree)