Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/etetoolkit/ete
Browse files Browse the repository at this point in the history
  • Loading branch information
fransua committed Sep 1, 2020
2 parents eaffd54 + 97e0ce9 commit 43e6a04
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 32 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.2
3.1.2
5 changes: 5 additions & 0 deletions ete3/coretype/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,11 @@ def get_midpoint_outgroup(self):
break
else:
current = current.up

# if we reached the root, the tree is already at midpoint. Return any child as valid outgroup
if current is None:
current = self.children[0]

return current

def populate(self, size, names_library=None, reuse_names=False,
Expand Down
56 changes: 34 additions & 22 deletions ete3/ncbi_taxonomy/ncbiquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def get_lineage_translator(self, taxids):

return id2lineages


def get_lineage(self, taxid):
"""Given a valid taxid number, return its corresponding lineage track as a
hierarchically sorted list of parent taxids.
Expand All @@ -241,7 +241,7 @@ def get_lineage(self, taxid):
raise ValueError("%s taxid not found" %taxid)
else:
warnings.warn("taxid %s was translated into %s" %(taxid, merged_conversion[taxid]))

track = list(map(int, raw_track[0].split(",")))
return list(reversed(track))

Expand Down Expand Up @@ -326,7 +326,7 @@ def translate_to_names(self, taxids):
for sp in taxids:
names.append(id2name.get(sp, sp))
return names


def get_descendant_taxa(self, parent, intermediate_nodes=False, rank_limit=None, collapse_subspecies=False, return_tree=False):
"""
Expand All @@ -342,11 +342,11 @@ def get_descendant_taxa(self, parent, intermediate_nodes=False, rank_limit=None,
except KeyError:
raise ValueError('%s not found!' %parent)

# checks if taxid is a deprecated one, and converts into the right one.
# checks if taxid is a deprecated one, and converts into the right one.
_, conversion = self._translate_merged([taxid]) #try to find taxid in synonyms table
if conversion:
if conversion:
taxid = conversion[taxid]

with open(self.dbfile+".traverse.pkl", "rb") as CACHED_TRAVERSE:
prepostorder = pickle.load(CACHED_TRAVERSE)
descendants = {}
Expand All @@ -358,12 +358,12 @@ def get_descendant_taxa(self, parent, intermediate_nodes=False, rank_limit=None,
descendants[tid] = descendants.get(tid, 0) + 1
elif found == 2:
break

if not found:
raise ValueError("taxid not found:%s" %taxid)
elif found == 1:
return [taxid]
return [taxid]

if rank_limit or collapse_subspecies or return_tree:
tree = self.get_topology(list(descendants.keys()), intermediate_nodes=intermediate_nodes, collapse_subspecies=collapse_subspecies, rank_limit=rank_limit)
if return_tree:
Expand All @@ -372,7 +372,7 @@ def get_descendant_taxa(self, parent, intermediate_nodes=False, rank_limit=None,
return list(map(int, [n.name for n in tree.get_descendants()]))
else:
return map(int, [n.name for n in tree])

elif intermediate_nodes:
return [tid for tid, count in six.iteritems(descendants)]
else:
Expand All @@ -398,7 +398,7 @@ def get_topology(self, taxids, intermediate_nodes=False, rank_limit=None, collap
"""
from .. import PhyloTree
taxids, merged_conversion = self._translate_merged(taxids)
taxids, merged_conversion = self._translate_merged(taxids)
if len(taxids) == 1:
root_taxid = int(list(taxids)[0])
with open(self.dbfile+".traverse.pkl", "rb") as CACHED_TRAVERSE:
Expand All @@ -407,7 +407,7 @@ def get_topology(self, taxids, intermediate_nodes=False, rank_limit=None, collap
found = 0
nodes = {}
hit = 0
visited = set()
visited = set()
start = prepostorder.index(root_taxid)
try:
end = prepostorder.index(root_taxid, start+1)
Expand Down Expand Up @@ -435,7 +435,7 @@ def get_topology(self, taxids, intermediate_nodes=False, rank_limit=None, collap
id2lineage = self.get_lineage_translator(taxids)
all_taxids = set()
for lineage in id2lineage.values():
all_taxids.update(lineage)
all_taxids.update(lineage)
id2rank = self.get_rank(all_taxids)
for sp in taxids:
track = []
Expand Down Expand Up @@ -493,7 +493,7 @@ def annotate_tree(self, t, taxid_attr="name", tax2name=None, tax2track=None, tax
:param t: a Tree (or Tree derived) instance.
:param name taxid_attr: Allows to set a custom node attribute
:param name taxid_attr: Allows to set a custom node attribute
containing the taxid number associated to each node (i.e.
species in PhyloTree instances).
Expand All @@ -513,7 +513,7 @@ def annotate_tree(self, t, taxid_attr="name", tax2name=None, tax2track=None, tax
merged_conversion = {}

taxids, merged_conversion = self._translate_merged(taxids)

if not tax2name or taxids - set(map(int, list(tax2name.keys()))):
tax2name = self.get_taxid_translator(taxids)
if not tax2track or taxids - set(map(int, list(tax2track.keys()))):
Expand Down Expand Up @@ -542,9 +542,9 @@ def annotate_tree(self, t, taxid_attr="name", tax2name=None, tax2track=None, tax
node_taxid = merged_conversion[node_taxid]
n.add_features(sci_name = tax2name.get(node_taxid, getattr(n, taxid_attr, '')),
common_name = tax2common_name.get(node_taxid, ''),
lineage = tax2track[node_taxid],
rank = tax2rank.get(node_taxid, 'Unknown'),
named_lineage = [tax2name.get(tax, str(tax)) for tax in tax2track[node_taxid]])
lineage = tax2track.get(node_taxid, []),
rank = tax2rank.get(node_taxid, 'Unknown'),
named_lineage = [tax2name.get(tax, str(tax)) for tax in tax2track.get(node_taxid, [])])
elif n.is_leaf():
n.add_features(sci_name = getattr(n, taxid_attr, 'NA'),
common_name = '',
Expand Down Expand Up @@ -674,19 +674,30 @@ def load_ncbi_tree_from_dump(tar):
name2rank = {}
node2common = {}
print("Loading node names...")
unique_nocase_synonyms = set()
for line in tar.extractfile("names.dmp"):
line = str(line.decode())
fields = [_f.strip() for _f in line.split("|")]
nodename = fields[0]
name_type = fields[3].lower()
taxname = fields[1]

# Clean up tax names so we make sure the don't include quotes. See https://github.com/etetoolkit/ete/issues/469
taxname = taxname.rstrip('"').lstrip('"')

if name_type == "scientific name":
node2taxname[nodename] = taxname
if name_type == "genbank common name":
node2common[nodename] = taxname
elif name_type in set(["synonym", "equivalent name", "genbank equivalent name",
"anamorph", "genbank synonym", "genbank anamorph", "teleomorph"]):
synonyms.add( (nodename, taxname) )

# Keep track synonyms, but ignore duplicate case-insensitive names. See https://github.com/etetoolkit/ete/issues/469
synonym_key = (nodename, taxname.lower())
if synonym_key not in unique_nocase_synonyms:
unique_nocase_synonyms.add(synonym_key)
synonyms.add((nodename, taxname))

print(len(node2taxname), "names loaded.")
print(len(synonyms), "synonyms loaded.")

Expand Down Expand Up @@ -749,7 +760,7 @@ def update_db(dbfile, targz_file=None):
md5_check = md5_file.readline().split()[0]
targz_file = "taxdump.tar.gz"
do_download = False

if os.path.exists("taxdump.tar.gz"):
local_md5 = md5(open("taxdump.tar.gz", "rb").read()).hexdigest()
if local_md5 != md5_check:
Expand All @@ -773,7 +784,8 @@ def update_db(dbfile, targz_file=None):
print("Updating database: %s ..." %dbfile)
generate_table(t)

open("syn.tab", "w").write('\n'.join(["%s\t%s" %(v[0],v[1]) for v in synonyms]))
with open("syn.tab", "w") as SYN:
SYN.write('\n'.join(["%s\t%s" %(v[0],v[1]) for v in synonyms]))

with open("merged.tab", "w") as merged:
for line in tar.extractfile("merged.dmp"):
Expand All @@ -786,7 +798,7 @@ def update_db(dbfile, targz_file=None):
raise
else:
os.system("rm syn.tab merged.tab taxa.tab")
# remove only downloaded taxdump file
# remove only downloaded taxdump file
if not targz_file:
os.system("rm taxdump.tar.gz")

Expand Down
10 changes: 9 additions & 1 deletion ete3/test/test_interop.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ def test_parent_child_table(self):
newick = tree.write(format_root_node=True, format=1)
self.assertEqual(newick, "(B:0.1,(D:1,E:1.5)C:0.2)A:1;")

def test_skbio(self):

# Disabled temporarily. following error is reported:
#
# File "/home/travis/build/etetoolkit/ete/test_tmp/miniconda3/envs/test_3.5/lib/python3.5/site-packages/parso/__init__.py", line 41, in <module>
# from parso.parser import ParserSyntaxError
# File "/home/travis/build/etetoolkit/ete/test_tmp/miniconda3/envs/test_3.5/lib/python3.5/site-packages/parso/parser.py", line 113
# node_map: Dict[str, type] = {}
# SyntaxError: invalid syntax
def disabled_test_skbio(self):
from skbio import TreeNode
skb_tree = TreeNode.read([u"(B:0.1,(D:1,E:1.5)C:0.2)A:1;"])
for node in skb_tree.traverse():
Expand Down
6 changes: 3 additions & 3 deletions ete3/test/test_ncbiquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def test_ncbiquery(self):
#Out[10]: [63221, 741158, 2665953, 1425170]
self.assertEqual(set(out), set([63221, 741158, 2665953, 1425170]))

out = ncbi.get_descendant_taxa("9605", intermediate_nodes=False, rank_limit="species")
#Out[11]: [9606, 1425170]
self.assertEqual(set(out), set([9606, 1425170]))
out = ncbi.get_descendant_taxa("9596", intermediate_nodes=False, rank_limit="species")
#Out[11]: [9597, 9598]
self.assertEqual(set(out), set([9597, 9598]))

def test_get_topology(self):
ncbi = NCBITaxa(dbfile=DATABASE_PATH)
Expand Down
11 changes: 6 additions & 5 deletions ete3/treeview/layouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@

def basic(node):
if node.is_leaf():
#node.img_style["size"]=1
#node.img_style["shape"] = "circle"
node.img_style["size"]=2
node.img_style["shape"] = "square"
faces.add_face_to_node(faces.AttrFace("name","Arial",10,"#4f8f0f",None), node, 0 )

def phylogeny(node):
leaf_color = "#000000"
node.img_style["shape"] = "circle"
node.img_style["shape"] = "square"
node.img_style["size"] = 2
if hasattr(node,"evoltype"):
if node.evoltype == 'D':
node.img_style["fgcolor"] = "#FF0000"
Expand All @@ -71,14 +72,14 @@ def phylogeny(node):

if node.is_leaf():
node.img_style["shape"] = "square"
node.img_style["size"] = 4
node.img_style["size"] = 2
node.img_style["fgcolor"] = leaf_color
faces.add_face_to_node( faces.AttrFace("name","Arial",11,leaf_color,None), node, 0 )
if hasattr(node,"sequence"):
SequenceFace = faces.SequenceFace(node.sequence,"aa",13)
faces.add_face_to_node(SequenceFace, node, 1, aligned=True)
else:
node.img_style["size"] = 6
node.img_style["size"] = 2

def heatmap(node):
square_size = 10
Expand Down

0 comments on commit 43e6a04

Please sign in to comment.