Skip to content

Rename tree height to time #1331

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

Merged
merged 1 commit into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def write_table(tree):

write_table(tree)
print(tree.draw_text())
tree.draw_svg("_static/tree_structure1.svg", tree_height_scale="rank")
tree.draw_svg("_static/tree_structure1.svg", time_scale="rank")

edges = """\
left right parent child
Expand All @@ -327,7 +327,7 @@ def write_table(tree):

write_table(tree)
print(tree.draw_text())
tree.draw_svg("_static/tree_structure2.svg", tree_height_scale="rank")
tree.draw_svg("_static/tree_structure2.svg", time_scale="rank")


def tree_traversal():
Expand Down Expand Up @@ -396,7 +396,7 @@ def finding_nearest_neighbors():
)

tree = ts.first()
tree.draw_svg("_static/different_time_samples.svg", tree_height_scale="rank")
tree.draw_svg("_static/different_time_samples.svg", time_scale="rank")


# moving_along_tree_sequence()
Expand Down
6 changes: 6 additions & 0 deletions python/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
- Add ``Table.assert_equals`` and ``TableCollection.assert_equals`` which give an exact
report of any differences. (:user:`benjeffery`,:issue:`1076`, :pr:`1328`)

**Changes**

- In drawing methods ``max_tree_height`` and ``tree_height_scale`` have been deprecated
in favour of ``max_time`` and ``time_scale``
(:user:`benjeffery`,:issue:`1262`, :pr:`1331`).

**Fixes**

- Tree sequences were not properly init'd after unpickling
Expand Down
137 changes: 85 additions & 52 deletions python/tests/test_drawing.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,9 +590,15 @@ def test_unused_args(self):
with pytest.raises(ValueError):
t.draw(format=self.drawing_format, node_colours={})
with pytest.raises(ValueError):
t.draw(format=self.drawing_format, max_tree_height=1234)
t.draw(format=self.drawing_format, max_time=1234)
with pytest.raises(ValueError):
t.draw(format=self.drawing_format, tree_height_scale="time")
with pytest.warns(FutureWarning):
t.draw(format=self.drawing_format, max_tree_height=1234)
with pytest.raises(ValueError):
t.draw(format=self.drawing_format, time_scale="time")
with pytest.raises(ValueError):
with pytest.warns(FutureWarning):
t.draw(format=self.drawing_format, tree_height_scale="time")


class TestDrawUnicode(TestDrawText):
Expand Down Expand Up @@ -1381,7 +1387,7 @@ def test_tree_sequence_non_minlex(self):
)
self.verify_text_rendering(ts.draw_text(order="tree"), drawn_tree)

def test_max_tree_height(self):
def test_max_time(self):
ts = self.get_simple_ts()
tree = (
" 9 \n"
Expand All @@ -1399,7 +1405,7 @@ def test_max_tree_height(self):
"0 1 2 3\n"
)
t = ts.first()
self.verify_text_rendering(t.draw_text(max_tree_height="ts"), tree)
self.verify_text_rendering(t.draw_text(max_time="ts"), tree)

tree = (
" 9 \n"
Expand All @@ -1411,10 +1417,10 @@ def test_max_tree_height(self):
"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", ""]:
self.verify_text_rendering(t.draw_text(max_time="tree"), tree)
for bad_max_time in [1, "sdfr", ""]:
with pytest.raises(ValueError):
t.draw_text(max_tree_height=bad_max_tree_height)
t.draw_text(max_time=bad_max_time)


class TestDrawSvg(TestTreeDraw, xmlunittest.XmlTestMixin):
Expand Down Expand Up @@ -1509,7 +1515,7 @@ def test_bad_tick_spacing(self):
def test_no_mixed_yscales(self):
ts = self.get_simple_ts()
with pytest.raises(ValueError, match="varying yscales"):
ts.draw_svg(y_axis=True, max_tree_height="tree")
ts.draw_svg(y_axis=True, max_time="tree")

def test_draw_defaults(self):
t = self.get_binary_tree()
Expand All @@ -1521,7 +1527,7 @@ def test_draw_defaults(self):
@pytest.mark.parametrize("y_axis", (True, False))
@pytest.mark.parametrize("y_label", (True, False))
@pytest.mark.parametrize(
"tree_height_scale",
"time_scale",
(
"rank",
"time",
Expand All @@ -1530,15 +1536,15 @@ def test_draw_defaults(self):
@pytest.mark.parametrize("y_ticks", ([], [0, 1], None))
@pytest.mark.parametrize("y_gridlines", (True, False))
def test_draw_svg_y_axis_parameter_combos(
self, y_axis, y_label, tree_height_scale, y_ticks, y_gridlines
self, y_axis, y_label, time_scale, y_ticks, y_gridlines
):
t = self.get_binary_tree()
svg = t.draw_svg(
y_axis=y_axis,
y_label=y_label,
y_ticks=y_ticks,
y_gridlines=y_gridlines,
tree_height_scale=tree_height_scale,
time_scale=time_scale,
)
self.verify_basic_svg(svg)
ts = self.get_simple_ts()
Expand All @@ -1547,7 +1553,7 @@ def test_draw_svg_y_axis_parameter_combos(
y_label=y_label,
y_ticks=y_ticks,
y_gridlines=y_gridlines,
tree_height_scale=tree_height_scale,
time_scale=time_scale,
)
self.verify_basic_svg(svg, width=200 * ts.num_trees)

Expand Down Expand Up @@ -1680,46 +1686,57 @@ def test_one_mutation_label_colour(self):
self.verify_basic_svg(svg)
assert svg.count(f'stroke="{colour}"') == 1

def test_bad_tree_height_scale(self):
def test_bad_time_scale(self):
t = self.get_binary_tree()
for bad_scale in ["te", "asdf", "", [], b"23"]:
with pytest.raises(ValueError):
t.draw_svg(tree_height_scale=bad_scale)
t.draw_svg(time_scale=bad_scale)
with pytest.raises(ValueError):
with pytest.warns(FutureWarning):
t.draw_svg(tree_height_scale=bad_scale)

def test_bad_max_tree_height(self):
def test_bad_max_time(self):
t = self.get_binary_tree()
for bad_height in ["te", "asdf", "", [], b"23"]:
with pytest.raises(ValueError):
t.draw_svg(max_tree_height=bad_height)
t.draw_svg(max_time=bad_height)
with pytest.raises(ValueError):
with pytest.warns(FutureWarning):
t.draw_svg(max_tree_height=bad_height)

def test_height_scale_time_and_max_tree_height(self):
def test_time_scale_time_and_max_time(self):
ts = msprime.simulate(5, recombination_rate=2, random_seed=2)
t = ts.first()
# The default should be the same as tree.
svg1 = t.draw_svg(max_tree_height="tree")
svg1 = t.draw_svg(max_time="tree")
self.verify_basic_svg(svg1)
svg2 = t.draw_svg()
assert svg1 == svg2
svg3 = t.draw_svg(max_tree_height="ts")
svg3 = t.draw_svg(max_time="ts")
assert svg1 != svg3
svg4 = t.draw_svg(max_tree_height=max(ts.tables.nodes.time))
svg4 = t.draw_svg(max_time=max(ts.tables.nodes.time))
assert svg3 == svg4

def test_height_scale_rank_and_max_tree_height(self):
# Make sure the rank height scale and max_tree_height interact properly.
with pytest.warns(FutureWarning):
svg5 = t.draw_svg(max_tree_height="tree")
assert svg5 == svg1
svg6 = t.draw_svg(max_time="tree", max_tree_height="i should be ignored")
assert svg6 == svg1

def test_time_scale_rank_and_max_time(self):
# Make sure the rank height scale and max_time interact properly.
ts = msprime.simulate(5, recombination_rate=2, random_seed=2)
t = ts.first()
# The default should be the same as tree.
svg1 = t.draw_svg(max_tree_height="tree", tree_height_scale="rank")
svg1 = t.draw_svg(max_time="tree", time_scale="rank")
self.verify_basic_svg(svg1)
svg2 = t.draw_svg(tree_height_scale="rank")
svg2 = t.draw_svg(time_scale="rank")
assert svg1 == svg2
svg3 = t.draw_svg(max_tree_height="ts", tree_height_scale="rank")
svg3 = t.draw_svg(max_time="ts", time_scale="rank")
assert svg1 != svg3
self.verify_basic_svg(svg3)
# Numeric max tree height not supported for rank scale.
# Numeric max time not supported for rank scale.
with pytest.raises(ValueError):
t.draw_svg(max_tree_height=2, tree_height_scale="rank")
t.draw_svg(max_time=2, time_scale="rank")

#
# TODO: update the tests below here to check the new SVG based interface.
Expand Down Expand Up @@ -1826,7 +1843,7 @@ def test_extra_mutations(self, all_muts, x_axis):
svg_no_css = svg[svg.find("</style>") :]
assert svg_no_css.count("extra") == 1 * extra_mut_copies

def test_max_tree_height(self):
def test_max_time(self):
nodes = io.StringIO(
"""\
id is_sample time
Expand Down Expand Up @@ -1862,8 +1879,11 @@ def test_max_tree_height(self):
snippet2 = svg2[svg2.rfind("edge", 0, str_pos) : str_pos]
assert snippet1 != snippet2

