tabtk 1.0.0__tar.gz → 1.0.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tabtk
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: tabtk: A toolkit for sequence similarity analysis based on tabular data
5
5
  Author-email: Chrispin Chaguza <chrispin.chaguza@gmail.com>
6
6
  Maintainer-email: Chrispin Chaguza <chrispin.chaguza@gmail.com>
@@ -1,4 +1,4 @@
1
1
  """tabkit: A toolkit for sequence similarity analysis based on tabular data"""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.0.2"
4
4
 
@@ -16,6 +16,8 @@ import pandas as pd
16
16
  import networkx as nx
17
17
  import math
18
18
  import datetime
19
+ import statistics
20
+ import glob
19
21
  from .__init__ import __version__
20
22
 
21
23
  def pairwiseSimilarity(firstRecord,secondRecord):
@@ -55,7 +57,7 @@ def pairwiseSimilarity(firstRecord,secondRecord):
55
57
  return(similarityData)
56
58
 
57
59
 
58
- def alignmentSimilarity(ij):
60
+ def alignmentSimilarity(i,j):
59
61
  seqMatch=0
60
62
  seqMisMatch=0
61
63
 
@@ -87,6 +89,11 @@ def mashSimilarity(cmdValues):
87
89
  else:
88
90
  pass
89
91
 
92
+ if int(cmdValues["length"])>=16:
93
+ print("Note: use shorter k-mers ≤16 when working diverse sequences")
94
+ else:
95
+ pass
96
+
90
97
  tmpOut = f"mash.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
91
98
  tmpOutR = f"mash.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
92
99
 
@@ -122,6 +129,98 @@ def mashSimilarity(cmdValues):
122
129
 
123
130
  return(mashResults)
124
131
 
