GenomeTreeTk 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- genometreetk/VERSION +136 -0
- genometreetk/__init__.py +22 -0
- genometreetk/arb.py +126 -0
- genometreetk/blast.py +85 -0
- genometreetk/bootstrap.py +373 -0
- genometreetk/cm_files/README +2 -0
- genometreetk/cm_files/lsu_archaea.cm +20824 -0
- genometreetk/cm_files/lsu_bacteria.cm +20327 -0
- genometreetk/cm_files/lsu_eukaryote.cm +23641 -0
- genometreetk/combine_support.py +151 -0
- genometreetk/common.py +104 -0
- genometreetk/derep_tree.py +236 -0
- genometreetk/fasttree.py +156 -0
- genometreetk/jackknife_markers.py +232 -0
- genometreetk/jackknife_taxa.py +136 -0
- genometreetk/main.py +667 -0
- genometreetk/msa_filter.py +499 -0
- genometreetk/phylogenetic_diversity.py +270 -0
- genometreetk/prune.py +99 -0
- genometreetk/reroot_tree.py +152 -0
- genometreetk/rna_workflow.py +834 -0
- genometreetk/tree_support.py +77 -0
- genometreetk-0.3.1.data/scripts/genometreetk +457 -0
- genometreetk-0.3.1.dist-info/METADATA +22 -0
- genometreetk-0.3.1.dist-info/RECORD +28 -0
- genometreetk-0.3.1.dist-info/WHEEL +5 -0
- genometreetk-0.3.1.dist-info/licenses/LICENSE +675 -0
- genometreetk-0.3.1.dist-info/top_level.txt +1 -0
genometreetk/VERSION
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
0.3.1
|
|
2
|
+
- requires gtdblib >= 1.12.1
|
|
3
|
+
- messages from gtdblib use the GenomeTreeTk log format, are written to genometreetk.log, and are suppressed by --silent
|
|
4
|
+
- errors reported by gtdblib (e.g. a taxon without a rank prefix) are logged with exit code 1 instead of a traceback
|
|
5
|
+
|
|
6
|
+
0.3.0
|
|
7
|
+
- replaced biolib with gtdblib (>= 1.12.0); packaging now uses setuptools and requires Python >= 3.7
|
|
8
|
+
- bootstrap: MSA replicates are created from a shared numpy matrix (about 7x faster and 4x less memory for 200,000 x 5,000 MSAs)
|
|
9
|
+
- bootstrap: added --seed; replicates are identical for any number of CPUs
|
|
10
|
+
- bootstrap: reruns safely resume interrupted runs; FastTree failures are reported instead of ignored
|
|
11
|
+
- bootstrap: fixed --boot_dir with MSA replicates; --msa_only no longer requires FastTree
|
|
12
|
+
- bootstrap and jk_markers: support values are calculated with gtdblib, which keeps the rooting and taxon labels of the input tree and writes whole-number support
|
|
13
|
+
- jk_markers: FastTree failures are reported instead of ignored
|
|
14
|
+
- combine: handles nodes without support values (e.g. the root) and decimal support values
|
|
15
|
+
- errors now exit with a non-zero code
|
|
16
|
+
- fixed pull writing invalid taxonomy strings for leaves without labelled ancestors
|
|
17
|
+
- fixed derep_tree (required --msa_file and failed on Python 3) and arb_records (failed on Python 3)
|
|
18
|
+
- removed unused modules (infer_workflow, markers, ncbi, aai)
|
|
19
|
+
- added end-to-end tests of the commands in tests/
|
|
20
|
+
|
|
21
|
+
0.2.3
|
|
22
|
+
- added sh_uf_hack command
|
|
23
|
+
|
|
24
|
+
0.2.2
|
|
25
|
+
- fixed bug with filtered MSA columns being written out in a random order within each marker
|
|
26
|
+
- now generating final_mask.txt which is the mask after filtering and subsampling
|
|
27
|
+
|
|
28
|
+
0.2.1
|
|
29
|
+
- modified bootstrap method to support use of FastTreeMP with multiple CPUs
|
|
30
|
+
|
|
31
|
+
0.2.0
|
|
32
|
+
- added msa_filter method
|
|
33
|
+
|
|
34
|
+
0.1.9
|
|
35
|
+
- added support to create MSA replicates without inferring replicate trees
|
|
36
|
+
- added support to infer trees from MSA replicates if they do not already exist
|
|
37
|
+
|
|
38
|
+
0.1.8
|
|
39
|
+
- better support for doing bootstrap trees across multiple servers
|
|
40
|
+
|
|
41
|
+
0.1.7
|
|
42
|
+
- updated propagate command to work with new Gxyz style genome IDs
|
|
43
|
+
- updated 'bootstrap' command to not require input tree
|
|
44
|
+
|
|
45
|
+
0.1.6
|
|
46
|
+
- fixed more merging issues
|
|
47
|
+
|
|
48
|
+
0.1.5
|
|
49
|
+
- fixed mering issue
|
|
50
|
+
|
|
51
|
+
0.1.4
|
|
52
|
+
- added prune method
|
|
53
|
+
|
|
54
|
+
0.1.3
|
|
55
|
+
- modified main.py to have Python 3 print statements
|
|
56
|
+
|
|
57
|
+
0.1.2
|
|
58
|
+
- updated shebang to Python 3
|
|
59
|
+
|
|
60
|
+
0.1.1
|
|
61
|
+
- added CM data files to repository
|
|
62
|
+
|
|
63
|
+
0.1.0
|
|
64
|
+
- initial migration to Python 3
|
|
65
|
+
|
|
66
|
+
0.0.55
|
|
67
|
+
- added rm_support
|
|
68
|
+
- bootstrap command will not look for files with the extension '.treefile'
|
|
69
|
+
|
|
70
|
+
0.0.54
|
|
71
|
+
- modified PD calculations when ingroup does not encompass root node; this
|
|
72
|
+
makes PD a rooted tree calculation, but this is probably best for most
|
|
73
|
+
situations
|
|
74
|
+
- simplified interface to PD calculations to remove notion of representative genomes
|
|
75
|
+
|
|
76
|
+
0.0.53
|
|
77
|
+
- better handling of support values when 'stripping' a tree
|
|
78
|
+
|
|
79
|
+
0.0.52
|
|
80
|
+
- modified cluster_de_novo to ensure all genomes as assigned to the closest type genome
|
|
81
|
+
- fixed synonym table: species were being indicated as synonyms of multiple species (e.g. Shigella boydii)
|
|
82
|
+
|
|
83
|
+
0.0.51
|
|
84
|
+
- added --rnd_type_genome option for evaluating impact of type genome selection on de novo clusters
|
|
85
|
+
|
|
86
|
+
0.0.50
|
|
87
|
+
- added --gamma option to bootstrap command so it isn't automatically used
|
|
88
|
+
|
|
89
|
+
0.0.49
|
|
90
|
+
- used for GTDB r89
|
|
91
|
+
- added QC exception list to qc_genomes command
|
|
92
|
+
- added species classification exception list to qc_genomes command
|
|
93
|
+
- added species classification exception list to select_type_genomes command
|
|
94
|
+
- added species classification exception list to cluster_named_types command
|
|
95
|
+
- added GTDB type genomes exception list to select_type_genomes command
|
|
96
|
+
- added species type genome radius information to file indicating species clusters
|
|
97
|
+
- simplified interface to cluster_user as species ANI radius information is now in cluster file
|
|
98
|
+
- stripped 'Candidatus' from all species names
|
|
99
|
+
|
|
100
|
+
0.0.48
|
|
101
|
+
- added type species of genus information for resolving priority of species with same publication date
|
|
102
|
+
- changed {manual_curation} to {unresolved}
|
|
103
|
+
- changed determination of genus name for de novo species clusters to consider most common genus name in cluster
|
|
104
|
+
- added checks to ensure genomes marked as assembled from type material or NCBI representative genomes as not actually a subspecies
|
|
105
|
+
|
|
106
|
+
0.0.47
|
|
107
|
+
- initial implementation of filtering of percentage of bac120 or ar122 marker genes
|
|
108
|
+
|
|
109
|
+
0.0.46
|
|
110
|
+
- initial type genome workflow for GTDB r89
|
|
111
|
+
|
|
112
|
+
0.0.45
|
|
113
|
+
- improved dereplication workflow for GTDB r89
|
|
114
|
+
|
|
115
|
+
0.0.44
|
|
116
|
+
- add method to dump 5S, 16S, and 23S sequences to file
|
|
117
|
+
|
|
118
|
+
0.0.43
|
|
119
|
+
- improvements to code for assigning genomes to canonical genome set
|
|
120
|
+
|
|
121
|
+
0.0.42
|
|
122
|
+
- initial implementation of code to assign genomes to canonical genome set
|
|
123
|
+
|
|
124
|
+
0.0.41
|
|
125
|
+
- fixed bug with parsing contig length from SSU file
|
|
126
|
+
|
|
127
|
+
0.0.40
|
|
128
|
+
- fixed issue with rerooting trees with bootstraps between [0, 1]
|
|
129
|
+
|
|
130
|
+
0.0.39
|
|
131
|
+
- added GTR model when inferring SSU or LSU trees
|
|
132
|
+
|
|
133
|
+
0.0.38
|
|
134
|
+
- new method for selecting GTDB representatives
|
|
135
|
+
|
|
136
|
+
0.0.37
|
genometreetk/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# #
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify #
|
|
4
|
+
# it under the terms of the GNU General Public License as published by #
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or #
|
|
6
|
+
# (at your option) any later version. #
|
|
7
|
+
# #
|
|
8
|
+
# This program is distributed in the hope that it will be useful, #
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
11
|
+
# GNU General Public License for more details. #
|
|
12
|
+
# #
|
|
13
|
+
# You should have received a copy of the GNU General Public License #
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
|
15
|
+
# #
|
|
16
|
+
###############################################################################
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
# Set the module version.
|
|
21
|
+
with open(os.path.join(__path__[0], 'VERSION'), 'r') as f:
|
|
22
|
+
__version__ = f.readline().strip()
|
genometreetk/arb.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# #
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify #
|
|
4
|
+
# it under the terms of the GNU General Public License as published by #
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or #
|
|
6
|
+
# (at your option) any later version. #
|
|
7
|
+
# #
|
|
8
|
+
# This program is distributed in the hope that it will be useful, #
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
11
|
+
# GNU General Public License for more details. #
|
|
12
|
+
# #
|
|
13
|
+
# You should have received a copy of the GNU General Public License #
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
|
15
|
+
# #
|
|
16
|
+
###############################################################################
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import csv
|
|
21
|
+
import logging
|
|
22
|
+
|
|
23
|
+
import gtdblib.util.bio.seq_io as seq_io
|
|
24
|
+
from gtdblib.taxonomy.taxonomy import read_taxonomy
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Arb(object):
|
|
28
|
+
"""Methods for producing files for ARB."""
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
"""Initialization."""
|
|
32
|
+
|
|
33
|
+
self.logger = logging.getLogger()
|
|
34
|
+
|
|
35
|
+
def _record(self, fout,
|
|
36
|
+
genome_id,
|
|
37
|
+
metadata_fields,
|
|
38
|
+
metadata_values,
|
|
39
|
+
aligned_seq):
|
|
40
|
+
"""Write out ARB record for genome."""
|
|
41
|
+
|
|
42
|
+
fout.write("BEGIN\n")
|
|
43
|
+
fout.write("db_name=%s\n" % genome_id)
|
|
44
|
+
for col_header, value in zip(metadata_fields, metadata_values):
|
|
45
|
+
# replace equal signs as these are incompatible with the ARB parser
|
|
46
|
+
if value:
|
|
47
|
+
value = value.replace('=', '/')
|
|
48
|
+
|
|
49
|
+
fout.write("%s=%s\n" % (col_header, value))
|
|
50
|
+
|
|
51
|
+
fout.write("warning=\n")
|
|
52
|
+
fout.write("aligned_seq=%s\n" % (aligned_seq))
|
|
53
|
+
fout.write("END\n\n")
|
|
54
|
+
|
|
55
|
+
def create_records(self, metadata_file, msa_file, taxonomy_file, genome_list, output_file):
|
|
56
|
+
"""Create ARB records from GTDB metadata."""
|
|
57
|
+
|
|
58
|
+
seqs = {}
|
|
59
|
+
if msa_file:
|
|
60
|
+
seqs = seq_io.read(msa_file)
|
|
61
|
+
|
|
62
|
+
taxonomy = {}
|
|
63
|
+
if taxonomy_file:
|
|
64
|
+
taxonomy = read_taxonomy(taxonomy_file)
|
|
65
|
+
|
|
66
|
+
genomes_to_keep = set()
|
|
67
|
+
if genome_list:
|
|
68
|
+
for line in open(genome_list):
|
|
69
|
+
genomes_to_keep.add(line.strip())
|
|
70
|
+
|
|
71
|
+
fout = open(output_file, 'w')
|
|
72
|
+
|
|
73
|
+
delimiter = ','
|
|
74
|
+
if metadata_file.endswith('.tsv'):
|
|
75
|
+
delimiter = '\t'
|
|
76
|
+
|
|
77
|
+
header = True
|
|
78
|
+
for row in csv.reader(open(metadata_file, newline=''), delimiter=delimiter):
|
|
79
|
+
if header:
|
|
80
|
+
fields = [f.lower().replace(' ', '_').replace('-', '_') for f in row[1:]]
|
|
81
|
+
if taxonomy:
|
|
82
|
+
fields.append('gtdb_taxonomy')
|
|
83
|
+
header = False
|
|
84
|
+
else:
|
|
85
|
+
genome_id = row[0]
|
|
86
|
+
values = row[1:]
|
|
87
|
+
if taxonomy:
|
|
88
|
+
values.append('; '.join(taxonomy[genome_id]))
|
|
89
|
+
aligned_seq = seqs.get(genome_id, '')
|
|
90
|
+
|
|
91
|
+
if not genomes_to_keep or genome_id in genomes_to_keep:
|
|
92
|
+
self._record(fout, genome_id, fields, values, aligned_seq)
|
|
93
|
+
|
|
94
|
+
fout.close()
|
|
95
|
+
|
|
96
|
+
def write(self, hashes, io):
|
|
97
|
+
"""Write data to a GreenGenes formatted files.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
hashes : list of dict[feature] -> value
|
|
102
|
+
GreenGenes style metadata.
|
|
103
|
+
io : output stream
|
|
104
|
+
Handle to output stream.
|
|
105
|
+
"""
|
|
106
|
+
is_first = True
|
|
107
|
+
for dahash in hashes:
|
|
108
|
+
if is_first:
|
|
109
|
+
is_first = False
|
|
110
|
+
else:
|
|
111
|
+
io.write('\n')
|
|
112
|
+
|
|
113
|
+
io.write('BEGIN\n')
|
|
114
|
+
for key in sorted(dahash.keys()):
|
|
115
|
+
if key != 'warning' and key != 'aligned_seq':
|
|
116
|
+
io.write('='.join([key, dahash[key]]) + '\n')
|
|
117
|
+
|
|
118
|
+
# the warning field must be the second to last as it is used
|
|
119
|
+
# to indicates that the aligned sequence is to follow
|
|
120
|
+
io.write('='.join(['warning', dahash.get('warning', '')]) + '\n')
|
|
121
|
+
|
|
122
|
+
# the aligned sequence must be the last field
|
|
123
|
+
io.write('='.join(['aligned_seq', dahash.get('aligned_seq', '')]) + '\n')
|
|
124
|
+
|
|
125
|
+
io.write('END\n')
|
|
126
|
+
|
genometreetk/blast.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# #
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify #
|
|
4
|
+
# it under the terms of the GNU General Public License as published by #
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or #
|
|
6
|
+
# (at your option) any later version. #
|
|
7
|
+
# #
|
|
8
|
+
# This program is distributed in the hope that it will be useful, #
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
11
|
+
# GNU General Public License for more details. #
|
|
12
|
+
# #
|
|
13
|
+
# You should have received a copy of the GNU General Public License #
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
|
15
|
+
# #
|
|
16
|
+
###############################################################################
|
|
17
|
+
|
|
18
|
+
"""Minimal BLAST wrapper used to identify rRNA sequences with incongruent taxonomy."""
|
|
19
|
+
|
|
20
|
+
import subprocess
|
|
21
|
+
from collections import namedtuple
|
|
22
|
+
|
|
23
|
+
from gtdblib.util.shell.execute import check_dependencies
|
|
24
|
+
|
|
25
|
+
# fields written by blastn with BLAST_CUSTOM_FMT
|
|
26
|
+
BLAST_CUSTOM_FMT = '6 qseqid qlen sseqid stitle slen length pident evalue bitscore'
|
|
27
|
+
BlastHit = namedtuple('BlastHit', ['query_id',
|
|
28
|
+
'query_len',
|
|
29
|
+
'subject_id',
|
|
30
|
+
'subject_annotation',
|
|
31
|
+
'subject_len',
|
|
32
|
+
'alignment_len',
|
|
33
|
+
'perc_identity',
|
|
34
|
+
'evalue',
|
|
35
|
+
'bitscore'])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BlastError(Exception):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _run(cmd):
|
|
43
|
+
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
44
|
+
if proc.returncode != 0:
|
|
45
|
+
raise BlastError('{} failed with exit code {}: {}'.format(
|
|
46
|
+
cmd[0], proc.returncode, proc.stderr.strip()))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_blastn_db(fasta_file, db_file):
|
|
50
|
+
"""Create nucleotide BLAST database."""
|
|
51
|
+
|
|
52
|
+
check_dependencies(['makeblastdb'])
|
|
53
|
+
_run(['makeblastdb', '-dbtype', 'nucl', '-in', fasta_file, '-out', db_file])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def blastn(query_seqs, nucl_db, output_file, cpus=1, evalue=1e-3, max_matches=500, task='megablast'):
|
|
57
|
+
"""Search query sequences against a nucleotide database, writing hits in BLAST_CUSTOM_FMT."""
|
|
58
|
+
|
|
59
|
+
check_dependencies(['blastn'])
|
|
60
|
+
_run(['blastn',
|
|
61
|
+
'-num_threads', str(cpus),
|
|
62
|
+
'-query', query_seqs,
|
|
63
|
+
'-db', nucl_db,
|
|
64
|
+
'-out', output_file,
|
|
65
|
+
'-evalue', str(evalue),
|
|
66
|
+
'-max_target_seqs', str(max_matches),
|
|
67
|
+
'-task', task,
|
|
68
|
+
'-outfmt', BLAST_CUSTOM_FMT])
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def read_hits(table):
|
|
72
|
+
"""Read hits from a table written by blastn()."""
|
|
73
|
+
|
|
74
|
+
with open(table) as f:
|
|
75
|
+
for line in f:
|
|
76
|
+
tokens = line.rstrip('\n').split('\t')
|
|
77
|
+
yield BlastHit(query_id=tokens[0],
|
|
78
|
+
query_len=int(tokens[1]),
|
|
79
|
+
subject_id=tokens[2],
|
|
80
|
+
subject_annotation=tokens[3],
|
|
81
|
+
subject_len=int(tokens[4]),
|
|
82
|
+
alignment_len=int(tokens[5]),
|
|
83
|
+
perc_identity=float(tokens[6]),
|
|
84
|
+
evalue=float(tokens[7]),
|
|
85
|
+
bitscore=float(tokens[8]))
|