svg1 = ts.at_index(0).draw(max_tree_height="ts")
svg2 = ts.at_index(1).draw(max_tree_height="ts")
svg1 = ts.at_index(0).draw(max_time="ts")
svg2 = ts.at_index(1).draw(max_time="ts")
with pytest.warns(FutureWarning):
svg3 = ts.at_index(1).draw(max_tree_height="ts")
assert svg3 == svg2
# when scaled, node 3 should be at the *same* height in both trees, so the edge
# definition should be the same
self.verify_basic_svg(svg1)
Expand Down Expand Up @@ -1913,25 +1933,36 @@ def test_draw_integer_breaks_ts(self):

def test_draw_even_height_ts(self):
ts = msprime.simulate(5, recombination_rate=1, random_seed=1)
svg = ts.draw_svg(max_tree_height="tree")
svg = ts.draw_svg(max_time="tree")
self.verify_basic_svg(svg, width=200 * ts.num_trees)
with pytest.warns(FutureWarning):
svg = ts.draw_svg(max_tree_height="tree")
self.verify_basic_svg(svg, width=200 * ts.num_trees)

def test_draw_sized_ts(self):
ts = msprime.simulate(5, recombination_rate=1, random_seed=1)
svg = ts.draw_svg(size=(600, 400))
self.verify_basic_svg(svg, width=600, height=400)

