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.
@@ -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("-name_split", required=False,
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("-w", default=None, dest="write_groups", required=False,
95
- help="Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95').")
96
- subparser.add_argument("-wi", action="store_true", dest="write_individual_groups", required=False,
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("-a", action="store_true", dest="align_core", required=False,
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.name_split])
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', 'name_split', 'clustering_format', 'pident', 'len_diff'] if
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.name_split, options.gene_ident, combined_out_file, translate)
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.name_split, options.gene_ident, combined_out_file, translate)
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
@@ -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)
@@ -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 += ',"'+'\t'.join(tmp_list)+'"'
35
+ full_out += ',"'+' '.join(tmp_list)+'"'
36
36
  else:
37
37
  full_out = ',""'
38
38
  gpa_outfile.write(full_out)
@@ -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("-name_split", action="store", dest="name_split",
26
- help="substring used to split the filename and extract the genome name ('_combined.gff3' or '.gff').",
27
- required=True)
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 (without .fasta).",
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
- combined_out_file = os.path.join(output_path, options.output_file + '.fasta')
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.name_split, options.gene_ident, combined_out_file, options.translate)
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.name_split, options.gene_ident, combined_out_file, options.translate)
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.name_split, combined_out_file, options.translate)
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'
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, name_split, gene_ident, combined_out, translate):
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
- for gff_file in glob.glob(os.path.join(input_dir, '*' + name_split)):
234
- genome_name = os.path.basename(gff_file).split(name_split)[0]
235
- corresponding_fasta_file = os.path.splitext(gff_file)[0] + '.fa'
236
- if not os.path.exists(corresponding_fasta_file):
237
- continue
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 translate == False:
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
- os.remove(combined_out_file_aa.name)
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
- for gff_file in glob.glob(os.path.join(input_dir, '*' + name_split)):
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
- os.remove(combined_out_file_aa.name)
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, name_split, combined_out, translate):
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
- for fasta_file in glob.glob(os.path.join(input_dir, '*' + name_split)):
364
- genome_name = os.path.basename(fasta_file).split(name_split)[0]
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
- os.remove(combined_out_file_aa)
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
- combined_fasta_filename = os.path.join(output_dir, "combined_group_sequences_dna.fasta")
405
-
406
- # Open combined FASTA file for writing all sequences
407
- with open(combined_fasta_filename, 'w') as combined_fasta, open(combined_fasta_filename.replace('_dna.fasta','_aa.fasta'), 'w') as combined_fasta_aa:
408
- for key_prefix in key_order:
409
- for key, values in cores.items():
410
- if any(part in options.write_groups.split(',') for part in key.split('_')):
411
- if key.startswith(key_prefix):
412
- for value in values:
413
- output_filename = f"{key}_{value}_dna.fasta"
414
- if 'First' in key_prefix:
415
- sequences_to_write = pangenome_clusters_First_sequences_sorted[value]
416
- else:
417
- sequences_to_write = combined_pangenome_clusters_Second_sequences[value]
418
-
419
- # Write individual FASTA file
420
- 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:
421
- for header in sequences_to_write:
422
- if header in sequences:
423
- sequence = sequences[header]
424
- wrapped_sequence = wrap_sequence(sequence)
425
- # Handle Amino Acid Sequences (AA)
426
- if options.sequence_type == 'AA':
427
- seq_aa = translate_frame(sequence)
428
- wrapped_sequence_aa = wrap_sequence(seq_aa)
429
- # Write individual group file for AA, if option is enabled
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
- outfile_aa.write(f">{header}\n")
432
- outfile_aa.write(f"{wrapped_sequence_aa}\n")
478
+ outfile.write(f">{header}\n")
479
+ outfile.write(f"{wrapped_sequence}\n")
433
480
  else:
434
- os.remove(outfile_aa.name) # Delete individual file if option is disabled
435
- # Always write to the combined AA file
436
- combined_fasta_aa.write(f">Group_{value}|{header}\n")
437
- combined_fasta_aa.write(f"{wrapped_sequence_aa}\n")
438
- # Handle Nucleotide Sequences
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
- os.remove(outfile.name) # Delete individual file if option is disabled
451
- # Always write to the combined nucleotide file
452
- combined_fasta.write(f">Group_{value}|{header}\n")
453
- combined_fasta.write(f"{wrapped_sequence}\n")
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
- # Iterate over each gene family file
543
- for gene_file in os.listdir(group_directory):
544
- if gene_file.endswith(affix) and not gene_file.startswith('combined_group_sequences'):
545
- #print(gene_file)
546
- current_group = int(gene_file.split('_')[3].split('.')[0])
547
- gene_path = os.path.join(group_directory, gene_file)
548
-
549
- # Check for matching group in paralog_groups
550
- if sub_group_directory and paralog_groups and '>Group_'+str(current_group) in paralog_groups:
551
- for subgroup, size in enumerate(paralog_groups['>Group_' + str(current_group)]['sizes']):
552
- if size >= threshold_size:
553
- gene_path = os.path.join(sub_group_directory,f"Group_{current_group}_subgroup_{subgroup}{affix}")
554
- concatenated_sequences = perform_alignment(gene_path, group_directory, gene_file, options, concatenated_sequences, True)
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
- else:
557
- concatenated_sequences = perform_alignment(gene_path, group_directory, gene_file, options, concatenated_sequences, False)
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
1
+ Metadata-Version: 2.2
2
2
  Name: PyamilySeq
3
- Version: 1.0.1
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.1: A tool for gene clustering and analysis.
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/ -name_split _combined.gff3
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-w 99 -a
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|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
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.1
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 -w 99 -a
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
- [-input_fasta INPUT_FASTA] [-name_split NAME_SPLIT] [-sequence_type {AA,DNA}] [-gene_ident GENE_IDENT]
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
- -name_split NAME_SPLIT
190
- Substring to split filenames and extract genome names (e.g., '_combined.gff3') - Use with -input_type
191
- separate/combined.
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
- -w WRITE_GROUPS Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95').
206
- -wi Output individual FASTA files for each group.
207
- -a Align and concatenate sequences for 'core' groups.
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
- [-reclustered RECLUSTERED] [-seq_tag SEQUENCE_TAG] [-group_mode {Species,Genus}] [-species_groups SPECIES_GROUPS] [-genus_groups GENUS_GROUPS]
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
- -w WRITE_GROUPS Output gene groups as a single FASTA file (specify levels: e.g., '-w 99,95').
242
- -wi Output individual FASTA files for each group.
243
- -a Align and concatenate sequences for 'core' groups.
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 -name_split .gff3 -output_dir .../test_data/genomes -output_name combine_fasta_seqs.fa -input_type combined
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} -name_split NAME_SPLIT -output_dir OUTPUT_DIR -output_name
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.1: Seq-Combiner - A tool to extract sequences from GFF/FASTA files and prepare them for PyamilySeq.
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
- for combining multiple FASTA files together.
273
- -name_split NAME_SPLIT
274
- substring used to split the filename and extract the genome name ('_combined.gff3' or '.gff').
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
- "misc_RNA,gene,mRNA,CDS,rRNA,tRNA,tmRNA,CRISPR,ncRNA,regulatory_region,oriC,pseudo" - Not compatible with "fasta" input mode.
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 74 -input_fasta .../test/species/ -output_dir .../test/species/ -sequence_type AA
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.1: Group-Splitter - A tool to split multi-copy gene groups
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 74 -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
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.1: Cluster-Summary - A tool to summarise CD-HIT clustering files.
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.8.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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,,