2 usage: python $ERANGEPATH/findall.py label samplerdsfile regionoutfile
3 [--control controlrdsfile] [--minimum minHits] [--ratio minRatio]
4 [--spacing maxSpacing] [--listPeak] [--shift #bp | learn] [--learnFold num]
5 [--noshift] [--autoshift] [--reportshift] [--nomulti] [--minPlus fraction]
6 [--maxPlus fraction] [--leftPlus fraction] [--minPeak RPM] [--raw]
7 [--revbackground] [--pvalue self|back|none] [--nodirectionality]
8 [--strandfilter plus/minus] [--trimvalue percent] [--notrim]
9 [--cache pages] [--log altlogfile] [--flag aflag] [--append] [--RNA]
11 where values in brackets are optional and label is an arbitrary string.
13 Use -ratio (default 4 fold) to set the minimum fold enrichment
14 over the control, -minimum (default 4) is the minimum number of reads
15 (RPM) within the region, and -spacing (default readlen) to set the maximum
16 distance between reads in the region. -listPeak lists the peak of the
17 region. Peaks mut be higher than -minPeak (default 0.5 RPM).
18 Pvalues are calculated from the sample (change with -pvalue),
19 unless the -revbackground flag and a control RDS file are provided.
21 By default, all numbers and parameters are on a reads per
22 million (RPM) basis. -raw will treat all settings, ratios and reported
23 numbers as raw counts rather than RPM. Use -notrim to turn off region
24 trimming and -trimvalue to control trimming (default 10% of peak signal)
26 The peak finder uses minimal directionality information that can
27 be turned off with -nodirectionality ; the fraction of + strand reads
28 required to be to the left of the peak (default 0.3) can be set with
29 -leftPlus ; -minPlus and -maxPlus change the minimum/maximum fraction
30 of plus reads in a region, which (defaults 0.25 and 0.75, respectively).
32 Use -shift to shift reads either by half the expected
33 fragment length (default 0 bp) or '-shift learn ' to learn the shift
34 based on the first chromosome. If you prefer to learn the shift
35 manually, use -autoshift to calculate a per-region shift value, which
36 can be reported using -reportshift. -strandfilter should only be used
37 when explicitely calling unshifted stranded peaks from non-ChIP-seq
38 data such as directional RNA-seq. regionoutfile is written over by
39 default unless given the -append flag.
52 from commoncode import writeLog, findPeak, getBestShiftForRegion, getConfigParser, getConfigOption, getConfigIntOption, getConfigFloatOption, getConfigBoolOption
57 versionString = "findall: version 3.2"
69 (options, args) = parser.parse_args(argv[1:])
79 findall(factor, hitfile, outfilename, options.minHits, options.minRatio, options.maxSpacing, options.listPeak, options.shift,
80 options.stringency, options.noshift, options.autoshift, options.reportshift,
81 options.minPlusRatio, options.maxPlusRatio, options.leftPlusRatio, options.minPeak,
82 options.normalize, options.logfilename, options.withFlag, options.doDirectionality,
83 options.trimValue, options.doTrim, options.doAppend, options.rnaSettings,
84 options.cachePages, options.ptype, options.mockfile, options.doRevBackground, options.noMulti,
85 options.strandfilter, options.combine5p)
91 parser = optparse.OptionParser(usage=usage)
92 parser.add_option("--control", dest="mockfile")
93 parser.add_option("--minimum", type="float", dest="minHits")
94 parser.add_option("--ratio", type="float", dest="minRatio")
95 parser.add_option("--spacing", type="int", dest="maxSpacing")
96 parser.add_option("--listPeak", action="store_true", dest="listPeak")
97 parser.add_option("--shift", dest="shift")
98 parser.add_option("--learnFold", type="float", dest="stringency")
99 parser.add_option("--noshift", action="store_true", dest="noShift")
100 parser.add_option("--autoshift", action="store_true", dest="autoshift")
101 parser.add_option("--reportshift", action="store_true", dest="reportshift")
102 parser.add_option("--nomulti", action="store_true", dest="noMulti")
103 parser.add_option("--minPlus", type="float", dest="minPlusRatio")
104 parser.add_option("--maxPlus", type="float", dest="maxPlusRatio")
105 parser.add_option("--leftPlus", type="float", dest="leftPlusRatio")
106 parser.add_option("--minPeak", type="float", dest="minPeak")
107 parser.add_option("--raw", action="store_false", dest="normalize")
108 parser.add_option("--revbackground", action="store_true", dest="doRevBackground")
109 parser.add_option("--pvalue", dest="ptype")
110 parser.add_option("--nodirectionality", action="store_false", dest="doDirectionality")
111 parser.add_option("--strandfilter", dest="strandfilter")
112 parser.add_option("--trimvalue", type="float", dest="trimValue")
113 parser.add_option("--notrim", action="store_false", dest="doTrim")
114 parser.add_option("--cache", type="int", dest="cachePages")
115 parser.add_option("--log", dest="logfilename")
116 parser.add_option("--flag", dest="withFlag")
117 parser.add_option("--append", action="store_true", dest="doAppend")
118 parser.add_option("--RNA", action="store_true", dest="rnaSettings")
119 parser.add_option("--combine5p", action="store_true", dest="combine5p")
121 configParser = getConfigParser()
123 minHits = getConfigFloatOption(configParser, section, "minHits", 4.0)
124 minRatio = getConfigFloatOption(configParser, section, "minRatio", 4.0)
125 maxSpacing = getConfigIntOption(configParser, section, "maxSpacing", 50)
126 listPeak = getConfigBoolOption(configParser, section, "listPeak", False)
127 shift = getConfigOption(configParser, section, "shift", None)
128 stringency = getConfigFloatOption(configParser, section, "stringency", 4.0)
129 noshift = getConfigBoolOption(configParser, section, "noshift", False)
130 autoshift = getConfigBoolOption(configParser, section, "autoshift", False)
131 reportshift = getConfigBoolOption(configParser, section, "reportshift", False)
132 minPlusRatio = getConfigFloatOption(configParser, section, "minPlusRatio", 0.25)
133 maxPlusRatio = getConfigFloatOption(configParser, section, "maxPlusRatio", 0.75)
134 leftPlusRatio = getConfigFloatOption(configParser, section, "leftPlusRatio", 0.3)
135 minPeak = getConfigFloatOption(configParser, section, "minPeak", 0.5)
136 normalize = getConfigBoolOption(configParser, section, "normalize", True)
137 logfilename = getConfigOption(configParser, section, "logfilename", "findall.log")
138 withFlag = getConfigOption(configParser, section, "withFlag", "")
139 doDirectionality = getConfigBoolOption(configParser, section, "doDirectionality", True)
140 trimValue = getConfigOption(configParser, section, "trimValue", None)
141 doTrim = getConfigBoolOption(configParser, section, "doTrim", True)
142 doAppend = getConfigBoolOption(configParser, section, "doAppend", False)
143 rnaSettings = getConfigBoolOption(configParser, section, "rnaSettings", False)
144 cachePages = getConfigOption(configParser, section, "cachePages", None)
145 ptype = getConfigOption(configParser, section, "ptype", None)
146 mockfile = getConfigOption(configParser, section, "mockfile", None)
147 doRevBackground = getConfigBoolOption(configParser, section, "doRevBackground", False)
148 noMulti = getConfigBoolOption(configParser, section, "noMulti", False)
149 strandfilter = getConfigOption(configParser, section, "strandfilter", None)
150 combine5p = getConfigBoolOption(configParser, section, "combine5p", False)
152 parser.set_defaults(minHits=minHits, minRatio=minRatio, maxSpacing=maxSpacing, listPeak=listPeak, shift=shift,
153 stringency=stringency, noshift=noshift, autoshift=autoshift, reportshift=reportshift,
154 minPlusRatio=minPlusRatio, maxPlusRatio=maxPlusRatio, leftPlusRatio=leftPlusRatio, minPeak=minPeak,
155 normalize=normalize, logfilename=logfilename, withFlag=withFlag, doDirectionality=doDirectionality,
156 trimValue=trimValue, doTrim=doTrim, doAppend=doAppend, rnaSettings=rnaSettings,
157 cachePages=cachePages, ptype=ptype, mockfile=mockfile, doRevBackground=doRevBackground, noMulti=noMulti,
158 strandfilter=strandfilter, combine5p=combine5p)
163 def findall(factor, hitfile, outfilename, minHits=4.0, minRatio=4.0, maxSpacing=50, listPeak=False, shift=None,
164 stringency=4.0, noshift=False, autoshift=False, reportshift=False,
165 minPlusRatio=0.25, maxPlusRatio=0.75, leftPlusRatio=0.3, minPeak=0.5,
166 normalize=True, logfilename="findall.log", withFlag="", doDirectionality=True,
167 trimValue=None, doTrim=True, doAppend=False, rnaSettings=False,
168 cachePages=None, ptype=None, mockfile=None, doRevBackground=False, noMulti=False,
169 strandfilter=None, combine5p=False):
171 shiftValue = determineShiftValue(autoshift, shift, noshift, rnaSettings)
173 if trimValue is not None:
174 trimValue = float(trimValue) / 100.
175 trimString = "%2.1f%s" % ((100. * trimValue), "%")
184 print "Swapping IP and background to calculate FDR"
188 if mockfile is not None:
192 if ptype is not None:
193 ptype = ptype.upper()
199 elif ptype == "SELF":
201 elif ptype == "BACK":
202 if doControl and doRevBackground:
205 print "must have a control dataset and -revbackground for pValue type 'back'"
207 print "could not use pValue type : %s" % ptype
211 if cachePages is not None:
218 print "restrict to flag = %s" % withFlag
222 print "using unique reads only"
226 print "using settings appropriate for RNA: -nodirectionality -notrim -noshift"
228 doDirectionality = False
231 if strandfilter is not None:
232 if strandfilter == "plus":
236 print "only analyzing reads on the plus strand"
237 elif strandfilter == "minus":
241 print "only analyzing reads on the minus strand"
243 stringency = max(stringency, 1.0)
244 writeLog(logfilename, versionString, string.join(sys.argv[1:]))
247 mockRDS = ReadDataset.ReadDataset(mockfile, verbose=True, cache=doCache)
249 if cachePages > mockRDS.getDefaultCacheSize():
250 mockRDS.setDBcache(cachePages)
253 hitRDS = ReadDataset.ReadDataset(hitfile, verbose=True, cache=doCache)
254 readlen = hitRDS.getReadSize()
258 if cachePages > hitRDS.getDefaultCacheSize():
259 hitRDS.setDBcache(cachePages)
266 outfile = open(outfilename, fileMode)
268 outfile.write("#ERANGE %s\n" % versionString)
270 mockRDSsize = len(mockRDS) / 1000000.
271 controlSampleString = "\t%s (%.1f M reads)" % (mockfile, mockRDSsize)
273 controlSampleString = " none"
275 hitRDSsize = len(hitRDS) / 1000000.
276 outfile.write("#enriched sample:\t%s (%.1f M reads)\n#control sample:%s\n" % (hitfile, hitRDSsize, controlSampleString))
279 outfile.write("#restrict to Flag = %s\n" % withFlag)
281 print "\nenforceDirectionality=%s listPeak=%s nomulti=%s cache=%s " % (doDirectionality, listPeak, noMulti, doCache)
282 print "spacing<%d minimum>%.1f ratio>%.1f minPeak=%.1f\ttrimmed=%s\tstrand=%s" % (maxSpacing, minHits, minRatio, minPeak, trimString, stranded)
283 print "minPlus=%.2f maxPlus=%.2f leftPlus=%.2f shift=%s pvalue=%s" % (minPlusRatio, maxPlusRatio, leftPlusRatio, str(shiftValue), pValueType)
285 outfile.write("#enforceDirectionality=%s listPeak=%s nomulti=%s cache=%s\n" % (doDirectionality, listPeak, noMulti, doCache))
286 outfile.write("#spacing<%d minimum>%.1f ratio>%.1f minPeak=%.1f trimmed=%s strand=%s\n" % (maxSpacing, minHits, minRatio, minPeak, trimString, stranded))
287 outfile.write("#minPlus=%.2f maxPlus=%.2f leftPlus=%.2f shift=%s pvalue=%s\n" % (minPlusRatio, maxPlusRatio, leftPlusRatio, str(shiftValue), pValueType))
289 print "Normalizing to RPM"
294 headerList = ["#regionID\tchrom\tstart\tstop", countLabel, "fold\tmulti%"]
296 headerList.append("plus%\tleftPlus%")
299 headerList.append("peakPos\tpeakHeight")
302 headerList.append("readShift")
305 headerList.append("pValue")
307 headline = string.join(headerList, "\t")
308 print >> outfile, headline
310 statistics = {"index": 0,
317 if minRatio < minPeak:
320 hitChromList = hitRDS.getChromosomes()
322 mockChromList = mockRDS.getChromosomes()
326 mockSampleSize = mockRDSsize
328 hitSampleSize = hitRDSsize
332 for chromosome in hitChromList:
333 if doNotProcessChromosome(chromosome, doControl, mockChromList):
336 print "chromosome %s" % (chromosome)
337 hitDict = hitRDS.getReadsDict(fullChrom=True, chrom=chromosome, flag=withFlag, withWeight=True,
338 doMulti=useMulti, findallOptimize=True, strand=stranded,
340 maxCoord = hitRDS.getMaxCoordinate(chromosome, doMulti=useMulti)
341 if shiftValue == "learn":
342 shiftValue = learnShift(hitDict, hitSampleSize, mockRDS, chromosome, doControl, useMulti, normalize,
343 mockSampleSize, minRatio, maxSpacing, maxCoord, stringency, readlen, minHits,
344 logfilename, outfile, outfilename)
346 regionStats, allRegionWeights, outregions = locateRegions(hitRDS, hitSampleSize, mockRDS, mockSampleSize,
347 chromosome, useMulti, normalize, maxSpacing,
348 doDirectionality, doTrim, minHits, minRatio,
349 readlen, shiftValue, minPeak, minPlusRatio,
350 maxPlusRatio, leftPlusRatio, listPeak, noMulti,
351 doControl, factor, trimValue, outputRegionList=True)
353 statistics["index"] += regionStats["index"]
354 statistics["total"] += regionStats["total"]
355 statistics["failed"] += regionStats["failed"]
356 if not doRevBackground:
358 p, poissonmean = calculatePValue(allRegionWeights)
361 shiftModeValue = writeRegionsToFile(outfile, outregions, doPvalue, p, poissonmean, reportshift, shiftValue)
364 #now do background swapping the two samples around
365 print "calculating background..."
366 backgroundTrimValue = 1/20.
367 backgroundRegionStats, backgroundRegionWeights = locateRegions(mockRDS, mockSampleSize, hitRDS, hitSampleSize,
368 chromosome, useMulti, normalize, maxSpacing,
369 doDirectionality, doTrim, minHits, minRatio,
370 readlen, shiftValue, minPeak, minPlusRatio,
371 maxPlusRatio, leftPlusRatio, listPeak, noMulti,
372 doControl, factor, backgroundTrimValue)
374 statistics["mIndex"] += backgroundRegionStats["index"]
375 statistics["mTotal"] += backgroundRegionStats["total"]
376 statistics["failed"] += backgroundRegionStats["failed"]
377 print statistics["mIndex"], statistics["mTotal"]
379 if pValueType == "self":
380 p, poissonmean = calculatePValue(allRegionWeights)
382 p, poissonmean = calculatePValue(backgroundRegionWeights)
385 shiftModeValue = writeRegionsToFile(outfile, outregions, doPvalue, p, poissonmean, reportshift, shiftValue)
387 footer = getFooter(statistics, doDirectionality, doRevBackground, shiftValue, reportshift, shiftModeValue)
389 outfile.write(footer)
392 writeLog(logfilename, versionString, "%s%s" % (outfilename, footer.replace("\n#", " | ")))
395 def determineShiftValue(autoshift, shift, noshift, rnaSettings):
400 if shift is not None:
402 shiftValue = int(shift)
406 print "Will try to learn shift"
408 if noshift or rnaSettings:
414 def doNotProcessChromosome(chromosome, doControl, mockChromList):
415 skipChromosome = False
416 if chromosome == "chrM":
417 skipChromosome = True
419 if doControl and (chromosome not in mockChromList):
420 skipChromosome = True
422 return skipChromosome
425 def calculatePValue(dataList):
427 listSize = float(len(dataList))
429 poissonmean = sum(dataList) / listSize
430 except ZeroDivisionError:
433 print "Poisson n=%d, p=%f" % (listSize, poissonmean)
434 p = math.exp(-poissonmean)
436 return p, poissonmean
439 def learnShift(hitDict, hitSampleSize, mockRDS, chrom, doControl, useMulti, normalize, mockSampleSize, minRatio, maxSpacing, maxCoord,
440 stringency, readlen, minHits, logfilename, outfile, outfilename, minSites=30):
442 print "learning shift.... will need at least %d training sites" % minSites
443 previousHit = -1 * maxSpacing
450 for read in hitDict[chrom]:
452 sense = read["sense"]
453 weight = read["weight"]
454 if abs(pos - previousHit) > maxSpacing or pos == maxCoord:
457 sumAll /= hitSampleSize
459 regionStart = hitList[0]
460 regionStop = hitList[-1]
461 regionLength = regionStop - regionStart
462 # we're going to require stringent settings
463 if sumAll >= stringency * minHits and numStarts > stringency * minRatio and regionLength > stringency * readlen:
464 foldRatio = getFoldRatio(mockRDS, chrom, regionStart, regionStop, doControl, useMulti, normalize, mockSampleSize, sumAll, minRatio)
466 if foldRatio >= minRatio:
467 localshift = getBestShiftForRegion(readList, regionStart, regionLength, doWeight=True)
469 shiftDict[localshift] += 1
471 shiftDict[localshift] = 1
480 if pos not in hitList:
484 totalWeight += weight
485 readList.append({"start": pos, "sense": sense, "weight": weight})
490 learningSettings = ["#learn: stringency=%.2f min_signal=%2.f min_ratio=%.2f min_region_size=%d" % (stringency, stringency * minHits,
491 stringency * minRatio, stringency * readlen),
492 "#number of training examples: %d" % count]
493 outline = string.join(learningSettings, "\n")
495 writeLog(logfilename, versionString, "%s%s" % (outfilename, outline))
497 outline = "#too few training examples to pick a shiftValue - defaulting to 0\n#consider picking a lower minimum or threshold"
498 print >> outfile, outline
499 writeLog(logfilename, versionString, "%s%s" % (outfilename, outline))
502 for shift in sorted(shiftDict):
503 if shiftDict[shift] > bestCount:
505 bestCount = shiftDict[shift]
507 shiftValue = bestShift
510 outline = "#picked shiftValue to be %d" % shiftValue
512 print >> outfile, outline
513 writeLog(logfilename, versionString, "%s%s" % (outfilename, outline))
518 def getFoldRatio(rds, chrom, start, stop, doControl, useMulti, normalize, sampleSize, sumAll, minRatio):
520 foldRatio = getFoldRatioFromRDS(rds, chrom, start, stop, useMulti, normalize, sampleSize, sumAll)
527 def getFoldRatioFromRDS(rds, chrom, start, stop, useMulti, normalize, sampleSize, sumAll):
528 numMock = 1. + rds.getCounts(chrom, start, stop, uniqs=True, multi=useMulti, splices=False, reportCombined=True)
530 numMock /= sampleSize
532 foldRatio = sumAll / numMock
537 def locateRegions(rds, rdsSampleSize, referenceRDS, referenceSampleSize, chrom, useMulti,
538 normalize, maxSpacing, doDirectionality, doTrim, minHits, minRatio, readlen,
539 shiftValue, minPeak, minPlusRatio, maxPlusRatio, leftPlusRatio, listPeak,
540 noMulti, doControl, factor, trimValue, outputRegionList=False):
543 totalRegionWeight = 0
545 previousHit = - 1 * maxSpacing
546 currentHitList = [-1]
547 currentTotalWeight = 0
548 currentUniqReadCount = 0
553 hitDict = rds.getReadsDict(fullChrom=True, chrom=chrom, withWeight=True, doMulti=useMulti, findallOptimize=True)
554 maxCoord = rds.getMaxCoordinate(chrom, doMulti=useMulti)
555 for read in hitDict[chrom]:
557 sense = read["sense"]
558 weight = read["weight"]
559 if abs(pos - previousHit) > maxSpacing or pos == maxCoord:
560 sumAll = currentTotalWeight
562 sumAll /= rdsSampleSize
564 regionStart = currentHitList[0]
565 regionStop = currentHitList[-1]
566 regionWeights.append(int(sumAll))
567 if sumAll >= minHits and numStarts > minRatio and (regionStop - regionStart) > readlen:
569 #first pass uses getFoldRatio on mockRDS as there may not be control
570 foldRatio = getFoldRatioFromRDS(referenceRDS, chrom, regionStart, regionStop, useMulti, normalize, referenceSampleSize, sumAll)
571 if foldRatio >= minRatio:
572 # first pass, with absolute numbers
573 peak = findPeak(currentReadList, regionStart, regionStop - regionStart, readlen, doWeight=True, leftPlus=doDirectionality, shift=shiftValue)
575 bestPos = peak.topPos[0]
576 numHits = peak.numHits
577 peakScore = peak.smoothArray[bestPos]
578 numPlus = peak.numPlus
580 numLeft = peak.numLeft
582 peakScore /= rdsSampleSize
585 minSignalThresh = trimValue * peakScore
587 stop = regionStop - regionStart - 1
589 while not startFound:
590 if peak.smoothArray[start] >= minSignalThresh or start == bestPos:
597 if peak.smoothArray[stop] >= minSignalThresh or stop == bestPos:
602 regionStop = regionStart + stop
604 trimPeak = findPeak(currentReadList, regionStart, regionStop - regionStart, readlen, doWeight=True, leftPlus=doDirectionality, shift=shift)
606 sumAll = trimPeak.numHits
607 numPlus = trimPeak.numPlus
608 numLeft = trimPeak.numLeft
610 sumAll /= rdsSampleSize
612 foldRatio = getFoldRatio(referenceRDS, chrom, regionStart, regionStop, doControl, useMulti, normalize, referenceSampleSize, sumAll, minRatio)
614 sumMulti = rds.getCounts(chrom, regionStart, regionStop, uniqs=False, multi=useMulti, splices=False, reportCombined=True)
615 # just in case it changed, use latest data
617 bestPos = trimPeak.topPos[0]
618 peakScore = trimPeak.smoothArray[bestPos]
624 peakScore /= rdsSampleSize
626 elif outputRegionList:
627 sumMulti = currentTotalWeight - currentUniqReadCount
632 sumMulti /= rdsSampleSize
635 multiP = 100. * (sumMulti / sumAll)
642 # check that we still pass threshold
643 if sumAll >= minHits and foldRatio >= minRatio and (regionStop - regionStart) > readlen:
644 plusRatio = float(numPlus)/numHits
645 if peakScore >= minPeak and minPlusRatio <= plusRatio <= maxPlusRatio:
649 peakDescription = "\t%d\t%.1f" % (regionStart + bestPos, peakScore)
652 if leftPlusRatio < numLeft / numPlus:
655 plusP = plusRatio * 100.
656 leftP = 100. * numLeft / numPlus
657 # we have a region that passes all criteria
658 region = Region.DirectionalRegion(regionStart, regionStop + readlen - 1,
659 factor, index, chrom, sumAll,
660 foldRatio, multiP, plusP, leftP,
661 peakDescription, shift)
662 outregions.append(region)
664 totalRegionWeight += sumAll
668 # we have a region, but didn't check for directionality
670 totalRegionWeight += sumAll
672 region = Region.Region(regionStart, regionStop + readlen - 1, factor, index, chrom,
673 sumAll, foldRatio, multiP, peakDescription, shift)
674 outregions.append(region)
677 currentTotalWeight = 0
678 currentUniqReadCount = 0
682 if pos not in currentHitList:
685 currentHitList.append(pos)
686 currentTotalWeight += weight
688 currentUniqReadCount += 1
690 currentReadList.append({"start": pos, "sense": sense, "weight": weight})
693 statistics = {"index": index,
694 "total": totalRegionWeight,
695 "failed": failedCounter
699 return statistics, regionWeights, outregions
701 return statistics, regionWeights
704 def writeRegionsToFile(outfile, outregions, doPvalue, pValue, poissonmean, reportshift, shiftValue):
707 for region in outregions:
708 # iterative poisson from http://stackoverflow.com/questions/280797?sort=newest
710 outputList = [region.printRegionWithShift()]
711 if shiftValue == "auto":
713 shiftDict[region.shift] += 1
715 shiftDict[region.shift] = 1
717 outputList = [region.printRegion()]
719 # iterative poisson from http://stackoverflow.com/questions/280797?sort=newest
721 sumAll = int(region.numReads)
722 for i in xrange(sumAll):
723 pValue *= poissonmean
726 outputList.append("%1.2f" % pValue)
728 outline = string.join(outputList, "\t")
730 print >> outfile, outline
733 for shift in sorted(shiftDict):
734 if shiftDict[shift] > bestCount:
736 bestCount = shiftDict[shift]
741 def getFooter(stats, doDirectionality, doRevBackground, shiftValue, reportshift, shiftModeValue):
742 footerList = ["#stats:\t%.1f RPM in %d regions" % (stats["total"], stats["index"])]
744 footerList.append("#\t\t%d additional regions failed directionality filter" % stats["failed"])
748 percent = min(100. * (float(stats["mIndex"])/stats["index"]), 100)
749 except (ValueError, ZeroDivisionError):
752 footerList.append("#%d regions (%.1f RPM) found in background (FDR = %.2f percent)" % (stats["mIndex"], stats["mTotal"], percent))
754 if shiftValue == "auto" and reportshift:
755 footerList.append("#mode of shift values: %d" % shiftModeValue)
757 footer = string.join(footerList, "\n")
761 if __name__ == "__main__":