132
+ def blastSimilarity(cmdValues):
133
+ if not shutil.which("blastn"):
134
+ print("Install BLAST and try again... exiting...")
135
+ sys.exit()
136
+
137
+ else:
138
+ pass
139
+
140
+ tmpFileNames = []
141
+ fileNames = []
142
+
143
+ tmpCmd="wc -l "+str(cmdValues["data"])+" | awk '{print $1}'"
144
+ dataFileLines=subprocess.Popen(tmpCmd,shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
145
+ dataLines = int(dataFileLines.communicate()[0])
146
+ dataFileLines.kill()
147
+
148
+ bar = ChargingBar("Loading data", max=int(dataLines))
149
+ for fileName in open(cmdValues["data"],"r"):
150
+ fileNames.append(str(fileName).strip())
151
+
152
+ bar.next()
153
+ bar.finish()
154
+
155
+ for i in fileNames:
156
+ tmpFileNames.append(f"{Path(i).stem}.tmpfna")
157
+
158
+ with open(f"{Path(i).stem}.tmpfna","w") as fh:
159
+ for j in SeqIO.parse(i,"fasta"):
160
+ fh.write(f">{Path(os.path.basename(i)).stem}\n{j.seq}\n")
161
+
162
+ tmpOut = f"blast.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
163
+
164
+ Cmd1 = f"cat {" ".join(tmpFileNames)} > {tmpOut}"
165
+ Cmd2 = f"makeblastdb -in {tmpOut} -dbtype nucl"
166
+
167
+ subprocess.call(Cmd1,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
168
+ subprocess.call(Cmd2,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
169
+
170
+ print("Calculating percent similarity... may take longer... be patient...")
171
+
172
+ tmpOut1 = f"blast.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
173
+ tmpOut2 = f"blast.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
174
+
175
+ blastCmd1 = f"echo \'qseqid sseqid length pident qcovs\' | tr \' \' \'\\t\' > {tmpOut2}"
176
+ blastCmd2 = f"blastn -db {tmpOut} -query {tmpOut} -word_size {cmdValues["length"]} -num_threads {cmdValues["threads"]} -outfmt \'6 qseqid sseqid length pident qcovs\' -evalue 0.001 >> {tmpOut2}"
177
+
178
+ subprocess.call(blastCmd1,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
179
+ subprocess.call(blastCmd2,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
180
+
181
+ blastData = pd.read_csv(tmpOut2,delimiter="\t",dtype={'pident': float,'qcovs': float})
182
+ blastData["tmp"] = blastData.apply(lambda x: (x["qcovs"] * x["pident"])/100,axis=1)
183
+
184
+ blastData["qseqidR"] = blastData.apply(lambda x: x["qseqid"] if x["qseqid"] > x["sseqid"] else x["sseqid"],axis=1)
185
+ blastData["sseqidR"] = blastData.apply(lambda x: x["qseqid"] if x["qseqid"] < x["sseqid"] else x["sseqid"],axis=1)
186
+
187
+ blastData["qseqid"] = blastData["qseqidR"]
188
+ blastData["sseqid"] = blastData["sseqidR"]
189
+
190
+ blastData["cov"] = blastData[["qseqid","sseqid","tmp"]].groupby(["qseqid","sseqid"])["tmp"].transform(lambda x: statistics.mean(x))
191
+ blastDataR = blastData.groupby(["qseqid","sseqid"]).first().reset_index()
192
+
193
+ blastData = blastDataR.drop(columns=["tmp","length","pident","qseqidR","sseqidR"])
194
+ blastDataFinal = blastData[["sseqid","qseqid","cov"]].rename(columns={"sseqid":"seq1","qseqid":"seq2","cov":"pid"}).values.tolist()
195
+
196
+ bar = ChargingBar("Cleaning temporary files", max=len(fileNames))
197
+ for fileName in tmpFileNames:
198
+ if os.path.exists(fileName):
199
+ os.remove(fileName)
200
+ else:
201
+ pass
202
+
203
+ bar.next()
204
+ bar.finish()
205
+
206
+ if os.path.exists(tmpOut1):
207
+ os.remove(tmpOut1)
208
+ else:
209
+ pass
210
+
211
+ if os.path.exists(tmpOut2):
212
+ os.remove(tmpOut2)
213
+ else:
214
+ pass
215
+
216
+ for file in glob.glob(f"{tmpOut}*"):
217
+ if os.path.exists(file):
218
+ os.remove(file)
219
+ else:
220
+ pass
221
+
222
+ return(blastDataFinal)
223
+
125
224
 
126
225
  def fastaniSimilarity(cmdValues):
127
226
  if not shutil.which("fastANI"):
@@ -131,6 +230,11 @@ def fastaniSimilarity(cmdValues):
131
230
  else:
132
231
  pass
133
232
 
233
+ if int(cmdValues["length"])>=16:
234
+ print("Note: use shorter k-mers ≤16 when working diverse sequences")
235
+ else:
236
+ pass
237
+
134
238
  tmpOut = f"mash.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
135
239
 
136
240
  fastaniCmd = f"fastANI --rl {cmdValues["data"]} --ql {cmdValues["data"]} -k {cmdValues["length"]} --matrix --fragLen {cmdValues["fragment"]} --minFraction {cmdValues["fraction"]} --output {tmpOut} -t {cmdValues["threads"]}"
@@ -143,11 +247,8 @@ def fastaniSimilarity(cmdValues):
143
247
 
144
248
  with open(tmpOut,"r") as fastaniFile:
145
249
  for itemPos,fastaniOutput in enumerate(fastaniFile):
146
- if itemPos == 0:
147
- pass
148
- else:
149
- item = fastaniOutput.strip().split("\t")
150
- fastaniResults.append(f"{Path(item[0]).stem}\t{Path(item[1]).stem}\t{float(item[2])}")
250
+ item = fastaniOutput.strip().split("\t")
251
+ fastaniResults.append(f"{Path(item[0]).stem}\t{Path(item[1]).stem}\t{float(item[2])}")
151
252
 
152
253
  if os.path.exists(tmpOut):
153
254
  os.remove(tmpOut)
@@ -170,7 +271,7 @@ def similarity(cmdValues):
170
271
  else:
171
272
  pass
172
273
 
173
- if (not cmdValues["aln"]) and (not cmdValues["mash"]) and (not cmdValues["fastani"]):
274
+ if (not cmdValues["blast"]) and (not cmdValues["aln"]) and (not cmdValues["mash"]) and (not cmdValues["fastani"]):
174
275
  dataMatrixDF = loadDataTable(cmdValues)
175
276
 
176
277
  itemPairs = itertools.permutations([item for pos,item in enumerate(dataMatrixDF.keys()) if pos>0], r=2)
@@ -192,7 +293,7 @@ def similarity(cmdValues):
192
293
  bar.next()
193
294
  bar.finish()
194
295
 
195
- elif (not cmdValues["aln"]) and (cmdValues["mash"]) and (not cmdValues["fastani"]):
296
+ elif (not cmdValues["blast"]) and (not cmdValues["aln"]) and (cmdValues["mash"]) and (not cmdValues["fastani"]):
196
297
  similarityResults = mashSimilarity(cmdValues)
197
298
 
198
299
  with open(cmdValues["output"],"w") as simData:
@@ -205,7 +306,7 @@ def similarity(cmdValues):
205
306
  bar.next()
206
307
  bar.finish()
207
308
 
208
- elif (not cmdValues["aln"]) and (not cmdValues["mash"]) and (cmdValues["fastani"]):
309
+ elif (not cmdValues["blast"]) and (not cmdValues["aln"]) and (not cmdValues["mash"]) and (cmdValues["fastani"]):
209
310
  similarityResults = fastaniSimilarity(cmdValues)
210
311
 
211
312
  with open(cmdValues["output"],"w") as simData:
@@ -218,14 +319,13 @@ def similarity(cmdValues):
218
319
  bar.next()
219
320
  bar.finish()
220
321
 
221
- elif (cmdValues["aln"]) and (not cmdValues["mash"]) and (not cmdValues["fastani"]):
322
+ elif (not cmdValues["blast"]) and (cmdValues["aln"]) and (not cmdValues["mash"]) and (not cmdValues["fastani"]):
222
323
  alignment={}
223
324
 
224
325
  for i in SeqIO.parse(cmdValues['data'],"fasta"):
225
326
  alignment[i.id]=i
226
327
 
227
328
  fhandle=open(str(cmdValues['outputFile']),"w")
228
-
229
329
  fhandle.write("seq1\tseq2\tpid\n")
230
330
 
231
331
  tmpList = sorted(map(sorted, combinations(set([i for i in alignment.keys()]), 2)))
@@ -234,6 +334,19 @@ def similarity(cmdValues):
234
334
  args=[(alignment[m],alignment[n]) for m,n in tmpList]
235
335
  results=pool.starmap(alignmentSimilarity, args)
236
336
 
337
+ elif (cmdValues["blast"]) and (not cmdValues["aln"]) and (not cmdValues["mash"]) and (not cmdValues["fastani"]):
338
+ similarityResults = blastSimilarity(cmdValues)
339
+
340
+ with open(cmdValues["output"],"w") as simData:
341
+ simData.write("seq1\tseq2\tpid\n")
342
+
343
+ bar = ChargingBar('Writing similarity values', max=len(similarityResults))
344
+ for itemPair in similarityResults:
345
+ simData.write(f"{"\t".join([str(r) for r in itemPair])}\n")
346
+
347
+ bar.next()
348
+ bar.finish()
349
+
237
350
  else:
238
351
  pass
239
352
 
@@ -258,6 +371,7 @@ def transpose(cmdValues):
258
371
  def lineages1Levels(cmdValues):
259
372
  np.random.rand(1)
260
373
 
374
+ print(cmdValues["thresholds"][0])
261
375
  snpDistDF = pd.read_csv(cmdValues["data"],delimiter="\t",header=0)
262
376
 
263
377
  Graph = nx.Graph()
@@ -857,15 +971,19 @@ def gwas(cmdValues):
857
971
  bar.finish()
858
972
 
859
973
 
860
- def queryKmers(seqNum,seqFile,kmerFile):
974
+ def queryKmers(seqNum,seqFile,kmerFile,cmdValues):
861
975
  seqFileName = Path(os.path.basename(seqFile)).stem
862
976
  tmpOutFileA = f"bifrost.{str(datetime.datetime.now()).replace(" ","").replace("-",".").replace(":",".")}"
863
977
 
864
978
  tmpCmd1 = f"Bifrost build -t 3 -k 31 -i -d -r {seqFile} -o {tmpOutFileA}.graph"
865
979
  subprocess.call(tmpCmd1,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
866
980
 
867
- tmpCmd2 = f"Bifrost query -t 5 -e 1 -q {kmerFile} -g {tmpOutFileA}.graph.gfa.gz -o {tmpOutFileA}"
868
- subprocess.call(tmpCmd2,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
981
+ if cmdValues["approximate"]:
982
+ tmpCmd2 = f"Bifrost query -a -t 5 -e 1 -q {kmerFile} -g {tmpOutFileA}.graph.gfa.gz -o {tmpOutFileA}"
983
+ subprocess.call(tmpCmd2,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
984
+ else:
985
+ tmpCmd2 = f"Bifrost query -t 5 -e 1 -q {kmerFile} -g {tmpOutFileA}.graph.gfa.gz -o {tmpOutFileA}"
986
+ subprocess.call(tmpCmd2,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
869
987
 
870
988
  tmpCmd3 = f"echo {seqFileName} > {tmpOutFileA}.out.tsv"
871
989
  subprocess.call(tmpCmd3,shell=True,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
@@ -1096,10 +1214,10 @@ def table(cmdValues):
1096
1214
  print("Query k-mers against sequences... may take longer... be patient...")
1097
1215
 
1098
1216
  with multiprocessing.Pool(processes=cmdValues["threads"]) as pool:
1099
- args = [(seqFileNum,seqFileName,kmersFile) for seqFileNum,seqFileName in seqFileDF]
1217
+ args = [(seqFileNum,seqFileName,kmersFile,cmdValues) for seqFileNum,seqFileName in seqFileDF]
1100
1218
  kmerResults = pool.starmap(queryKmers, args)
1101
1219
 
1102
- with open(f"{Path(cmdValues["output"]).stem}.table.tsv","w") as kmerData:
1220
+ with open(f"{cmdValues["output"]}","w") as kmerData:
1103
1221
  kmerFiles = []
1104
1222
  kmerHeaderFiles = []
1105
1223
 
@@ -1217,6 +1335,8 @@ def tabtkMain():
1217
1335
  dest='mash',help='Calculate similarity using MASH')
1218
1336
  similarityOptions.add_argument('--fastani','-n',action='store_true',default=False,
1219
1337
  dest='fastani',help='Calculate similarity using fastANI')
1338
+ similarityOptions.add_argument('--blast','-b',action='store_true',default=False,
1339
+ dest='blast',help='Calculate similarity using BLAST')
1220
1340
  similarityOptions.add_argument('--aln','-a',action='store_true',default=False,
1221
1341
  dest='aln',help='Calculate similarity based on a given sequence alignment')
1222
1342
  similarityOptions.add_argument('--fraction','-c',action='store',required=False,nargs=1,
@@ -1403,7 +1523,7 @@ def tabtkMain():
1403
1523
  help='K-mer length (default: 31)')
1404
1524
  kmerMatrixOptions.add_argument('--min','-m',action='store',required=False,nargs=1,
1405
1525
  metavar='minabundance',dest='minabundance',default=1,type=int,
1406
- help='Minimum k-mer abundance (minabundance: 1)')
1526
+ help='Minimum k-mer abundance (default: 1)')
1407
1527
  kmerMatrixOptions.add_argument('--maxmem','-x',action='store',required=False,nargs=1,
1408
1528
  metavar='maxmemory',dest='maxmemory',default=31,type=int,
1409
1529
  help='Maximum memory (default: 5000)')
@@ -1414,6 +1534,9 @@ def tabtkMain():
1414
1534
  kmerMatrixOptions.add_argument('--kmers','-k',action='store',required=False,nargs=1,
1415
1535
  metavar='kmers',dest='kmers',default="",
1416
1536
  help='Only query input sequence against a given k-mer database')
1537
+ kmerMatrixOptions.add_argument('--approx','-a',action='store_true',required=False,
1538
+ dest='approximate',default=False,
1539
+ help='Search inexact k-mers (default: False)')
1417
1540
  kmerMatrixOptions.add_argument('--threads','-t',action='store',required=False,nargs=1,
1418
1541
  metavar='threads',dest='threads',default=5,type=int,
1419
1542
  help='Number of threads (default: 5)')
@@ -1445,6 +1568,7 @@ def tabtkMain():
1445
1568
  'size': int(options.size[0:][0]) if isinstance(options.size,list) else int(options.size),
1446
1569
  'mash': options.mash,
1447
1570
  'fastani': options.fastani,
1571
+ 'blast': options.blast,
1448
1572
  'aln': options.aln,
1449
1573
  'threads': int(options.threads[0:][0]) if isinstance(options.threads,list) else int(options.threads)
1450
1574
  }
@@ -1537,6 +1661,7 @@ def tabtkMain():
1537
1661
  'maxmemory': int(options.maxmemory[0:][0]) if isinstance(options.maxmemory,list) else int(options.maxmemory),
1538
1662
  'length': int(options.length[0:][0]) if isinstance(options.length,list) else int(options.length),
1539
1663
  'kmers': options.kmers[0:][0] if isinstance(options.kmers,list) else options.kmers,
1664
+ 'approximate': options.approximate,
1540
1665
  'threads': int(options.threads[0:][0]) if isinstance(options.threads,list) else int(options.threads)
1541
1666
  }
1542
1667
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tabtk
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: tabtk: A toolkit for sequence similarity analysis based on tabular data
5
5
  Author-email: Chrispin Chaguza <chrispin.chaguza@gmail.com>
6
6
  Maintainer-email: Chrispin Chaguza <chrispin.chaguza@gmail.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes