comparison spp/R/zroutines.R @ 6:ce08b0efa3fd draft

Uploaded
author zzhou
date Tue, 27 Nov 2012 16:11:40 -0500
parents
children
comparison
equal deleted inserted replaced
5:608a8e0eac56 6:ce08b0efa3fd
1 #library(caTools)
2 #dyn.load("src/bed2vector.so");
3 #dyn.load("src/wdl.so");
4 #dyn.load("src/peaks.so");
5 #dyn.load("src/cdensum.so");
6
7
8 # -------- ROUTINES FOR READING IN THE DATA FILES ------------
9 # fix.chromosome.names : remove ".fa" suffix from match sequence names
10 read.eland.tags <- function(filename,read.tag.names=F,fix.chromosome.names=T,max.eland.tag.length=-1,extended=F,multi=F) {
11 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
12 storage.mode(max.eland.tag.length) <- "integer";
13 callfunction <- "read_eland";
14 if(extended) { callfunction <- "read_eland_extended"; };
15 if(multi) { callfunction <- "read_eland_multi"; };
16 tl <- lapply(.Call(callfunction,filename,rtn,max.eland.tag.length),function(d) {
17 xo <- order(abs(d$t));
18 d$t <- d$t[xo];
19 d$n <- d$n[xo];
20 if(read.tag.names) {
21 d$s <- d$s[xo];
22 }
23 return(d);
24 });
25 if(fix.chromosome.names) {
26 # remove ".fa"
27 names(tl) <- gsub("\\.fa","",names(tl))
28 }
29 # separate tags and quality
30 if(read.tag.names) {
31 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),names=lapply(tl,function(d) d$s)));
32 } else {
33 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
34 }
35 }
36
37 read.tagalign.tags <- function(filename,fix.chromosome.names=T,fix.quality=T) {
38 tl <- lapply(.Call("read_tagalign",filename),function(d) {
39 xo <- order(abs(d$t));
40 d$t <- d$t[xo];
41 d$n <- d$n[xo];
42 #if(fix.quality) {
43 # d$n <- 4-cut(d$n,breaks=c(0,250,500,750,1000),labels=F)
44 #}
45 if(fix.quality) { # Anshul: changed the way the quality field is processed
46 if (min(d$n)<0.5){
47 d$n = ceiling(1000/4^d$n);
48 }
49 break.vals <- unique(sort(c(0,unique(d$n))));
50 d$n <- length(break.vals)-1-cut(d$n,breaks=break.vals,labels=F);
51 }
52 return(d);
53 });
54 if(fix.chromosome.names) {
55 # remove ".fa"
56 names(tl) <- gsub("\\.fa","",names(tl))
57 }
58 # separate tags and quality
59 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
60 }
61
62
63 read.short.arachne.tags <- function(filename,fix.chromosome.names=F) {
64 tl <- lapply(.Call("read_arachne",filename),function(d) {
65 xo <- order(abs(d$t));
66 d$t <- d$t[xo];
67 d$n <- d$n[xo];
68 return(d);
69 });
70 if(fix.chromosome.names) {
71 # remove ".fa"
72 names(tl) <- gsub("\\.fa","",names(tl))
73 }
74 # separate tags and quality
75 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
76 }
77
78
79 read.arachne.tags <- function(filename,fix.chromosome.names=F) {
80 tl <- lapply(.Call("read_arachne_long",filename),function(d) {
81 xo <- order(abs(d$t));
82 d$t <- d$t[xo];
83 d$n <- d$n[xo];
84 d$l <- d$l[xo];
85 return(d);
86 });
87 if(fix.chromosome.names) {
88 # remove ".fa"
89 names(tl) <- gsub("\\.fa","",names(tl))
90 }
91 # separate tags and quality
92 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),length=lapply(tl,function(d) d$l)));
93 }
94
95 read.bowtie.tags <- function(filename,read.tag.names=F,fix.chromosome.names=F) {
96 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
97 tl <- lapply(.Call("read_bowtie",filename,rtn),function(d) {
98 xo <- order(abs(d$t));
99 d$t <- d$t[xo];
100 d$n <- d$n[xo];
101 if(read.tag.names) {
102 d$s <- d$s[xo];
103 }
104 return(d);
105 });
106 if(fix.chromosome.names) {
107 # remove ".fa"
108 names(tl) <- gsub("\\.fa","",names(tl))
109 }
110 # separate tags and quality
111 if(read.tag.names) {
112 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),names=lapply(tl,function(d) d$s)));
113 } else {
114 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
115 }
116 }
117
118 read.bam.tags <- function(filename,read.tag.names=F,fix.chromosome.names=F) {
119 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
120 tl <- lapply(.Call("read_bam",filename,rtn),function(d) {
121 xo <- order(abs(d$t));
122 d$t <- d$t[xo];
123 d$n <- d$n[xo];
124 if(read.tag.names) {
125 d$s <- d$s[xo];
126 }
127 return(d);
128 });
129 if(fix.chromosome.names) {
130 # remove ".fa"
131 names(tl) <- gsub("\\.fa","",names(tl))
132 }
133 # separate tags and quality
134 if(read.tag.names) {
135 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),names=lapply(tl,function(d) d$s)));
136 } else {
137 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
138 }
139 }
140
141
142 read.helicos.tags <- function(filename,read.tag.names=F,fix.chromosome.names=F,include.length.info=T) {
143 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
144 tl <- lapply(.Call("read_helicostabf",filename,rtn),function(d) {
145 xo <- order(abs(d$t));
146 d$t <- d$t[xo];
147 d$n <- d$n[xo];
148 d$l <- d$l[xo];
149 if(read.tag.names) {
150 d$s <- d$s[xo];
151 }
152 return(d);
153 });
154 if(fix.chromosome.names) {
155 # remove ".fa"
156 names(tl) <- gsub("\\.fa","",names(tl))
157 }
158 # separate tags and quality
159 if(read.tag.names) {
160 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),length=lapply(tl,function(d) d$l),names=lapply(tl,function(d) d$s)));
161 } else {
162 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),length=lapply(tl,function(d) d$l)));
163 }
164 }
165
166 read.maqmap.tags <- function(filename,read.tag.names=F,fix.chromosome.names=T) {
167 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
168 tl <- lapply(.Call("read_maqmap",filename,rtn),function(d) {
169 xo <- order(abs(d$t));
170 d$t <- d$t[xo];
171 d$n <- d$n[xo];
172 if(read.tag.names) {
173 d$s <- d$s[xo];
174 }
175 return(d);
176 });
177 if(fix.chromosome.names) {
178 # remove ".fa"
179 names(tl) <- gsub("\\.fa","",names(tl))
180 }
181 # separate tags and quality
182 if(read.tag.names) {
183 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),names=lapply(tl,function(d) d$s)));
184 } else {
185 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
186 }
187 }
188
189
190 read.bin.maqmap.tags <- function(filename,read.tag.names=F,fix.chromosome.names=T) {
191 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
192 tl <- lapply(.Call("read_binmaqmap",filename,rtn),function(d) {
193 xo <- order(abs(d$t));
194 d$t <- d$t[xo];
195 d$n <- d$n[xo];
196 if(read.tag.names) {
197 d$s <- d$s[xo];
198 }
199 return(d);
200 });
201 if(fix.chromosome.names) {
202 # remove ".fa"
203 names(tl) <- gsub("\\.fa","",names(tl))
204 }
205 # separate tags and quality
206 if(read.tag.names) {
207 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n),names=lapply(tl,function(d) d$s)));
208 } else {
209 return(list(tags=lapply(tl,function(d) d$t),quality=lapply(tl,function(d) d$n)));
210 }
211 }
212
213
214 # read in tags from an extended eland format with match length information
215 read.meland.tags <- function(filename,read.tag.names=F,fix.chromosome.names=T) {
216 if(read.tag.names) { rtn <- as.integer(1); } else { rtn <- as.integer(0); };
217 tl <- lapply(.Call("read_meland",filename,rtn),function(d) {
218 xo <- order(abs(d$t));
219 d$t <- d$t[xo];
220 d$n <- d$n[xo];
221 d$l <- d$l[xo];
222 if(read.tag.names) {
223 d$s <- d$s[xo];
224 }
225 return(d);
226 });
227
228 if(fix.chromosome.names) {
229 # remove ".fa"
230 names(tl) <- gsub("\\.fa","",names(tl))
231 }
232 # separate tags and quality
233 chrl <- names(tl); names(chrl) <- chrl;
234 # reformulate quality scores into monotonic integers
235 ml <- max(unlist(lapply(tl,function(d) max(d$l))));
236 qual <- lapply(chrl,function(chr) (ml-tl[[chr]]$l)+tl[[chr]]$n/10);
237 if(read.tag.names) {
238 return(list(tags=lapply(tl,function(d) d$t),quality=qual,names=lapply(tl,function(d) d$s)));
239 } else {
240 return(list(tags=lapply(tl,function(d) d$t),quality=qual));
241 }
242 }
243
244 # -------- ROUTINES FOR ASSESSING BINDING PATTERN AND SELECTING INFORMATIVE TAGS ------------
245
246 # removes tag positions that have anomalously high counts on both strands
247 # z - z-score used to determine anomalous bins
248 # zo - z used to filter out one-strand matches
249 # trim.fraction - fraction of top bins to discard when calculating overall background density
250 remove.tag.anomalies <- function(data, bin=1,trim.fraction=1e-3,z=5,zo=3*z) {
251
252 t.remove.tag.anomalies <- function(tv,bin=1,trim.fraction=1e-3,z=5,zo=3*z,return.indecies=F) {
253 tt <- table(floor(tv/bin));
254
255 # trim value
256 stt <- sort(as.numeric(tt));
257 stt <- stt[1:(length(stt)*(1-trim.fraction))];
258 mtc <- mean(stt); tcd <- sqrt(var(stt));
259
260 thr <- max(1,ceiling(mtc+z*tcd));
261 thr.o <- max(1,ceiling(mtc+zo*tcd));
262 # filter tt
263 tt <- tt[tt>=thr]
264 # get + and - tags
265 tp <- as.numeric(names(tt));
266 pti <- tp>0;
267 it <- intersect(tp[pti],(-1)*tp[!pti]);
268 # add one-strand matches
269 it <- unique(c(it,tp[tt>=thr.o]));
270 sit <- c(it,(-1)*it);
271
272 if(bin>1) {
273 sit <- sit*bin;
274 sit <- c(sit,unlist(lapply(1:bin,function(i) sit+i)))
275 }
276 if(return.indecies) {
277 return(!tv %in% sit);
278 } else {
279 return(tv[!tv %in% sit]);
280 }
281 }
282
283 vil <- lapply(data$tags,t.remove.tag.anomalies,return.indecies=T,bin=bin,trim.fraction=trim.fraction,z=z,zo=zo);
284 chrl <- names(data$tags); names(chrl) <- chrl;
285 data$tags <- lapply(chrl,function(chr) data$tags[[chr]][vil[[chr]]]);
286 # count tags to remove empty chromosomes
287 nt <- unlist(lapply(data$tags,length));
288 if(any(nt==0)) {
289 data$tags <- data$tags[nt!=0]
290 }
291
292 if(!is.null(data$quality)) {
293 data$quality <- lapply(chrl,function(chr) data$quality[[chr]][vil[[chr]]]);
294 data$quality <- data$quality[nt!=0];
295 }
296 if(!is.null(data$names)) {
297 data$names <- lapply(chrl,function(chr) data$names[[chr]][vil[[chr]]]);
298 data$names <- data$names[nt!=0];
299 }
300
301 return(data);
302 }
303
304 # caps or removes tag positions that are significantly higher than local background
305 remove.local.tag.anomalies <- function(tags,window.size=200,eliminate.fold=10,cap.fold=4,z.threshold=3) {
306 lapply(tags,filter.singular.positions.by.local.density,window.size=2e2,eliminate.fold=10,cap.fold=4,z.threshold=3);
307 }
308
309
310
311 # assess strand cross-correlation, determine peak position, determine appropriate window size
312 # for binding detection.
313 get.binding.characteristics <- function(data,srange=c(50,500),bin=5,cluster=NULL,debug=F,min.tag.count=1e3,acceptance.z.score=3,remove.tag.anomalies=T,anomalies.z=5,accept.all.tags=F) {
314 if(remove.tag.anomalies) {
315 data <- remove.tag.anomalies(data,z=anomalies.z);
316 }
317
318 # take highest quality tag bin
319 if(!is.null(data$quality) & !accept.all.tags) {
320 min.bin <- min(unlist(lapply(data$quality,min)))
321 chrl <- names(data$tags); names(chrl) <- chrl;
322 otl <- lapply(chrl,function(chr) data$tags[[chr]][data$quality[[chr]]==min.bin]);
323 } else {
324 otl <- data$tags;
325 }
326 # remove empty chromosomes
327 otl <- otl[unlist(lapply(otl,length))!=0];
328
329
330 # calculate strand scc
331 if(!is.null(cluster)) {
332 cc <- clusterApplyLB(cluster,otl,tag.scc,srange=srange,bin=bin);
333 names(cc) <- names(otl);
334 } else {
335 cc <- lapply(otl,tag.scc,srange=srange,bin=bin);
336 }
337 ccl<-list(sample=cc);
338 ccl.av <- lapply(names(ccl),t.plotavcc,type='l',ccl=ccl,return.ac=T,ttl=list(sample=otl),plot=F)[[1]]
339 ccl.av <- data.frame(x=as.numeric(names(ccl.av)),y=as.numeric(ccl.av));
340
341 # find peak
342 pi <- which.max(ccl.av$y);
343
344 # determine width at third-height
345 th <- (ccl.av$y[pi]-ccl.av$y[length(ccl.av$y)])/3+ccl.av$y[length(ccl.av$y)]
346 whs <- max(ccl.av$x[ccl.av$y>=th]);
347
348 if (! is.integer(whs)) { # Anshul: added this to avoid situations where whs ends up being -Inf
349 whs <- ccl.av$x[ min(c(2*pi,length(ccl.av$y))) ]
350 }
351
352 # determine acceptance of different quality bins
353
354 # calculates tag scc for the best tags, and combinations of best tag category with every other category
355 # for subsequent selection of acceptable categories
356 scc.acceptance.calc <- function() {
357
358 qr <- range(unlist(lapply(data$quality,range)))
359
360 # start with best tags
361
362 # determine half-width for scc calculations
363 pi <- which.max(ccl.av$y);
364
365 # determine width at half-height
366 th <- (ccl.av$y[pi]-ccl.av$y[length(ccl.av$y)])/2+ccl.av$y[length(ccl.av$y)]
367 lwhs <- max(ccl.av$x[ccl.av$y>=th])-ccl.av$x[pi];
368 lwhs <- max(c(20,bin*10,lwhs));
369 srange <- ccl.av$x[pi]+c(-lwhs,lwhs)
370
371 # calculate chromosome-average scc
372 t.scc <- function(tags) {
373 if(is.null(cluster)) {
374 cc <- lapply(tags,tag.scc,srange=srange,bin=bin);
375 } else {
376 cc <- clusterApplyLB(cluster,tags,tag.scc,srange=srange,bin=bin); names(cc) <- names(tags);
377 }
378 return(t.plotavcc(1,type='l',ccl=list(cc),ttl=list(tags),plot=F,return.ac=T))
379 }
380
381
382 # returns info list for a given tag length (lv), mismatch count (nv)
383 t.cat <- function(qual) {
384 # construct tag set
385 if(qual==qr[1]) {
386 ts <- otl;
387 } else {
388 nts <- names(otl); names(nts) <- nts;
389 # select tags
390 at <- lapply(nts,function(chr) data$tags[[chr]][data$quality[[chr]]==qual]);
391 ntags <- sum(unlist(lapply(at,length)));
392 if(ntags<min.tag.count) { return(NULL); }
393
394 # append to otl
395 ts <- lapply(nts,function(nam) c(otl[[nam]],at[[nam]]));
396 }
397
398 return(t.scc(ts));
399 }
400
401
402 # calculate cross-correlation values for each quality bin
403 ql <- sort(unique(unlist(lapply(data$quality,unique)))); names(ql) <- ql;
404
405 qccl <- lapply(ql,t.cat);
406
407 # acceptance tests
408 ac <- c(T,unlist(lapply(qccl[-1],function(d) if(is.null(d)) { return(F) } else { t.test(d-qccl[[as.character(min.bin)]],alternative="greater")$p.value<pnorm(acceptance.z.score,lower.tail=F) }))); names(ac) <- names(qccl);
409 return(list(informative.bins=ac,quality.cc=qccl))
410 }
411
412 if(accept.all.tags | is.null(data$quality)) {
413 return(list(cross.correlation=ccl.av,peak=list(x=ccl.av$x[pi],y=ccl.av$y[pi]),whs=whs))
414 } else {
415 acc <- scc.acceptance.calc();
416 return(list(cross.correlation=ccl.av,peak=list(x=ccl.av$x[pi],y=ccl.av$y[pi]),whs=whs,quality.bin.acceptance=acc));
417 }
418
419 }
420
421
422 # select a set of informative tags based on the pre-calculated binding characteristics
423 select.informative.tags <- function(data,binding.characteristics=NULL) {
424 if(is.null(binding.characteristics)) {
425 return(data$tags);
426 }
427 if(is.null(binding.characteristics$quality.bin.acceptance)) {
428 cat("binding characteristics doesn't contain quality selection info, accepting all tags\n");
429 return(data$tags);
430 }
431
432 ib <- binding.characteristics$quality.bin.acceptance$informative.bins;
433 abn <- names(ib)[ib]
434
435 chrl <- names(data$tags); names(chrl) <- chrl;
436 lapply(chrl,function(chr) {
437 data$tags[[chr]][as.character(data$quality[[chr]]) %in% abn]
438 })
439 }
440
441 # -------- ROUTINES FOR CALLING BINDING POSITIONS ------------
442
443 # determine binding positions
444 # signal.data - IP tag lists
445 # control.data - input tag lists
446 # e.value - desired E-value threshold (either E-value or FDR threshold must be provided)
447 # fdr - desired FDR threshold
448 # min.dist - minimal distance between detected positions
449 # tag.count.whs - size of the window to be used to estimate confidence interval of the peak fold enrichment ratios
450 # enrichmnent.z - Z-score defining the desired confidence level for enrichment interval estimates
451 # enrichment.background.scales - define how many tiems larger should be the window for estimating background
452 # tag density when evaluating peak enrichment confidence intervals.
453 # If multiple values are given, multiple independent interval estimates will be
454 # calculated.
455 # tec.filter - whether to mask out the regions that exhibit significant background enrichment
456 # tec.window.size, tec.z - window size and Z-score for maksing out significant background enrichment regions
457 #
458 # If the control.data is not provided, the method will assess significance of the determined binding positions
459 # based on the randomizations of the original data. The following paramters control such randomizations:
460 # n.randomizations - number of randomizations to be performed
461 # shuffle.window - size of the bin that defines the tags that are kept together during randomization.
462 # value of 0 means that all tags are shuffled independently
463 #
464 # Binding detection methods:
465 # tag.wtd - default method.
466 # must specify parameter "whs", which is the half-size of the window used to calculate binding scores
467 # tag.lwcc - LWCC method;
468 # must specify whs - a size of the window used to calculate binding scores
469 # can specify isize (default=15bp) - size of the internal window that is masked out
470 find.binding.positions <- function(signal.data,f=1,e.value=NULL,fdr=NULL, masked.data=NULL,control.data=NULL,whs=200,min.dist=200,window.size=4e7,cluster=NULL,debug=T,n.randomizations=3,shuffle.window=1,min.thr=2,topN=NULL, tag.count.whs=100, enrichment.z=2, method=tag.wtd, tec.filter=T,tec.window.size=1e4,tec.z=5,tec.masking.window.size=tec.window.size, tec.poisson.z=5,tec.poisson.ratio=5, tec=NULL, n.control.samples=1, enrichment.scale.down.control=F, enrichment.background.scales=c(1,5,10), use.randomized.controls=F, background.density.scaling=T, mle.filter=F, min.mle.threshold=1, ...) {
471
472 if(f<1) {
473 if(debug) { cat("subsampling signal ... "); }
474 signal.data <- lapply(signal.data,function(x) sample(x,length(x)*f))
475 if(debug) { cat("done\n"); }
476 }
477
478
479 if(!is.null(control.data) & !use.randomized.controls) {
480 # limit both control and signal data to a common set of chromosomes
481 chrl <- intersect(names(signal.data),names(control.data));
482 signal.data <- signal.data[chrl];
483 control.data <- control.data[chrl];
484 control <- list(control.data);
485 } else {
486 control <- NULL;
487 }
488
489 prd <- lwcc.prediction(signal.data,min.dist=min.dist,whs=whs,window.size=window.size,e.value=e.value,fdr=fdr,debug=debug,n.randomizations=n.randomizations,shuffle.window=shuffle.window,min.thr=min.thr,cluster=cluster,method=method,bg.tl=control.data,mask.tl=masked.data, topN=topN, control=control,tec.filter=tec.filter,tec.z=tec.z,tec.window.size=tec.window.size, tec.masking.window.size=tec.masking.window.size, tec.poisson.z=tec.poisson.z,tec.poisson.ratio=tec.poisson.ratio, background.density.scaling=background.density.scaling, ...);
490
491 # add tag counts
492 chrl <- names(prd$npl); names(chrl) <- chrl;
493 prd$npl <- lapply(chrl,function(chr) {
494 pd <- prd$npl[[chr]];
495 pd$nt <- points.within(abs(signal.data[[chr]]),pd$x-tag.count.whs,pd$x+tag.count.whs,return.point.counts=T);
496 return(pd);
497 });
498 prd$f <- f;
499 prd$n <- sum(unlist(lapply(signal.data,length)));
500 if(!is.null(control.data)) {
501 prd$n.bg <- sum(unlist(lapply(control.data,length)));
502 }
503
504 # calculate enrichment ratios
505 prd <- calculate.enrichment.estimates(prd,signal.data,control.data=control.data,fraction=1,tag.count.whs=tag.count.whs,z=enrichment.z,scale.down.control=enrichment.scale.down.control,background.scales=enrichment.background.scales);
506
507 if(mle.filter) {
508 if(!is.null(prd$npl)) {
509 if(length(prd$npl)>1) {
510 mle.columns <- grep("enr.mle",colnames(prd$npl[[1]]));
511 if(length(mle.columns)>1) {
512 prd$npl <- lapply(prd$npl,function(d) d[apply(d[,mle.columns],1,function(x) all(x>min.mle.threshold)),])
513 }
514 }
515 }
516 }
517
518 prd$whs <- whs;
519
520 return(prd);
521 }
522
523
524
525 # -------- ROUTINES FOR WRITING OUT TAG DENSITY AND ENRICHMENT PROFILES ------------
526 # calculate smoothed tag density, optionally subtracting the background
527 get.smoothed.tag.density <- function(signal.tags,control.tags=NULL,bandwidth=150,bg.weight=NULL,tag.shift=146/2,step=round(bandwidth/3),background.density.scaling=T,rngl=NULL,scale.by.dataset.size=F) {
528 chrl <- names(signal.tags); names(chrl) <- chrl;
529
530 if(!is.null(control.tags)) {
531 bg.weight <- dataset.density.ratio(signal.tags,control.tags,background.density.scaling=background.density.scaling);
532 }
533
534 if(scale.by.dataset.size) {
535 den.scaling <- dataset.density.size(signal.tags,background.density.scaling=background.density.scaling)/1e6;
536 } else {
537 den.scaling <- 1;
538 }
539
540 lapply(chrl,function(chr) {
541 ad <- abs(signal.tags[[chr]]+tag.shift);
542 rng <- NULL;
543 if(!is.null(rngl)) {
544 rng <- rngl[[chr]];
545 }
546 if(is.null(rng)) {
547 rng <- range(ad);
548 }
549
550 ds <- densum(ad,bw=bandwidth,from=rng[1],to=rng[2],return.x=T,step=step);
551 if(!is.null(control.tags)) {
552 if(!is.null(control.tags[[chr]])) {
553 bsd <- densum(abs(control.tags[[chr]]+tag.shift),bw=bandwidth,from=rng[1],to=rng[2],return.x=F,step=step);
554 ds$y <- ds$y-bsd*bg.weight;
555 }
556 }
557 return(data.frame(x=seq(ds$x[1],ds$x[2],by=step),y=den.scaling*ds$y))
558 })
559 }
560
561 # get smoothed maximum likelihood estimate of the log2 signal to control enrichment ratio
562 get.smoothed.enrichment.mle <- function(signal.tags, control.tags, tag.shift=146/2, background.density.scaling=F, pseudocount=1,bg.weight=NULL, ... ) {
563 # determine common range
564 chrl <- intersect(names(signal.tags),names(control.tags)); names(chrl) <- chrl;
565 rngl <- lapply(chrl,function(chr) range(c(range(abs(signal.tags[[chr]]+tag.shift)),range(abs(control.tags[[chr]]+tag.shift)))))
566 ssd <- get.smoothed.tag.density(signal.tags, rngl=rngl, ..., scale.by.dataset.size=F)
567 csd <- get.smoothed.tag.density(control.tags, rngl=rngl, ..., scale.by.dataset.size=F)
568 if(is.null(bg.weight)) {
569 bg.weight <- dataset.density.ratio(signal.tags,control.tags,background.density.scaling=background.density.scaling);
570 }
571 cmle <- lapply(chrl,function(chr) { d <- ssd[[chr]]; d$y <- log2(d$y+pseudocount) - log2(csd[[chr]]$y+pseudocount) - log2(bg.weight); return(d); })
572 }
573
574
575 # returns a conservative upper/lower bound profile (log2) given signal tag list, background tag list and window scales
576 get.conservative.fold.enrichment.profile <- function(ftl,btl,fws,bwsl=c(1,5,25,50)*fws,step=50,tag.shift=146/2,alpha=0.05,use.most.informative.scale=F,quick.calculation=T,background.density.scaling=T,bg.weight=NULL,posl=NULL,return.mle=F) {
577 # include only chromosomes with more than 2 reads
578 ftl <- ftl[unlist(lapply(ftl,length))>2]
579 chrl <- names(ftl); names(chrl) <- chrl;
580 if(!is.null(posl)) {
581 chrl <- chrl[chrl %in% names(posl)];
582 }
583 # calculate background tag ratio
584 if(is.null(bg.weight)) {
585 bg.weight <- dataset.density.ratio(ftl,btl,background.density.scaling=background.density.scaling);
586 }
587 lapply(chrl,function(chr) {
588 if(is.null(btl[[chr]])) { bt <- c(); } else { bt <- abs(btl[[chr]]+tag.shift); }
589 if(is.null(posl)) {
590 x <- mbs.enrichment.bounds(abs(ftl[[chr]]+tag.shift),bt,fws=fws,bwsl=bwsl,step=step,calculate.upper.bound=T,bg.weight=bg.weight,use.most.informative.scale=use.most.informative.scale,quick.calculation=quick.calculation,alpha=alpha);
591 } else {
592 x <- mbs.enrichment.bounds(abs(ftl[[chr]]+tag.shift),bt,fws=fws,bwsl=bwsl,step=step,calculate.upper.bound=T,bg.weight=bg.weight,use.most.informative.scale=use.most.informative.scale,quick.calculation=quick.calculation,alpha=alpha,pos=posl[[chr]]);
593 }
594 # compose profile showing lower bound for enriched, upper bound for depleted regions
595 ps <- rep(1,length(x$mle));
596 vi <- which(!is.na(x$lb) & x$lb>1);
597 ps[vi] <- x$lb[vi];
598 vi <- which(!is.na(x$ub) & x$ub<1);
599 ps[vi] <- x$ub[vi];
600 ps <- log2(ps);
601 if(is.null(posl)) {
602 if(return.mle) {
603 return(data.frame(x=seq(x$x$s,x$x$e,by=x$x$step),y=ps,mle=log2(x$mle),lb=log2(x$lb),ub=log2(x$ub)));
604 } else {
605 return(data.frame(x=seq(x$x$s,x$x$e,by=x$x$step),y=ps));
606 }
607 } else {
608 if(return.mle) {
609 return(data.frame(x=posl[[chr]],y=ps,mle=log2(x$mle),lb=log2(x$lb),ub=log2(x$ub)));
610 } else {
611 return(data.frame(x=posl[[chr]],y=ps));
612 }
613 }
614 })
615 }
616
617
618 # write a per-chromosome $x/$y data structure into a wig file
619 writewig <- function(dat,fname,feature,threshold=5,zip=F) {
620 chrl <- names(dat); names(chrl) <- chrl;
621 invisible(lapply(chrl,function(chr) {
622 bdiff <- dat[[chr]];
623 ind <- seq(1,length(bdiff$x));
624 ind <- ind[!is.na(bdiff$y[ind])];
625 header <- chr==chrl[1];
626 write.probe.wig(chr,bdiff$x[ind],bdiff$y[ind],fname,append=!header,feature=feature,header=header);
627 }))
628 if(zip) {
629 zf <- paste(fname,"zip",sep=".");
630 system(paste("zip \"",zf,"\" \"",fname,"\"",sep=""));
631 system(paste("rm \"",fname,"\"",sep=""));
632 return(zf);
633 } else {
634 return(fname);
635 }
636 }
637
638
639
640 # -------- ROUTINES FOR ANALYZING SATURATION PROPERTIES ------------
641
642 # PUBLIC
643 # calculate minimal saturation enrichment ratios (MSER)
644 get.mser <- function(signal.data,control.data,n.chains=5,step.size=1e5, chains=NULL, cluster=NULL, test.agreement=0.99, return.chains=F, enrichment.background.scales=c(1), n.steps=1, ...) {
645 if(is.null(chains)) {
646 ci <- c(1:n.chains); names(ci) <- ci;
647 if(is.null(cluster)) {
648 chains <- lapply(ci,get.subsample.chain.calls,signal.data=signal.data,control.data=control.data,n.steps=n.steps,step.size=step.size,subsample.control=F, enrichment.background.scales=enrichment.background.scales, ...);
649 } else {
650 chains <- clusterApplyLB(cluster,ci,get.subsample.chain.calls,signal.data=signal.data,control.data=control.data,n.steps=n.steps,step.size=step.size,subsample.control=F, enrichment.background.scales=enrichment.background.scales, ...);
651 names(chains) <- ci;
652 }
653 }
654 cvl <- mser.chain.interpolation(chains=chains,enrichment.background.scales=enrichment.background.scales,test.agreement=test.agreement,return.lists=F);
655 if(n.steps>1) {
656 msers <- cvl;
657 } else {
658 msers <- unlist(lapply(cvl,function(d) d$me))
659 }
660 if(return.chains) {
661 return(list(mser=msers,chains=chains));
662 } else {
663 return(msers);
664 }
665 }
666
667 # PUBLIC
668 # interpolate MSER dependency on tag counts
669 get.mser.interpolation <- function(signal.data,control.data,target.fold.enrichment=5,n.chains=10,n.steps=6,step.size=1e5, chains=NULL, test.agreement=0.99, return.chains=F, enrichment.background.scales=c(1), excluded.steps=c(seq(2,n.steps-2)), ...) {
670 msers <- get.mser(signal.data,control.data,n.chains=n.chains,n.steps=n.steps,step.size=step.size,chains=chains,test.agrement=test.agreement,return.chains=T,enrichment.background.scales=enrichment.background.scales,excluded.steps=excluded.steps, ...);
671
672 # adjust sizes in case a subset of chromosomes was used
673 mser <- mser.chain.interpolation(chains=msers$chains,enrichment.background.scales=enrichment.background.scales,test.agreement=test.agreement,return.lists=T);
674 sr <- sum(unlist(lapply(signal.data,length)))/mser[[1]][[1]]$n[1];
675
676 # Subsampling each chain requires removing a fraction of each chromosome's
677 # tag list. To get the exact step.size, this often leaves chromosomes with
678 # a non-integer number of tags. The non-integer values are floored, so each
679 # chr can contribute at most 0.999.. <= 1 error to the step.size.
680 floor.error <- length(msers$chains[[1]][[1]]$npl)
681 intpn <- lapply(mser,function(ms) {
682 lmvo <- do.call(rbind,ms)
683 lmvo$n <- lmvo$n*sr;
684 # Don't select rows corresponding to excluded.steps
685 # Keep in mind that nd values are negative.
686 lmvo <- lmvo[lmvo$nd <= (lmvo$nd[1] + floor.error) & lmvo$nd >= (lmvo$nd[1] - floor.error),];
687 lmvo <- na.omit(lmvo);
688 if(any(lmvo$me==1)) {
689 return(list(prediction=NA));
690 }
691 lmvo$n <- log10(lmvo$n); lmvo$me <- log10(lmvo$me-1)
692 # remove non-standard steps
693 emvf <- lm(me ~ n,data=lmvo);
694 tfe <- (log10(target.fold.enrichment-1)-coef(emvf)[[1]])/coef(emvf)[[2]];
695 tfen <- 10^tfe;
696 return(list(prediction=tfen,log10.fit=emvf));
697 })
698
699 if(return.chains) {
700 return(list(interpolation=intpn,chains=msers$chains))
701 } else {
702 return(intpn);
703 }
704
705 return(msers);
706
707 }
708
709
710 # output binding detection results to a text file
711 # the file will contain a table with each row corresponding
712 # to a detected position, with the following columns:
713 # chr - chromosome or target sequence
714 # pos - position of detected binding site on the chromosome/sequence
715 # score - a score reflecting magnitude of the binding
716 # Evalue - E-value corresponding to the peak magnitude
717 # FDR - FDR corresponding to the peak magnitude
718 # enrichment.lb - lower bound of the fold-enrichment ratio
719 # enrichment.mle - maximum likelihood estimate of the fold-enrichment ratio
720 output.binding.results <- function(results,filename) {
721 write(file=filename,"chr\tpos\tscore\tEvalue\tFDR\tenrichment.lb\tenrichment.mle",append=F);
722 chrl <- names(results$npl); names(chrl) <- chrl;
723 x <- lapply(chrl,function(chr) {
724 d <- results$npl[[chr]];
725 if(dim(d)[1]>0) {
726 if(results$thr$type=="topN") {
727 od <- cbind(rep(chr,dim(d)[1]),subset(d,select=c(x,y,enr,enr.mle)))
728 } else {
729 od <- cbind(rep(chr,dim(d)[1]),subset(d,select=c(x,y,evalue,fdr,enr,enr.mle)))
730 }
731 write.table(od,file=filename,col.names=F,row.names=F,sep="\t",append=T,quote=F)
732 }
733 })
734 }
735
736
737 # -------- LOW-LEVEL ROUTINES ------------
738
739 # calculates tag strand cross-correlation for a range of shifts (on positive strand)
740 tag.scc <- function(tags,srange=c(50,250),bin=1,tt=NULL,llim=10) {
741 if(is.null(tt)) {
742 tt <- table(sign(tags)*as.integer(floor(abs(tags)/bin+0.5)));
743 }
744 if(!is.null(llim)) { l <- mean(tt); tt <- tt[tt<llim*l] }
745 tc <- as.integer(names(tt));
746 tt <- as.numeric(tt);
747
748 pv <- tt; pv[tc<0]<-0;
749 nv <- tt; nv[tc>0]<-0;
750
751 pti <- which(tc>0)
752 nti <- which(tc<0);
753
754 ptc <- tc[pti];
755 ntc <- (-1)*tc[nti];
756
757 ptv <- tt[pti];
758 ntv <- tt[nti];
759
760 trng <- range(c(range(ptc),range(ntc)))
761 l <- diff(trng)+1;
762 rm(tc,tt);
763
764 mp <- sum(ptv)*bin/l; mn <- sum(ntv)*bin/l;
765 ptv <- ptv-mp; ntv <- ntv-mn;
766 ss <- sqrt((sum(ptv*ptv)+(l-length(ptv))*mp^2) * (sum(ntv*ntv)+(l-length(ntv))*mn^2));
767
768 t.cor <- function(s) {
769 smi <- match(ptc+s,ntc);
770 return((sum(ptv[!is.na(smi)]*ntv[na.omit(smi)]) -
771 mn*sum(ptv[is.na(smi)]) -
772 mp*sum(ntv[-na.omit(smi)]) +
773 mp*mn*(l-length(ptv)-length(ntv)+length(which(!is.na(smi)))))/ss);
774 }
775 shifts <- floor(seq(srange[1],srange[2],by=bin)/bin+0.5);
776 scc <- unlist(lapply(shifts,t.cor)); names(scc) <- shifts*bin;
777 return(scc);
778 }
779
780
781 # plot tag cross-correlation
782 t.plotcc <- function(ac, lab=c(10,5,7), ylab="correlation", xlab="lag", pch=19, grid.i=c(-5:5), grid.s=10, type='b', plot.grid=F, cols=c(1,2,4,"orange",8,"pink"), min.peak.x=NULL, xlim=NULL, plot.147=F, plot.max=T, rmw=1, rescale=F, legendx="right", ltys=rep(1,length(ac)), ...) {
783 if(is.list(ac)) {
784 cols <- cols[1:length(ac)];
785
786 if(!is.null(xlim)) {
787 vx <- as.numeric(names(ac[[1]])); vx <- which(vx>=xlim[1] & vx<=xlim[2]);
788 ac[[1]] <- (ac[[1]])[vx];
789 } else {
790 xlim <- range(as.numeric(names(ac[[1]])));
791 }
792
793
794 plot(as.numeric(names(ac[[1]])),runmean(ac[[1]],rmw),type=type,pch=pch,xlab=xlab,ylab=ylab,lab=lab, col=cols[1], xlim=xlim, lty=ltys[1], ...);
795 if(length(ac)>1) {
796 for(i in seq(2,length(ac))) {
797 irng <- range(ac[[i]]);
798 vx <- as.numeric(names(ac[[i]])); vx <- which(vx>=xlim[1] & vx<=xlim[2]);
799 if(rescale) {
800 lines(as.numeric(names(ac[[i]])[vx]),runmean((ac[[i]][vx]-irng[1])/diff(irng)*diff(range(ac[[1]]))+min(ac[[1]]),rmw),col=cols[i],lty=ltys[i]);
801 } else {
802 lines(as.numeric(names(ac[[i]]))[vx],runmean(ac[[i]][vx],rmw),col=cols[i],lty=ltys[i]);
803 }
804 }
805 }
806 if(is.null(min.peak.x)) {
807 m <- as.numeric(names(ac[[1]])[which.max(ac[[1]])]);
808 } else {
809 sac <- (ac[[1]])[which(as.numeric(names(ac[[1]]))>min.peak.x)]
810 m <- as.numeric(names(sac)[which.max(sac)]);
811 }
812 legend(x="topright",bty="n",legend=c(names(ac)),col=cols,lty=ltys)
813 } else {
814 if(!is.null(xlim)) {
815 vx <- as.numeric(names(ac));
816 vx <- which(vx>=xlim[1] & vx<=xlim[2]);
817 ac <- ac[vx];
818 } else {
819 xlim <- range(as.numeric(names(ac)));
820 }
821
822 plot(names(ac),runmean(ac,rmw),type=type,pch=pch,xlab=xlab,ylab=ylab,lab=lab, xlim=xlim, ...);
823 if(is.null(min.peak.x)) {
824 m <- as.numeric(names(ac)[which.max(ac)]);
825 } else {
826 sac <- ac[which(names(ac)>min.peak.x)]
827 m <- as.numeric(names(sac)[which.max(sac)]);
828 }
829 }
830 if(plot.147) {
831 abline(v=147,lty=2,col=8);
832 }
833 if(plot.grid) {
834 abline(v=m+grid.i*grid.s,lty=3,col="pink");
835 }
836 if(plot.max) {
837 abline(v=m,lty=2,col=2);
838 legend(x=legendx,bty="n",legend=c(paste("max at ",m,"bp",sep="")));
839 return(m);
840 }
841 }
842
843 # plot chromosome-acerage cross-correlation
844 t.plotavcc <- function(ci, main=paste(ci,"chromosome average"), ccl=tl.cc, return.ac=F, ttl=tl, plot=T, ... ) {
845 cc <- ccl[[ci]];
846 if(length(cc)==1) { return(cc[[1]]) };
847 if(length(cc)==0) { return(c()) };
848 ac <- do.call(rbind,cc);
849 # omit NA chromosomes
850 ina <- apply(ac,1,function(d) any(is.na(d)));
851
852 tags <- ttl[[ci]];
853 avw <- unlist(lapply(tags,length)); avw <- avw/sum(avw);
854 ac <- ac[!ina,]; avw <- avw[!ina];
855 ac <- apply(ac,2,function(x) sum(x*avw));
856 if(plot) {
857 m <- t.plotcc(ac, main=main, ...);
858 if(!return.ac) { return(m) }
859 }
860 if(return.ac) { return(ac) }
861 }
862
863 t.plotchrcc <- function(ci,ncol=4, ccl=tl.cc, ... ) {
864 cc <- ccl[[ci]];
865 ac <- do.call(rbind,cc);
866 par(mfrow = c(length(cc)/ncol,ncol), mar = c(3.5,3.5,2.0,0.5), mgp = c(2,0.65,0), cex = 0.8)
867 lapply(names(cc),function(ch) { t.plotcc(cc[[ch]],main=paste(ci,": chr",ch,sep=""), ...) })
868 }
869
870 t.plotavccl <- function(ci, ccl=tl.ccl, main=paste(ci,"chromosome average"), rtl=tl, ... ) {
871 #cc <- lapply(ccl[[ci]],function(x) { if(!is.null(x$M)) { x$M <- NULL;}; return(x); });
872 cc <- ccl[[ci]];
873 chrs <- names(cc[[1]]); names(chrs) <- chrs;
874 acl <- lapply(cc,function(x) do.call(rbind,x));
875 tags <- rtl[[ci]][chrs];
876 avw <- unlist(lapply(tags,length)); avw <- avw/sum(avw);
877 acl <- lapply(acl,function(ac) apply(ac,2,function(x) sum(x*avw)))
878 t.plotcc(acl, main=main, ...);
879 }
880
881 t.plotchrccl <- function(ci,ccl=tl.ccl,ncol=4, ... ) {
882 par(mfrow = c(length(cc[[1]])/ncol,ncol), mar = c(3.5,3.5,2.0,0.5), mgp = c(2,0.65,0), cex = 0.8)
883 lapply(names(cc[[1]]),function(ch) { t.plotcc(lapply(cc,function(x) x[[ch]]),main=paste(ci,": chr",ch,sep=""), ...) })
884 }
885
886
887
888 show.scc <- function(tl,srange,cluster=NULL) {
889 if(!is.null(cluster)) {
890 cc <- clusterApplyLB(cluster,tl,tag.scc,srange=srange);
891 names(cc) <- names(tl);
892 } else {
893 cc <- lapply(tl,tag.scc,srange=srange);
894 }
895 par(mfrow = c(1,1), mar = c(3.5,3.5,2.0,0.5), mgp = c(2,0.65,0), cex = 0.8);
896 ccl<-list(sample=cc);
897 ccl.av <- lapply(names(ccl),t.plotavcc,type='l',ccl=ccl,xlim=srange,return.ac=F,ttl=list(sample=tl),main="")[[1]]
898 }
899
900 # find regions of significant tag enrichment
901 find.significantly.enriched.regions <- function(signal.data,control.data,window.size=500,multiplier=1,z.thr=3,mcs=0,debug=F,background.density.scaling=T,masking.window.size=window.size,poisson.z=0,poisson.ratio=4,either=F,tag.shift=146/2,bg.weight=NULL) {
902 if(is.null(bg.weight)) {
903 bg.weight <- dataset.density.ratio(signal.data,control.data,background.density.scaling=background.density.scaling);
904 }
905
906 if(debug) {
907 cat("bg.weight=",bg.weight,"\n");
908 }
909 chrl <- names(signal.data); names(chrl) <- chrl;
910 tec <- lapply(chrl,function(chr) {
911 d <- tag.enrichment.clusters(signal.data[[chr]],control.data[[chr]],bg.weight=bg.weight*multiplier,thr=z.thr,wsize=window.size,mcs=mcs,min.tag.count.z=poisson.z,min.tag.count.ratio=poisson.ratio,either=either,tag.shift=tag.shift);
912 d$s <- d$s-masking.window.size/2; d$e <- d$e+masking.window.size/2;
913 return(d);
914 })
915 }
916
917
918 # given tag position vectors, find contigs of significant enrichment of signal over background
919 # thr - z score threshold
920 # mcs - minimal cluster size
921 # bg.weight - fraction by which background counts should be multipled
922 # min.tag.count.z will impose a poisson constraint based on randomized signal in parallel of background constaint (0 - no constraint)
923 tag.enrichment.clusters <- function(signal,background,wsize=200,thr=3,mcs=1,bg.weight=1,min.tag.count.z=0,tag.av.den=NULL,min.tag.count.thr=0,min.tag.count.ratio=4,either=F,tag.shift=146/2) {
924 if(is.null(tag.av.den)) {
925 tag.av.den <- length(signal)/diff(range(abs(signal)));
926 }
927 if(min.tag.count.z>0) {
928 min.tag.count.thr <- qpois(pnorm(min.tag.count.z,lower.tail=F),min.tag.count.ratio*tag.av.den*wsize,lower.tail=F)
929 } else {
930 min.tag.count.thr <- 0;
931 }
932
933 #if(bg.weight!=1) {
934 # background <- sample(background,length(background)*(bg.weight),replace=T);
935 #}
936 # make up combined position, flag vectors
937 pv <- abs(c(signal,background)+tag.shift);
938 fv <- c(rep(1,length(signal)),rep(0,length(background)));
939 po <- order(pv);
940 pv <- pv[po];
941 fv <- fv[po];
942
943 #thr <- pnorm(thr,lower.tail=F);
944
945 storage.mode(wsize) <- storage.mode(mcs) <- storage.mode(fv) <- "integer";
946 storage.mode(thr) <- storage.mode(pv) <- "double";
947 storage.mode(bg.weight) <- "double";
948 storage.mode(min.tag.count.thr) <- "double";
949 either <- as.integer(either);
950 storage.mode(either) <- "integer";
951
952 z <- .Call("find_poisson_enrichment_clusters",pv,fv,wsize,thr,mcs,bg.weight,min.tag.count.thr,either)
953 return(z);
954 }
955
956
957
958
959
960 # estimates threshold, calculates predictions on complete data and randomized data
961 # input: tvl
962 # control - a list of control tag datasets
963 # no randomization is done if control is supplied
964 # return.rtp - return randomized tag peaks - do not fit thresholds or do actual predictions
965 # topN - use min threshold to do a run, return topN peaks from entire genome
966 # threshold - specify a user-defined threshold
967 lwcc.prediction <- function(tvl,e.value=NULL, fdr=0.01, chrl=names(tvl), min.thr=0, n.randomizations=1, shuffle.window=1, debug=T, predict.on.random=F, shuffle.both.strands=T,strand.shuffle.only=F, return.rtp=F, control=NULL, print.level=0, threshold=NULL, topN=NULL, bg.tl=NULL, tec.filter=T, tec.window.size=1e3,tec.z=3, tec.masking.window.size=tec.window.size, tec.poisson.z=3,tec.poisson.ratio=4, bg.reverse=T, return.control.predictions=F, return.core.data=F, background.density.scaling=T, ... ) {
968
969 control.predictions <- NULL;
970 core.data <- list();
971
972 if(!is.null(bg.tl) & tec.filter) {
973 if(debug) { cat("finding background exclusion regions ... "); }
974 tec <- find.significantly.enriched.regions(bg.tl,tvl,window.size=tec.window.size,z.thr=tec.z,masking.window.size=tec.masking.window.size,poisson.z=tec.poisson.z,poisson.ratio=tec.poisson.ratio,background.density.scaling=background.density.scaling,either=T);
975 if(return.core.data) {
976 core.data <- c(core.data,list(tec=tec));
977 }
978 if(debug) { cat("done\n"); }
979 }
980
981
982 if(is.null(threshold) & is.null(topN)) { # threshold determination is needed
983 # generate control predictions
984 if(!is.null(control)) {
985 if(debug) { cat("determining peaks on provided",length(control),"control datasets:\n"); }
986 if(!is.null(bg.tl)) {
987 if(bg.reverse) {
988 if(debug) { cat("using reversed signal for FDR calculations\n"); }
989 rbg.tl <- tvl;
990 } else {
991 if(debug) { cat("generating randomized (within chromosome) background ... "); }
992 rbg.tl <- lapply(bg.tl,function(d) {
993 if(length(d)<2) { return(d); }
994 rng <- range(abs(d));
995 rd <- round(runif(length(d),rng[1],rng[2]));
996 nrd <- sample(1:length(rd),length(which(d<0)));
997 rd[nrd] <- rd[nrd]*(-1);
998 return(rd);
999 })
1000 if(debug) { cat("done\n"); }
1001 }
1002 } else {
1003 rbg.tl <- NULL;
1004 }
1005 n.randomizations <- length(control);
1006 #signal.size <- sum(unlist(lapply(tvl,length)));
1007 rtp <- lapply(control,function(d) {
1008 # calculate tag.weight
1009 #tag.weight <- sum(unlist(lapply(tvl,length)))/sum(unlist(lapply(d,length)));
1010 tag.weight <- dataset.density.ratio(tvl,d,background.density.scaling=background.density.scaling);
1011 #cat("tag.weight=",tag.weight," ");
1012 return(window.call.mirror.binding(d,min.thr=min.thr, tag.weight=tag.weight,bg.tl=rbg.tl, debug=debug, round.up=T,background.density.scaling=background.density.scaling, ...));
1013 #return(window.call.mirror.binding(d,min.thr=min.thr, method=tag.wtd,wsize=200,bg.tl=control.data,window.size=window.size,debug=T,min.dist=min.dist,cluster=cluster))
1014 });
1015 if(return.core.data) {
1016 core.data <- c(core.data,list(rtp.unfiltered=rtp));
1017 }
1018 if(tec.filter) {
1019 if(debug) { cat("excluding systematic background anomalies ... "); }
1020 rtp <- lapply(rtp,filter.binding.sites,tec,exclude=T);
1021 if(debug) { cat("done\n"); }
1022 }
1023 } else {
1024 if(debug) { cat("determining peaks on ",n.randomizations,"randomized datasets:\n"); }
1025 rtp <- lapply(1:n.randomizations,function(i) {
1026 rd <- generate.randomized.data(tvl,shuffle.window=shuffle.window,shuffle.both.strands=shuffle.both.strands,strand.shuffle.only=strand.shuffle.only);
1027 return(window.call.mirror.binding(rd,min.thr=min.thr,bg.tl=bg.tl, debug=debug, ...));
1028 #return(window.call.mirror.binding(rd,min.thr=min.thr, method=tag.wtd,wsize=200,bg.tl=control.data,window.size=window.size,debug=T,min.dist=min.dist))
1029 });
1030 }
1031 if(return.control.predictions) {
1032 control.predictions <- rtp;
1033 }
1034 rtp <- do.call(rbind,lapply(rtp,function(d) do.call(rbind,d))); # merge tables
1035
1036 # generate real data predictions
1037 if(debug) { cat("determining peaks on real data:\n"); }
1038 npl <- window.call.mirror.binding(tvl,min.thr=min.thr,bg.tl=bg.tl, debug=debug, background.density.scaling=background.density.scaling, ...);
1039 #npl <- window.call.mirror.binding(tvl,min.thr=min.thr, method=tag.wtd,wsize=200,bg.tl=control.data,window.size=window.size,debug=T,min.dist=min.dist,cluster=cluster);
1040 if(return.core.data) {
1041 core.data <- c(core.data,list(npl.unfiltered=npl));
1042 }
1043
1044 if(!is.null(bg.tl) & tec.filter) {
1045 if(debug) { cat("excluding systematic background anomalies ... "); }
1046 npl <- filter.binding.sites(npl,tec,exclude=T);
1047 if(debug) { cat("done\n"); }
1048 }
1049
1050 # calculate E-value and FDRs for all of the peaks
1051 if(debug) { cat("calculating statistical thresholds\n"); }
1052 chrl <- names(npl); names(chrl) <- chrl;
1053 npld <- do.call(rbind,lapply(names(npl),function(chr) { k <- npl[[chr]]; if(!is.null(k) & dim(k)[1]>0) { k$chr <- rep(chr,dim(k)[1]) }; return(k) }))
1054 npld <- cbind(npld,get.eval.fdr.vectors(npld$y,rtp$y));
1055 # correct for n.randomizations
1056 npld$fdr <- npld$fdr/n.randomizations;
1057 npld$evalue <- npld$evalue/n.randomizations;
1058
1059 if(return.core.data) {
1060 core.data <- c(core.data,list(npld=npld));
1061 }
1062
1063 # determine actual thresholds
1064 if(is.null(e.value)) {
1065 if(is.null(fdr)) { fdr <- 0.01; }
1066 thr <- list(root=min(npld$y[npld$fdr<=fdr]),type="FDR",fdr=fdr)
1067 if(debug) { cat("FDR",fdr,"threshold=",thr$root,"\n"); }
1068 } else {
1069 # determine threshold based on e-value
1070 thr <- list(root=min(npld$y[npld$evalue<=e.value]),type="Evalue",e.value=e.value)
1071 if(debug) { cat("E-value",e.value,"threshold=",thr$root,"\n"); }
1072 }
1073
1074
1075 npld <- npld[npld$y>=thr$root,];
1076 if(dim(npld)[1]>0) {
1077 npl <- tapply(c(1:dim(npld)[1]),as.factor(npld$chr),function(ii) {df <- npld[ii,]; df$chr <- NULL; return(df) });
1078 } else {
1079 npl <- list();
1080 }
1081 } else {
1082 if(is.null(threshold)) {
1083 thr <- list(root=min.thr,type="minimal");
1084 } else {
1085 thr <- list(root=threshold,type="user specified");
1086 }
1087
1088 cat("calling binding positions using",thr$type,"threshold (",thr$root,") :\n");
1089 npl <- window.call.mirror.binding(tvl=tvl,min.thr=thr$root,bg.tl=bg.tl, debug=debug, ...);
1090 if(!is.null(bg.tl) & tec.filter) {
1091 if(debug) { cat("excluding systematic background anomalies ... "); }
1092 npl <- filter.binding.sites(npl,tec,exclude=T);
1093 if(debug) { cat("done\n"); }
1094 }
1095
1096 if(!is.null(topN)) {
1097 # determine threshold based on topN peaks
1098 ay <- unlist(lapply(npl,function(d) d$y));
1099 if(length(ay)>topN) {
1100 thr <- list(root=sort(ay,decreasing=T)[topN],type="topN",topN=topN);
1101 cat(paste("determined topN threshold :",thr$root,"\n"));
1102 npl <- lapply(npl,function(d) d[d$y>thr$root,]);
1103 }
1104 }
1105 }
1106
1107 if(return.core.data) {
1108 return(c(list(npl=npl,thr=thr),core.data));
1109 }
1110 if(return.control.predictions & !is.null(control.predictions)) {
1111 return(list(npl=npl,thr=thr,control.predictions=control.predictions));
1112 }
1113 return(list(npl=npl,thr=thr));
1114 }
1115
1116 # window tag difference method
1117 wtd <- function(x,y,s,e,whs=200,return.peaks=T,min.thr=5,min.dist=200,step=1,direct.count=F,tag.weight=1,bg.x=NULL,bg.y=NULL,bg.weight=1,mask.x=NULL,mask.y=NULL,ignore.masking=F, bg.whs=whs, round.up=F, ...) {
1118 ignore.masking <- ignore.masking | (is.null(mask.x) & is.null(mask.y));
1119 if(step>1) {
1120 x <- floor(x/step+0.5); y <- floor(y/step+0.5)
1121
1122 if(!is.null(bg.x)) {
1123 bg.x <- floor(bg.x/step+0.5); bg.y <- floor(bg.y/step+0.5)
1124 }
1125
1126 if(!is.null(mask.x)) {
1127 mask.x <- floor(mask.x/step+0.5); mask.y <- floor(mask.y/step+0.5)
1128 }
1129
1130
1131 whs <- floor(whs/step+0.5);
1132 bg.whs <- floor(bg.whs/step+0.5);
1133 min.dist <- floor(min.dist/step +0.5);
1134 s <- floor(s/step+0.5)
1135 e <- floor(e/step+0.5)
1136 }
1137
1138 # scale bg.weight, since within calculation they are considered independent
1139 bg.weight <- bg.weight*tag.weight;
1140
1141 rx <- c(s-whs,e+whs);
1142
1143 # compile tag vectors
1144 xt <- table(x);
1145 xh <- integer(diff(rx)+1);
1146 xh[as.integer(names(xt))-rx[1]+1] <- as.integer(xt);
1147
1148 yt <- table(y);
1149 yh <- integer(diff(rx)+1);
1150 yh[as.integer(names(yt))-rx[1]+1] <- as.integer(yt);
1151
1152 # compile background vectors
1153 if(!is.null(bg.x) & length(bg.x)>0) {
1154 bg.subtract <- 1;
1155
1156 bg.xt <- table(bg.x);
1157 bg.xh <- integer(diff(rx)+1);
1158 bg.xh[as.integer(names(bg.xt))-rx[1]+1] <- as.integer(bg.xt);
1159 rm(bg.xt);
1160
1161 bg.yt <- table(bg.y);
1162 bg.yh <- integer(diff(rx)+1);
1163 bg.yh[as.integer(names(bg.yt))-rx[1]+1] <- as.integer(bg.yt);
1164 rm(bg.yt);
1165
1166 # adjust bg.weight according to bg.whs
1167 if(bg.whs!=whs) {
1168 bg.weight <- bg.weight*whs/bg.whs;
1169 }
1170 } else {
1171 bg.subtract <- 0;
1172 bg.xh <- bg.yh <- c();
1173 }
1174
1175 # record masked positions
1176 if(!ignore.masking) {
1177 if(!is.null(mask.x) & length(mask.x)>0) {
1178 mvx <- unique(mask.x); mvx <- setdiff(mvx,as.numeric(names(xt)));
1179 mvx <- mvx[mvx>=rx[1] & mvx<=rx[2]];
1180 xh[mvx-rx[1]+1] <- -1;
1181 }
1182
1183 if(!is.null(mask.y) & length(mask.y)>0) {
1184 mvy <- unique(mask.y); mvy <- setdiff(mvy,as.numeric(names(yt)));
1185 mvy <- mvy[mvy>=rx[1] & mvy<=rx[2]];
1186 yh[mvy-rx[1]+1] <- -1;
1187 }
1188 }
1189
1190 rm(xt,yt);
1191
1192 if(round.up) { round.up <- 1; } else { round.up <- 0; }
1193
1194 storage.mode(xh) <- storage.mode(yh) <- "integer";
1195 storage.mode(bg.xh) <- storage.mode(bg.yh) <- "integer";
1196 nx <- length(xh); storage.mode(nx) <- storage.mode(whs) <- storage.mode(bg.whs) <- "integer";
1197 rp <- as.integer(return.peaks);
1198 dcon <- as.integer(direct.count);
1199 storage.mode(rp) <- storage.mode(min.dist) <- "integer";
1200 storage.mode(min.thr) <- "double";
1201 storage.mode(dcon) <- "integer";
1202 storage.mode(tag.weight) <- "double";
1203 storage.mode(bg.weight) <- "double";
1204 storage.mode(bg.subtract) <- "integer";
1205 storage.mode(round.up) <- "integer";
1206 im <- as.integer(ignore.masking);
1207 storage.mode(im) <- "integer";
1208 z <- .Call("wtd",xh,yh,whs,rp,min.dist,min.thr,dcon,tag.weight,im,bg.subtract,bg.xh,bg.yh,bg.whs,bg.weight,round.up);
1209 if(return.peaks) {
1210 return(data.frame(x=(z$x+rx[1])*step,y=z$v));
1211 } else {
1212 return(list(x=rx*step,y=z));
1213 }
1214 }
1215
1216
1217 tag.wtd <- function(ctv,s,e,return.peaks=T, bg.ctv=NULL, mask.ctv=NULL, ...) {
1218 x <- ctv[ctv>=s & ctv<=e];
1219 y <- (-1)*ctv[ctv<=-s & ctv>=-e];
1220
1221 if(!is.null(bg.ctv)) {
1222 bg.x <- bg.ctv[bg.ctv>=s & bg.ctv<=e];
1223 bg.y <- (-1)*bg.ctv[bg.ctv<=-s & bg.ctv>=-e];
1224 } else {
1225 bg.x <- bg.y <- NULL;
1226 }
1227
1228 if(!is.null(mask.ctv)) {
1229 mask.x <- mask.ctv[mask.ctv>=s & mask.ctv<=e];
1230 mask.y <- (-1)*mask.ctv[mask.ctv<=-s & mask.ctv>=-e];
1231 } else {
1232 mask.x <- mask.y <- NULL;
1233 }
1234
1235 if(length(x)==0 | length(y) ==0) {
1236 if(return.peaks) {
1237 return(data.frame(x=c(),y=c()));
1238 } else {
1239 rx <- range(c(x,y));
1240 return(list(x=rx,y=numeric(diff(rx)+1)));
1241 }
1242 } else {
1243 return(wtd(x,y,s,e,return.peaks=return.peaks, bg.x=bg.x,bg.y=bg.y, mask.x=mask.x,mask.y=mask.y, ...))
1244 }
1245 }
1246
1247 # shuffles tags in chromosome blocks of a specified size
1248 # note: all coordinates should be positive
1249 tag.block.shuffle <- function(tags,window.size=100) {
1250 if(length(tags)<3) {
1251 warning("too few tags for shuffling");
1252 return(tags);
1253 }
1254 rng <- range(tags);
1255 #if(rng[1]<0) { stop("negative tag coordinates found") }
1256 if(diff(rng)<=window.size) {
1257 warning(paste("tag range (",diff(rng),") is smaller than shuffle window size"));
1258 return(tags);
1259 }
1260
1261 if(window.size==0) {
1262 return(as.integer(runif(length(tags),min=rng[1],max=rng[2])))
1263 } else if(window.size==1) {
1264 tt <- table(tags);
1265 return(rep(runif(length(tt),min=rng[1],max=rng[2]),as.integer(tt)))
1266 } else {
1267 # block positions
1268 bp <- tags %/% window.size;
1269 # block-relative tag positions
1270 rp <- tags %% window.size;
1271
1272 # shuffle block positions
1273 bpu <- unique(bp);
1274 rbp <- range(bpu);
1275 bps <- as.integer(runif(length(bpu),min=rbp[1],max=rbp[2]));
1276 bpi <- match(bp,bpu);
1277 sbp <- bps[bpi];
1278 #sbp <- rbp[1]+match(bp,sample(rbp[1]:rbp[2]))
1279 return(sbp*window.size+rp);
1280 }
1281 }
1282
1283
1284 # calculate window cross-correlation
1285 lwcc <- function(x,y,s,e,whs=100,isize=20,return.peaks=T,min.thr=1,min.dist=100,step=1,tag.weight=1,bg.x=NULL,bg.y=NULL,bg.weight=NULL,mask.x=NULL,mask.y=NULL,bg.whs=whs,round.up=F) {
1286 if(step>1) {
1287 x <- floor(x/step+0.5); y <- floor(y/step+0.5)
1288
1289 if(!is.null(bg.x)) {
1290 bg.x <- floor(bg.x/step+0.5); bg.y <- floor(bg.y/step+0.5)
1291 }
1292
1293 if(!is.null(mask.x)) {
1294 mask.x <- floor(mask.x/step+0.5); mask.y <- floor(mask.y/step+0.5)
1295 }
1296
1297 whs <- floor(whs/step+0.5);
1298 bg.whs <- floor(bg.whs/step+0.5);
1299 isize <- floor(isize/step+0.5);
1300 min.dist <- floor(min.dist/step +0.5);
1301 s <- floor(s/step+0.5)
1302 e <- floor(e/step+0.5)
1303 }
1304
1305 # scale bg.weight, since within calculation they are considered independent
1306 bg.weight <- bg.weight*tag.weight;
1307
1308
1309 rx <- c(s-whs,e+whs);
1310 xt <- table(x);
1311 xh <- integer(diff(rx)+1);
1312 xh[as.integer(names(xt))-rx[1]+1] <- as.integer(xt);
1313
1314 yt <- table(y);
1315
1316 yh <- integer(diff(rx)+1);
1317 yh[as.integer(names(yt))-rx[1]+1] <- as.integer(yt);
1318
1319 # compile background vectors
1320 if(!is.null(bg.x) & length(bg.x)>0) {
1321 bg.subtract <- 1;
1322
1323 bg.xt <- table(bg.x);
1324 bg.xh <- integer(diff(rx)+1);
1325 bg.xh[as.integer(names(bg.xt))-rx[1]+1] <- as.integer(bg.xt);
1326 rm(bg.xt);
1327
1328 bg.yt <- table(bg.y);
1329 bg.yh <- integer(diff(rx)+1);
1330 bg.yh[as.integer(names(bg.yt))-rx[1]+1] <- as.integer(bg.yt);
1331 rm(bg.yt);
1332
1333 # adjust bg.weight according to bg.whs
1334 bg.weight <- bg.weight*(whs-isize)/bg.whs;
1335 } else {
1336 bg.subtract <- 0;
1337 bg.xh <- bg.yh <- c();
1338 }
1339
1340 # record masked positions
1341 if(!is.null(mask.x) & length(mask.x)>0) {
1342 mvx <- unique(mask.x); mvx <- setdiff(mvx,as.numeric(names(xt)));
1343 mvx <- mvx[mvx>=rx[1] & mvx<=rx[2]];
1344
1345 xh[mvx-rx[1]+1] <- -1;
1346 }
1347
1348 if(!is.null(mask.y) & length(mask.y)>0) {
1349 mvy <- unique(mask.y); mvy <- setdiff(mvy,as.numeric(names(yt)));
1350 mvy <- mvy[mvy>=rx[1] & mvy<=rx[2]];
1351 yh[mvy-rx[1]+1] <- -1;
1352 }
1353
1354 rm(xt,yt);
1355 if(round.up) { round.up <- 1; } else { round.up <- 0; }
1356
1357 storage.mode(xh) <- storage.mode(yh) <- "integer";
1358 storage.mode(bg.xh) <- storage.mode(bg.yh) <- "integer";
1359 nx <- length(xh); storage.mode(nx) <- storage.mode(whs) <- storage.mode(isize) <- storage.mode(bg.whs) <- "integer";
1360 rp <- as.integer(return.peaks);
1361 storage.mode(rp) <- storage.mode(min.dist) <- "integer";
1362 storage.mode(min.thr) <- "double";
1363 storage.mode(tag.weight) <- "double";
1364 storage.mode(bg.weight) <- "double";
1365 storage.mode(bg.subtract) <- "integer";
1366 storage.mode(round.up) <- "integer";
1367
1368 # allocate return arrays
1369 #cc <- numeric(nx); storage.mode(cc) <- "double";
1370 z <- .Call("lwcc",xh,yh,whs,isize,rp,min.dist,min.thr,tag.weight,bg.subtract,bg.xh,bg.yh,bg.whs,bg.weight,round.up);
1371 if(return.peaks) {
1372 return(data.frame(x=(z$x+rx[1])*step,y=z$v));
1373 } else {
1374 return(list(x=rx*step,y=z));
1375 }
1376 }
1377
1378
1379 tag.lwcc <- function(ctv,s,e,return.peaks=T, bg.ctv=NULL, mask.ctv=NULL, ...) {
1380 x <- ctv[ctv>=s & ctv<=e];
1381 y <- (-1)*ctv[ctv<=-s & ctv>=-e];
1382
1383 if(!is.null(bg.ctv)) {
1384 bg.x <- bg.ctv[bg.ctv>=s & bg.ctv<=e];
1385 bg.y <- (-1)*bg.ctv[bg.ctv<=-s & bg.ctv>=-e];
1386 } else {
1387 bg.x <- bg.y <- NULL;
1388 }
1389
1390 if(!is.null(mask.ctv)) {
1391 mask.x <- mask.ctv[mask.ctv>=s & mask.ctv<=e];
1392 mask.y <- (-1)*mask.ctv[mask.ctv<=-s & mask.ctv>=-e];
1393 } else {
1394 mask.x <- mask.y <- NULL;
1395 }
1396
1397 if(length(x)==0 | length(y) ==0) {
1398 if(return.peaks) {
1399 return(data.frame(x=c(),y=c()));
1400 } else {
1401 rx <- range(c(x,y));
1402 return(list(x=rx,y=numeric(diff(rx)+1)));
1403 }
1404 } else {
1405 return(lwcc(x,y, s,e,return.peaks=return.peaks, bg.x=bg.x,bg.y=bg.y, mask.x=mask.x,mask.y=mask.y, ...))
1406 }
1407 }
1408
1409 # determine mirror-based binding positions using sliding window along each chromosome
1410 # extra parameters are passed on to call.nucleosomes()
1411 window.call.mirror.binding <- function(tvl,window.size=4e7, debug=T, cluster=NULL, bg.tl=NULL, mask.tl=NULL, background.density.scaling=T, ...) {
1412 chrl <- names(tvl);
1413 # determine bg.weight
1414 if(!is.null(bg.tl)) {
1415 bg.weight <- dataset.density.ratio(tvl,bg.tl,background.density.scaling=background.density.scaling);
1416 } else {
1417 bg.weight <- NULL;
1418 }
1419 if(debug) {
1420 cat("bg.weight=",bg.weight," ");
1421 }
1422
1423 names(chrl) <- chrl;
1424
1425 if(is.null(cluster)) {
1426 return(lapply(chrl,function(chr) {
1427 bg.ctv <- NULL; if(!is.null(bg.tl)) { bg.ctv <- bg.tl[[chr]]; };
1428 mask.ctv <- NULL; if(!is.null(mask.tl)) { mask.ctv <- mask.tl[[chr]]; };
1429
1430 window.chr.call.mirror.binding(list(ctv=tvl[[chr]],bg.ctv=bg.ctv,mask.ctv=mask.ctv),window.size=window.size,chr=chr,debug=debug, bg.weight=bg.weight, bg.ctv=bg.ctv, mask.ctv=mask.ctv, ...);
1431 }));
1432 } else {
1433 # add bg.ctv and mask.ctv to parallel call
1434 tvll <- lapply(chrl,function(chr) {
1435 bg.ctv <- NULL; if(!is.null(bg.tl)) { bg.ctv <- bg.tl[[chr]]; };
1436 mask.ctv <- NULL; if(!is.null(mask.tl)) { mask.ctv <- mask.tl[[chr]]; };
1437 return(list(ctv=tvl[[chr]],bg.ctv=bg.ctv,mask.ctv=mask.ctv))
1438 });
1439 bl <- clusterApplyLB(cluster,tvll,window.chr.call.mirror.binding,window.size=window.size,debug=debug, bg.weight=bg.weight, ...);
1440 names(bl) <- chrl;
1441 return(bl);
1442 }
1443 }
1444
1445 window.chr.call.mirror.binding <- function(ctvl,window.size,debug=T, chr="NA", cluster=NULL, method=tag.wtd, bg.ctv=NULL, mask.ctv=NULL, ...) {
1446 ctv <- ctvl$ctv; bg.ctv <- ctvl$bg.ctv; mask.ctv <- ctvl$mask.ctv;
1447 if(is.null(ctv)) { return(data.frame(x=c(),y=c())) }
1448 if(length(ctv)<2) { return(data.frame(x=c(),y=c())) }
1449
1450 dr <- range(unlist(lapply(ctv,function(x) range(abs(x)))))
1451 n.windows <- ceiling(diff(dr)/window.size);
1452
1453
1454 pinfo <- c();
1455 if(debug) {
1456 cat(paste("processing ",chr," in ",n.windows," steps [",sep=""));
1457 }
1458 for(i in 1:n.windows) {
1459 s <- dr[1]+(i-1)*window.size;
1460 npn <- method(s=s, e=s+window.size,ctv=ctv, return.peaks=T, bg.ctv=bg.ctv, mask.ctv=mask.ctv, ... );
1461 if(length(npn) > 0) { pinfo <- rbind(pinfo,npn) }
1462 if(debug) {
1463 cat(".");
1464 }
1465 }
1466 if(debug) {
1467 cat(paste("] done (",dim(pinfo)[1],"positions)\n"));
1468 } else {
1469 cat(".");
1470 }
1471 return(data.frame(x=pinfo[,1],y=pinfo[,2]));
1472 }
1473
1474 generate.randomized.data <- function(data,shuffle.window=1,shuffle.both.strands=T,strand.shuffle.only=F,chrl=names(data)) {
1475 names(chrl) <- unlist(chrl);
1476 if(strand.shuffle.only) {
1477 # shuffle just strand assignment, not tag positions
1478 rt <- lapply(data[unlist(chrl)],function(tv) tv*sample(c(-1,1),length(tv),replace=T));
1479 } else {
1480 if(shuffle.both.strands) {
1481 rt <- lapply(data[unlist(chrl)],function(tv) {
1482 pti <- which(tv>0); return(c(tag.block.shuffle(tv[pti],window.size=shuffle.window),tag.block.shuffle(tv[-pti],window.size=shuffle.window)))
1483 });
1484 } else {
1485 rt <- lapply(data[unlist(chrl)],function(tv) { pti <- which(tv>0); return(c(tag.block.shuffle(tv[pti],window.size=shuffle.window),tv[-pti]))});
1486 }
1487 }
1488 }
1489
1490 # determine threshold based on E value
1491 # for efficiency chrl should include just one or two small chromosomes
1492 # optional parameters are passed to call.nucleosomes()
1493 determine.lwcc.threshold <- function(tvl,chrl=names(tvl),e.value=100, n.randomizations=1, min.thr=1, debug=F, tol=1e-2, shuffle.window=1, shuffle.both.strands=T, return.rtp=F, control=NULL, strand.shuffle=F, ...) {
1494 names(chrl) <- unlist(chrl);
1495
1496 # determine fraction of total tags contained in the specified nucleosomes
1497 ntags <- sum(unlist(lapply(tvl,function(cv) length(cv))));
1498 nctags <- sum(unlist(lapply(chrl, function(cn) length(tvl[[cn]]))));
1499 # calculate actual target E value
1500 if(!is.null(control)) {
1501 n.randomizations <- length(control);
1502 }
1503 eval <- e.value*n.randomizations*nctags/ntags
1504 if(eval<1) {
1505 warning("specified e.value and set of chromosomes results in target e.value of less than 1");
1506 eval <- 1;
1507 }
1508
1509 if(debug) {
1510 cat(paste("randomizations =",n.randomizations," chromosomes =",length(chrl),"\n"))
1511 cat(paste("adjusted target eval =",eval,"\ngenerating randomized tag peaks ..."));
1512 }
1513
1514 # get peaks on randomized tags
1515 if(is.null(control)) {
1516 rtp <- data.frame(do.call(rbind,lapply(1:n.randomizations,function(i) {
1517 if(strand.shuffle) {
1518 # shuffle just strand assignment, not tag positions
1519 rt <- lapply(tvl[unlist(chrl)],function(tv) tv*sample(c(-1,1),length(tv),replace=T));
1520 } else {
1521 if(shuffle.both.strands) {
1522 rt <- lapply(tvl[unlist(chrl)],function(tv) {
1523 pti <- which(tv>0); return(c(tag.block.shuffle(tv[pti],window.size=shuffle.window),tag.block.shuffle(tv[-pti],window.size=shuffle.window)))
1524 });
1525 } else {
1526 rt <- lapply(tvl[unlist(chrl)],function(tv) { pti <- which(tv>0); return(c(tag.block.shuffle(tv[pti],window.size=shuffle.window),tv[-pti]))});
1527 }
1528 }
1529 if(debug) {
1530 cat(".");
1531 }
1532 rl <- window.call.mirror.binding(rt,min.thr=min.thr, debug=F, ...);
1533
1534 return(do.call(rbind,rl))
1535 #return(do.call(rbind,window.call.mirror.binding(rt,min.thr=min.thr, debug=F, whs=100,isize=10,window.size=3e7,min.dist=200)))
1536 })));
1537
1538 } else {
1539 if(debug) {
1540 cat(" using provided controls ");
1541 }
1542 rtp <- data.frame(do.call(rbind,lapply(control,function(rt) do.call(rbind,window.call.mirror.binding(rt,min.thr=min.thr, debug=F, ...)))))
1543 }
1544
1545 if(return.rtp) {
1546 return(rtp)
1547 }
1548
1549 if(debug) {
1550 cat(" done\nfinding threshold .");
1551 }
1552
1553 # determine range and starting value
1554 rng <- c(min.thr,max(na.omit(rtp$y)))
1555
1556 # find E value threshold
1557 count.nucs.f <- function(nthr) {
1558 return(eval-length(which(rtp$y>=nthr)));
1559 }
1560
1561 # estimate position of the root by downward bisection iterations
1562 mv <- c(eval); mvp <- c(rng[2]); ni <- 1;
1563 max.it <- 2*as.integer(log2(rng[2]/rng[1])+0.5);
1564 while((ni<=max.it) & (mv[1]>=0)) {
1565 np <- mvp[1]/2;
1566 npv <- count.nucs.f(np);
1567 mv <- c(npv,mv);
1568 mvp <- c(np,mvp);
1569 ni <- ni+1;
1570 }
1571
1572
1573 if(ni>max.it) {
1574 # determine lowest value
1575 if(debug) {
1576 cat(paste("exceeded max.it (",max.it,"), returning lowest point",signif(mvp[1],4)));
1577 }
1578 return(list(root=mvp[1]))
1579 } else {
1580 rng <- mvp[1:2];
1581 if(mv[2]==0) rng[2] <- mvp[3];
1582 if(debug) {
1583 cat(paste("bound to (",signif(rng[1],4),signif(rng[2],4),") "));
1584 }
1585 }
1586
1587 # find root on the right side
1588 x <- uniroot(count.nucs.f,rng,tol=tol);
1589 #x$max <- o$par;
1590 #x$f.max <- (-1)*o$value;
1591 if(debug) {
1592 cat(paste(" done (thr=",signif(x$root,4),")\n"));
1593 }
1594 return(x);
1595
1596 }
1597
1598
1599 # determine membership of points in fragments
1600 points.within <- function(x,fs,fe,return.list=F,return.unique=F,sorted=F,return.point.counts=F) {
1601 if(is.null(x) | length(x) < 1) { return(c()) };
1602 if(!sorted) {
1603 ox <- rank(x,ties="first");
1604 x <- sort(x);
1605 }
1606
1607 se <- c(fs,fe);
1608 fi <- seq(1:length(fs));
1609 fi <- c(fi,-1*fi);
1610
1611 fi <- fi[order(se)];
1612 se <- sort(se);
1613
1614 storage.mode(x) <- storage.mode(fi) <- storage.mode(se) <- "integer";
1615 if(return.unique) { iu <- 1; } else { iu <- 0; }
1616 if(return.list) { il <- 1; } else { il <- 0; }
1617 if(return.point.counts) { rpc <- 1; } else { rpc <- 0; }
1618 storage.mode(iu) <- storage.mode(il) <- storage.mode(rpc) <- "integer";
1619 result <- .Call("points_within",x,se,fi,il,iu,rpc);
1620 if(!sorted & !return.point.counts) {
1621 result <- result[ox];
1622 }
1623 return(result);
1624 }
1625
1626
1627 # determine cooridnates of points x relative to signed
1628 # positions pos within size range
1629 get.relative.coordinates <- function(x,pos,size,sorted=F) {
1630 if(!sorted) {
1631 op <- order(abs(pos));
1632 x <- sort(x); pos <- pos[op];
1633 }
1634 #dyn.load("~/zhao/sc/peaks.so");
1635 storage.mode(x) <- storage.mode(pos) <- storage.mode(size) <- "integer";
1636 rf <- .Call("get_relative_coordinates",x,pos,size);
1637 if(!sorted) {
1638 rf$i <- op[rf$i];
1639 } else {
1640 return(rf$i);
1641 }
1642 return(rf);
1643 }
1644
1645 # given list of magnitude values for signal(x) and control (y),
1646 # return a dataframe with $e.val and $fdr
1647 get.eval.fdr.vectors <- function(x,y) {
1648 nx <- length(x); ny <- length(y);
1649 if(nx==0) { return(data.frame(evalue=c(),fdr=c())) }
1650 if(ny==0) { return(data.frame(evalue=rep(0,nx),fdr=rep(1,nx))) }
1651 ex <- ecdf(x); ey <- ecdf(y);
1652
1653 evals <- (1-ey(x))*ny;
1654 yvals <- (1-ex(x))*nx;
1655 fdr <- (evals+0.5)/(yvals+0.5); # with pseudo-counts
1656 fdr[yvals==0] <- min(fdr); # correct for undercounts
1657 # find a min x corresponding to a minimal FDR
1658 mfdr <- min(fdr);
1659 mfdrmx <- min(x[fdr==mfdr]);
1660 # correct
1661 fdr[x>=mfdrmx] <- mfdr;
1662 return(data.frame(evalue=(evals+1),fdr=fdr));
1663 }
1664
1665
1666 # filter predictions to remove calls failling into the tag enrichment clusters ( chr list of $s/$e dfs)
1667 filter.binding.sites <- function(bd,tec,exclude=F) {
1668 chrl <- names(bd); names(chrl) <- chrl;
1669 lapply(chrl,function(chr) {
1670 cbd <- bd[[chr]];
1671 if(is.null(cbd)) { return(NULL) };
1672 if(length(cbd)==0) { return(NULL) };
1673 if(dim(cbd)[1]>0) {
1674 ctec <- tec[[chr]];
1675 if(length(ctec$s)>0) {
1676 if(exclude) {
1677 pwi <- which(points.within(cbd$x,ctec$s,ctec$e)== -1);
1678 } else {
1679 pwi <- which(points.within(cbd$x,ctec$s,ctec$e)> -1);
1680 }
1681 return(cbd[pwi,]);
1682 } else {
1683 if(exclude) {
1684 return(cbd);
1685 } else {
1686 return(data.frame(x=c(),y=c()));
1687 }
1688 }
1689 } else {
1690 return(cbd);
1691 }
1692 });
1693 }
1694
1695
1696 # PUBLIC
1697 # generate predictions on sequential (chained) subsamples of data
1698 # if step.size <1, it is intepreted as a fraciton and a each subsequent subsample
1699 # is of a size (1-fraction.step)*N (N - size of the signal data);
1700 # otherwise the step.size is interpreted as a number of tags, and each subsample is of the size N-step.size
1701 get.subsample.chain.calls <- function(signal.data,control.data,n.steps=NULL,step.size=1e6,subsample.control=F,debug=F,min.ntags=1e3, excluded.steps=c(), test.chromosomes=NULL, ... ) {
1702
1703 if(!is.null(test.chromosomes)) {
1704 # adjust step size
1705 sz <- sum(unlist(lapply(signal.data,length)))
1706 signal.data <- signal.data[test.chromosomes];
1707 control.data <- control.data[test.chromosomes];
1708
1709 if(step.size>1) {
1710 step.size <- step.size*sum(unlist(lapply(signal.data,length)))/sz;
1711 # cat("adjusted step.size=",step.size,"\n");
1712 }
1713 }
1714
1715 if(is.null(n.steps)) {
1716 if(step.size<1) {
1717 # down to 10%
1718 n.steps <- log(0.1)/log(step.size);
1719 } else {
1720 n.steps <- floor(sum(unlist(lapply(signal.data,length)))/step.size)
1721 }
1722 }
1723 if(subsample.control & !is.null(control.data)) {
1724 # normalize control to the signal size
1725 if(debug) { cat("pre-subsampling control.\n"); }
1726 bg.weight <- sum(unlist(lapply(signal.data,length)))/sum(unlist(lapply(control.data,length)))
1727 control.data <- lapply(control.data,function(d) sample(d,length(d)*bg.weight,replace=(bg.weight>1)))
1728 }
1729 calls <- list();
1730 callnames <- c();
1731 for(i in 0:n.steps) {
1732 if(debug) { cat("chained subsample step",i,":\n"); }
1733 if(!i %in% excluded.steps) {
1734 ans <- list(find.binding.positions(signal.data=signal.data,control.data=control.data,debug=debug, skip.control.normalization=T, ...));
1735 names(ans) <- as.character(c(i));
1736 calls <- c(calls,ans);
1737 callnames <- c(callnames,i);
1738 }
1739 # subsample
1740 if(step.size<1) {
1741 # fraction steps
1742 f <- 1-step.size;
1743 } else {
1744 # bin steps
1745 sz <- sum(unlist(lapply(signal.data,length)));
1746 f <- (sz-step.size)/sz;
1747 if(f<=0) break;
1748 }
1749 if(debug) { cat("chained subsampling using fraction",f,".\n"); }
1750 signal.data <- lapply(signal.data,function(d) sample(d,length(d)*f));
1751 if(subsample.control & !is.null(control.data)) {
1752 control.data <- lapply(control.data,function(d) sample(d,length(d)*f));
1753 }
1754 sz <- sum(unlist(lapply(signal.data,length)));
1755 if(sz<min.ntags) break;
1756 }
1757 names(calls) <- callnames;
1758 return(calls);
1759 }
1760
1761
1762 # chain-subsample dataset and calculate MSER interpolation
1763 mser.chain.interpolation <- function(signal.data=NULL,control.data=NULL,chains=NULL,n.chains=5,debug=F, enrichment.background.scales=c(1,5), test.agreement=0.99, agreement.distance=50, return.median=F, mean.trim=0.1, enr.field="enr", return.lists=F, ...) {
1764 if(is.null(chains)) {
1765 cn <- c(1:n.chains); names(cn) <- cn;
1766 tf <- function(i, ...) get.subsample.chain.calls(signal.data,control.data,debug=debug, enrichment.background.scales=enrichment.background.scales, ...);
1767 chains <- lapply(cn,tf,...);
1768 }
1769 names(enrichment.background.scales) <- enrichment.background.scales;
1770 lapply(enrichment.background.scales,function(scale) {
1771 actual.enr.field <- enr.field;
1772 if(scale>1) {
1773 actual.enr.field <- paste(actual.enr.field,scale,sep=".");
1774 }
1775
1776 cvl <- lapply(chains,function(chain) {
1777 nn <- sort(unlist(lapply(chain,function(d) d$n)),decreasing=T);
1778 nd <- diff(nn);
1779 nn <- nn[-length(nn)];
1780 me <- lapply(c(2:length(chain)),function(i) {
1781 sla <- t.precalculate.ref.peak.agreement(chain[[i-1]],chain[i],agreement.distance=agreement.distance,enr.field=actual.enr.field)
1782 me <- t.find.min.saturated.enr(sla,thr=1-test.agreement)
1783 menr <- max(min(na.omit(unlist(lapply(chain[[i-1]]$npl,function(d) d[actual.enr.field])))),min(na.omit(unlist(lapply(chain[[i]]$npl,function(d) d[actual.enr.field])))),1)
1784 if(me<=menr) { me <- 1; };
1785 return(me);
1786 })
1787 data.frame(n=nn,me=unlist(me),nd=nd);
1788 });
1789 if(return.lists) { return(cvl) }
1790 cvl <- na.omit(do.call(rbind,cvl));
1791 if(return.median) {
1792 tv <- tapply(cvl$me,as.factor(cvl$n),median)
1793 } else {
1794 tv <- tapply(cvl$me,as.factor(cvl$n),mean,trim=mean.trim);
1795 }
1796 df <- data.frame(n=as.numeric(names(tv)),me=as.numeric(tv));
1797 return(df[order(df$n,decreasing=T),])
1798 })
1799 }
1800
1801
1802
1803 # returns agreement as a function of dataset size, possibly filtering peaks by min.enr threshold, and by max.fdr
1804 chain.to.reference.comparison <- function(chains,min.enr=NULL,debug=F,agreement.distance=50, return.median=F, mean.trim=0.1, enr.field="enr",max.fdr=NULL) {
1805 cvl <- lapply(chains,function(chain) {
1806 # filter chain by fdr
1807 if(!is.null(max.fdr)) {
1808 chain <- lapply(chain,function(d) { d$npl <- lapply(d$npl,function(cd) cd[cd$fdr<=max.fdr,]); return(d); });
1809 }
1810 nn <- sort(unlist(lapply(chain,function(d) d$n)),decreasing=T);
1811 nn <- nn[-length(nn)];
1812 me <- lapply(c(2:length(chain)),function(i) {
1813 sla <- t.precalculate.ref.peak.agreement(chain[[1]],chain[i],agreement.distance=agreement.distance,enr.field=enr.field)
1814 # calculate overlap
1815 x <- lapply(sla,function(mpd) {
1816 if(!is.null(min.enr)) {
1817
1818 me <- mpd$re >= min.enr;
1819 me[is.na(me)] <- F;
1820 mpd <- mpd[me,];
1821 ome <- mpd$oe < min.enr;
1822 ome[is.na(ome)] <- T;
1823 mpd$ov[ome] <- 0;
1824 }
1825 return(mean(mpd$ov));
1826 })
1827 })
1828
1829 data.frame(n=nn,me=unlist(me));
1830 });
1831
1832 cvl <- na.omit(do.call(rbind,cvl));
1833 if(return.median) {
1834 tv <- tapply(cvl$me,as.factor(cvl$n),median)
1835 } else {
1836 tv <- tapply(cvl$me,as.factor(cvl$n),mean,trim=mean.trim);
1837 }
1838 df <- data.frame(n=as.numeric(names(tv)),me=as.numeric(tv));
1839 return(df[order(df$n,decreasing=T),])
1840 }
1841
1842
1843 # estimates enrichment confidence interval based on 2*tag.count.whs window around each position, and a z-score (alpha/2)
1844 # if(multiple.background.scales=T) the enrichment is also estimated using 5- and 10-fold increased background tag window
1845 # adds $enr (lower bound), $enr.ub (upper bound) and $enr.mle fields
1846 calculate.enrichment.estimates <- function(binding.positions,signal.data=NULL,control.data=NULL,fraction=1,tag.count.whs=100,z=2,effective.genome.size=3e9,scale.down.control=F,background.scales=c(1),bg.weight=NULL) {
1847 f <- fraction;
1848 qv <- pnorm(z,lower.tail=F);
1849 cn <- names(binding.positions$npl); names(cn) <- cn;
1850
1851 if(is.null(control.data)) {
1852 # estimate from gamma distribution
1853 fg.lambda <- f*sum(unlist(lapply(signal.data,length)))*2*tag.count.whs/effective.genome.size;
1854 binding.positions$npl <- lapply(binding.positions$npl,function(d) {
1855 d$enr <- qgamma(qv,d$nt,scale=1)/fg.lambda;
1856 d$enr.ub <- qgamma(1-qv,d$nt,scale=1)/fg.lambda;
1857 d$enr.mle <- d$nt/fg.lambda;
1858 return(d);
1859 });
1860 } else {
1861 # estimate using beta distribution
1862 if(is.null(bg.weight)) {
1863 bg.weight <- sum(unlist(lapply(signal.data,length)))/sum(unlist(lapply(control.data,length)))
1864 }
1865
1866 if(scale.down.control) {
1867 # sample down control to be the same size as true signal.data (bg.weight*f)
1868 control.data <- lapply(control.data,function(d) sample(d,length(d)*bg.weight*f,replace=(f*bg.weight>1)))
1869 #bg.weight <- sum(unlist(lapply(signal.data,length)))/sum(unlist(lapply(control.data,length)))
1870 bg.weight <- 1/f;
1871
1872 }
1873
1874 binding.positions$enrichment.bg.weight <- bg.weight;
1875 binding.positions$enrichment.whs <- tag.count.whs;
1876 binding.positions$enrichment.z <- z;
1877
1878 binding.positions$npl <- lapply(cn,function(chr) {
1879 d <- binding.positions$npl[[chr]];
1880
1881 edf <- lapply(background.scales,function(background.width.multiplier) {
1882 sig.mult <- bg.weight*f/background.width.multiplier;
1883 nbg <- points.within(abs(control.data[[chr]]),d$x-tag.count.whs*background.width.multiplier,d$x+tag.count.whs*background.width.multiplier,return.point.counts=T,return.unique=F);
1884
1885 nfg <- d$nt;
1886
1887
1888 # Poisson ratio Bayesian LB with non-informative prior (Clopper & Pearson 1934)
1889 nf <- ((nfg+0.5)/(nbg+0.5))*qf(1-qv,2*(nfg+0.5),2*(nbg+0.5),lower.tail=F)
1890 nf <- nf/sig.mult;
1891
1892 ub <- ((nfg+0.5)/(nbg+0.5))*qf(qv,2*(nfg+0.5),2*(nbg+0.5),lower.tail=F)
1893 ub <- ub/sig.mult;
1894
1895 mle <- (nfg+0.5)/(nbg+0.5);
1896 mle <- mle/sig.mult;
1897 if(is.null(nbg)) { nbg <- numeric(0) }
1898 if(is.null(nf)) { nf <- numeric(0) }
1899 if(is.null(ub)) { ub <- numeric(0) }
1900 if(is.null(mle)) { mle <- numeric(0) }
1901 return(data.frame(nbg=nbg,lb=nf,ub=ub,mle=mle))
1902 })
1903
1904 adf <- do.call(cbind,lapply(c(1:length(background.scales)),function(i) {
1905 df <- edf[[i]];
1906 cn <- c("nbgt","enr","enr.ub","enr.mle");
1907 if(background.scales[i]>1) {
1908 cn <- paste(cn,as.character(background.scales[i]),sep=".");
1909 }
1910 names(df) <- cn;
1911 return(df);
1912 }))
1913
1914 return(cbind(d,adf));
1915 });
1916 }
1917
1918 return(binding.positions);
1919 }
1920
1921
1922 # precalculate peak agreement of a sampling list given a reference
1923 t.precalculate.ref.peak.agreement <- function(ref,sf,agreement.distance=50,enr.field="enr") {
1924 ref <- ref$npl;
1925 cn <- names(ref); names(cn) <- cn;
1926
1927 # for each sampling round
1928 lapply(sf,function(sd) {
1929 # calculate overlap
1930
1931 ov <- data.frame(do.call(rbind,lapply(cn,function(chr) {
1932 if(dim(ref[[chr]])[1]<1) { return(cbind(ov=c(),re=c(),oe=c())) };
1933 pwi <- points.within(ref[[chr]]$x,sd$npl[[chr]]$x-agreement.distance,sd$npl[[chr]]$x+agreement.distance);
1934 pwi[pwi==-1] <- NA;
1935 renr <- ref[[chr]][,enr.field]
1936 oenr <- sd$npl[[chr]][,enr.field][pwi];
1937 if(length(oenr)==0) { oenr <- rep(NA,length(renr)); }
1938 return(cbind(ov=as.integer(!is.na(pwi)),re=renr,oe=oenr));
1939 })))
1940 })
1941 }
1942
1943
1944 # find minimal saturated enrichment given a list of replicate agreement matrices (for one fraction)
1945 t.find.min.saturated.enr <- function(pal,thr=0.01,plot=F,return.number.of.peaks=F,plot.individual=T,return.median=F,return.vector=F) {
1946 nr <- length(pal);
1947 # merge replicate data frames
1948 mpd <- data.frame(do.call(rbind,pal));
1949
1950 mpd$re[is.na(mpd$re)] <- Inf;
1951 mpd$oe[is.na(mpd$oe)] <- Inf;
1952
1953
1954
1955 # round up values to avoid miscounting
1956 mpd$re <- round(mpd$re,digits=2);
1957 mpd$oe <- round(mpd$oe,digits=2);
1958
1959 me <- pmin(mpd$re,mpd$oe);
1960 ome <- order(me,decreasing=T);
1961 df <- data.frame(me=me[ome],ov=mpd$ov[ome]);
1962 recdf <- ecdf(-mpd$re); ren <- length(mpd$re);
1963
1964 # collapse equal peak heights
1965 xk <- tapply(df$ov,as.factor(df$me),sum); xk <- data.frame(ov=as.numeric(xk),me=as.numeric(names(xk))); xk <- xk[order(xk$me,decreasing=T),];
1966
1967
1968 cso <- cumsum(xk$ov)/(recdf(-xk$me)*ren);
1969 cso[is.na(cso)] <- 0;
1970 cso[!is.finite(cso)] <- 0;
1971 mv <- max(which(cso >= 1-thr))
1972 menr <- xk$me[mv];
1973
1974 ir <- lapply(pal,function(d) {
1975 d$re[is.na(d$re)] <- Inf;
1976 d$oe[is.na(d$oe)] <- Inf;
1977
1978 me <- pmin(d$re,d$oe);
1979 ome <- order(me,decreasing=T);
1980 df <- data.frame(me=me[ome],ov=d$ov[ome]);
1981 cso <- cumsum(df$ov)/c(1:length(df$ov));
1982 mv <- max(which(cso >= 1-thr))
1983 menr <- df$me[mv];
1984 return(list(df=df,menr=menr));
1985 });
1986
1987 if(plot) {
1988 par(mar = c(3.5,3.5,2.0,0.5), mgp = c(2,0.65,0), cex = 0.8);
1989 plot(df$me,cumsum(df$ov)/c(1:length(df$ov)),type='l',ylab="fraction of positions overlapping with reference",xlab="minimal enrichment of binding positions",xlim=c(min(df$me),2*menr));
1990 abline(h=1-thr,lty=2,col=4)
1991 if(plot.individual) {
1992 lapply(ir,function(d) {
1993 df <- d$df;
1994 lines(df$me,cumsum(df$ov)/c(1:length(df$ov)),col=8);
1995 abline(v=menr,col="pink",lty=3)
1996 });
1997 lines(df$me,cumsum(df$ov)/c(1:length(df$ov)),col=1);
1998 }
1999 abline(v=menr,col=2,lty=2)
2000 legend(x="bottomright",lty=c(1,2,1,3,2),col=c(1,2,8,"pink",4),legend=c("combined samples","combined sample MSER","individual samples","individual MSERs","consistency threshold"));
2001 }
2002
2003 if(return.number.of.peaks) {
2004 mpd <- data.frame(do.call(rbind,pal));
2005 return(length(which(!is.na(mpd$re) & mpd$re >=menr))/nr);
2006 } else {
2007 if(return.vector) {
2008 return(unlist(lapply(ir,function(d) d$menr)));
2009 }
2010 if(return.median) {
2011 return(median(unlist(lapply(ir,function(d) d$menr))));
2012 } else {
2013 return(menr);
2014 }
2015 }
2016 }
2017
2018
2019
2020 # determine d1/d2 dataset size ratio. If background.density.scaling=F, the ratio of tag counts is returned.
2021 # if background.density.scaling=T, regions of significant tag enrichment are masked prior to ratio calculation.
2022 dataset.density.ratio <- function(d1,d2,min.tag.count.z=4.3,wsize=1e3,mcs=0,background.density.scaling=T) {
2023 if(!background.density.scaling) {
2024 return(sum(unlist(lapply(d1,length)))/sum(unlist(lapply(d2,length))))
2025 }
2026
2027 chrl <- intersect(names(d1),names(d2));
2028 ntc <- do.call(rbind,lapply(chrl,function(chr) {
2029 x1 <- tag.enrichment.clusters(abs(d1[[chr]]),c(),wsize=wsize,bg.weight=0,min.tag.count.z=min.tag.count.z,mcs=mcs,either=F)
2030 x2 <- tag.enrichment.clusters(abs(d2[[chr]]),c(),wsize=wsize,bg.weight=0,min.tag.count.z=min.tag.count.z,mcs=mcs,either=F)
2031 return(c(length(which(points.within(abs(d1[[chr]]),c(x1$s,x2$s)-wsize/2,c(x1$e,x2$e)+wsize/2)==-1)),length(which(points.within(abs(d2[[chr]]),c(x1$s,x2$s)-wsize/2,c(x1$e,x2$e)+wsize/2)==-1))))
2032 }))
2033 ntcs <- apply(ntc,2,sum);
2034 #print(ntcs/c(sum(unlist(lapply(d1,length))),sum(unlist(lapply(d2,length)))));
2035 return(ntcs[1]/ntcs[2])
2036 }
2037
2038 # returns effective size of the dataset based on the same logic as dataset.density.ratio
2039 dataset.density.size <- function(d1,min.tag.count.z=4.3,wsize=1e3,mcs=0,background.density.scaling=T) {
2040 if(!background.density.scaling) {
2041 return(sum(unlist(lapply(d1,length))))
2042 }
2043
2044 chrl <- names(d1);
2045 ntc <- lapply(chrl,function(chr) {
2046 x1 <- tag.enrichment.clusters(abs(d1[[chr]]),c(),wsize=wsize,bg.weight=0,min.tag.count.z=min.tag.count.z,mcs=mcs,either=F)
2047 return(length(which(points.within(abs(d1[[chr]]),x1$s-wsize/2,x1$e+wsize/2)==-1)))
2048 })
2049 return(sum(unlist(ntc)))
2050 }
2051
2052 old.dataset.density.ratio <- function(d1,d2,min.tag.count.z=4.3,wsize=1e3,mcs=0,background.density.scaling=T) {
2053 if(!background.density.scaling) {
2054 return(sum(unlist(lapply(d1,length)))/sum(unlist(lapply(d2,length))))
2055 }
2056
2057 t.chromosome.counts <- function(tl) {
2058 lapply(tl,function(d) {
2059 x <- tag.enrichment.clusters(abs(d),c(),wsize=wsize,bg.weight=0,min.tag.count.z=min.tag.count.z,mcs=mcs,either=F)
2060 x$s <- x$s-wsize/2; x$e <- x$e+wsize/2;
2061 x <- regionset.intersection.c(list(x),do.union=T)
2062 return(c(n=length(which(points.within(abs(d),x$s,x$e)==-1)),s=diff(range(abs(d))),m=sum(x$e-x$s)));
2063 })
2064 }
2065
2066 l1 <- t.chromosome.counts(d1);
2067 l2 <- t.chromosome.counts(d2);
2068
2069 l2 <- data.frame(do.call(rbind,l2[names(l1)]));
2070 l1 <- data.frame(do.call(rbind,l1));
2071
2072 # genome size
2073 gs <- sum(pmax(l1$s,l2$s))
2074
2075 den1 <- sum(l1$n)/(gs-sum(l1$m))
2076 den2 <- sum(l2$n)/(gs-sum(l2$m))
2077 return(den1/den2);
2078 }
2079
2080
2081
2082
2083 # calculate cumulative density based on sum of scaled gaussian curves
2084 # (by Michael Tolstorukov)
2085 #
2086 # vin - input vector; bw -- standard deviation, dw-gaussina cutoff in stdev; dout - output "density")
2087 # output - if return.x=F vector of cumulative density values corresponding to integer positions described by range(vin)
2088 # output - if return.x=T a data structure with $x and $y corresponding to the cumulative density
2089 # optional match.wt.f is a function that will return weights for a tag vector
2090 densum <- function(vin,bw=5,dw=3,match.wt.f=NULL,return.x=T,from=min(vin),to=max(vin),step=1) {
2091 # construct vector of unique tags and their counts
2092 tc <- table(vin[vin>=from & vin<=to]);
2093 pos <- as.numeric(names(tc)); storage.mode(pos) <- "double";
2094 tc <- as.numeric(tc); storage.mode(tc) <- "double";
2095 n <- length(pos)
2096 # weight counts
2097 if(!is.null(match.wt.f)) {
2098 tc <- tc*match.wt.f(pos);
2099 }
2100
2101 rng <- c(from,to);
2102 if(rng[1]<0) { stop("range extends into negative values") }
2103 if(range(pos)[1]<0) { stop("position vector contains negative values") }
2104
2105 storage.mode(n) <- storage.mode(rng) <- storage.mode(bw) <- storage.mode(dw) <- storage.mode(step) <- "integer";
2106
2107 spos <- rng[1]; storage.mode(spos) <- "double";
2108
2109 dlength <- floor((rng[2] - rng[1])/step) + 1; # length of output array
2110 if(dlength<1) { stop("zero data range") }
2111 dout <- numeric(dlength); storage.mode(dout) <- "double";
2112 storage.mode(dlength) <- "integer";
2113 .C("cdensum",n,pos,tc,spos,bw,dw,dlength,step,dout,DUP=F);
2114
2115 if(return.x) {
2116 return(list(x=c(rng[1],rng[1]+step*(dlength-1)),y=dout,step=step))
2117 } else {
2118 return(dout)
2119 }
2120 }
2121
2122 # count tags within sliding window of a specified size
2123 # vin - tag vector (postive values, pre-shifted)
2124 # window.size/window.step - window characteristics
2125 # tv - optional, pre-sorted, pre-trimmed tag vector
2126 window.tag.count <- function(vin,window.size,window.step=1,return.x=T,from=min(vin)+floor(window.size/2),to=max(vin)-floor(window.size/2),tv=NULL) {
2127 whs <- floor(window.size/2);
2128 # select tags with margins
2129 if(is.null(tv)) {
2130 tv <- sort(vin[vin>=from-whs-1 & vin<=to+whs+1])
2131 }
2132 storage.mode(tv) <- "double";
2133 n <- length(tv)
2134 nsteps <- ceiling((to-from)/window.step);
2135
2136 storage.mode(n) <- storage.mode(nsteps) <- storage.mode(window.size) <- storage.mode(window.step) <- "integer";
2137
2138 spos <- from; storage.mode(spos) <- "double";
2139
2140 if(nsteps<1) { stop("zero data range") }
2141 #dout <- integer(nsteps); storage.mode(dout) <- "integer";
2142 #.C("window_n_tags",n,tv,spos,window.size,window.step,nsteps,dout,DUP=F);
2143 dout <- .Call("cwindow_n_tags",tv,spos,window.size,window.step,nsteps);
2144
2145 if(return.x) {
2146 return(list(x=c(from,from+(nsteps-1)*window.step),y=dout,step=window.step))
2147 } else {
2148 return(dout)
2149 }
2150 }
2151
2152 # count tags in windows around specified positions (pos)
2153 window.tag.count.around <- function(vin,window.size,pos,return.x=T,tc=NULL,sorted=F) {
2154 if(is.null(tc)) {
2155 tc <- table(vin);
2156 }
2157 if(!sorted) {
2158 op <- rank(pos);
2159 pos <- sort(pos);
2160 }
2161 storage.mode(pos) <- "double";
2162 tpos <- as.integer(names(tc)); storage.mode(tpos) <- "double";
2163 tc <- as.integer(tc); storage.mode(tc) <- "integer";
2164
2165 whs <- floor(window.size/2);
2166
2167 storage.mode(whs) <- "integer";
2168 twc <- .Call("cwindow_n_tags_around",tpos,tc,pos,whs);
2169 if(return.x) {
2170 if(sorted) {
2171 return(data.frame(x=pos,y=twc));
2172 } else {
2173 return(data.frame(x=pos[op],y=twc[op]));
2174 }
2175 } else {
2176 if(sorted) {
2177 return(twc);
2178 } else {
2179 return(twc[op]);
2180 }
2181 }
2182 }
2183
2184 # given a tag vector (signed), identify and clean up (either remove or cap) singular positions that exceed local tag density
2185 # vin - tag vector
2186 # cap.fold - maximal fold over enrichment over local density allowed for a single tag position, at which the tag count is capped
2187 # eliminate.fold - max fold enrichment that, when exceeded, results in exclusion of all the tags at that position (e.g. counted as anomaly)
2188 # z.threshold - Z-score used to determine max allowed counts
2189 filter.singular.positions.by.local.density <- function(tags,window.size=200,cap.fold=4,eliminate.fold=10,z.threshold=3) {
2190 # tabulate tag positions
2191 if(length(tags)<2) { return(tags); };
2192
2193 tc <- table(tags);
2194 pos <- as.numeric(names(tc)); storage.mode(pos) <- "double";
2195 tc <- as.integer(tc); storage.mode(tc) <- "integer";
2196 n <- length(pos);
2197
2198 whs <- floor(window.size/2);
2199
2200 storage.mode(n) <- storage.mode(whs) <- "integer";
2201 twc <- .Call("cwindow_n_tags_around",pos,tc,pos,whs);
2202 twc <- (twc-tc+1)/window.size; # local density
2203
2204 pv <- pnorm(z.threshold,lower.tail=F)
2205 # exclude
2206 max.counts <- qpois(pv,twc*eliminate.fold,lower.tail=F)
2207 tc[tc>max.counts] <- 0;
2208 # cap
2209 max.counts <- qpois(pv,twc*cap.fold,lower.tail=F)
2210 ivi <- which(tc>max.counts);
2211 tc[ivi] <- max.counts[ivi]+1;
2212
2213 # reconstruct tag vector
2214 tv <- rep(pos,tc);
2215 to <- order(abs(tv)); tv <- tv[to];
2216 return(tv);
2217 }
2218
2219
2220
2221 # calculates enrichment bounds using multiple background scales
2222 # ft - foreground tags (pre-shifted, positive)
2223 # bt - background tags
2224 # fws - foreground window size
2225 # bwsl - background window size list
2226 # step - window step
2227 # rng - from/to coordinates (to will be adjusted according to step)
2228 #
2229 # returns: a list with $x ($s $e $step), $lb vector and $mle vector ($ub if calculate.upper.bound=T)
2230 mbs.enrichment.bounds <- function(ft,bt,fws,bwsl,step=1,rng=NULL,alpha=0.05,calculate.upper.bound=F,bg.weight=length(ft)/length(bt),use.most.informative.scale=F,quick.calculation=F,pos=NULL) {
2231 # determine range
2232 if(is.null(rng)) {
2233 rng <- range(range(ft));
2234 }
2235 # foreground counts
2236 if(is.null(pos)) {
2237 fwc <- window.tag.count(ft,fws,window.step=step,from=rng[1],to=rng[2],return.x=T);
2238 } else {
2239 fwc <- window.tag.count.around(ft,fws,pos,return.x=T)
2240 }
2241 fwc$y <- fwc$y+0.5;
2242
2243 zal <- qnorm(alpha/2,lower.tail=F);
2244
2245 # background counts
2246 bt <- sort(bt);
2247 if(!is.null(pos)) {
2248 tc <- table(bt);
2249 }
2250 bgcm <- lapply(bwsl,function(bgws) {
2251 if(is.null(pos)) {
2252 window.tag.count(bt,bgws,window.step=step,from=rng[1],to=rng[2],return.x=F,tv=bt)+0.5;
2253 } else {
2254 window.tag.count.around(bt,bgws,pos,return.x=F,tc=tc)+0.5
2255 }
2256 })
2257 if(!is.null(pos)) {
2258 rm(tc);
2259 }
2260
2261 # pick most informative scale
2262 if(use.most.informative.scale) {
2263 bgcm <- t(do.call(cbind,bgcm))
2264 isi <- max.col(t((bgcm)/(bwsl/fws))) # add pseudo-counts to select lowest scale in case of a tie
2265
2266 bgc <- c(bgcm)[isi+dim(bgcm)[1]*(c(1:length(isi))-1)]
2267
2268 if(quick.calculation) {
2269 rte <- fwc$y+bgc-0.25*zal*zal; rte[rte<0] <- 0;
2270 dn <- bgc - 0.25*zal*zal;
2271 lbm=(sqrt(fwc$y*bgc) - 0.5*zal*sqrt(rte))/dn;
2272 ivi <- which(lbm<0);
2273 lbm <- lbm*lbm*bwsl[isi]/fws/bg.weight;
2274 lbm[rte<=0] <- 1;
2275 lbm[dn<=0] <- 1;
2276 lbm[ivi] <- 1;
2277 } else {
2278 lbm <- (fwc$y/bgc)*qf(1-alpha/2,2*fwc$y,2*bgc,lower.tail=F)*bwsl[isi]/fws/bg.weight;
2279 }
2280
2281 mle <- fwc$y/bgc*bwsl[isi]/fws/bg.weight; mle[is.nan(mle)] <- Inf; mle[is.na(mle)] <- Inf;
2282
2283 rl <- list(x=list(s=fwc$x[1],e=fwc$x[2],step=fwc$step),lb=lbm,mle=mle);
2284
2285 if(calculate.upper.bound) {
2286 isi <- max.col(t((-bgcm)/(bwsl/fws))) # add pseudo-counts to select highest scale in case of a tie
2287 bgc <- c(bgcm)[isi+dim(bgcm)[1]*(c(1:length(isi))-1)]
2288
2289 if(quick.calculation) {
2290 ubm=(sqrt(fwc$y*bgc) + 0.5*zal*sqrt(rte))/dn;
2291 ivi <- which(ubm<0);
2292 ubm <- ubm*ubm*bwsl[isi]/fws/bg.weight;
2293 ubm[rte<=0] <- 1;
2294 ubm[ivi] <- 1;
2295 lbm[dn<=0] <- 1;
2296 } else {
2297 ubm <- (fwc$y/bgc)*qf(alpha/2,2*fwc$y,2*bgc,lower.tail=F)*bwsl[isi]/fws/bg.weight;
2298 }
2299 rl <- c(rl,list(ub=ubm));
2300 }
2301 return(rl);
2302
2303 } else {
2304 # determine lower bounds
2305 lbm <- lapply(c(1:length(bgcm)),function(i) {
2306 nbg <- bgcm[[i]];
2307 if(quick.calculation) {
2308 rte <- fwc$y+nbg-0.25*zal*zal; rte[rte<0] <- 0;
2309 dn <- (nbg - 0.25*zal*zal);
2310 lbm=(sqrt(fwc$y*nbg) - 0.5*zal*sqrt(rte))/dn;
2311 ivi <- which(lbm<0);
2312 lbm <- lbm*lbm*bwsl[i]/fws/bg.weight;
2313 lbm[rte<=0] <- 1;
2314 lbm[dn<=0] <- 1;
2315 lbm[ivi] <- 1;
2316 return(lbm);
2317 } else {
2318 return((fwc$y/nbg)*qf(1-alpha/2,2*fwc$y,2*nbg,lower.tail=F)*bwsl[i]/fws/bg.weight);
2319 }
2320 })
2321 lbm <- do.call(pmin,lbm);
2322
2323 # calculate mle
2324 #mle <- do.call(pmin,lapply(bgcm,function(bgc) fwc/bgc))
2325 mle <- do.call(pmin,lapply(c(1:length(bgcm)),function(i) {
2326 bgc <- bgcm[[i]];
2327 x <- fwc$y/bgc*bwsl[i]/fws/bg.weight; x[is.nan(x)] <- Inf; x[is.na(x)] <- Inf; return(x);
2328 }))
2329
2330 rl <- list(x=list(s=fwc$x[1],e=fwc$x[2],step=fwc$step),lb=lbm,mle=mle);
2331
2332 if(calculate.upper.bound) {
2333 # determine upper bound
2334 ubm <- lapply(c(1:length(bgcm)),function(i) {
2335 nbg <- bgcm[[i]];
2336 if(quick.calculation) {
2337 rte <- fwc$y+nbg-0.25*zal*zal; rte[rte<0] <- 0;
2338 dn <- (nbg - 0.25*zal*zal);
2339 ubm=(sqrt(fwc$y*nbg) + 0.5*zal*sqrt(rte))/dn;
2340 ivi <- which(ubm<0);
2341 ubm <- ubm*ubm*bwsl[i]/fws/bg.weight;
2342 ubm[rte<=0] <- 1;
2343 ubm[dn<=0] <- 1;
2344 ubm[ivi] <- 1;
2345 return(ubm);
2346 } else {
2347 return((fwc$y/nbg)*qf(alpha/2,2*fwc$y,2*nbg,lower.tail=F)*bwsl[i]/fws/bg.weight);
2348 }
2349 })
2350 ubm <- do.call(pmax,ubm);
2351 rl <- c(rl,list(ub=ubm));
2352 }
2353
2354 return(rl);
2355 }
2356 }
2357
2358 write.probe.wig <- function(chr,pos,val,fname,append=F,feature="M",probe.length=35,header=T) {
2359 min.dist <- min(diff(pos));
2360 if(probe.length>=min.dist) {
2361 probe.length <- min.dist-1;
2362 cat("warning: adjusted down wig segment length to",probe.length,"\n");
2363 }
2364 mdat <- data.frame(chr,as.integer(pos),as.integer(pos+probe.length),val)
2365
2366 if(header) {
2367 write(paste("track type=wiggle_0 name=\"Bed Format\" description=\"",feature,"\" visibility=dense color=200,100,0 altColor=0,100,200 priority=20",sep=""),file=fname,append=append)
2368 write.table(mdat,file=fname,col.names=F,row.names=F,quote=F,sep=" ",append=T);
2369 } else {
2370 write.table(mdat,file=fname,col.names=F,row.names=F,quote=F,sep=" ",append=append);
2371 }
2372
2373 }
2374
2375 # returns intersection of multiple region sets
2376 # each regionset needs to contain $s, $e and optional $v column
2377 regionset.intersection.c <- function(rsl,max.val=-1,do.union=F) {
2378 # translate into position/flag form
2379 rfl <- lapply(rsl,function(rs) {
2380 rp <- c(rs$s,rs$e); rf <- c(rep(c(1,-1),each=length(rs$s)));
2381
2382 ro <- order(rp);
2383 rp <- rp[ro]; rf <- rf[ro];
2384 if(!is.null(rs$v)) {
2385 rv <- c(rs$v,rs$v)[ro];
2386 return(data.frame(p=as.numeric(rp),f=as.integer(rf),v=as.numeric(rv)));
2387 } else {
2388 return(data.frame(p=as.numeric(rp),f=as.integer(rf)));
2389 }
2390 })
2391 rfd <- data.frame(do.call(rbind,lapply(1:length(rfl),function(i) {
2392 d <- rfl[[i]]; d$f <- d$f*i; return(d);
2393 })))
2394 rfd <- rfd[order(rfd$p),];
2395 if(is.null(rfd$v)) { max.val <- 0; }
2396 if(do.union) { ur <- 1; } else { ur <- 0; };
2397 rl <- .Call("region_intersection",as.integer(length(rfl)),as.numeric(rfd$p),as.integer(rfd$f),as.numeric(rfd$v),as.integer(max.val),as.integer(ur));
2398 return(data.frame(do.call(cbind,rl)));
2399 }
2400
2401
2402 # idenfity if binding peak falls within a larger region of significant tag enrichment, and if so record its booundaries
2403 add.broad.peak.regions <- function(chip.tags,input.tags,bp,window.size=500,z.thr=2) {
2404 se <- find.significantly.enriched.regions(chip.tags,input.tags,window.size=window.size,z.thr=z.thr,poisson.z=0,poisson.ratio=0,either=F)
2405 chrl <- names(bp$npl); names(chrl) <- chrl;
2406 bnpl <- lapply(chrl,function(chr) {
2407 npl <- bp$npl[[chr]];
2408 if(is.null(npl) | dim(npl)[1]<1) {
2409 return(npl);
2410 }
2411 pi <- points.within(npl$x,se[[chr]]$s,se[[chr]]$e,return.list=T);
2412
2413 pm <- do.call(rbind,lapply(pi,function(rl) {
2414 if(length(rl)>0) {
2415 return(range(c(se[[chr]]$s[rl],se[[chr]]$e[rl])))
2416 } else {
2417 return(c(NA,NA));
2418 }
2419 }))
2420
2421 npl$rs <- pm[,1];
2422 npl$re <- pm[,2];
2423 return(npl);
2424 })
2425 bp$npl <- bnpl;
2426 return(bp);
2427 }
2428
2429 # writing out binding results in a narrowpeak format, incorporating broad region boundaries if they are present
2430 # if broad region info is not present, margin is used to determine region width. The default margin is equal
2431 # to the window half size used to call the binding peaks
2432 write.narrowpeak.binding <- function(bd,fname,margin=bd$whs,npeaks=NA) { # Anshul: added npeaks option
2433 if(is.null(margin)) { margin <- 50; }
2434 chrl <- names(bd$npl); names(chrl) <- chrl;
2435 md <- do.call(rbind,lapply(chrl,function(chr) {
2436 df <- bd$npl[[chr]];
2437 x <- df$x;
2438 rs <- df$rs; if(is.null(rs)) { rs <- rep(NA,length(x)) }
2439 re <- df$re; if(is.null(re)) { re <- rep(NA,length(x)) }
2440 #ivi <- which(is.na(rs)); if(any(ivi)) {rs[ivi] <- x[ivi]-margin;}
2441 ivi <- which(is.na(rs)); if(any(ivi)) {rs[ivi] <- pmax(0,x[ivi]-margin);} # Anshul: added the pmax (0, ...) to avoid negative peak starts
2442 ivi <- which(is.na(re)); if(any(ivi)) {re[ivi] <- x[ivi]+margin;}
2443 #cbind(chr,rs,re,".","0",".",df$y,-1,format(df$fdr,scientific=T,digits=3),x-rs)
2444 cbind(chr,rs,re,".","0",".",df$y,-1,-log10(df$fdr),x-rs) # Anshul: converted fdr to -log10
2445 }))
2446 md <- md[order(as.numeric(md[,7]),decreasing=T),]
2447 if (!is.na(npeaks)) { # Anshul: added this option to print a limited number of peaks
2448 npeaks <- min(nrow(md),npeaks)
2449 md <- md[1:npeaks,]
2450 }
2451 write.table(md,file=fname,col.names=F,row.names=F,quote=F,sep="\t",append=F);
2452 }
2453
2454
2455 get.broad.enrichment.clusters <- function(signal.data,control.data,window.size=1e3,z.thr=3, tag.shift=146/2,background.density.scaling=F, ... ) {
2456 # find significantly enriched clusters
2457 bg.weight <- dataset.density.ratio(signal.data,control.data,background.density.scaling=background.density.scaling);
2458 se <- find.significantly.enriched.regions(signal.data,control.data,window.size=window.size,z.thr=z.thr,tag.shift=tag.shift, bg.weight=bg.weight, ...)
2459 chrl <- names(se); names(chrl) <- chrl;
2460 se <- lapply(chrl,function(chr) {
2461 d <- se[[chr]];
2462 if(length(d$s>1)) {
2463 d <- regionset.intersection.c(list(d,d),do.union=T);
2464 sc <- points.within(abs(signal.data[[chr]]+tag.shift),d$s,d$e,return.point.counts=T);
2465 cc <- points.within(abs(control.data[[chr]]+tag.shift),d$s,d$e,return.point.counts=T);
2466 d$rv <- log2((sc+1)/(cc+1)/bg.weight);
2467 return(d);
2468 } else {
2469 return(d)
2470 }
2471 })
2472 }
2473
2474 write.broadpeak.info <- function(bp,fname) {
2475 chrl <- names(bp); names(chrl) <- chrl;
2476 chrl <- chrl[unlist(lapply(bp,function(d) length(d$s)))>0]
2477 md <- do.call(rbind,lapply(chrl,function(chr) {
2478 df <- bp[[chr]];
2479 cbind(chr,df$s,df$e,".","0",".",df$rv,-1,-1)
2480 }))
2481 md <- md[order(as.numeric(md[,7]),decreasing=T),]
2482 write.table(md,file=fname,col.names=F,row.names=F,quote=F,sep="\t",append=F);
2483 }
2484
2485
2486 get.clusters2 <- function(x,CL) {
2487 temp <- which(diff(x) != 0)
2488 begin <- c(1, temp + 1)
2489 end <- c(temp, length(x))
2490 size <- end - begin + 1
2491
2492 begin <- begin[size >= CL]
2493 end <- end[size >= CL]
2494 size <- size[size >= CL]
2495
2496 size <- size[x[end] != 0]
2497 begin <- begin[x[end] != 0]
2498 end <- end[x[end] != 0]
2499
2500 return (list(size=size,begin=begin,end=end))
2501 }