annotate hetbox.py @ 6:99cda2ff12b8 draft

Current version - maybe ready to release
author nick
date Tue, 04 Jun 2013 00:06:36 -0400
parents dfa2e75da6aa
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
1 #!/usr/bin/env python
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
2 # New in this version:
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
3 # - Add in proper header line if not present
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
4
128db16c9399 Uploaded script
nick
parents:
diff changeset
5 import os,sys,numpy
128db16c9399 Uploaded script
nick
parents:
diff changeset
6 from rpy2.robjects import Formula
128db16c9399 Uploaded script
nick
parents:
diff changeset
7 from rpy2.robjects.packages import importr
128db16c9399 Uploaded script
nick
parents:
diff changeset
8 from rpy2 import robjects
128db16c9399 Uploaded script
nick
parents:
diff changeset
9
128db16c9399 Uploaded script
nick
parents:
diff changeset
10 def fail(message):
128db16c9399 Uploaded script
nick
parents:
diff changeset
11 sys.stderr.write(message+'\n')
128db16c9399 Uploaded script
nick
parents:
diff changeset
12 sys.exit(1)
128db16c9399 Uploaded script
nick
parents:
diff changeset
13
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
14 COLUMN_LABELS = ['SAMPLE', 'CHR', 'POS', 'A', 'C', 'G', 'T', 'CVRG', 'ALLELES', 'MAJOR', 'MINOR', 'MINOR.FREQ.PERC.'] #, 'STRAND.BIAS']
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
15
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
16 args = sys.argv[1:]
128db16c9399 Uploaded script
nick
parents:
diff changeset
17 if len(args) >= 1:
128db16c9399 Uploaded script
nick
parents:
diff changeset
18 infile = args[0]
128db16c9399 Uploaded script
nick
parents:
diff changeset
19 else:
128db16c9399 Uploaded script
nick
parents:
diff changeset
20 fail('Error: No input filename provided (as argument 1).')
128db16c9399 Uploaded script
nick
parents:
diff changeset
21 if len(args) >= 2:
128db16c9399 Uploaded script
nick
parents:
diff changeset
22 outfile = args[1]
128db16c9399 Uploaded script
nick
parents:
diff changeset
23 else:
128db16c9399 Uploaded script
nick
parents:
diff changeset
24 fail('Error: No output filename provided (as argument 2).')
128db16c9399 Uploaded script
nick
parents:
diff changeset
25 if len(args) >= 3:
128db16c9399 Uploaded script
nick
parents:
diff changeset
26 report = args[2]
4
dfa2e75da6aa fixed script typo
nick
parents: 2
diff changeset
27 else:
dfa2e75da6aa fixed script typo
nick
parents: 2
diff changeset
28 report = ''
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
29
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
30 # Check input file
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
31 add_header = False
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
32 if not os.path.exists(infile):
128db16c9399 Uploaded script
nick
parents:
diff changeset
33 fail('Error: Input file '+infile+' could not be found.')
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
34 with open(infile, 'r') as lines:
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
35 line = lines.readline()
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
36 if not line:
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
37 fail('Error: Input file seems to be empty')
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
38 line = line.strip().lstrip('#') # rm whitespace, comment chars
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
39 labels = line.split("\t")
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
40 if 'SAMPLE' not in labels or labels[11] != 'MINOR.FREQ.PERC.':
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
41 sys.stderr.write("Error: Input file does not seem to have a proper header "
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
42 +"line.\nAdding an artificial header..")
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
43 add_header = True
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
44
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
45
128db16c9399 Uploaded script
nick
parents:
diff changeset
46
128db16c9399 Uploaded script
nick
parents:
diff changeset
47 utils = importr('utils')
128db16c9399 Uploaded script
nick
parents:
diff changeset
48 graphics = importr('graphics')
128db16c9399 Uploaded script
nick
parents:
diff changeset
49 base = importr('base')
128db16c9399 Uploaded script
nick
parents:
diff changeset
50 stats = importr('stats')
128db16c9399 Uploaded script
nick
parents:
diff changeset
51 rprint = robjects.globalenv.get("print")
128db16c9399 Uploaded script
nick
parents:
diff changeset
52 grdevices = importr('grDevices')
128db16c9399 Uploaded script
nick
parents:
diff changeset
53 grdevices.png(file=outfile, width=1024, height=768)
128db16c9399 Uploaded script
nick
parents:
diff changeset
54
128db16c9399 Uploaded script
nick
parents:
diff changeset
55 # Read file into a data frame
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
56 if add_header:
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
57 # add header line manually if not present
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
58 DATA = utils.read_delim(infile, header=False)
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
59 labels = robjects.r.names(DATA)
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
60 for i in range(len(labels)):
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
61 try:
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
62 labels[i] = COLUMN_LABELS[i]
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
63 except IndexError, e:
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
64 fail("Error in input file: Too many columns (does not match hardcoded "
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
65 +"column labels).")
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
66 else:
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
67 DATA = utils.read_delim(infile)
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
68 # Remove comment from header, if present
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
69 labels = robjects.r.names(DATA)
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
70 if labels[0][0:2] == 'X.':
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
71 labels[0] = labels[0][2:]
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
72 # Multiply minor allele frequencies by 100 to get percentage
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
73 # .rx2() looks up a column by its label and returns it as a vector
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
74 # .ro turns the returned object into one that can be operated on per-element
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
75 minor_freq = DATA.rx2('MINOR.FREQ.PERC.').ro * 100
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
76 samples = DATA.rx2('SAMPLE')
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
77 # Formula() creates a Python object representing the R object returned by x ~ y
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
78 formula = Formula('minor_freq ~ samples')
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
79 # The "environment" in .getenvironment() is the entire R workspace in which the
128db16c9399 Uploaded script
nick
parents:
diff changeset
80 # Formula object exists. The R workspace meaning all the defined variables.
128db16c9399 Uploaded script
nick
parents:
diff changeset
81 # Here, the .getenvironment() method is being used to set some variables in the
128db16c9399 Uploaded script
nick
parents:
diff changeset
82 # R workspace
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
83 formula.getenvironment()['minor_freq'] = minor_freq
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
84 formula.getenvironment()['samples'] = samples
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
85
128db16c9399 Uploaded script
nick
parents:
diff changeset
86 # create boxplot - fill kwargs1 with the options for the boxplot function
6
99cda2ff12b8 Current version - maybe ready to release
nick
parents: 4
diff changeset
87 kwargs1 = {'ylab':"Minor allele frequency (%)", 'col':"gray", 'xaxt':"n", 'outpch':"*",'main':"Distribution of minor allele frequencies", 'cex.lab':"1.5"}
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
88 p = graphics.boxplot(formula, **kwargs1)
128db16c9399 Uploaded script
nick
parents:
diff changeset
89
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
90 table = base.table(DATA.rx2('SAMPLE'))
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
91 graphics.text(0.5, 1, 'N:', font=2)
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
92 for i in range(1, base.length(table)[0]+1, 1):
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
93 graphics.text(i, 1, table[i-1], font=2)
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
94
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
95 graphlabels = base.names(table)
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
96 kwargs3 = {'pos':"0", 'las':"2", 'cex.axis':"1"}
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
97 graphics.axis(1, at=range(1, len(graphlabels)+1, 1), labels=graphlabels, **kwargs3)
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
98 grdevices.dev_off()
128db16c9399 Uploaded script
nick
parents:
diff changeset
99
4
dfa2e75da6aa fixed script typo
nick
parents: 2
diff changeset
100 if not report:
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
101 sys.exit(0)
128db16c9399 Uploaded script
nick
parents:
diff changeset
102
2
3a1ce69571e5 Allow commented lines, de-kludge data frame handling
nick
parents: 0
diff changeset
103
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
104 ####################################
128db16c9399 Uploaded script
nick
parents:
diff changeset
105 # GENERATE REPORT
128db16c9399 Uploaded script
nick
parents:
diff changeset
106 # report should be something like:
128db16c9399 Uploaded script
nick
parents:
diff changeset
107 # SAMPLE NoHET MEDIAN MAD TEST
128db16c9399 Uploaded script
nick
parents:
diff changeset
108 # s1 7 10% n p/w/f
128db16c9399 Uploaded script
nick
parents:
diff changeset
109 # n <= 5 pass
128db16c9399 Uploaded script
nick
parents:
diff changeset
110 # 6 <= n <=10 warn
128db16c9399 Uploaded script
nick
parents:
diff changeset
111 # n >= 11 fail
128db16c9399 Uploaded script
nick
parents:
diff changeset
112 # MAD <= 2.0 fail
128db16c9399 Uploaded script
nick
parents:
diff changeset
113 # MAD > 2.0 pass
128db16c9399 Uploaded script
nick
parents:
diff changeset
114 ###################################
128db16c9399 Uploaded script
nick
parents:
diff changeset
115
128db16c9399 Uploaded script
nick
parents:
diff changeset
116 SAMPLES=[]
4
dfa2e75da6aa fixed script typo
nick
parents: 2
diff changeset
117 for i in range(len(table)):
dfa2e75da6aa fixed script typo
nick
parents: 2
diff changeset
118 SAMPLES.append(base.names(table)[i])
0
128db16c9399 Uploaded script
nick
parents:
diff changeset
119
128db16c9399 Uploaded script
nick
parents:
diff changeset
120 def boxstats(data,sample):
128db16c9399 Uploaded script
nick
parents:
diff changeset
121 VALUES = [100*float(x.strip().split('\t')[11]) for x in list(open(data)) if x.strip().split('\t')[0]==sample]
128db16c9399 Uploaded script
nick
parents:
diff changeset
122 NoHET = len(VALUES)
128db16c9399 Uploaded script
nick
parents:
diff changeset
123 MEDIAN = numpy.median(VALUES)
128db16c9399 Uploaded script
nick
parents:
diff changeset
124 MAD = numpy.median([abs(i - MEDIAN) for i in VALUES]) # Median absolute distance (robust spread statistic)
128db16c9399 Uploaded script
nick
parents:
diff changeset
125 return [NoHET,MEDIAN, MAD]
128db16c9399 Uploaded script
nick
parents:
diff changeset
126
128db16c9399 Uploaded script
nick
parents:
diff changeset
127 boxreport = open(report, "w+")
128db16c9399 Uploaded script
nick
parents:
diff changeset
128 boxreport.write("SAMPLE\tTOTAL.SITES\tMEDIAN.FREQ.\tMAD.FREQ\tEVAL\n")
128db16c9399 Uploaded script
nick
parents:
diff changeset
129 for sample in SAMPLES:
128db16c9399 Uploaded script
nick
parents:
diff changeset
130 ENTRY = [sample] + boxstats(infile,sample)
128db16c9399 Uploaded script
nick
parents:
diff changeset
131 if ENTRY[1] <= 5:
128db16c9399 Uploaded script
nick
parents:
diff changeset
132 ENTRY.append('pass')
128db16c9399 Uploaded script
nick
parents:
diff changeset
133 elif 6 <= ENTRY[1] <=10:
128db16c9399 Uploaded script
nick
parents:
diff changeset
134 ENTRY.append('warn')
128db16c9399 Uploaded script
nick
parents:
diff changeset
135 elif ENTRY[1] >= 11:
128db16c9399 Uploaded script
nick
parents:
diff changeset
136 ENTRY.append('fail')
128db16c9399 Uploaded script
nick
parents:
diff changeset
137 if ENTRY[3] <=2.0:
128db16c9399 Uploaded script
nick
parents:
diff changeset
138 ENTRY.append('fail')
128db16c9399 Uploaded script
nick
parents:
diff changeset
139 elif ENTRY[3] >2.0:
128db16c9399 Uploaded script
nick
parents:
diff changeset
140 ENTRY.append('pass')
128db16c9399 Uploaded script
nick
parents:
diff changeset
141 if len(set(ENTRY[4:6])) == 2:
128db16c9399 Uploaded script
nick
parents:
diff changeset
142 ENTRY.append('warn')
128db16c9399 Uploaded script
nick
parents:
diff changeset
143 else:
128db16c9399 Uploaded script
nick
parents:
diff changeset
144 ENTRY.append(list(set(ENTRY[4:6]))[0])
128db16c9399 Uploaded script
nick
parents:
diff changeset
145 boxreport.write ('%s\t%d\t%.1f\t%.1f\t%s\n' % tuple([ENTRY[i] for i in [0,1,2,3,6]]))
128db16c9399 Uploaded script
nick
parents:
diff changeset
146
128db16c9399 Uploaded script
nick
parents:
diff changeset
147 boxreport.close()
128db16c9399 Uploaded script
nick
parents:
diff changeset
148
128db16c9399 Uploaded script
nick
parents:
diff changeset
149
128db16c9399 Uploaded script
nick
parents:
diff changeset
150
128db16c9399 Uploaded script
nick
parents:
diff changeset
151
128db16c9399 Uploaded script
nick
parents:
diff changeset
152
128db16c9399 Uploaded script
nick
parents:
diff changeset
153
128db16c9399 Uploaded script
nick
parents:
diff changeset
154 #####################################
128db16c9399 Uploaded script
nick
parents:
diff changeset
155 #STUFF
128db16c9399 Uploaded script
nick
parents:
diff changeset
156 #
128db16c9399 Uploaded script
nick
parents:
diff changeset
157 #kwargs = {'ylab':"Minor allele frequency (sites >= 2%)",'col':"blue", 'axes':"FALSE", 'outpch':"*", 'ylim':"c(-0.03,0.5)", 'main':"Minor allele frequencies run020 at 2%"}
128db16c9399 Uploaded script
nick
parents:
diff changeset
158 #boxplot(freq~id,data=run020[run020$freq>=0.02,], col="blue", axes=FALSE, outpch="*", ylab="Minor allele frequency (sites >= 2%)", ylim=c(-0.03,0.5), main="Minor allele frequencies run020 at 2%")
128db16c9399 Uploaded script
nick
parents:
diff changeset
159 #biglabels2=sort(as.vector(unique(run020$id)))
128db16c9399 Uploaded script
nick
parents:
diff changeset
160 #biglabels=apply(as.matrix(biglabels2), 1,function(x) substr(x,1,5))
128db16c9399 Uploaded script
nick
parents:
diff changeset
161 #axis(1, at=c(1:length(biglabels)),labels=biglabels, pos=-0.02, las=2, cex.axis=0.9)
128db16c9399 Uploaded script
nick
parents:
diff changeset
162 #axis(2, at=c(seq(0,50,5)/100), pos=0,cex.axis=0.9)
128db16c9399 Uploaded script
nick
parents:
diff changeset
163 #nbig=as.vector(table(run020[run020$freq>=0.02,1]))
128db16c9399 Uploaded script
nick
parents:
diff changeset
164 #for (i in 1:length(nbig)){text(i,-0.01,nbig[i],cex=0.9, font=2)}
128db16c9399 Uploaded script
nick
parents:
diff changeset
165