-
Notifications
You must be signed in to change notification settings - Fork 51
/
qcreporter.py
138 lines (121 loc) · 6.07 KB
/
qcreporter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import os,sys
def formatDivID(str):
str = str.replace(" ", "-")
str = str.replace(".", "-")
str = str.replace("/", "-")
return str
def formatNumber(num):
num = float(num)
unit = ["", "K", "M", "G", "T", "P"]
order = 0
while num > 1024.0:
order += 1
num /= 1024.0
if order == 0:
return str(int(num))
else:
return '{:0.3f}'.format(num) + " " + unit[order]
class QCReporter:
def __init__(self):
self.figures = []
def addFigure(self, title, figure, div='', summary=''):
self.figures.append((title, figure, div, summary))
def setStat(self, stat):
self.stat = stat
def setVersion(self, ver):
self.version = ver
def output(self, filename):
io = open(filename, "w")
self.outputHeader(io)
def outputHeader(self, io):
io.write("<HTML>\n")
io.write("<HEAD>\n")
io.write('<script src="http://cdn.plot.ly/plotly-latest.min.js"></script>\n')
self.outputCSS(io)
io.write("</HEAD>\n")
io.write("<BODY>\n")
io.write("<DIV id='container'>\n")
self.outputMenu(io)
self.outputSummary(io)
self.outputFigures(io)
io.write("</DIV>\n")
self.outputPlotly(io)
io.write("</BODY>\n")
io.write("</HTML>")
io.flush()
def outputCSS(self, io):
io.write("<style type=\"text/css\">"+"\n")
io.write("#menu {text-align:left;}"+"\n")
io.write(".menu-item{font-size:14px;padding:4px;}"+"\n")
io.write("#container {text-align:center;padding-left:30px;}"+"\n")
io.write(".figure-title {color:#bbbbbb;font-size:30px;padding:10px;text-align:left;}"+"\n")
io.write(".figure-div {margin-top:40px;text-align:center}"+"\n")
io.write(".summary-table {padding:5px;border:1px solid #eeeeee;width:800px}"+"\n")
io.write(".col1 {text-align:right;padding:5px;padding-right:20px;color:#666666;}"+"\n")
io.write(".col2 {text-align:left;padding:5px;padding-left:20px;color:#332299;}"+"\n")
io.write(".plotly-div {width:800;height:600;text-align:center;}"+"\n")
io.write("li {color:#666666;font-size:15px;border:0px;}"+"\n")
io.write("</style>"+"\n")
def outputPlotly(self, io):
io.write("<script type=\"text/javascript\">"+"\n")
for figure in self.figures:
content = figure[1]
div = figure[2]
if div != '':
io.write(content)
io.write("\n")
io.write("</script>"+"\n")
def outputMenu(self, io):
io.write("<div id='menu'><ul>\n")
idx = 1
io.write("<li class='menu-item'><a href='#summary'>1, AfterQC summary</a> </li>\n")
for figure in self.figures:
idx += 1
io.write("<li class='menu-item'><a href='#" + formatDivID(figure[0]) + "'>" + str(idx) + ", " + figure[0] + "</a> </li>\n")
io.write("</ul></div>\n")
def outputRow(self, io, k, v):
io.write("<tr><td class='col1'>" + str(k) + "</td><td class='col2'>" + str(v) + "</td></tr>\n")
def getSequencing(self):
ret = str(self.stat["afterqc_main_summary"]["readlen"])
if self.stat["command"]["read2_file"] != None:
ret = "2*" + ret + " pair end"
else:
ret += " single end"
return ret
def outputSummary(self, io):
io.write("<div class='figure-div'>\n")
io.write("<div class='figure-title'><a name='summary'>1, AfterQC summary</a></div>\n")
io.write("<table class='summary-table'>\n")
self.outputRow(io, "AfterQC Version:", self.version)
self.outputRow(io, "sequencing:", self.getSequencing())
self.outputRow(io, "total reads:", formatNumber(self.stat["afterqc_main_summary"]["total_reads"]))
self.outputRow(io, "filtered out reads:", '{:0.3f}'.format(self.stat["afterqc_main_summary"]["bad_reads"]) + " <font color='#aaaaaa'>(" + '{:0.3f}'.format(100.0 * float(self.stat["afterqc_main_summary"]["bad_reads"])/float(self.stat["afterqc_main_summary"]["total_reads"])) + "%)</font>")
self.outputRow(io, "total bases:", formatNumber(self.stat["afterqc_main_summary"]["total_bases"]))
self.outputRow(io, "filtered out bases:", '{:0.3f}'.format(self.stat["afterqc_main_summary"]["total_bases"] - self.stat["afterqc_main_summary"]["good_bases"]) + " <font color='#aaaaaa'>(" + '{:0.3f}'.format(100.0 * float(self.stat["afterqc_main_summary"]["total_bases"] - self.stat["afterqc_main_summary"]["good_bases"])/float(self.stat["afterqc_main_summary"]["total_bases"])) + "%)</font>")
if self.stat["command"]["read2_file"] != None:
self.outputRow(io, "estimated seq error:", '{:0.3f}'.format(self.stat["afterqc_overlap"]["error_rate"]*100) + "%")
self.outputRow(io, "adapter trimmed reads:", formatNumber(self.stat["afterqc_overlap"]['trimmed_adapter_reads']))
self.outputRow(io, "adapter trimmed bases:", formatNumber(self.stat["afterqc_overlap"]['trimmed_adapter_bases']))
self.outputRow(io, "auto trimming", "front:" + str(self.stat["command"]["trim_front"]) + ", tail:" + str(self.stat["command"]["trim_tail"]) + " (use <font color='#aaaaaa'>-f0 -t0</font> to disable)")
io.write("</table>\n")
io.write("</div>\n")
def outputFigures(self, io):
io.write("<div id='figures'>")
idx = 1
for figure in self.figures:
title = figure[0]
content = figure[1]
div = figure[2]
summary = figure[3]
idx += 1
io.write("<div class='figure-div'>\n")
io.write("<div class='figure-title'><a name='" + formatDivID(title) + "'>" + str(idx) + ", " + title + "</a></div>\n")
if div == '':
# an image figure
io.write("<div class='figure'><img src='" + content + "'></div>\n")
else:
# a plotly figure
io.write("<div id='" + div + "' class='plotly-div'></div>\n")
io.write("<div class='figure-summary'>" + summary + "</div>\n")
io.write("</div>\n")
io.write("</div>\n")