The aim of these exercises is for you to derive simple functions based on phylo2vec definitions and functions we saw in the tutorial. You will also learn how to test the validity and benchmark the efficiency of your implementations using pytest and pytest-benchmark, respectively.
Imports¶
import os
import numpy as np
import phylo2vec as p2v
os.chdir("../")
bench_dir = "src/benchmarks"
test_dir = "src/tests"Testing with pytest¶
The pytest framework makes it easy to write small, readable tests for Python applications and libraries.
We have already added the package to our repository via pixi add pytest.
To write a test, create a python file starting with test_. Define test functions starting with test_.
See the example below of tests/test_example.py:
from IPython.display import Markdown
# Read the file and display in markdown
with open(f'{test_dir}/test_example.py', 'r') as f:
benchmark_content = f.read()
Markdown(
f"""
```python
{benchmark_content}
```
"""
)To run tests, simply run:
!pixi run pytest $test_dir -v⠁ activating environment ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0 -- /workspaces/phylo2vec-workshop/.pixi/envs/default/bin/python3.11
cachedir: .pytest_cache
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 47 items
src/tests/test_example.py::test_fibonacci PASSED [ 2%]
src/tests/test_example.py::test_fail_fibonacci FAILED [ 4%]
src/tests/test_example.py::test_from_and_to_newick[5] PASSED [ 6%]
src/tests/test_example.py::test_from_and_to_newick[6] PASSED [ 8%]
src/tests/test_example.py::test_from_and_to_newick[7] PASSED [ 10%]
src/tests/test_example.py::test_from_and_to_newick[8] PASSED [ 12%]
src/tests/test_example.py::test_from_and_to_newick[9] PASSED [ 14%]
src/tests/test_example.py::test_from_and_to_newick[10] PASSED [ 17%]
src/tests/test_example.py::test_from_and_to_newick[11] PASSED [ 19%]
src/tests/test_example.py::test_from_and_to_newick[12] PASSED [ 21%]
src/tests/test_example.py::test_from_and_to_newick[13] PASSED [ 23%]
src/tests/test_example.py::test_from_and_to_newick[14] PASSED [ 25%]
src/tests/test_example.py::test_from_and_to_newick[15] PASSED [ 27%]
src/tests/test_example.py::test_from_and_to_newick[16] PASSED [ 29%]
src/tests/test_example.py::test_from_and_to_newick[17] PASSED [ 31%]
src/tests/test_example.py::test_from_and_to_newick[18] PASSED [ 34%]
src/tests/test_example.py::test_from_and_to_newick[19] PASSED [ 36%]
src/tests/test_example.py::test_from_and_to_newick[20] PASSED [ 38%]
src/tests/test_example.py::test_from_and_to_newick[21] PASSED [ 40%]
src/tests/test_example.py::test_from_and_to_newick[22] PASSED [ 42%]
src/tests/test_example.py::test_from_and_to_newick[23] PASSED [ 44%]
src/tests/test_example.py::test_from_and_to_newick[24] PASSED [ 46%]
src/tests/test_example.py::test_from_and_to_newick[25] PASSED [ 48%]
src/tests/test_example.py::test_from_and_to_newick[26] PASSED [ 51%]
src/tests/test_example.py::test_from_and_to_newick[27] PASSED [ 53%]
src/tests/test_example.py::test_from_and_to_newick[28] PASSED [ 55%]
src/tests/test_example.py::test_from_and_to_newick[29] PASSED [ 57%]
src/tests/test_example.py::test_from_and_to_newick[30] PASSED [ 59%]
src/tests/test_example.py::test_from_and_to_newick[31] PASSED [ 61%]
src/tests/test_example.py::test_from_and_to_newick[32] PASSED [ 63%]
src/tests/test_example.py::test_from_and_to_newick[33] PASSED [ 65%]
src/tests/test_example.py::test_from_and_to_newick[34] PASSED [ 68%]
src/tests/test_example.py::test_from_and_to_newick[35] PASSED [ 70%]
src/tests/test_example.py::test_from_and_to_newick[36] PASSED [ 72%]
src/tests/test_example.py::test_from_and_to_newick[37] PASSED [ 74%]
src/tests/test_example.py::test_from_and_to_newick[38] PASSED [ 76%]
src/tests/test_example.py::test_from_and_to_newick[39] PASSED [ 78%]
src/tests/test_example.py::test_from_and_to_newick[40] PASSED [ 80%]
src/tests/test_example.py::test_from_and_to_newick[41] PASSED [ 82%]
src/tests/test_example.py::test_from_and_to_newick[42] PASSED [ 85%]
src/tests/test_example.py::test_from_and_to_newick[43] PASSED [ 87%]
src/tests/test_example.py::test_from_and_to_newick[44] PASSED [ 89%]
src/tests/test_example.py::test_from_and_to_newick[45] PASSED [ 91%]
src/tests/test_example.py::test_from_and_to_newick[46] PASSED [ 93%]
src/tests/test_example.py::test_from_and_to_newick[47] PASSED [ 95%]
src/tests/test_example.py::test_from_and_to_newick[48] PASSED [ 97%]
src/tests/test_example.py::test_from_and_to_newick[49] PASSED [100%]
=================================== FAILURES ===================================
_____________________________ test_fail_fibonacci ______________________________
def test_fail_fibonacci():
> assert fibonacci(10) == 54 # This test is expected to fail
^^^^^^^^^^^^^^^^^^^^^^^^^^
E assert 55 == 54
E + where 55 = fibonacci(10)
src/tests/test_example.py:17: AssertionError
=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
/workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
import cgi
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED src/tests/test_example.py::test_fail_fibonacci - assert 55 == 54
=================== 1 failed, 46 passed, 1 warning in 0.27s ====================
pytest automatically discovers files and functions starting with test_.
It will show a summary of passed and failed tests.
The -v option is optional, but helps visualizing which tests passed/failed.
Benchmarking with pytest-benchmark¶
The pytest-benchmark is a package that integrates with pytest to measure and report performance of your code. It uses a similar syntax as pytest tests.
We have already added the package to our repository via pixi add pytest-benchmark.
To write a test, create a python file starting with test_. Define test functions starting with test_.
See the example below of src/benchmarks/test_bench.py:
# Read the file and display in markdown
with open(f"{bench_dir}/test_bench.py", "r") as f:
benchmark_content = f.read()
Markdown(
f"""
```python
{benchmark_content}
```
"""
)To run a benchmark, you can simply run:
!pixi run pytest $bench_dir⠁ activating environment ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 18 items
src/benchmarks/test_bench.py .................. [100%]
=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
/workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
import cgi
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
---------------------------------------------------------------------------------------------------- benchmark: 18 tests ----------------------------------------------------------------------------------------------------
Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fibonacci[200] 382.2500 (1.0) 9,908.5000 (3.95) 433.4687 (1.0) 110.3238 (1.88) 402.3000 (1.0) 9.5000 (1.27) 10189;12944 2,306.9718 (1.0) 112778 20
test_fibonacci[300] 389.7000 (1.02) 22,234.4500 (8.87) 435.9270 (1.01) 117.3388 (2.00) 409.2500 (1.02) 9.0000 (1.20) 8525;11109 2,293.9620 (0.99) 111645 20
test_fibonacci[400] 412.2500 (1.08) 73,262.0500 (29.24) 477.7996 (1.10) 254.8987 (4.35) 430.8000 (1.07) 9.9999 (1.33) 6723;17333 2,092.9274 (0.91) 107666 20
test_fibonacci[500] 422.3000 (1.10) 2,505.6500 (1.0) 448.9827 (1.04) 58.5759 (1.0) 438.8500 (1.09) 7.5000 (1.0) 3766;5593 2,227.2574 (0.97) 107666 20
test_fibonacci[600] 433.8000 (1.13) 3,382.9500 (1.35) 484.9448 (1.12) 110.8138 (1.89) 451.8500 (1.12) 9.0000 (1.20) 9742;12439 2,062.0903 (0.89) 104954 20
test_fibonacci[100] 439.9999 (1.15) 43,991.9995 (17.56) 508.4703 (1.17) 369.6834 (6.31) 461.0001 (1.15) 21.0002 (2.80) 3386;10442 1,966.6832 (0.85) 126040 1
test_fibonacci[700] 453.3500 (1.19) 2,786.7000 (1.11) 501.1224 (1.16) 103.8136 (1.77) 471.3500 (1.17) 8.5500 (1.14) 8655;11284 1,995.5203 (0.86) 101236 20
test_fibonacci[800] 465.8500 (1.22) 15,560.5500 (6.21) 530.3421 (1.22) 138.9651 (2.37) 485.4000 (1.21) 9.5000 (1.27) 13520;16030 1,885.5754 (0.82) 99911 20
test_fibonacci[900] 531.0003 (1.39) 48,119.9995 (19.20) 702.6036 (1.62) 506.6704 (8.65) 572.0003 (1.42) 60.0003 (8.00) 4385;26263 1,423.2776 (0.62) 119977 1
test_p2v_sample_vector[100] 5,769.9999 (15.09) 51,265.9999 (20.46) 7,273.0330 (16.78) 2,350.3239 (40.12) 6,301.9997 (15.66) 290.0006 (38.67) 2168;2451 137.4942 (0.06) 11139 1
test_p2v_sample_vector[200] 11,271.0004 (29.49) 54,582.0003 (21.78) 13,192.1766 (30.43) 3,108.3485 (53.07) 12,033.0005 (29.91) 341.0005 (45.47) 4294;5496 75.8025 (0.03) 32157 1
test_p2v_sample_vector[300] 17,441.9993 (45.63) 56,545.9995 (22.57) 19,134.5051 (44.14) 3,070.7591 (52.42) 18,334.0007 (45.57) 381.0001 (50.80) 1082;1735 52.2616 (0.02) 16434 1
test_p2v_sample_vector[400] 23,644.0001 (61.85) 64,298.9999 (25.66) 25,554.7083 (58.95) 3,401.3163 (58.07) 24,725.9995 (61.46) 450.0007 (60.00) 1270;2012 39.1317 (0.02) 21023 1
test_p2v_sample_vector[500] 29,525.0002 (77.24) 79,417.9996 (31.70) 31,320.9925 (72.26) 3,499.1136 (59.74) 30,526.0000 (75.88) 512.0010 (68.27) 811;1258 31.9275 (0.01) 14610 1
test_p2v_sample_vector[600] 35,746.9999 (93.52) 83,648.9999 (33.38) 37,774.1198 (87.14) 3,312.6795 (56.55) 36,988.9995 (91.94) 610.9995 (81.47) 1200;1682 26.4732 (0.01) 19598 1
test_p2v_sample_vector[700] 41,817.9998 (109.40) 111,127.0003 (44.35) 45,535.0322 (105.05) 6,993.2364 (119.39) 43,400.9999 (107.88) 900.9998 (120.13) 1420;2292 21.9611 (0.01) 18251 1
test_p2v_sample_vector[800] 47,708.9998 (124.81) 125,945.0000 (50.26) 51,593.4772 (119.02) 7,911.5503 (135.06) 49,151.0000 (122.17) 841.0007 (112.13) 1147;2042 19.3823 (0.01) 15889 1
test_p2v_sample_vector[900] 53,167.9998 (139.09) 114,212.9995 (45.58) 55,896.6661 (128.95) 4,774.5360 (81.51) 54,782.9995 (136.17) 791.0003 (105.47) 1053;1319 17.8902 (0.01) 14009 1
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Legend:
Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
OPS: Operations Per Second, computed as 1 / Mean
======================== 18 passed, 1 warning in 15.14s ========================
To save results, you can use the --benchmark-autosave option
!pixi run pytest $bench_dir --benchmark-autosave⠁ activating environment ============================= test session starts ==============================
platform linux -- Python 3.11.13, pytest-8.4.2, pluggy-1.6.0
benchmark: 5.1.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /workspaces/phylo2vec-workshop
plugins: benchmark-5.1.0, anyio-4.10.0
collected 18 items
src/benchmarks/test_bench.py .................. [100%]
Saved benchmark data in: /workspaces/phylo2vec-workshop/.benchmarks/Linux-CPython-3.11-64bit/0002_c5d0e011fb6e64de7b82770013bbea31d824a8e9_20250916_214206_uncommited-changes.json
=============================== warnings summary ===============================
.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44
/workspaces/phylo2vec-workshop/.pixi/envs/default/lib/python3.11/site-packages/ete3/webplugin/webapp.py:44: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
import cgi
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
---------------------------------------------------------------------------------------------------- benchmark: 18 tests -----------------------------------------------------------------------------------------------------
Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fibonacci[200] 383.2000 (1.0) 5,487.7500 (2.39) 434.4212 (1.0) 107.5064 (1.31) 402.7500 (1.0) 9.5500 (1.19) 11337;14001 2,301.9134 (1.0) 118822 20
test_fibonacci[300] 389.7500 (1.02) 3,060.2000 (1.34) 449.2870 (1.03) 119.7369 (1.46) 409.2500 (1.02) 9.5000 (1.19) 13700;16135 2,225.7490 (0.97) 118977 20
test_fibonacci[400] 409.7500 (1.07) 2,715.1000 (1.18) 468.8582 (1.08) 119.4249 (1.46) 428.3000 (1.06) 9.0000 (1.12) 13061;15452 2,132.8411 (0.93) 108850 20
test_fibonacci[600] 433.3000 (1.13) 3,652.3000 (1.59) 469.5002 (1.08) 81.8914 (1.0) 451.8500 (1.12) 8.0500 (1.01) 5466;7642 2,129.9246 (0.93) 106417 20
test_fibonacci[100] 439.9999 (1.15) 99,676.0000 (43.49) 524.8717 (1.21) 473.2371 (5.78) 471.0000 (1.17) 29.9997 (3.75) 2976;9641 1,905.2275 (0.83) 118695 1
test_fibonacci[700] 455.8500 (1.19) 106,743.5000 (46.57) 558.4633 (1.29) 442.0954 (5.40) 474.3500 (1.18) 117.7000 (14.71) 815;15726 1,790.6280 (0.78) 100919 20
test_fibonacci[800] 465.3500 (1.21) 2,291.9000 (1.0) 501.4572 (1.15) 85.8540 (1.05) 482.9000 (1.20) 8.0000 (1.0) 3620;5271 1,994.1883 (0.87) 72015 20
test_fibonacci[900] 475.4000 (1.24) 2,339.3500 (1.02) 518.7727 (1.19) 98.3800 (1.20) 493.9000 (1.23) 8.5000 (1.06) 6677;8913 1,927.6265 (0.84) 96442 20
test_fibonacci[500] 489.9994 (1.28) 52,227.0002 (22.79) 750.7442 (1.73) 555.9586 (6.79) 570.9999 (1.42) 421.0005 (52.63) 2573;679 1,332.0116 (0.58) 73497 1
test_p2v_sample_vector[100] 5,881.0001 (15.35) 49,983.0003 (21.81) 7,571.1856 (17.43) 2,467.1965 (30.13) 6,391.9997 (15.87) 1,354.5000 (169.31) 3042;3155 132.0797 (0.06) 13337 1
test_p2v_sample_vector[200] 11,481.9995 (29.96) 45,244.9995 (19.74) 14,078.5847 (32.41) 3,883.9567 (47.43) 12,202.9996 (30.30) 811.9996 (101.50) 5799;6193 71.0299 (0.03) 27573 1
test_p2v_sample_vector[300] 17,692.9998 (46.17) 60,022.0001 (26.19) 19,240.9226 (44.29) 2,658.5263 (32.46) 18,624.9999 (46.24) 371.9997 (46.50) 1924;3546 51.9726 (0.02) 36750 1
test_p2v_sample_vector[400] 24,144.9998 (63.01) 68,907.9998 (30.07) 27,009.2678 (62.17) 5,178.9016 (63.24) 25,187.0006 (62.54) 570.0003 (71.25) 2159;2712 37.0243 (0.02) 18869 1
test_p2v_sample_vector[500] 29,836.0001 (77.86) 81,041.0002 (35.36) 32,351.1328 (74.47) 4,642.7613 (56.69) 31,038.0001 (77.07) 580.0002 (72.50) 1843;2441 30.9108 (0.01) 22763 1
test_p2v_sample_vector[600] 36,327.9996 (94.80) 779,402.9998 (340.07) 39,409.7790 (90.72) 8,083.2200 (98.71) 37,649.9993 (93.48) 682.0001 (85.25) 1154;2047 25.3744 (0.01) 18766 1
test_p2v_sample_vector[700] 42,167.9997 (110.04) 107,921.0006 (47.09) 46,003.2612 (105.90) 6,519.6108 (79.61) 44,092.9998 (109.48) 801.0002 (100.12) 1159;1913 21.7376 (0.01) 15976 1
test_p2v_sample_vector[800] 48,660.9997 (126.99) 109,102.9999 (47.60) 52,922.3153 (121.82) 8,304.0366 (101.40) 50,402.9999 (125.15) 992.4997 (124.06) 1116;1942 18.8956 (0.01) 15356 1
test_p2v_sample_vector[900] 54,280.9994 (141.65) 129,662.0003 (56.57) 57,057.8936 (131.34) 4,878.0978 (59.57) 55,884.0002 (138.76) 803.0001 (100.37) 730;922 17.5261 (0.01) 9451 1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Legend:
Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
OPS: Operations Per Second, computed as 1 / Mean
======================== 18 passed, 1 warning in 16.50s ========================
A file will appear in the .benchmarks directory with the result of your benchmark. There are several options for plotting the benchmark results, we show here one with seaborn and pandas. Here is an example script:
import json
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
dfs = []
for benchmark_file in Path(".benchmarks").rglob("*.json"):
# Load the benchmark data
with open(benchmark_file, "r") as f:
data_i = json.load(f)
df_i = pd.DataFrame(data_i["benchmarks"])
df_i["param"] = df_i.param.astype(int)
df_i["name"] = df_i["name"].apply(lambda x: x.replace("test_", "").split("[")[0])
df_i = pd.concat(
[df_i.drop("stats", axis=1), pd.json_normalize(df_i["stats"])], axis=1
)
df_i["cpu_time"] = df_i["mean"]
df_i["cpu_stddev"] = df_i["stddev"]
df_i["run"] = df_i["name"] + f"_{Path(benchmark_file).stem.split('_')[0]}"
dfs.append(df_i)
df = pd.concat(dfs, axis=0).reset_index(drop=True).query("run.str.contains('sample')")
sns.pointplot(
x="param",
y="cpu_time",
hue="run",
palette="Blues",
linestyles=None,
data=df,
markersize=3,
linewidth=1.25,
)
plt.ylabel("Time (s)")
plt.xlabel("Number of leaves")
plt.show()
Exercise 1: Adjacency matrix with phylo2vec¶
The goal of this exercise is to create an adjacency matrix using phylo2vec.
An adjacency matrix can be used to represent any graph (and thus, any tree). It is a square matrix such that each element is 1 when there is an edge from a node to node , and 0 when there is no edge.
As a phylo2vec vector represents a rooted binary tree, it represents a directed graph. Thus, each edge goes from a parent to a child, but not vice versa.
To check that your function works, write a test file called test_adjacency.py in the tests directory, and run pytest to check that you pass all tests!
Example inputs and outputs:
# Example 0
v0 = np.array([0, 2])
a0 = np.array([[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 0]])
# Example 1
v1 = np.array([0, 0, 0])
a1 = np.array([[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0]])
# Example 2
v2 = np.array([0, 1, 0])
a2 = np.array([[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0]])
# Example 3
v3 = np.array([0, 1, 2, 3, 4])
a3 = np.array(
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])#################################################
############# YOUR CODE STARTS HERE #############
#################################################
def adjacency_matrix(v: np.ndarray) -> np.ndarray:
"""Create the adjacency matrix of the tree represented by a phylo2vec vector.
Parameters
----------
v: np.ndarray
A phylo2vec vector.
Returns
-------
np.ndarray
The adjacency matrix of the tree represented by the vector.
"""
raise NotImplementedError
#################################################
############## YOUR CODE ENDS HERE ##############Exercise 2: Visualising trees with phylo2vec¶
The goal of this exercise is to plot trees using phylo2vec. You are free to decide:
- the language to use (Rust, R, Python, ...)
- the output format (ASCII, image, interactive visualisation etc.)
- the dependencies that you may need.
Ideally, we would like to minimize dependencies, but plotting libraries might be necessary to render nice phylogenetic trees!
Use pytest-benchmark to evaluate the efficiency of your solution.
#################################################
############# YOUR CODE STARTS HERE #############
#################################################
def visualize_tree(v: np.ndarray):
"""Visualize the tree represented by a phylo2vec vector.
Parameters
----------
v: np.ndarray
A phylo2vec vector.
"""
# You may also try to plot a tree with branch lengths using the phylo2vec matrix format
raise NotImplementedError
#################################################
############## YOUR CODE ENDS HERE ##############