Skip to content

Commit

Permalink
Merge pull request #18 from JLSteenwyk/update_python_version
Browse files Browse the repository at this point in the history
removed the use of the root.txt file from the DVMC function
  • Loading branch information
JLSteenwyk authored Dec 11, 2023
2 parents f3fdcb1 + 3b96efb commit bc12ce9
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 116 deletions.
3 changes: 3 additions & 0 deletions change_log.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Major changes to PhyKIT are summarized here.

1.12.2
- removed root.txt file from DVMC function. User's are now recommended to trim outgroup taxa beforehand

1.11.3
- Added an optional argument to the prune_tree function wherein instead of pruning tips specified
in the input file, those tips will be kept
Expand Down
5 changes: 4 additions & 1 deletion docs/change_log/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Change log
^^^^^

Major changes to PhyKIT are summarized here.

**1.12.2**: removed root.txt file from DVMC function. User's are now recommended to trim outgroup taxa beforehand

**1.11.3**: Added an optional argument to the prune_tree function wherein instead of pruning tips
specified in the input file, those tips will be kept.

Expand Down Expand Up @@ -75,4 +78,4 @@ alignment to compare it to
the quality of an alignment given an input query alignment
and a reference alignment to compare it to

**0.0.9**: PhyKIT now handles error stemming from piping output
**0.0.9**: PhyKIT now handles error stemming from piping output
27 changes: 14 additions & 13 deletions docs/usage/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -577,29 +577,30 @@ Degree of violation of the molecular clock
Function names: degree_of_violation_of_a_molecular_clock, dvmc |br|
Command line interface: pk_degree_of_violation_of_a_molecular_clock, pk_dvmc

Calculate degree of violation of the molecular clock (or DVMC) in a phylogeny.
Calculate degree of violation of a molecular clock (or DVMC) in a phylogeny.

Lower DVMC values are thought to be desirable because they are indicative
of a lower degree of violation in the molecular clock assumption.

Typically, outgroup taxa are not included in molecular clock analysis. Thus,
prior to calculating DVMC from a single gene tree, outgroup taxa are pruned
from the phylogeny. PhyKIT will prune taxa using tip names from a single column
file, which is specified using the -r/--root file. If the tip name does not
exist in the input tree, rather than raising an error/warning message, the tip
name is skipped. If the user wants to calculate DVMC for phylogenies with incomplete
taxa representation, this will allow the user to use one <root file> for all trees.
Lastly, an empty root file can be used if the user does not wish to prune outgroup taxa.
prior to calculating DVMC from a single gene tree, users may want to prune
outgroup taxa from the phylogeny. To prune tips from a phylogeny, see the
prune_tree function.

Calculate DVMC in a tree following Liu et al., PNAS (2017), doi: 10.1073/pnas.1616744114.
Calculate DVMC in a tree following Liu et al., PNAS (2017), doi: 10.1073/pnas.1616744114.

Options
=====================================================
<tree> first argument after
function name should be
a tree file

.. code-block:: shell
phykit degree_of_violation_of_a_molecular_clock -t/--tree <tree> -r/--root <root_taxa>
phykit degree_of_violation_of_a_molecular_clock <tree>
Options: |br|
*-t/\\-\\-tree*: input file tree name |br|
*-r/\\-\\-root*: single column file with tip names of root taxa
*<tree>*: input file tree name

|
Expand All @@ -621,7 +622,7 @@ of the Royal Society B (2014).
phykit evolutionary_rate <tree>
Options: |br|
*-t/\\-\\-tree*: input file tree name
*<tree>*: input file tree name

|
Expand Down
27 changes: 8 additions & 19 deletions phykit/phykit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,13 +1081,9 @@ def dvmc(argv):
of a lower degree of violation in the molecular clock assumption.
Typically, outgroup taxa are not included in molecular clock analysis. Thus,
prior to calculating DVMC from a single gene tree, outgroup taxa are pruned
from the phylogeny. PhyKIT will prune taxa using tip names from a single column
file, which is specified using the -r/--root file. If the tip name does not
exist in the input tree, rather than raising an error/warning message, the tip
name is skipped. If the user wants to calculate DVMC for phylogenies with incomplete
taxa representation, this will allow the user to use one <root file> for all trees.
Lastly, an empty root file can be used if the user does not wish to prune outgroup taxa.
prior to calculating DVMC from a single gene tree, users may want to prune
outgroup taxa from the phylogeny. To prune tips from a phylogeny, see the
prune_tree function.
Calculate DVMC in a tree following Liu et al., PNAS (2017), doi: 10.1073/pnas.1616744114.
Expand All @@ -1097,24 +1093,17 @@ def dvmc(argv):
pk_degree_of_violation_of_a_molecular_clock, pk_dvmc
Usage:
phykit degree_of_violation_of_a_molecular_clock -t/--tree <tree>
-r/--root <root_taxa>
phykit degree_of_violation_of_a_molecular_clock <tree>
Options
=====================================================
-t/--tree input file tree name
-r/--root single column file with
tip names of root taxa
<tree> first argument after
function name should be
a tree file
"""
),
)
parser.add_argument(
"-r", "--root", type=str, required=True, help=SUPPRESS, metavar=""
)
parser.add_argument(
"-t", "--tree", type=str, required=True, help=SUPPRESS, metavar=""
)
parser.add_argument("tree", type=str, help=SUPPRESS)
args = parser.parse_args(argv)
DVMC(args).run()

Expand Down
29 changes: 3 additions & 26 deletions phykit/services/tree/dvmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,12 @@ def __init__(self, args) -> None:

def run(self):
tree = self.read_tree_file()
outgroup = read_single_column_file_to_list(self.outgroup_taxa_file_path)
dvmc = self.determine_dvmc(tree, outgroup)
dvmc = self.determine_dvmc(tree)

print(round(dvmc, 4))

def process_args(self, args):
return dict(tree_file_path=args.tree, outgroup_taxa_file_path=args.root)

def get_names_of_outgroup_taxa_that_are_present(
self, outgroup: list, tree: Tree
) -> list:
# initialize list for outgroup taxa that are present in tree
out_pres = []
# loop through terminal branch
for term in tree.get_terminals():
# if outgroup taxa is present, append it to out_pres
if term.name in outgroup:
out_pres.append(term.name)

return out_pres
return dict(tree_file_path=args.tree)

def get_term_to_root_dist_and_sum_of_distances(self, tree) -> Tuple[float, float]:
"""
Expand Down Expand Up @@ -68,16 +54,7 @@ def calculate_dvmc(self, dist: float, sum_dist: float, num_spp: int) -> float:

