diff --git a/tools/ecoSort.py b/tools/ecoSort.py index 4aac925..e030e60 100755 --- a/tools/ecoSort.py +++ b/tools/ecoSort.py @@ -5,11 +5,16 @@ import sys import os import gzip import re +import string from reportlab.graphics.shapes import * from reportlab.graphics.charts.barcharts import VerticalBarChart from reportlab.graphics.charts.piecharts import Pie -from reportlab.graphics import renderPDF +from reportlab.lib.styles import getSampleStyleSheet +from reportlab.lib.units import cm +from reportlab.lib import colors +from reportlab.platypus import * + ##### # @@ -337,7 +342,7 @@ class ColumnFile(object): ########### -class Table(list): +class ecoTable(list): """ Data object inheriting from list """ @@ -364,59 +369,113 @@ class Table(list): ########### -def _makeHistogram(data,label,title,path): + + +def drawGraphs(data,path='graph.pdf'): + """ + Generate a pdf file with graph illustrating the data given as + arguments. Takes two arguments : + 1- an array of array. Each element contains : + * Table object + * number of columns 1 and 2 to be ploted + * a Title + * Number of element to be ploted (10 by default) + * type of graph (1 for histogram or 2 for pie) + 2- path of file-to-be (graph.pdf by default) + """ - drawing = Drawing(350, 450) - - drawing.add(String(35,430,title,fontSize=10)) - - bc = VerticalBarChart() - bc.x = 40 - bc.y = 100 - bc.height = 300 - bc.width = 300 - bc.bars.strokeWidth = 1 - bc.barSpacing = 2 - bc.barLabelFormat = '%d' - bc.barLabels.dy = -5 - bc.barLabels.fontSize = 9 - (len(data[0])/8) - bc.data = data + def box(flt, center=True): + box_style = [('BOX', (0, 0), (-1, -1), 0.5, colors.lightgrey)] + if center: + box_style += [('ALIGN', (0, 0), (-1, -1), 'CENTER')] + return Table([[flt]], style=box_style) + + def makeHistogram(data,label): + + c = VerticalBarChart() + c.x = 10 + c.y = 70 + c.height = 150 + c.width = 300 + c.bars.strokeWidth = 1 + c.barSpacing = 1 + c.barLabels.dy = 5 + c.barLabelFormat = '%d' + c.barLabels.fontSize = 9 - (len(data[0])/10) + c.data = data + + c.categoryAxis.labels.boxAnchor = 'e' + c.categoryAxis.labels.textAnchor = 'start' + c.categoryAxis.labels.dx = -40 + c.categoryAxis.labels.dy = -50 + c.categoryAxis.labels.angle = 45 + c.categoryAxis.labels.width = 10 + c.categoryAxis.labels.height = 4 + c.categoryAxis.categoryNames = label + c.categoryAxis.strokeWidth = 1 + c.categoryAxis.labels.fontSize = 8 + + + c.valueAxis.valueMin = min(data[0])*0.7 + c.valueAxis.valueMax = max(data[0]) + step = (max(data[0]) - min(data[0])) / 10 + c.valueAxis.valueStep = step > 1 and step or 1 + + + return c + + + def makePie(data, label): - bc.valueAxis.valueMin = min(data[0])*0.7 - bc.valueAxis.valueMax = max(data[0]) - bc.valueAxis.valueStep = (max(data[0]) - min(data[0])) / 10 - bc.valueAxis.strokeWidth = 1 + c = Pie() + c.x = 100 + c.y = 100 + c.data = data + c.labels = label + return c + + styles = getSampleStyleSheet() + doc = SimpleDocTemplate(path) - bc.categoryAxis.labels.boxAnchor = 'e' - bc.categoryAxis.labels.dx = -40 - bc.categoryAxis.labels.dy = -50 - bc.categoryAxis.labels.angle = 45 - bc.categoryAxis.labels.width = 10 - bc.categoryAxis.labels.height = 4 - bc.categoryAxis.categoryNames = label - bc.categoryAxis.strokeWidth = 1 - bc.categoryAxis.labels.fontSize = 9 + elements = [] + elements.append(box(Paragraph("EcoPCR report", styles['Title']))) + elements.append(Spacer(0, 0.5 * cm)) + + for e in data: + count, label = [], [] + table = e[0] + col1, col2 = e[1]-1, e[2]-1 + title = e[3] + try: + treshold = e[4] + except: + treshold = 10 + try: + graphType= e[5] + except: + graphType= 1 + + for i in range(treshold): + count.append(table[i][col2]) + label.append(table[i][col1]) + + elements.append(box(Paragraph(title, styles['Normal']))) + if graphType == 2: + chart = makePie(count,label) + else: + chart = makeHistogram([tuple(count)],label) + drawing = Drawing(300, 250) + drawing.add(chart) + elements.append(box(drawing)) + elements.append(Spacer(0, 2 * cm)) + + doc.build(elements) + + + - drawing.add(bc) - - renderPDF.drawToFile(drawing, path ) - -def _makePie(data, label, title, path): - - drawing = Drawing(400,400) - drawing.add(String(50,50,title,fontSize=10)) - - pc = Pie() - pc.x = 100 - pc.y = 100 - pc.data = data - pc.labels = label - pc.labels.angle = 45 - - drawing.add(pc) - - renderPDF.drawToFile(drawing,path) + ########### @@ -499,7 +558,7 @@ def customSort(table,x,y): y = y-1 h = (table.headers[x],table.headers[y]) t = (table.types[x],table.types[y]) - cTable = Table(h,t) + cTable = ecoTable(h,t) tmp = {} @@ -538,7 +597,7 @@ def countColumnOccurrence(table,x): def buildSpecificityTable(table): header = ("mismatch","taxon","count") type = (int,str,int) - speTable = Table(header,type) + speTable = ecoTable(header,type) tmp = {} for l in table: @@ -580,7 +639,7 @@ def buildOligoTable(table, file, filter, oligoRef, strand='direct'): table[i]=[oligo,count,lctTaxid,scName,rank,mismatch] i = i + 1 - table.sort(sortTable) + table.sort(_sortTable) def buildTaxonomicTable(table): @@ -589,7 +648,7 @@ def buildTaxonomicTable(table): """ taxHeaders = ("scName","numOfOligo","numOfAmpl","taxid") taxTypes = (str, int, int, int) - taxTable = Table(taxHeaders, taxTypes) + taxTable = ecoTable(taxHeaders, taxTypes) tax = _parseTaxonomyResult(table) @@ -600,7 +659,7 @@ def buildTaxonomicTable(table): taxTable[i]=[scName,numOfOligo,numOfAmpl,taxid] i = i + 1 - taxTable.sort(sortTable) + taxTable.sort(_sortTable) return taxTable @@ -721,13 +780,13 @@ def grepTable(table,col,pattern): """ col = col -1 p = re.compile(pattern, re.IGNORECASE) - out = Table(table.headers,table.types) + out = ecoTable(table.headers,table.types) for l in table: if p.search(l[col]): out.append(l) return out -def drawGraph(table,x,y,path='graph.pdf',title='',treshold=10,graphType=1): +def drawGraph(data,path='graph.pdf'): """ Creates an histogram as pdf file Takes 5 arguments : @@ -739,18 +798,31 @@ def drawGraph(table,x,y,path='graph.pdf',title='',treshold=10,graphType=1): 6- the x first highest results (10 by default) 7- the graph type : 1 for histogram, 2 for pie """ - count, label = [], [] - x = x-1 - y = y-1 - for l in table: - count.append(l[y]) - label.append(str(l[x])) - if graphType == 1: - _makeHistogram([tuple(count[:treshold])], label[:treshold], title, path) - elif graphType == 2: - _makePie(count[:treshold], label[:treshold], title, path) - + drawing = Drawing(350, 450) + + + + for e in data: + count, label = [], [] + table = e[0] + col1 = e[1]-1 + col2 = e[2]-1 + title = e[3] + treshold = e[4] + graphType= e[5] + + for l in table: + count.append(l[y]) + label.append(str(l[x])) + if graphType == 1: + graph = _makeHistogram([tuple(count[:treshold])], label[:treshold], title, path) + elif graphType == 2: + _makePie(count[:treshold], label[:treshold], title, path) + drawing.add(String(35,430,title,fontSize=10)) + drawing.add(graph) + + renderPDF.drawToFile(drawing, path ) ###################### @@ -761,28 +833,24 @@ def init(): filter = Filter("/ecoPCRDB/gbmam") -# headers = ("oligo", "Num", "LCT Taxid", "Sc Name", "Rank", "distance") -# types = (str, int, int, str, str, int) -# -# o1Table = Table(headers, types) -# o2Table = Table(headers, types) -# -# buildOligoTable(o1Table, file, filter, oligo['o1'], 'direct') -# buildOligoTable(o2Table, file, filter, oligo['o2'], 'reverse') -# -# -# taxTable = buildTaxonomicTable(o1Table) -# speTable = buildSpecificityTable(o1Table) -# + headers = ("oligo", "Num", "LCT Taxid", "Sc Name", "Rank", "distance") + types = (str, int, int, str, str, int) + + o1Table = ecoTable(headers, types) + o2Table = ecoTable(headers, types) + + buildOligoTable(o1Table, file, filter, oligo['o1'], 'direct') + buildOligoTable(o2Table, file, filter, oligo['o2'], 'reverse') + + + taxTable = buildTaxonomicTable(o1Table) + speTable = buildSpecificityTable(o1Table) - seqHeaders = ("sequence","taxid") - seqTypes = (str,list) - seqTable = Table(seqHeaders,seqTypes) +# +# seqHeaders = ("sequence","taxid") +# seqTypes = (str,list) +# seqTable = Table(seqHeaders,seqTypes) - return buildSequenceTable(seqTable, file, filter) - - - - return seqTable + return o1Table, o2Table, taxTable