def test_tree_height_scale(self):
def test_time_scale(self):
ts = msprime.simulate(4, random_seed=2)
svg = ts.draw_svg(tree_height_scale="time")
svg = ts.draw_svg(time_scale="time")
self.verify_basic_svg(svg)
svg = ts.draw_svg(tree_height_scale="log_time")
svg = ts.draw_svg(time_scale="log_time")
self.verify_basic_svg(svg)
svg = ts.draw_svg(tree_height_scale="rank")
with pytest.warns(FutureWarning):
svg2 = ts.draw_svg(tree_height_scale="log_time")
assert svg2 == svg
svg = ts.draw_svg(time_scale="rank")
self.verify_basic_svg(svg)
svg3 = ts.draw_svg(time_scale="rank", tree_height_scale="ignore me please")
assert svg3 == svg
for bad_scale in [0, "", "NOT A SCALE"]:
with pytest.raises(ValueError):
ts.draw_svg(tree_height_scale=bad_scale)
ts.draw_svg(time_scale=bad_scale)
with pytest.raises(ValueError):
with pytest.warns(FutureWarning):
ts.draw_svg(tree_height_scale=bad_scale)

def test_x_scale(self):
ts = msprime.simulate(4, random_seed=2)
Expand Down Expand Up @@ -1963,7 +1994,15 @@ def test_y_axis(self):
("log_time", "Time"),
("rank", "Node time"),
]:
svg = tree.draw_svg(y_axis=True, tree_height_scale=hscale)
svg = tree.draw_svg(y_axis=True, time_scale=hscale)
if hscale is not None:
with pytest.warns(FutureWarning):
svg2 = tree.draw_svg(y_axis=True, tree_height_scale=hscale)
assert svg2 == svg
svg3 = tree.draw_svg(
y_axis=True, time_scale=hscale, tree_height_scale="ignore me please"
)
assert svg3 == svg
svg_no_css = svg[svg.find("</style>") :]
assert label in svg_no_css
assert svg_no_css.count("axes") == 1
Expand Down Expand Up @@ -2012,11 +2051,9 @@ def test_no_edges_show_empty(self):
tables = full_ts.dump_tables()
tables.edges.clear()
ts = tables.tree_sequence()
for tree_height_scale in ("time", "log_time", "rank"):
for time_scale in ("time", "log_time", "rank"):
# SVG should just be a row of 10 sample nodes
svg = ts.draw_svg(
tree_height_scale=tree_height_scale, x_lim=[0, ts.sequence_length]
)
svg = ts.draw_svg(time_scale=time_scale, x_lim=[0, ts.sequence_length])
self.verify_basic_svg(svg)
assert svg.count("rect") == 10 # Sample nodes are rectangles
assert svg.count('path class="edge"') == 0
Expand Down Expand Up @@ -2199,7 +2236,7 @@ def test_known_svg_tree_y_axis_rank(self, overwrite_viz, draw_plotbox):
y_axis=True,
y_label=label,
y_gridlines=True,
tree_height_scale="rank",
time_scale="rank",
style=".y-axis line.grid {stroke: #CCCCCC}",
debug_box=draw_plotbox,
)
Expand Down Expand Up @@ -2292,13 +2329,9 @@ def test_known_svg_ts_highlighted_mut(self, overwrite_viz, draw_plotbox):