return dvmc

def determine_dvmc(self, tree: Tree, outgroup: list):
# get names of outgroup taxa in tree
out_pres = self.get_names_of_outgroup_taxa_that_are_present(outgroup, tree)

# root tree on outgroup
tree.root_with_outgroup(out_pres)

# prune outgroup taxa from tree
tree = self.prune_tree_using_taxa_list(tree, out_pres)

def determine_dvmc(self, tree: Tree):
# loop through terminal branches and store
# distances from the root to the tip in a list.
# Also, calc the sum of all tip to root distances
Expand Down
2 changes: 1 addition & 1 deletion phykit/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.12.1"
__version__ = "1.12.2"
47 changes: 3 additions & 44 deletions tests/integration/tree/test_dvmc_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,79 +14,38 @@
class TestDVMC(object):
@patch("builtins.print")
def test_dvmc(self, mocked_print):
expected_result = 42.8016
expected_result = 40.0185
testargs = [
"phykit",
"dvmc",
"-t",
f"{here.parent.parent.parent}/sample_files/tree_simple.tre",
"-r",
f"{here.parent.parent.parent}/sample_files/tree_simple.outgroup.txt",
]
with patch.object(sys, "argv", testargs):
Phykit()
assert mocked_print.mock_calls == [call(expected_result)]

@patch("builtins.print")
def test_dvmc_alias(self, mocked_print):
expected_result = 42.8016
expected_result = 40.0185
testargs = [
"phykit",
"degree_of_violation_of_a_molecular_clock",
"-t",
f"{here.parent.parent.parent}/sample_files/tree_simple.tre",
"-r",
f"{here.parent.parent.parent}/sample_files/tree_simple.outgroup.txt",
]
with patch.object(sys, "argv", testargs):
Phykit()
assert mocked_print.mock_calls == [call(expected_result)]

@patch("builtins.print")
def test_dvmc_incorrect_outgroup_file(self, mocked_print):
testargs = [
"phykit",
"dvmc",
"-t",
f"{here.parent.parent.parent}/sample_files/tree_simple.tre",
"-r",
f"{here.parent.parent.parent}/sample_files/tree_simple.outgroup.tx",
]
with pytest.raises(SystemExit) as pytest_wrapped_e:
Phykit()

assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 2

@patch("builtins.print")
def test_dvmc_incorrect_tree_file(self, mocked_print):
testargs = [
"phykit",
"dvmc",
"-t",
f"{here.parent.parent.parent}/sample_files/tree_simple.tr",
"-r",
f"{here.parent.parent.parent}/sample_files/tree_simple.outgroup.txt",
"no_file",
]
with pytest.raises(SystemExit) as pytest_wrapped_e:
Phykit()

assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 2

@patch("builtins.print")
def test_dvmc_wrong_file_path(self, mocked_print):
testargs = [
"phykit",
"dvmc",
"-t",
f"{here.parent.parent.parent}/sample_files/tree_simple.tre",
"-r",
f"no_file"
]

with pytest.raises(SystemExit) as pytest_wrapped_e:
Phykit()

assert pytest_wrapped_e.type == SystemExit
assert pytest_wrapped_e.value.code == 2
13 changes: 1 addition & 12 deletions tests/unit/services/tree/test_dvmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@

@pytest.fixture
def args():
kwargs = dict(tree="/some/path/to/file.tre", root="/home/path/to/file.txt",)
kwargs = dict(tree="/some/path/to/file.tre")
return Namespace(**kwargs)


class TestDVMC(object):
def test_init_sets_tree_file_path(self, args):
d = DVMC(args)
assert d.outgroup_taxa_file_path == args.root
assert d.output_file_path is None

def test_read_file_reads_tree_file_path(self, mocker, args):
Expand All @@ -24,13 +23,3 @@ def test_read_file_reads_tree_file_path(self, mocker, args):
d.read_tree_file()
mock_read.assert_called_with(args.tree, "newick")

# def test_calculate_dvmc_zero_branch_len(self, tree_zero_branch_length, args):
# d = DVMC(args)
# res = d.calculate_dvmc(tree_zero_branch_length, args.root)
# assert res == 0.0

# def test_calculate_dvmc(self, tree_simple, tree_simple_outgroup, args):
# d = DVMC(args)
# res = d.calculate_dvmc(tree_simple, tree_simple_outgroup)
# assert isinstance(res, float)
# assert isclose(res, 42.80162365633575, rel_tol=0.001)

0 comments on commit bc12ce9

Please sign in to comment.