PyamilySeq 1.0.1__py3-none-any.whl → 1.1.0__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.
- PyamilySeq/Group_Extractor.py +83 -0
- PyamilySeq/Group_Sizes.py +87 -0
- PyamilySeq/PyamilySeq.py +16 -11
- PyamilySeq/PyamilySeq_Genus.py +3 -3
- PyamilySeq/PyamilySeq_Species.py +2 -2
- PyamilySeq/Seq_Combiner.py +25 -8
- PyamilySeq/constants.py +1 -1
- PyamilySeq/utils.py +118 -86
- {PyamilySeq-1.0.1.dist-info → pyamilyseq-1.1.0.dist-info}/METADATA +46 -85
- pyamilyseq-1.1.0.dist-info/RECORD +20 -0
- {PyamilySeq-1.0.1.dist-info → pyamilyseq-1.1.0.dist-info}/WHEEL +1 -1
- {PyamilySeq-1.0.1.dist-info → pyamilyseq-1.1.0.dist-info}/entry_points.txt +6 -0
- PyamilySeq-1.0.1.dist-info/RECORD +0 -18
- {PyamilySeq-1.0.1.dist-info → pyamilyseq-1.1.0.dist-info}/LICENSE +0 -0
- {PyamilySeq-1.0.1.dist-info → pyamilyseq-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import csv
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_fasta(fasta_file):
|
|
7
|
+
"""
|
|
8
|
+
Parses a FASTA file and returns a dictionary of gene IDs and sequences.
|
|
9
|
+
"""
|
|
10
|
+
sequences = {}
|
|
11
|
+
with open(fasta_file, 'r') as f:
|
|
12
|
+
gene_id = None
|
|
13
|
+
sequence = []
|
|
14
|
+
for line in f:
|
|
15
|
+
line = line.strip()
|
|
16
|
+
if line.startswith(">"):
|
|
17
|
+
if gene_id: # Save the previous gene
|
|
18
|
+
sequences[gene_id] = ''.join(sequence)
|
|
19
|
+
gene_id = line[1:].split()[0].split('|')[1].replace('ENSB_','') # Extract the gene ID after ">"
|
|
20
|
+
sequence = []
|
|
21
|
+
else:
|
|
22
|
+
sequence.append(line)
|
|
23
|
+
if gene_id: # Save the last gene
|
|
24
|
+
sequences[gene_id] = ''.join(sequence)
|
|
25
|
+
return sequences
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def parse_csv(csv_file):
|
|
29
|
+
"""
|
|
30
|
+
Parses a CSV file to extract group IDs and gene IDs (skipping the first line).
|
|
31
|
+
"""
|
|
32
|
+
groups = {}
|
|
33
|
+
with open(csv_file, 'r') as f:
|
|
34
|
+
reader = csv.reader(f, delimiter=',') # Assuming tab-delimited CSV
|
|
35
|
+
next(reader) # Skip the first line
|
|
36
|
+
for row in reader:
|
|
37
|
+
group_id = row[0]
|
|
38
|
+
gene_ids = row[14:] # Read from column 14 onward
|
|
39
|
+
gene_ids = [gene.strip() for genes in gene_ids for gene in genes.split(';') if
|
|
40
|
+
gene.strip()] # Flatten and clean
|
|
41
|
+
groups[group_id] = gene_ids
|
|
42
|
+
return groups
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def write_group_fastas(groups, sequences, output_dir):
|
|
46
|
+
"""
|
|
47
|
+
Writes individual FASTA files for each group with the relevant sequences.
|
|
48
|
+
"""
|
|
49
|
+
if not os.path.exists(output_dir):
|
|
50
|
+
os.makedirs(output_dir)
|
|
51
|
+
|
|
52
|
+
for group_id, gene_ids in groups.items():
|
|
53
|
+
group_file = os.path.join(output_dir, f"{group_id}.fasta")
|
|
54
|
+
with open(group_file, 'w') as f:
|
|
55
|
+
for gene_id in gene_ids:
|
|
56
|
+
if gene_id in sequences:
|
|
57
|
+
f.write(f">{gene_id}\n{sequences[gene_id]}\n")
|
|
58
|
+
else:
|
|
59
|
+
print(f"Warning: Gene ID {gene_id} not found in FASTA file.")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def main():
|
|
63
|
+
parser = argparse.ArgumentParser(description="Process FASTA and CSV files to create grouped FASTA outputs.")
|
|
64
|
+
parser.add_argument("-fasta", required=True, help="Input FASTA file containing gene sequences.")
|
|
65
|
+
parser.add_argument("-csv", required=True, help="Input CSV file containing group and gene information.")
|
|
66
|
+
parser.add_argument("-output_dir", required=True, help="Directory to save the grouped FASTA files.")
|
|
67
|
+
|
|
68
|
+
args = parser.parse_args()
|
|
69
|
+
|
|
70
|
+
# Parse the input files
|
|
71
|
+
print("Parsing FASTA file...")
|
|
72
|
+
sequences = parse_fasta(args.fasta)
|
|
73
|
+
print("Parsing CSV file...")
|
|
74
|
+
groups = parse_csv(args.csv)
|
|
75
|
+
|
|
76
|
+
# Write the grouped FASTA files
|
|
77
|
+
print("Writing grouped FASTA files...")
|
|
78
|
+
write_group_fastas(groups, sequences, args.output_dir)
|
|
79
|
+
print("Process completed successfully.")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
main()
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import csv
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_fasta_stats(fasta_file):
|
|
7
|
+
"""
|
|
8
|
+
Parses a FASTA file and calculates sequence statistics.
|
|
9
|
+
"""
|
|
10
|
+
lengths = []
|
|
11
|
+
with open(fasta_file, 'r') as f:
|
|
12
|
+
sequence = []
|
|
13
|
+
for line in f:
|
|
14
|
+
line = line.strip()
|
|
15
|
+
if line.startswith(">"):
|
|
16
|
+
if sequence: # Save the previous sequence length
|
|
17
|
+
lengths.append(len(''.join(sequence)))
|
|
18
|
+
sequence = [] # Reset for the next sequence
|
|
19
|
+
else:
|
|
20
|
+
sequence.append(line)
|
|
21
|
+
if sequence: # Save the last sequence length
|
|
22
|
+
lengths.append(len(''.join(sequence)))
|
|
23
|
+
|
|
24
|
+
# Calculate statistics
|
|
25
|
+
num_sequences = len(lengths)
|
|
26
|
+
if num_sequences > 0:
|
|
27
|
+
avg_length = sum(lengths) / num_sequences
|
|
28
|
+
min_length = min(lengths)
|
|
29
|
+
max_length = max(lengths)
|
|
30
|
+
length_diff = max_length - min_length
|
|
31
|
+
percent_diff = (length_diff / min_length * 100) if min_length > 0 else 0
|
|
32
|
+
else:
|
|
33
|
+
avg_length = min_length = max_length = length_diff = percent_diff = 0
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
"num_sequences": num_sequences,
|
|
37
|
+
"min_length": min_length,
|
|
38
|
+
"max_length": max_length,
|
|
39
|
+
"avg_length": avg_length,
|
|
40
|
+
"length_diff": length_diff,
|
|
41
|
+
"percent_diff": percent_diff
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def process_fasta_directory(input_dir, output_csv):
|
|
46
|
+
"""
|
|
47
|
+
Processes a directory of FASTA files and writes statistics to a CSV file.
|
|
48
|
+
"""
|
|
49
|
+
results = []
|
|
50
|
+
for filename in os.listdir(input_dir):
|
|
51
|
+
if filename.endswith(".fasta"):
|
|
52
|
+
file_path = os.path.join(input_dir, filename)
|
|
53
|
+
stats = parse_fasta_stats(file_path)
|
|
54
|
+
results.append({
|
|
55
|
+
"file_name": filename,
|
|
56
|
+
"num_sequences": stats["num_sequences"],
|
|
57
|
+
"min_length": stats["min_length"],
|
|
58
|
+
"max_length": stats["max_length"],
|
|
59
|
+
"avg_length": stats["avg_length"],
|
|
60
|
+
"length_diff": stats["length_diff"],
|
|
61
|
+
"percent_diff": stats["percent_diff"]
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
# Write results to a CSV file
|
|
65
|
+
with open(output_csv, 'w', newline='') as csvfile:
|
|
66
|
+
fieldnames = ["file_name", "num_sequences", "min_length", "max_length", "avg_length", "length_diff",
|
|
67
|
+
"percent_diff"]
|
|
68
|
+
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|
69
|
+
writer.writeheader()
|
|
70
|
+
writer.writerows(results)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def main():
|
|
74
|
+
parser = argparse.ArgumentParser(description="Summarize sequence statistics for a directory of FASTA files.")
|
|
75
|
+
parser.add_argument("-input_dir", required=True, help="Directory containing FASTA files.")
|
|
76
|
+
parser.add_argument("-output_csv", required=True, help="Output CSV file to save statistics.")
|
|
77
|
+
|
|
78
|
+
args = parser.parse_args()
|
|
79
|
+
|
|
80
|
+
# Process the directory of FASTA files
|
|
81
|
+
print("Processing FASTA files...")
|
|
82
|
+
process_fasta_directory(args.input_dir, args.output_csv)
|
|
83
|
+
print(f"Statistics saved to {args.output_csv}")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
PyamilySeq/PyamilySeq.py
CHANGED
|
@@ -54,8 +54,10 @@ def main():
|
|
|
54
54
|
help="Directory containing GFF/FASTA files - Use with -input_type separate/combined.")
|
|
55
55
|
full_parser.add_argument("-input_fasta", required=False,
|
|
56
56
|
help="Input FASTA file - Use with - input_type fasta.")
|
|
57
|
-
full_parser.add_argument("-
|
|
58
|
-
help="Substring to split filenames and extract genome names (e.g., '_combined.gff3') - Use with -input_type separate/combined.")
|
|
57
|
+
full_parser.add_argument("-name_split_gff", required=False,
|
|
58
|
+
help="Substring to split filenames and extract genome names for gff files (e.g., '_combined.gff3') - Use with -input_type separate/combined.")
|
|
59
|
+
full_parser.add_argument("-name_split_fasta", required=False,
|
|
60
|
+
help="Substring to split filenames and extract genome names for fasta files if named differently to paired gff files (e.g., '_dna.fasta') - Use with -input_type separate/combined.")
|
|
59
61
|
full_parser.add_argument("-sequence_type", choices=['AA', 'DNA'], default="AA", required=False,
|
|
60
62
|
help="Clustering mode: 'DNA' or 'AA'.")
|
|
61
63
|
full_parser.add_argument("-gene_ident", default="CDS", required=False,
|
|
@@ -91,12 +93,12 @@ def main():
|
|
|
91
93
|
help="Gene groupings for 'Species' mode (default: '99,95,15').")
|
|
92
94
|
subparser.add_argument("-genus_groups", default="1,2,3,4,5,6,7,8,9,10", required=False,
|
|
93
95
|
help="Gene groupings for 'Genus' mode (default: '1-10').")
|
|
94
|
-
subparser.add_argument("-
|
|
95
|
-
help="Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95').")
|
|
96
|
-
subparser.add_argument("-
|
|
96
|
+
subparser.add_argument("-write_groups", default=None, dest="write_groups", required=False,
|
|
97
|
+
help="Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95'). - triggers '-wig'.")
|
|
98
|
+
subparser.add_argument("-write_individual_groups", action="store_true", dest="write_individual_groups", required=False,
|
|
97
99
|
help="Output individual FASTA files for each group.")
|
|
98
|
-
subparser.add_argument("-
|
|
99
|
-
help="Align and concatenate sequences for 'core' groups.")
|
|
100
|
+
subparser.add_argument("-align", action="store_true", dest="align_core", required=False,
|
|
101
|
+
help="Align and concatenate sequences for 'core' groups specified with '-w'.")
|
|
100
102
|
subparser.add_argument("-align_aa", action="store_true", required=False,
|
|
101
103
|
help="Align sequences as amino acids.")
|
|
102
104
|
subparser.add_argument("-no_gpa", action="store_false", dest="gene_presence_absence_out", required=False,
|
|
@@ -115,6 +117,9 @@ def main():
|
|
|
115
117
|
# Parse Arguments
|
|
116
118
|
options = parser.parse_args()
|
|
117
119
|
|
|
120
|
+
if options.write_groups != None and options.write_individual_groups == False:
|
|
121
|
+
options.write_individual_groups = True
|
|
122
|
+
|
|
118
123
|
# Example of conditional logic based on selected mode
|
|
119
124
|
print(f"Running PyamilySeq {PyamilySeq_Version} in {options.run_mode} mode:")
|
|
120
125
|
if options.run_mode == "Full" and options.verbose == True:
|
|
@@ -129,13 +134,13 @@ def main():
|
|
|
129
134
|
sys.exit("Currently reclustering only works on Partial Mode.")
|
|
130
135
|
required_full_mode = [options.input_type, options.pident, options.len_diff]
|
|
131
136
|
if options.input_type != 'fasta':
|
|
132
|
-
required_full_mode.extend([options.input_dir, options.
|
|
137
|
+
required_full_mode.extend([options.input_dir, options.name_split_gff])
|
|
133
138
|
if all(required_full_mode):
|
|
134
139
|
# Proceed with the Full mode
|
|
135
140
|
pass
|
|
136
141
|
else:
|
|
137
142
|
missing_options = [opt for opt in
|
|
138
|
-
['input_type', 'input_dir', '
|
|
143
|
+
['input_type', 'input_dir', 'name_split_gff', 'clustering_format', 'pident', 'len_diff'] if
|
|
139
144
|
not options.__dict__.get(opt)]
|
|
140
145
|
sys.exit(f"Missing required options for Full mode: {', '.join(missing_options)}")
|
|
141
146
|
if options.align_core:
|
|
@@ -234,10 +239,10 @@ def main():
|
|
|
234
239
|
translate = False
|
|
235
240
|
file_to_cluster = combined_out_file
|
|
236
241
|
if options.input_type == 'separate':
|
|
237
|
-
read_separate_files(options.input_dir, options.
|
|
242
|
+
read_separate_files(options.input_dir, options.name_split_gff, options.name_split_fasta, options.gene_ident, combined_out_file, translate)
|
|
238
243
|
run_cd_hit(options, file_to_cluster, clustering_output, clustering_mode)
|
|
239
244
|
elif options.input_type == 'combined':
|
|
240
|
-
read_combined_files(options.input_dir, options.
|
|
245
|
+
read_combined_files(options.input_dir, options.name_split_gff, options.gene_ident, combined_out_file, translate)
|
|
241
246
|
run_cd_hit(options, file_to_cluster, clustering_output, clustering_mode)
|
|
242
247
|
elif options.input_type == 'fasta':
|
|
243
248
|
combined_out_file = options.input_fasta
|
PyamilySeq/PyamilySeq_Genus.py
CHANGED
|
@@ -23,8 +23,8 @@ def gene_presence_absence_output(options, genus_dict, pangenome_clusters_First_s
|
|
|
23
23
|
gpa_outfile.write('"\n')
|
|
24
24
|
for cluster, sequences in pangenome_clusters_First_sequences_sorted.items():
|
|
25
25
|
average_sequences_per_genome = len(sequences) / len(pangenome_clusters_First_sorted[cluster])
|
|
26
|
-
gpa_outfile.write('"group_'+str(cluster)+'","","",'+str(len(pangenome_clusters_First_sorted[cluster]))+'","'+str(len(sequences))+'","'+str(average_sequences_per_genome)+
|
|
27
|
-
'","","","","","","","",""
|
|
26
|
+
gpa_outfile.write('"group_'+str(cluster)+'","","","'+str(len(pangenome_clusters_First_sorted[cluster]))+'","'+str(len(sequences))+'","'+str(average_sequences_per_genome)+
|
|
27
|
+
'","","","","","","","",""')
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
for genus in genus_dict.keys():
|
|
@@ -34,7 +34,7 @@ def gene_presence_absence_output(options, genus_dict, pangenome_clusters_First_s
|
|
|
34
34
|
if value.split('_')[0] == genus:
|
|
35
35
|
tmp_list.append(value)
|
|
36
36
|
if tmp_list:
|
|
37
|
-
full_out += ',"'+''.join(tmp_list)+'"'
|
|
37
|
+
full_out += ',"'+' '.join(tmp_list)+'"'
|
|
38
38
|
else:
|
|
39
39
|
full_out = ',""'
|
|
40
40
|
gpa_outfile.write(full_out)
|
PyamilySeq/PyamilySeq_Species.py
CHANGED
|
@@ -21,7 +21,7 @@ def gene_presence_absence_output(options, genome_dict, pangenome_clusters_First_
|
|
|
21
21
|
gpa_outfile.write('"\n')
|
|
22
22
|
for cluster, sequences in pangenome_clusters_First_sequences_sorted.items():
|
|
23
23
|
average_sequences_per_genome = len(sequences) / len(pangenome_clusters_First_sorted[cluster])
|
|
24
|
-
gpa_outfile.write('"group_'+str(cluster)+'","","",'+str(len(pangenome_clusters_First_sorted[cluster]))+'","'+str(len(sequences))+'","'+str(average_sequences_per_genome)+
|
|
24
|
+
gpa_outfile.write('"group_'+str(cluster)+'","","","'+str(len(pangenome_clusters_First_sorted[cluster]))+'","'+str(len(sequences))+'","'+str(average_sequences_per_genome)+
|
|
25
25
|
'","","","","","","","","",""')
|
|
26
26
|
|
|
27
27
|
|
|
@@ -32,7 +32,7 @@ def gene_presence_absence_output(options, genome_dict, pangenome_clusters_First_
|
|
|
32
32
|
if value.split('|')[0] == genome:
|
|
33
33
|
tmp_list.append(value.split('|')[1])
|
|
34
34
|
if tmp_list:
|
|
35
|
-
full_out += ',"'+'
|
|
35
|
+
full_out += ',"'+' '.join(tmp_list)+'"'
|
|
36
36
|
else:
|
|
37
37
|
full_out = ',""'
|
|
38
38
|
gpa_outfile.write(full_out)
|
PyamilySeq/Seq_Combiner.py
CHANGED
|
@@ -22,14 +22,17 @@ def main():
|
|
|
22
22
|
' "combined" for GFF files with embedded FASTA sequences and "fasta" for combining multiple '
|
|
23
23
|
'FASTA files together.',
|
|
24
24
|
required=True)
|
|
25
|
-
required.add_argument("-
|
|
26
|
-
help="
|
|
27
|
-
required=
|
|
25
|
+
required.add_argument("-name_split_gff", action="store", dest="name_split_gff",
|
|
26
|
+
help="Substring used to split the filename and extract the genome name ('_combined.gff3' or '.gff'). - Not needed with -input_type fasta",
|
|
27
|
+
required=False)
|
|
28
|
+
required.add_argument("-name_split_fasta", action="store", dest="name_split_fasta",
|
|
29
|
+
help="Substring used to split filenames and extract genome names for fasta files if named differently to paired gff files (e.g., '_dna.fasta').",
|
|
30
|
+
required=False)
|
|
28
31
|
required.add_argument("-output_dir", action="store", dest="output_dir",
|
|
29
32
|
help="Directory for all output files.",
|
|
30
33
|
required=True)
|
|
31
34
|
required.add_argument("-output_name", action="store", dest="output_file",
|
|
32
|
-
help="Output file name
|
|
35
|
+
help="Output file name.",
|
|
33
36
|
required=True)
|
|
34
37
|
|
|
35
38
|
optional = parser.add_argument_group('Optional Arguments')
|
|
@@ -48,19 +51,33 @@ def main():
|
|
|
48
51
|
options = parser.parse_args()
|
|
49
52
|
|
|
50
53
|
|
|
54
|
+
if options.input_type == 'separate' and options.name_split_gff is None:
|
|
55
|
+
print("Please provide a substring to split the filename and extract the genome name.")
|
|
56
|
+
exit(1)
|
|
57
|
+
if options.input_type == 'combined' and options.name_split_gff is None:
|
|
58
|
+
print("Please provide a substring to split the filename and extract the genome name.")
|
|
59
|
+
exit(1)
|
|
60
|
+
if options.input_type == 'fasta' and options.name_split_fasta is None:
|
|
61
|
+
print("Please provide a substring to split the filename and extract the genome name.")
|
|
62
|
+
exit
|
|
51
63
|
|
|
52
64
|
output_path = os.path.abspath(options.output_dir)
|
|
53
65
|
if not os.path.exists(output_path):
|
|
54
66
|
os.makedirs(output_path)
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
output_file = options.output_file + '.fasta'
|
|
69
|
+
if os.path.exists(os.path.join(output_path, output_file)):
|
|
70
|
+
print(f"Output file {output_file} already exists in the output directory. Please delete or rename the file and try again.")
|
|
71
|
+
exit(1)
|
|
72
|
+
|
|
73
|
+
combined_out_file = os.path.join(output_path, output_file )
|
|
57
74
|
|
|
58
75
|
if options.input_type == 'separate':
|
|
59
|
-
read_separate_files(options.input_dir, options.
|
|
76
|
+
read_separate_files(options.input_dir, options.name_split_gff, options.name_split_fasta, options.gene_ident, combined_out_file, options.translate)
|
|
60
77
|
elif options.input_type == 'combined':
|
|
61
|
-
read_combined_files(options.input_dir, options.
|
|
78
|
+
read_combined_files(options.input_dir, options.name_split_gff, options.gene_ident, combined_out_file, options.translate)
|
|
62
79
|
elif options.input_type == 'fasta':
|
|
63
|
-
read_fasta_files(options.input_dir, options.
|
|
80
|
+
read_fasta_files(options.input_dir, options.name_split_fasta, combined_out_file, options.translate)
|
|
64
81
|
|
|
65
82
|
if __name__ == "__main__":
|
|
66
83
|
main()
|
PyamilySeq/constants.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
PyamilySeq_Version = 'v1.0
|
|
1
|
+
PyamilySeq_Version = 'v1.1.0'
|
|
2
2
|
|
PyamilySeq/utils.py
CHANGED
|
@@ -228,15 +228,33 @@ def run_mafft_on_sequences(options, sequences, output_file):
|
|
|
228
228
|
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
def read_separate_files(input_dir,
|
|
231
|
+
def read_separate_files(input_dir, name_split_gff, name_split_fasta, gene_ident, combined_out, translate):
|
|
232
|
+
paired_files_found = None
|
|
232
233
|
with open(combined_out, 'w') as combined_out_file, open(combined_out.replace('_dna.fasta','_aa.fasta'), 'w') as combined_out_file_aa:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
gff_files = glob.glob(os.path.join(input_dir, '*' + name_split_gff))
|
|
235
|
+
if not gff_files:
|
|
236
|
+
sys.exit("Error: No GFF files found.")
|
|
237
|
+
for gff_file in gff_files:
|
|
238
|
+
genome_name = os.path.basename(gff_file).split(name_split_gff)[0]
|
|
239
|
+
if name_split_fasta == None:
|
|
240
|
+
possible_extensions = ['.fa', '.fasta', '.fna']
|
|
241
|
+
corresponding_fasta_file = None
|
|
242
|
+
for ext in possible_extensions:
|
|
243
|
+
temp_file = os.path.splitext(gff_file)[0] + ext
|
|
244
|
+
if os.path.exists(temp_file):
|
|
245
|
+
corresponding_fasta_file = temp_file
|
|
246
|
+
break
|
|
247
|
+
if corresponding_fasta_file is None:
|
|
248
|
+
print("Corresponding FASTA file for GFF file '" + gff_file + "' not found. Skipping. - Try using the -name_split_fasta option.")
|
|
249
|
+
continue
|
|
250
|
+
else:
|
|
251
|
+
corresponding_fasta_file = os.path.join(input_dir, genome_name + name_split_fasta)
|
|
252
|
+
if not os.path.exists(corresponding_fasta_file):
|
|
253
|
+
print("Corresponding FASTA file for GFF file '" + gff_file + "' not found. Skipping. - Try using the -name_split_fasta option.")
|
|
254
|
+
continue
|
|
238
255
|
|
|
239
256
|
gff_features = []
|
|
257
|
+
paired_files_found = True
|
|
240
258
|
with open(gff_file, 'r') as file:
|
|
241
259
|
seen_seq_ids = collections.defaultdict(int)
|
|
242
260
|
lines = file.readlines()
|
|
@@ -244,6 +262,7 @@ def read_separate_files(input_dir, name_split, gene_ident, combined_out, transla
|
|
|
244
262
|
line_data = line.split('\t')
|
|
245
263
|
if len(line_data) == 9:
|
|
246
264
|
if any(gene_type in line_data[2] for gene_type in gene_ident):
|
|
265
|
+
seq_id = line_data[8].split('ID=')[1].split(';')[0]
|
|
247
266
|
contig = line_data[0]
|
|
248
267
|
feature = line_data[2]
|
|
249
268
|
strand = line_data[6]
|
|
@@ -253,7 +272,6 @@ def read_separate_files(input_dir, name_split, gene_ident, combined_out, transla
|
|
|
253
272
|
seen_seq_ids[seq_id] + 1
|
|
254
273
|
else:
|
|
255
274
|
seen_seq_ids[seq_id] = 1
|
|
256
|
-
seq_id = line_data[8].split('ID=')[1].split(';')[0]
|
|
257
275
|
gff_features.append((contig, start, end, strand, feature, seq_id))
|
|
258
276
|
fasta_dict = collections.defaultdict(str)
|
|
259
277
|
with open(corresponding_fasta_file, 'r') as file:
|
|
@@ -288,14 +306,20 @@ def read_separate_files(input_dir, name_split, gene_ident, combined_out, transla
|
|
|
288
306
|
wrapped_sequence = '\n'.join([seq[i:i + 60] for i in range(0, len(seq), 60)])
|
|
289
307
|
combined_out_file.write(f">{genome_name}|{seq_id}\n{wrapped_sequence}\n")
|
|
290
308
|
|
|
291
|
-
if
|
|
309
|
+
if not paired_files_found:
|
|
310
|
+
sys.exit("Could not find matching GFF/FASTA files - Please check input directory and -name_split_gff and -name_split_fasta parameters.")
|
|
311
|
+
if translate == False or translate == None:
|
|
292
312
|
#Clean up unused file
|
|
293
|
-
|
|
313
|
+
if combined_out_file.name != combined_out_file_aa.name:
|
|
314
|
+
os.remove(combined_out_file_aa.name)
|
|
294
315
|
|
|
295
316
|
|
|
296
317
|
def read_combined_files(input_dir, name_split, gene_ident, combined_out, translate):
|
|
297
318
|
with open(combined_out, 'w') as combined_out_file, open(combined_out.replace('_dna.fasta','_aa.fasta'), 'w') as combined_out_file_aa:
|
|
298
|
-
|
|
319
|
+
gff_files = glob.glob(os.path.join(input_dir, '*' + name_split))
|
|
320
|
+
if not gff_files:
|
|
321
|
+
sys.exit("Error: No GFF files found - check input directory and -name_split_gff parameter.")
|
|
322
|
+
for gff_file in gff_files:
|
|
299
323
|
genome_name = os.path.basename(gff_file).split(name_split)[0]
|
|
300
324
|
fasta_dict = collections.defaultdict(str)
|
|
301
325
|
gff_features = []
|
|
@@ -352,16 +376,20 @@ def read_combined_files(input_dir, name_split, gene_ident, combined_out, transla
|
|
|
352
376
|
wrapped_sequence = '\n'.join([seq[i:i + 60] for i in range(0, len(seq), 60)])
|
|
353
377
|
combined_out_file.write(f">{genome_name}|{seq_id}\n{wrapped_sequence}\n")
|
|
354
378
|
|
|
355
|
-
if translate == False:
|
|
379
|
+
if translate == False or translate == None:
|
|
356
380
|
#Clean up unused file
|
|
357
|
-
|
|
381
|
+
if combined_out_file.name != combined_out_file_aa.name:
|
|
382
|
+
os.remove(combined_out_file_aa.name)
|
|
358
383
|
|
|
359
384
|
|
|
360
385
|
|
|
361
|
-
def read_fasta_files(input_dir,
|
|
386
|
+
def read_fasta_files(input_dir, name_split_fasta, combined_out, translate):
|
|
362
387
|
with open(combined_out, 'w') as combined_out_file, open(combined_out.replace('_dna.fasta','_aa.fasta'), 'w') as combined_out_file_aa:
|
|
363
|
-
|
|
364
|
-
|
|
388
|
+
fasta_files = glob.glob(os.path.join(input_dir, '*' + name_split_fasta))
|
|
389
|
+
if not fasta_files:
|
|
390
|
+
sys.exit("Error: No GFF files found.")
|
|
391
|
+
for fasta_file in fasta_files:
|
|
392
|
+
genome_name = os.path.basename(fasta_file).split(name_split_fasta)[0]
|
|
365
393
|
fasta_dict = collections.defaultdict(str)
|
|
366
394
|
with open(fasta_file, 'r') as file:
|
|
367
395
|
lines = file.readlines()
|
|
@@ -379,9 +407,10 @@ def read_fasta_files(input_dir, name_split, combined_out, translate):
|
|
|
379
407
|
wrapped_sequence = '\n'.join([seq[i:i + 60] for i in range(0, len(seq), 60)])
|
|
380
408
|
combined_out_file.write(f">{genome_name}|{seq_id}\n{wrapped_sequence}\n")
|
|
381
409
|
|
|
382
|
-
if translate == False:
|
|
410
|
+
if translate == False or translate == None:
|
|
383
411
|
#Clean up unused file
|
|
384
|
-
|
|
412
|
+
if combined_out_file.name != combined_out_file_aa.name:
|
|
413
|
+
os.remove(combined_out_file_aa.name)
|
|
385
414
|
|
|
386
415
|
def write_groups_func(options, output_dir, key_order, cores, sequences,
|
|
387
416
|
pangenome_clusters_First_sequences_sorted, combined_pangenome_clusters_Second_sequences):
|
|
@@ -401,63 +430,65 @@ def write_groups_func(options, output_dir, key_order, cores, sequences,
|
|
|
401
430
|
if not os.path.exists(output_dir):
|
|
402
431
|
os.makedirs(output_dir)
|
|
403
432
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
for
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
433
|
+
for group in options.write_groups.split(','):
|
|
434
|
+
|
|
435
|
+
combined_fasta_filename = os.path.join(output_dir, "combined_group_sequences_" + group + "_dna.fasta")
|
|
436
|
+
|
|
437
|
+
# Open combined FASTA file for writing all sequences
|
|
438
|
+
with open(combined_fasta_filename, 'w') as combined_fasta, open(combined_fasta_filename.replace('_dna.fasta','_aa.fasta'), 'w') as combined_fasta_aa:
|
|
439
|
+
for key_prefix in key_order:
|
|
440
|
+
for key, values in cores.items():
|
|
441
|
+
if any(part in group for part in key.split('_')):
|
|
442
|
+
if key.startswith(key_prefix):
|
|
443
|
+
for value in values:
|
|
444
|
+
output_filename = f"{key}_{value}_dna.fasta"
|
|
445
|
+
if 'First' in key_prefix:
|
|
446
|
+
sequences_to_write = pangenome_clusters_First_sequences_sorted[value]
|
|
447
|
+
else:
|
|
448
|
+
sequences_to_write = combined_pangenome_clusters_Second_sequences[value]
|
|
449
|
+
|
|
450
|
+
# Write individual FASTA file
|
|
451
|
+
with open(os.path.join(output_dir,output_filename), 'w') as outfile, open(os.path.join(output_dir, output_filename.replace('_dna.fasta','_aa.fasta')), 'w') as outfile_aa:
|
|
452
|
+
for header in sequences_to_write:
|
|
453
|
+
if header in sequences:
|
|
454
|
+
sequence = sequences[header]
|
|
455
|
+
wrapped_sequence = wrap_sequence(sequence)
|
|
456
|
+
# Handle Amino Acid Sequences (AA)
|
|
457
|
+
if options.sequence_type == 'AA':
|
|
458
|
+
seq_aa = translate_frame(sequence)
|
|
459
|
+
wrapped_sequence_aa = wrap_sequence(seq_aa)
|
|
460
|
+
# Write individual group file for AA, if option is enabled
|
|
461
|
+
if options.write_individual_groups:
|
|
462
|
+
outfile_aa.write(f">{header}\n")
|
|
463
|
+
outfile_aa.write(f"{wrapped_sequence_aa}\n")
|
|
464
|
+
else:
|
|
465
|
+
os.remove(outfile_aa.name) # Delete individual file if option is disabled
|
|
466
|
+
# Always write to the combined AA file
|
|
467
|
+
combined_fasta_aa.write(f">Group_{value}|{header}\n")
|
|
468
|
+
combined_fasta_aa.write(f"{wrapped_sequence_aa}\n")
|
|
469
|
+
# Handle Nucleotide Sequences
|
|
470
|
+
else:
|
|
471
|
+
# If the option is disabled, delete individual AA file (if created)
|
|
472
|
+
try:
|
|
473
|
+
os.remove(outfile_aa.name) # Ensure outfile_aa is removed when sequence_type isn't 'AA'
|
|
474
|
+
except FileNotFoundError:
|
|
475
|
+
pass
|
|
476
|
+
# Write individual group file for nucleotide sequence, if option is enabled
|
|
430
477
|
if options.write_individual_groups:
|
|
431
|
-
|
|
432
|
-
|
|
478
|
+
outfile.write(f">{header}\n")
|
|
479
|
+
outfile.write(f"{wrapped_sequence}\n")
|
|
433
480
|
else:
|
|
434
|
-
os.remove(
|
|
435
|
-
# Always write to the combined
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
else:
|
|
440
|
-
# If the option is disabled, delete individual AA file (if created)
|
|
441
|
-
try:
|
|
442
|
-
os.remove(outfile_aa.name) # Ensure outfile_aa is removed when sequence_type isn't 'AA'
|
|
443
|
-
except FileNotFoundError:
|
|
444
|
-
pass
|
|
445
|
-
# Write individual group file for nucleotide sequence, if option is enabled
|
|
446
|
-
if options.write_individual_groups:
|
|
447
|
-
outfile.write(f">{header}\n")
|
|
448
|
-
outfile.write(f"{wrapped_sequence}\n")
|
|
481
|
+
os.remove(outfile.name) # Delete individual file if option is disabled
|
|
482
|
+
# Always write to the combined nucleotide file
|
|
483
|
+
combined_fasta.write(f">Group_{value}|{header}\n")
|
|
484
|
+
combined_fasta.write(f"{wrapped_sequence}\n")
|
|
485
|
+
|
|
449
486
|
else:
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
else:
|
|
456
|
-
if options.verbose == True:
|
|
457
|
-
print(f"Sequence {header} not found in original_fasta file.")
|
|
458
|
-
if options.sequence_type != 'AA':
|
|
459
|
-
#Clean up unused file
|
|
460
|
-
os.remove(combined_fasta_aa.name)
|
|
487
|
+
if options.verbose == True:
|
|
488
|
+
print(f"Sequence {header} not found in original_fasta file.")
|
|
489
|
+
if options.sequence_type != 'AA':
|
|
490
|
+
#Clean up unused file
|
|
491
|
+
os.remove(combined_fasta_aa.name)
|
|
461
492
|
print(f"Combined FASTA file saved to: {combined_fasta_filename}")
|
|
462
493
|
|
|
463
494
|
|
|
@@ -539,22 +570,23 @@ def process_gene_groups(options, group_directory, sub_group_directory, paralog_g
|
|
|
539
570
|
else:
|
|
540
571
|
affix = '_dna.fasta'
|
|
541
572
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
573
|
+
if options.align_core == True:
|
|
574
|
+
# Iterate over each gene family file
|
|
575
|
+
for gene_file in os.listdir(group_directory):
|
|
576
|
+
if gene_file.endswith(affix) and not gene_file.startswith('combined_group_sequences'):
|
|
577
|
+
#print(gene_file)
|
|
578
|
+
current_group = int(gene_file.split('_')[3].split('.')[0])
|
|
579
|
+
gene_path = os.path.join(group_directory, gene_file)
|
|
580
|
+
|
|
581
|
+
# Check for matching group in paralog_groups
|
|
582
|
+
if sub_group_directory and paralog_groups and '>Group_'+str(current_group) in paralog_groups:
|
|
583
|
+
for subgroup, size in enumerate(paralog_groups['>Group_' + str(current_group)]['sizes']):
|
|
584
|
+
if size >= threshold_size:
|
|
585
|
+
gene_path = os.path.join(sub_group_directory,f"Group_{current_group}_subgroup_{subgroup}{affix}")
|
|
586
|
+
concatenated_sequences = perform_alignment(gene_path, group_directory, gene_file, options, concatenated_sequences, True)
|
|
555
587
|
|
|
556
|
-
|
|
557
|
-
|
|
588
|
+
else:
|
|
589
|
+
concatenated_sequences = perform_alignment(gene_path, group_directory, gene_file, options, concatenated_sequences, False)
|
|
558
590
|
|
|
559
591
|
|
|
560
592
|
# Write the concatenated sequences to the output file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PyamilySeq
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: PyamilySeq - A a tool to investigate sequence-based gene groups identified by clustering methods such as CD-HIT, DIAMOND, BLAST or MMseqs2.
|
|
5
5
|
Home-page: https://github.com/NickJD/PyamilySeq
|
|
6
6
|
Author: Nicholas Dimonaco
|
|
@@ -45,7 +45,7 @@ To update to the newest version add '-U' to end of the pip install command.
|
|
|
45
45
|
```commandline
|
|
46
46
|
usage: PyamilySeq.py [-h] {Full,Partial} ...
|
|
47
47
|
|
|
48
|
-
PyamilySeq v1.0
|
|
48
|
+
PyamilySeq v1.1.0: A tool for gene clustering and analysis.
|
|
49
49
|
|
|
50
50
|
positional arguments:
|
|
51
51
|
{Full,Partial} Choose a mode: 'Full' or 'Partial'.
|
|
@@ -58,24 +58,24 @@ options:
|
|
|
58
58
|
```
|
|
59
59
|
### 'Full Mode': Will conduct clustering of sequences with CD-HIT as part of PyamilySeq run
|
|
60
60
|
```
|
|
61
|
-
PyamilySeq Full -output_dir .../PyamilySeq_10_AA_90_80_Full_GFFs -input_type combined -input_dir .../genomes/ -
|
|
61
|
+
PyamilySeq Full -output_dir .../PyamilySeq_10_AA_90_80_Full_GFFs -input_type combined -input_dir .../genomes/ -name_split_gff _combined.gff3
|
|
62
62
|
```
|
|
63
63
|
### 'Partial Mode': Will process the output of a sequence clustering from MMseqs, BLAST, DIAMOND etc.
|
|
64
64
|
```
|
|
65
|
-
PyamilySeq Partial -clustering_format CD-HIT -cluster_file .../all_10_combined_pep_CD-HIT_90_80.clstr -original_fasta .../all_10_combined_pep.fasta -output_dir .../PyamilySeq_10_AA_90_80_Partial-
|
|
65
|
+
PyamilySeq Partial -clustering_format CD-HIT -cluster_file .../all_10_combined_pep_CD-HIT_90_80.clstr -original_fasta .../all_10_combined_pep.fasta -output_dir .../PyamilySeq_10_AA_90_80_Partial -write_groups 99 -align
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
#### Note: using a '-clustering_format' other than the default CD-HIT, requires input to be two in two columns as below (Same format as MMseqs2 tsv and BLAST outfmt 6) - Genome name and sequence name are separated by '|'.
|
|
70
70
|
```
|
|
71
|
-
Escherichia_coli_110957|
|
|
72
|
-
Escherichia_coli_110957|
|
|
73
|
-
Escherichia_coli_110957|
|
|
74
|
-
Escherichia_coli_110957|
|
|
71
|
+
Escherichia_coli_110957|ENSB_lL-zIKt-gh0oSno Escherichia_coli_110957|ENSB_lL-zIKt-gh0oSno
|
|
72
|
+
Escherichia_coli_110957|ENSB_lL-zIKt-gh0oSno Escherichia_coli_113290|ENSB_2fj4rJ8e8Z9PNdX
|
|
73
|
+
Escherichia_coli_110957|ENSB_lL-zIKt-gh0oSno Escherichia_coli_b185|ENSB_G_PVe28-ej8q-3S
|
|
74
|
+
Escherichia_coli_110957|ENSB_TIZS9kbTvShDvyX Escherichia_coli_110957|ENSB_TIZS9kbTvShDvyX
|
|
75
75
|
```
|
|
76
76
|
### Example output:
|
|
77
77
|
```
|
|
78
|
-
Running PyamilySeq v1.0
|
|
78
|
+
Running PyamilySeq v1.1.0
|
|
79
79
|
Calculating Groups
|
|
80
80
|
Number of Genomes: 10
|
|
81
81
|
Gene Groups
|
|
@@ -92,51 +92,11 @@ Thank you for using PyamilySeq -- A detailed user manual can be found at https:/
|
|
|
92
92
|
Please report any issues to: https://github.com/NickJD/PyamilySeq/issues
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
[//]: # (## Genus mode: )
|
|
96
|
-
|
|
97
|
-
[//]: # (### In addition to "Species mode" (see above) which reports gene groups the same as pangenome tools such as Roary and Panaroo, Genus mode reports gene groups identified across multiple genera.)
|
|
98
|
-
|
|
99
|
-
[//]: # (#### Example:)
|
|
100
|
-
|
|
101
|
-
[//]: # (```)
|
|
102
|
-
|
|
103
|
-
[//]: # (PyamilySeq -run_mode Partial -group_mode Genus -clustering_format CD-HIT -output_dir .../test_data/genus/testing/)
|
|
104
|
-
|
|
105
|
-
[//]: # ( -cluster_file .../test_data/genus/CD-HIT/combined_cds_cd-hit_80_60.clstr -gpa )
|
|
106
|
-
|
|
107
|
-
[//]: # (```)
|
|
108
|
-
|
|
109
|
-
[//]: # (```commandline)
|
|
110
|
-
|
|
111
|
-
[//]: # (Running PyamilySeq v1.0.1)
|
|
112
|
-
|
|
113
|
-
[//]: # (Calculating Groups)
|
|
114
|
-
|
|
115
|
-
[//]: # (Genus Groups:)
|
|
116
|
-
[//]: # (First_genera_1: 28549)
|
|
117
|
-
|
|
118
|
-
[//]: # (First_genera_2: 12)
|
|
119
|
-
|
|
120
|
-
[//]: # (First_genera_3: 0)
|
|
121
|
-
|
|
122
|
-
[//]: # (First_genera_>: 0)
|
|
123
|
-
|
|
124
|
-
[//]: # (Total Number of First Gene Groups (Including Singletons): 28561)
|
|
125
|
-
|
|
126
|
-
[//]: # (Outputting gene_presence_absence file)
|
|
127
|
-
|
|
128
|
-
[//]: # (Thank you for using PyamilySeq -- A detailed user manual can be found at https://github.com/NickJD/PyamilySeq)
|
|
129
|
-
|
|
130
|
-
[//]: # (Please report any issues to: https://github.com/NickJD/PyamilySeq/issues)
|
|
131
|
-
|
|
132
|
-
[//]: # (#####)
|
|
133
|
-
|
|
134
|
-
[//]: # (```)
|
|
135
95
|
|
|
136
96
|
## Reclustering:
|
|
137
97
|
### Reclustering can be used to see where additional sequences/genes lay in relation to a contemporary pangenome/gene grouping.
|
|
138
98
|
```
|
|
139
|
-
PyamilySeq Partial -clustering_format CD-HIT -cluster_file .../all_10_combined_pep_CD-HIT_90_80.clstr -reclustered .../all_10_combined_pep_CD-HIT_90_80_AND_StORFs_CD-HIT_90_80.clstr -original_fasta .../all_10_combined_pep_AND_StORFs.fasta -output_dir .../PyamilySeq_10_AA_90_80_Partial_Reclustered_StORFs -
|
|
99
|
+
PyamilySeq Partial -clustering_format CD-HIT -cluster_file .../all_10_combined_pep_CD-HIT_90_80.clstr -reclustered .../all_10_combined_pep_CD-HIT_90_80_AND_StORFs_CD-HIT_90_80.clstr -original_fasta .../all_10_combined_pep_AND_StORFs.fasta -output_dir .../PyamilySeq_10_AA_90_80_Partial_Reclustered_StORFs -write_groups 99 -align
|
|
140
100
|
```
|
|
141
101
|
#### As can be seen below, the additional sequences recovered by the StORF-Reporter annotation tool have 'extended' contemporary or created entirely new gene groups. 'First' corresponds to the groups identified from the first clustering round and 'Second' for the second. In 'reclustering' mode, First_core_# groups are unaffected thus retaining the initial grouping information.
|
|
142
102
|
```commandline
|
|
@@ -170,25 +130,22 @@ Total Number of First Gene Groups That Had Additional Second Sequences But Not N
|
|
|
170
130
|
## PyamilySeq is separated into two main 'run modes', Full and Partial. They each have their own set of required and optional arguments.
|
|
171
131
|
### PyamilySeq - Full Menu:
|
|
172
132
|
```
|
|
173
|
-
usage: PyamilySeq.py Full [-h] -output_dir OUTPUT_DIR -input_type {separate,combined,fasta} [-input_dir INPUT_DIR]
|
|
174
|
-
[-
|
|
175
|
-
[-c PIDENT] [-s LEN_DIFF] [-fast_mode] [-group_mode {Species,Genus}] [-species_groups SPECIES_GROUPS]
|
|
176
|
-
[-genus_groups GENUS_GROUPS] [-w WRITE_GROUPS] [-wi] [-a] [-align_aa] [-no_gpa] [-M MEM] [-T THREADS]
|
|
177
|
-
[-verbose] [-v]
|
|
133
|
+
usage: PyamilySeq.py Full [-h] -output_dir OUTPUT_DIR -input_type {separate,combined,fasta} [-input_dir INPUT_DIR] [-input_fasta INPUT_FASTA] [-name_split_gff NAME_SPLIT_GFF] [-name_split_fasta NAME_SPLIT_FASTA] [-sequence_type {AA,DNA}] [-gene_ident GENE_IDENT] [-c PIDENT] [-s LEN_DIFF] [-fast_mode]
|
|
134
|
+
[-group_mode {Species,Genus}] [-species_groups SPECIES_GROUPS] [-genus_groups GENUS_GROUPS] [-write_groups WRITE_GROUPS] [-write_individual_groups] [-align] [-align_aa] [-no_gpa] [-M MEM] [-T THREADS] [-verbose] [-v]
|
|
178
135
|
|
|
179
136
|
options:
|
|
180
137
|
-h, --help show this help message and exit
|
|
181
138
|
-output_dir OUTPUT_DIR
|
|
182
139
|
Directory for all output files.
|
|
183
140
|
-input_type {separate,combined,fasta}
|
|
184
|
-
Type of input files: 'separate' for matching FASTA and GFF files, 'combined' for GFF+FASTA, or 'fasta'
|
|
185
|
-
for a prepared FASTA file.
|
|
141
|
+
Type of input files: 'separate' for matching FASTA and GFF files, 'combined' for GFF+FASTA, or 'fasta' for a prepared FASTA file.
|
|
186
142
|
-input_dir INPUT_DIR Directory containing GFF/FASTA files - Use with -input_type separate/combined.
|
|
187
143
|
-input_fasta INPUT_FASTA
|
|
188
144
|
Input FASTA file - Use with - input_type fasta.
|
|
189
|
-
-
|
|
190
|
-
Substring to split filenames and extract genome names (e.g., '_combined.gff3') - Use with -input_type
|
|
191
|
-
|
|
145
|
+
-name_split_gff NAME_SPLIT_GFF
|
|
146
|
+
Substring to split filenames and extract genome names for gff files (e.g., '_combined.gff3') - Use with -input_type separate/combined.
|
|
147
|
+
-name_split_fasta NAME_SPLIT_FASTA
|
|
148
|
+
Substring to split filenames and extract genome names for fasta files if named differently to paired gff files (e.g., '_dna.fasta') - Use with -input_type separate/combined.
|
|
192
149
|
-sequence_type {AA,DNA}
|
|
193
150
|
Clustering mode: 'DNA' or 'AA'.
|
|
194
151
|
-gene_ident GENE_IDENT
|
|
@@ -202,21 +159,23 @@ options:
|
|
|
202
159
|
Gene groupings for 'Species' mode (default: '99,95,15').
|
|
203
160
|
-genus_groups GENUS_GROUPS
|
|
204
161
|
Gene groupings for 'Genus' mode (default: '1-10').
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
-
|
|
162
|
+
-write_groups WRITE_GROUPS
|
|
163
|
+
Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95'). - triggers '-wig'.
|
|
164
|
+
-write_individual_groups
|
|
165
|
+
Output individual FASTA files for each group.
|
|
166
|
+
-align Align and concatenate sequences for 'core' groups specified with '-w'.
|
|
208
167
|
-align_aa Align sequences as amino acids.
|
|
209
168
|
-no_gpa Skip creation of gene_presence_absence.csv.
|
|
210
169
|
-M MEM Memory allocation for clustering (MB) - CD-HIT parameter '-M'.
|
|
211
170
|
-T THREADS Number of threads for clustering/alignment - CD-HIT parameter '-T' | MAFFT parameter '--thread'.
|
|
212
171
|
-verbose Print verbose output.
|
|
213
172
|
-v, --version Print version number and exit.
|
|
173
|
+
|
|
214
174
|
```
|
|
215
175
|
### PyamilySeq - Partial Menu:
|
|
216
176
|
```commandline
|
|
217
|
-
usage: PyamilySeq.py Partial [-h] -clustering_format {CD-HIT,MMseqs,BLAST} -cluster_file CLUSTER_FILE -original_fasta ORIGINAL_FASTA -output_dir OUTPUT_DIR
|
|
218
|
-
[-
|
|
219
|
-
[-w WRITE_GROUPS] [-wi] [-a] [-align_aa] [-no_gpa] [-M MEM] [-T THREADS] [-verbose] [-v]
|
|
177
|
+
usage: PyamilySeq.py Partial [-h] -clustering_format {CD-HIT,MMseqs,BLAST} -cluster_file CLUSTER_FILE -original_fasta ORIGINAL_FASTA -output_dir OUTPUT_DIR [-reclustered RECLUSTERED] [-seq_tag SEQUENCE_TAG] [-group_mode {Species,Genus}] [-species_groups SPECIES_GROUPS] [-genus_groups GENUS_GROUPS]
|
|
178
|
+
[-write_groups WRITE_GROUPS] [-write_individual_groups] [-align] [-align_aa] [-no_gpa] [-M MEM] [-T THREADS] [-verbose] [-v]
|
|
220
179
|
|
|
221
180
|
options:
|
|
222
181
|
-h, --help show this help message and exit
|
|
@@ -238,9 +197,11 @@ options:
|
|
|
238
197
|
Gene groupings for 'Species' mode (default: '99,95,15').
|
|
239
198
|
-genus_groups GENUS_GROUPS
|
|
240
199
|
Gene groupings for 'Genus' mode (default: '1-10').
|
|
241
|
-
-
|
|
242
|
-
|
|
243
|
-
-
|
|
200
|
+
-write_groups WRITE_GROUPS
|
|
201
|
+
Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95'). - triggers '-wig'.
|
|
202
|
+
-write_individual_groups
|
|
203
|
+
Output individual FASTA files for each group.
|
|
204
|
+
-align Align and concatenate sequences for 'core' groups specified with '-w'.
|
|
244
205
|
-align_aa Align sequences as amino acids.
|
|
245
206
|
-no_gpa Skip creation of gene_presence_absence.csv.
|
|
246
207
|
-M MEM Memory allocation for clustering (MB) - CD-HIT parameter '-M'.
|
|
@@ -253,14 +214,13 @@ options:
|
|
|
253
214
|
## Seq-Combiner: This tool is provided to enable the pre-processing of multiple GFF/FASTA files together ready to be clustered by the user.
|
|
254
215
|
### Example:
|
|
255
216
|
```bash
|
|
256
|
-
Seq-Combiner -input_dir .../test_data/genomes -
|
|
217
|
+
Seq-Combiner -input_dir .../test_data/genomes -name_split_gff .gff3 -output_dir .../test_data/genomes -output_name combine_fasta_seqs.fa -input_type combined
|
|
257
218
|
```
|
|
258
219
|
### Seq-Combiner Menu:
|
|
259
220
|
```
|
|
260
|
-
usage: Seq_Combiner.py [-h] -input_dir INPUT_DIR -input_type {separate,combined,fasta} -
|
|
261
|
-
OUTPUT_FILE [-gene_ident GENE_IDENT] [-translate] [-v]
|
|
221
|
+
usage: Seq_Combiner.py [-h] -input_dir INPUT_DIR -input_type {separate,combined,fasta} [-name_split_gff NAME_SPLIT_GFF] [-name_split_fasta NAME_SPLIT_FASTA] -output_dir OUTPUT_DIR -output_name OUTPUT_FILE [-gene_ident GENE_IDENT] [-translate] [-v]
|
|
262
222
|
|
|
263
|
-
PyamilySeq v1.0
|
|
223
|
+
PyamilySeq v1.1.0: Seq-Combiner - A tool to extract sequences from GFF/FASTA files and prepare them for PyamilySeq.
|
|
264
224
|
|
|
265
225
|
options:
|
|
266
226
|
-h, --help show this help message and exit
|
|
@@ -268,10 +228,11 @@ options:
|
|
|
268
228
|
Required Arguments:
|
|
269
229
|
-input_dir INPUT_DIR Directory location where the files are located.
|
|
270
230
|
-input_type {separate,combined,fasta}
|
|
271
|
-
Type of input files: "separate" for separate FASTA and GFF files, "combined" for GFF files with embedded FASTA sequences and "fasta"
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
231
|
+
Type of input files: "separate" for separate FASTA and GFF files, "combined" for GFF files with embedded FASTA sequences and "fasta" for combining multiple FASTA files together.
|
|
232
|
+
-name_split_gff NAME_SPLIT_GFF
|
|
233
|
+
Substring used to split the filename and extract the genome name ('_combined.gff3' or '.gff'). - Not needed with -input_type fasta
|
|
234
|
+
-name_split_fasta NAME_SPLIT_FASTA
|
|
235
|
+
Substring used to split filenames and extract genome names for fasta files if named differently to paired gff files (e.g., '_dna.fasta').
|
|
275
236
|
-output_dir OUTPUT_DIR
|
|
276
237
|
Directory for all output files.
|
|
277
238
|
-output_name OUTPUT_FILE
|
|
@@ -279,19 +240,19 @@ Required Arguments:
|
|
|
279
240
|
|
|
280
241
|
Optional Arguments:
|
|
281
242
|
-gene_ident GENE_IDENT
|
|
282
|
-
Default - "CDS": Identifier used for extraction of sequences such as
|
|
283
|
-
|
|
284
|
-
-translate Default - False: Translate extracted sequences to their AA counterpart?
|
|
243
|
+
Default - "CDS": Identifier used for extraction of sequences such as "misc_RNA,gene,mRNA,CDS,rRNA,tRNA,tmRNA,CRISPR,ncRNA,regulatory_region,oriC,pseudo" - Not compatible with "fasta" input mode.
|
|
244
|
+
-translate Default - False: Translate extracted sequences to their AA counterpart? - appends _aa.fasta to given output_name
|
|
285
245
|
|
|
286
246
|
Misc Arguments:
|
|
287
247
|
-v, --version Print out version number and exit
|
|
288
248
|
|
|
249
|
+
|
|
289
250
|
```
|
|
290
251
|
|
|
291
252
|
## Group-Splitter: This tool can split multi-copy gene groups using CD-HIT after initial PyamilySeq analysis.
|
|
292
253
|
### Example:
|
|
293
254
|
```bash
|
|
294
|
-
Group-Splitter -genome_num
|
|
255
|
+
Group-Splitter -genome_num 10 -input_fasta .../test/species/ -output_dir .../test/species/ -sequence_type AA
|
|
295
256
|
```
|
|
296
257
|
### Group-Splitter Menu:
|
|
297
258
|
```
|
|
@@ -302,7 +263,7 @@ usage: Group_Splitter.py [-h] -input_fasta INPUT_FASTA -sequence_type {AA,DNA}
|
|
|
302
263
|
[-M CLUSTERING_MEMORY] [-no_delete_temp_files]
|
|
303
264
|
[-verbose] [-v]
|
|
304
265
|
|
|
305
|
-
PyamilySeq v1.0
|
|
266
|
+
PyamilySeq v1.1.0: Group-Splitter - A tool to split multi-copy gene groups
|
|
306
267
|
identified by PyamilySeq.
|
|
307
268
|
|
|
308
269
|
options:
|
|
@@ -348,14 +309,14 @@ Misc Parameters:
|
|
|
348
309
|
## Cluster-Summary menu: This tool can be used to summarise CD-HIT .clstr files:
|
|
349
310
|
### Example:
|
|
350
311
|
```bash
|
|
351
|
-
Cluster-Summary -genome_num
|
|
312
|
+
Cluster-Summary -genome_num 10 -input_clstr .../test_data/species/E-coli/E-coli_extracted_pep_cd-hit_80.clstr -output_tsv .../test_data/species/E-coli/E-coli_extracted_pep_cd-hit_80_Summary.tsv
|
|
352
313
|
```
|
|
353
314
|
### Cluster-Summary Menu:
|
|
354
315
|
```
|
|
355
316
|
usage: Cluster_Summary.py [-h] -input_clstr INPUT_CLSTR -output OUTPUT -genome_num GENOME_NUM
|
|
356
317
|
[-output_dir OUTPUT_DIR] [-verbose] [-v]
|
|
357
318
|
|
|
358
|
-
PyamilySeq v1.0
|
|
319
|
+
PyamilySeq v1.1.0: Cluster-Summary - A tool to summarise CD-HIT clustering files.
|
|
359
320
|
|
|
360
321
|
options:
|
|
361
322
|
-h, --help show this help message and exit
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
PyamilySeq/Cluster_Summary.py,sha256=xkzkC9mHRqHNm2bp0gcBWOobKTabltBrVv6ze4nikyg,6982
|
|
2
|
+
PyamilySeq/Group_Extractor.py,sha256=oe2VmOVxdvTmAcy8NKwD1F27IdN2utAfczxsyxg96yc,2898
|
|
3
|
+
PyamilySeq/Group_Sizes.py,sha256=3snkAN19o3Y4IY6IqSim1qy415FfQe1Wb8vzWTKF0Wo,3028
|
|
4
|
+
PyamilySeq/Group_Splitter.py,sha256=OcMj9GnAyybs_DaNKRyvfL_nl2dB2gUI4BD_EQrBbWo,25653
|
|
5
|
+
PyamilySeq/PyamilySeq.py,sha256=iyLU8YYn06ppCBCb-HaARm0ez_uagkj4FRtqr3pFu9Q,17396
|
|
6
|
+
PyamilySeq/PyamilySeq_Genus.py,sha256=mBZNTWWk4a_5gsHzq0cG82Qck-SL9Xgg6jpByH6oKuk,12414
|
|
7
|
+
PyamilySeq/PyamilySeq_Species.py,sha256=yyMHBQhTq1yFUKbiba6vL9nYJ4rlKsmS30hQNimGEB8,16120
|
|
8
|
+
PyamilySeq/Seq_Combiner.py,sha256=wusCDrGwcVqQw3h5iPSY0_E5sauRFNHj0bXMBtELpl0,4700
|
|
9
|
+
PyamilySeq/Seq_Extractor.py,sha256=KMR0KcTJzrh99HcBN4qb76R2FuBvpYCDf4NwkmwhTPU,2870
|
|
10
|
+
PyamilySeq/Seq_Finder.py,sha256=ht-fSQ_opWKydcoWI9D3nTwLt6Rpgevnf2y0KxVjw4M,1881
|
|
11
|
+
PyamilySeq/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
PyamilySeq/clusterings.py,sha256=9fXnFZSypeZKtJK8OYONQKVpvLoeJCSxx2BRo5Vir38,22355
|
|
13
|
+
PyamilySeq/constants.py,sha256=7zjA69Blx4ycagDKCvaKdVuXidVVwu7adnmgm53_CTI,31
|
|
14
|
+
PyamilySeq/utils.py,sha256=EwZQP5eFaXiXVGw0Vckhu9tJkm8SOKAgGh7-JnIu_j4,29355
|
|
15
|
+
pyamilyseq-1.1.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
16
|
+
pyamilyseq-1.1.0.dist-info/METADATA,sha256=f8hZWEdD06WYoflfPls02q_6FVFYL18np1BGzWXwlGA,17957
|
|
17
|
+
pyamilyseq-1.1.0.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
|
|
18
|
+
pyamilyseq-1.1.0.dist-info/entry_points.txt,sha256=Qao6g8F37k35MQFkUpGt9xoozRBaTkIKUptXWAUs5-E,554
|
|
19
|
+
pyamilyseq-1.1.0.dist-info/top_level.txt,sha256=J6JhugUQTq4rq96yibAlQu3o4KCM9WuYfqr3w1r119M,11
|
|
20
|
+
pyamilyseq-1.1.0.dist-info/RECORD,,
|
|
@@ -5,3 +5,9 @@ PyamilySeq = PyamilySeq.PyamilySeq:main
|
|
|
5
5
|
Seq-Combiner = PyamilySeq.Seq_Combiner:main
|
|
6
6
|
Seq-Extractor = PyamilySeq.Seq_Extractor:main
|
|
7
7
|
Seq-Finder = PyamilySeq.Seq_Finder:main
|
|
8
|
+
cluster-summary = PyamilySeq.Cluster_Summary:main
|
|
9
|
+
group-splitter = PyamilySeq.Group_Splitter:main
|
|
10
|
+
pyamilyseq = PyamilySeq.PyamilySeq:main
|
|
11
|
+
seq-combiner = PyamilySeq.Seq_Combiner:main
|
|
12
|
+
seq-extractor = PyamilySeq.Seq_Extractor:main
|
|
13
|
+
seq-finder = PyamilySeq.Seq_Finder:main
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
PyamilySeq/Cluster_Summary.py,sha256=xkzkC9mHRqHNm2bp0gcBWOobKTabltBrVv6ze4nikyg,6982
|
|
2
|
-
PyamilySeq/Group_Splitter.py,sha256=OcMj9GnAyybs_DaNKRyvfL_nl2dB2gUI4BD_EQrBbWo,25653
|
|
3
|
-
PyamilySeq/PyamilySeq.py,sha256=QjaBK6t_CYlE1ojIhH1k_2LJw97oT6UblA1dk-3bcDk,16854
|
|
4
|
-
PyamilySeq/PyamilySeq_Genus.py,sha256=RdW-WU07fhXSi-mWfhXkUfffaQWCJ3UZmJBILUcGJG8,12414
|
|
5
|
-
PyamilySeq/PyamilySeq_Species.py,sha256=0i7cW14UyRwCTbuxFgp8heH4xadbUHRja4dsPrBj_Ms,16119
|
|
6
|
-
PyamilySeq/Seq_Combiner.py,sha256=V91AMp0VwObQe4x9kOCNsvwiUJ9L64y9gdcC22-vvtY,3530
|
|
7
|
-
PyamilySeq/Seq_Extractor.py,sha256=KMR0KcTJzrh99HcBN4qb76R2FuBvpYCDf4NwkmwhTPU,2870
|
|
8
|
-
PyamilySeq/Seq_Finder.py,sha256=ht-fSQ_opWKydcoWI9D3nTwLt6Rpgevnf2y0KxVjw4M,1881
|
|
9
|
-
PyamilySeq/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
PyamilySeq/clusterings.py,sha256=9fXnFZSypeZKtJK8OYONQKVpvLoeJCSxx2BRo5Vir38,22355
|
|
11
|
-
PyamilySeq/constants.py,sha256=vV8JkmE7De4xQucZiXP1sQm_kHAM74Ua5KOOp2ULeYE,31
|
|
12
|
-
PyamilySeq/utils.py,sha256=819POQB1h8Wm35XTZJa_GETealGjJGs-SBSpnj4eTwg,27226
|
|
13
|
-
PyamilySeq-1.0.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
14
|
-
PyamilySeq-1.0.1.dist-info/METADATA,sha256=TINmitLl74gWpOjLOQtbXxo8gjklnH7LUmFpluj6xr0,18363
|
|
15
|
-
PyamilySeq-1.0.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
16
|
-
PyamilySeq-1.0.1.dist-info/entry_points.txt,sha256=FhxILgre1lrvXRO5nod3UMcHmDeiutUwpU05uLNj66M,286
|
|
17
|
-
PyamilySeq-1.0.1.dist-info/top_level.txt,sha256=J6JhugUQTq4rq96yibAlQu3o4KCM9WuYfqr3w1r119M,11
|
|
18
|
-
PyamilySeq-1.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|