def test_known_svg_ts_rank(self, overwrite_viz, draw_plotbox):
ts = self.get_simple_ts()
svg1 = ts.draw_svg(
tree_height_scale="rank", y_axis=True, debug_box=draw_plotbox
)
svg1 = ts.draw_svg(time_scale="rank", y_axis=True, debug_box=draw_plotbox)
ts = self.get_simple_ts(use_mutation_times=True)
svg2 = ts.draw_svg(
tree_height_scale="rank", y_axis=True, debug_box=draw_plotbox
)
svg2 = ts.draw_svg(time_scale="rank", y_axis=True, debug_box=draw_plotbox)
assert svg1.count('class="site ') == ts.num_sites
assert svg1.count('class="mut ') == ts.num_mutations * 2
assert svg1.replace(" unknown_time", "") == svg2 # Trim the unknown_time class
Expand All @@ -2309,7 +2342,7 @@ def test_known_svg_ts_rank(self, overwrite_viz, draw_plotbox):
@pytest.mark.skip(reason="Fails on CI as OSX gives different random numbers")
def test_known_svg_nonbinary_ts(self, overwrite_viz, draw_plotbox):
ts = self.get_nonbinary_ts()
svg = ts.draw_svg(tree_height_scale="log_time", debug_box=draw_plotbox)
svg = ts.draw_svg(time_scale="log_time", debug_box=draw_plotbox)
assert svg.count('class="site ') == ts.num_sites
assert svg.count('class="mut ') == ts.num_mutations * 2
self.verify_known_svg(
Expand Down Expand Up @@ -2395,7 +2428,7 @@ def test_known_svg_ts_y_axis_log(self, overwrite_viz, draw_plotbox):
svg = ts.draw_svg(
y_axis=True,
y_label="Time (log scale)",
tree_height_scale="log_time",
time_scale="log_time",
debug_box=draw_plotbox,
)
self.verify_known_svg(
Expand All @@ -2413,7 +2446,7 @@ def test_known_svg_ts_mutation_times(self, overwrite_viz, draw_plotbox):

def test_known_svg_ts_mutation_times_logscale(self, overwrite_viz, draw_plotbox):
ts = self.get_simple_ts(use_mutation_times=True)
svg = ts.draw_svg(tree_height_scale="log_time", debug_box=draw_plotbox)
svg = ts.draw_svg(time_scale="log_time", debug_box=draw_plotbox)
assert svg.count('class="site ') == ts.num_sites
assert svg.count('class="mut ') == ts.num_mutations * 2
self.verify_known_svg(
Expand Down
2 changes: 1 addition & 1 deletion python/tests/tsutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def insert_discrete_time_mutations(ts, num_times=4, num_sites=10):
"""
Inserts mutations in the tree sequence at regularly-spaced num_sites
positions, at only a discrete set of times (the same for all trees): at
num_times times evenly spaced between 0 and the maximum tree height.
num_times times evenly spaced between 0 and the maximum time.
"""
tables = ts.tables
tables.sites.clear()
Expand Down
Loading