annotate sRbowtieCascade.py @ 2:fb341fa3b7fc draft

Uploaded
author drosofff
date Sun, 22 Jun 2014 13:39:49 -0400
parents 4c7013211739
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
4c7013211739 Uploaded
drosofff
parents:
diff changeset
1 #!/usr/bin/env python
4c7013211739 Uploaded
drosofff
parents:
diff changeset
2 # small RNA oriented bowtie wrapper in cascade for small RNA data set genome annotation
4c7013211739 Uploaded
drosofff
parents:
diff changeset
3 # version 0.9 13-6-2014
4c7013211739 Uploaded
drosofff
parents:
diff changeset
4 # Usage sRbowtie_cascade.py see Parser() for valid arguments
4c7013211739 Uploaded
drosofff
parents:
diff changeset
5 # Christophe Antoniewski <drosofff@gmail.com>
4c7013211739 Uploaded
drosofff
parents:
diff changeset
6
4c7013211739 Uploaded
drosofff
parents:
diff changeset
7 import sys, os, subprocess, tempfile, shutil, argparse
4c7013211739 Uploaded
drosofff
parents:
diff changeset
8 from collections import defaultdict
4c7013211739 Uploaded
drosofff
parents:
diff changeset
9
4c7013211739 Uploaded
drosofff
parents:
diff changeset
10 def Parser():
4c7013211739 Uploaded
drosofff
parents:
diff changeset
11 the_parser = argparse.ArgumentParser()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
12 the_parser.add_argument('--output', action="store", type=str, help="output file")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
13 the_parser.add_argument('--num-threads', dest="num_threads", action="store", type=str, help="number of bowtie threads")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
14 the_parser.add_argument('--mismatch', action="store", type=str, help="number of mismatches allowed")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
15 the_parser.add_argument('--indexing-flags', dest="indexing_flags", nargs='+', help="whether the index should be generated or not by bowtie-buid")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
16 the_parser.add_argument('--index',nargs='+', help="paths to indexed or fasta references")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
17 the_parser.add_argument('--indexName',nargs='+', help="Names of the indexes")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
18 the_parser.add_argument('--input',nargs='+', help="paths to multiple input files")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
19 the_parser.add_argument('--label',nargs='+', help="labels of multiple input files")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
20 args = the_parser.parse_args()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
21 return args
4c7013211739 Uploaded
drosofff
parents:
diff changeset
22
4c7013211739 Uploaded
drosofff
parents:
diff changeset
23 def stop_err( msg ):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
24 sys.stderr.write( '%s\n' % msg )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
25 sys.exit()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
26
4c7013211739 Uploaded
drosofff
parents:
diff changeset
27 def bowtie_squash(fasta):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
28 tmp_index_dir = tempfile.mkdtemp() # make temp directory for bowtie indexes
4c7013211739 Uploaded
drosofff
parents:
diff changeset
29 ref_file = tempfile.NamedTemporaryFile( dir=tmp_index_dir )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
30 ref_file_name = ref_file.name
4c7013211739 Uploaded
drosofff
parents:
diff changeset
31 ref_file.close() # by default, delete the temporary file, but ref_file.name is now stored in ref_file_name
4c7013211739 Uploaded
drosofff
parents:
diff changeset
32 os.symlink( fasta, ref_file_name ) # symlink between the fasta source file and the deleted ref_file name
4c7013211739 Uploaded
drosofff
parents:
diff changeset
33 cmd1 = 'bowtie-build -f %s %s' % (ref_file_name, ref_file_name ) # bowtie command line, which will work after changing dir (cwd=tmp_index_dir)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
34 try:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
35 FNULL = open(os.devnull, 'w')
4c7013211739 Uploaded
drosofff
parents:
diff changeset
36 tmp = tempfile.NamedTemporaryFile( dir=tmp_index_dir ).name # a path string for a temp file in tmp_index_dir. Just a string
4c7013211739 Uploaded
drosofff
parents:
diff changeset
37 tmp_stderr = open( tmp, 'wb' ) # creates and open a file handler pointing to the temp file
4c7013211739 Uploaded
drosofff
parents:
diff changeset
38 proc = subprocess.Popen( args=cmd1, shell=True, cwd=tmp_index_dir, stderr=FNULL, stdout=FNULL ) # both stderr and stdout of bowtie-build are redirected in dev/null
4c7013211739 Uploaded
drosofff
parents:
diff changeset
39 returncode = proc.wait()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
40 tmp_stderr.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
41 FNULL.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
42 sys.stdout.write(cmd1 + "\n")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
43 except Exception, e:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
44 # clean up temp dir
4c7013211739 Uploaded
drosofff
parents:
diff changeset
45 if os.path.exists( tmp_index_dir ):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
46 shutil.rmtree( tmp_index_dir )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
47 stop_err( 'Error indexing reference sequence\n' + str( e ) )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
48 # no Cleaning if no Exception, tmp_index_dir has to be cleaned after bowtie_alignment()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
49 index_full_path = os.path.join(tmp_index_dir, ref_file_name) # bowtie fashion path without extention
4c7013211739 Uploaded
drosofff
parents:
diff changeset
50 return index_full_path
4c7013211739 Uploaded
drosofff
parents:
diff changeset
51
4c7013211739 Uploaded
drosofff
parents:
diff changeset
52 def make_working_dir():
4c7013211739 Uploaded
drosofff
parents:
diff changeset
53 working_dir = tempfile.mkdtemp()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
54 return working_dir
4c7013211739 Uploaded
drosofff
parents:
diff changeset
55
4c7013211739 Uploaded
drosofff
parents:
diff changeset
56 def Clean_TempDir(directory):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
57 if os.path.exists( directory ):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
58 shutil.rmtree( directory )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
59 return
4c7013211739 Uploaded
drosofff
parents:
diff changeset
60
4c7013211739 Uploaded
drosofff
parents:
diff changeset
61 def bowtie_alignment(command_line="None", working_dir = ""):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
62 FNULL = open(os.devnull, 'w')
4c7013211739 Uploaded
drosofff
parents:
diff changeset
63 p = subprocess.Popen(args=command_line, cwd=working_dir, shell=True, stderr=FNULL, stdout=FNULL)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
64 returncode = p.wait()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
65 sys.stdout.write("%s\n" % command_line)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
66 FNULL.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
67 #p = subprocess.Popen(["wc", "-l", "%s/al.fasta"%working_dir], cwd=working_dir, stdout=subprocess.PIPE)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
68 #aligned = p.communicate()[0].split()[0]
4c7013211739 Uploaded
drosofff
parents:
diff changeset
69 aligned = 0
4c7013211739 Uploaded
drosofff
parents:
diff changeset
70 F = open ("%s/al.fasta" % working_dir, "r")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
71 for line in F:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
72 aligned += 1
4c7013211739 Uploaded
drosofff
parents:
diff changeset
73 F.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
74 sys.stdout.write("Aligned: %s\n" % aligned)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
75 return aligned/2
4c7013211739 Uploaded
drosofff
parents:
diff changeset
76
4c7013211739 Uploaded
drosofff
parents:
diff changeset
77 def CommandLiner (v_mis="1", pslots="12", index="dum/my", input="dum/my", working_dir=""):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
78 return "bowtie -v %s -k 1 --best -p %s --al %s/al.fasta --un %s/unal.fasta --suppress 1,2,3,4,5,6,7,8 %s -f %s" % (v_mis, pslots, working_dir, working_dir, index, input)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
79
4c7013211739 Uploaded
drosofff
parents:
diff changeset
80 def __main__():
4c7013211739 Uploaded
drosofff
parents:
diff changeset
81 args = Parser()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
82 ## first we make all indexes available. They can be already available or be squashed by bowtie-build
4c7013211739 Uploaded
drosofff
parents:
diff changeset
83 ## we keep them in a list that alternates indexPath and "toClear" or "DoNotDelete"
4c7013211739 Uploaded
drosofff
parents:
diff changeset
84 BowtieIndexList = []
4c7013211739 Uploaded
drosofff
parents:
diff changeset
85 for indexing_flags, bowtiePath in zip (args.indexing_flags, args.index):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
86 if indexing_flags == "history":
4c7013211739 Uploaded
drosofff
parents:
diff changeset
87 BowtieIndexList.append ( bowtie_squash (bowtiePath) )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
88 BowtieIndexList.append ( "toClear" )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
89 else:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
90 BowtieIndexList.append ( bowtiePath )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
91 BowtieIndexList.append ( "DoNotDelete")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
92 ###### temporary Indexes are generated. They must be deleted at the end (after removing file name in the temp path)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
93 ResultDict = defaultdict(list)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
94 for label, input in zip(args.label, args.input): ## the main cascade, iterating over samples and bowtie indexes
4c7013211739 Uploaded
drosofff
parents:
diff changeset
95 workingDir = make_working_dir()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
96 cmd = CommandLiner (v_mis=args.mismatch, pslots=args.num_threads, index=BowtieIndexList[0], input=input, working_dir=workingDir)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
97 ResultDict[label].append( bowtie_alignment(command_line=cmd, working_dir = workingDir) ) # first step of the cascade
4c7013211739 Uploaded
drosofff
parents:
diff changeset
98 if len(BowtieIndexList) > 2: # is there a second step to perform ?
4c7013211739 Uploaded
drosofff
parents:
diff changeset
99 os.rename("%s/al.fasta"%workingDir, "%s/toAlign.fasta"%workingDir) ## end of first step. the aligned reads are the input of the next step
4c7013211739 Uploaded
drosofff
parents:
diff changeset
100 cmd = CommandLiner (v_mis=args.mismatch, pslots=args.num_threads, index=BowtieIndexList[2], input="%s/toAlign.fasta"%workingDir, working_dir=workingDir)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
101 ResultDict[label].append( bowtie_alignment(command_line=cmd, working_dir = workingDir) )## second step of the cascade
4c7013211739 Uploaded
drosofff
parents:
diff changeset
102 if len(BowtieIndexList) > 4: ## remaining steps
4c7013211739 Uploaded
drosofff
parents:
diff changeset
103 for BowtieIndexPath in BowtieIndexList[4::2]:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
104 os.rename("%s/unal.fasta"%workingDir, "%s/toAlign.fasta"%workingDir)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
105 cmd = CommandLiner (v_mis=args.mismatch, pslots=args.num_threads, index=BowtieIndexPath, input="%s/toAlign.fasta"%workingDir, working_dir=workingDir)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
106 ResultDict[label].append( bowtie_alignment(command_line=cmd, working_dir = workingDir) )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
107 Fun = open("%s/unal.fasta"%workingDir, "r") ## to finish, compute the number of unmatched reads
4c7013211739 Uploaded
drosofff
parents:
diff changeset
108 n = 0
4c7013211739 Uploaded
drosofff
parents:
diff changeset
109 for line in Fun:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
110 n += 1
4c7013211739 Uploaded
drosofff
parents:
diff changeset
111 ResultDict[label].append(n/2)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
112 Fun.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
113 Clean_TempDir (workingDir) # clean the sample working directory
4c7013211739 Uploaded
drosofff
parents:
diff changeset
114 ## cleaning
4c7013211739 Uploaded
drosofff
parents:
diff changeset
115 for IndexPath, IndexFlag in zip(BowtieIndexList[::2], BowtieIndexList[1::2]):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
116 if IndexFlag == "toClear":
4c7013211739 Uploaded
drosofff
parents:
diff changeset
117 Clean_TempDir ("/".join(IndexPath.split("/")[:-1]))
4c7013211739 Uploaded
drosofff
parents:
diff changeset
118 ## end of cleaning
4c7013211739 Uploaded
drosofff
parents:
diff changeset
119
4c7013211739 Uploaded
drosofff
parents:
diff changeset
120
4c7013211739 Uploaded
drosofff
parents:
diff changeset
121
4c7013211739 Uploaded
drosofff
parents:
diff changeset
122 F = open (args.output, "w")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
123 print >> F, "alignment reference\t%s" % "\t".join(args.label)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
124 for i, reference in enumerate(args.indexName):
4c7013211739 Uploaded
drosofff
parents:
diff changeset
125 F.write ("%s" % reference)
4c7013211739 Uploaded
drosofff
parents:
diff changeset
126 for sample in args.label:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
127 F.write ("\t%s" % "{:,}".format(ResultDict[sample][i]) )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
128 print >> F
4c7013211739 Uploaded
drosofff
parents:
diff changeset
129 F.write ("Remaining Unmatched")
4c7013211739 Uploaded
drosofff
parents:
diff changeset
130 for sample in args.label:
4c7013211739 Uploaded
drosofff
parents:
diff changeset
131 F.write ("\t%s" % "{:,}".format(ResultDict[sample][-1]) )
4c7013211739 Uploaded
drosofff
parents:
diff changeset
132 print >> F
4c7013211739 Uploaded
drosofff
parents:
diff changeset
133
4c7013211739 Uploaded
drosofff
parents:
diff changeset
134 F.close()
4c7013211739 Uploaded
drosofff
parents:
diff changeset
135
4c7013211739 Uploaded
drosofff
parents:
diff changeset
136 if __name__=="__main__": __main__()