Update the library listing and summary reports to be prettier and easier to use.
[htsworkflow.git] / gaworkflow / frontend / fctracker / views.py
1 # Create your views here.
2 from gaworkflow.frontend.fctracker.models import Library
3 from gaworkflow.frontend.fctracker.results import get_flowcell_result_dict, flowcellIdStrip
4 from gaworkflow.pipeline.runfolder import ElementTree
5 from gaworkflow.pipeline import runfolder
6 from gaworkflow.frontend import settings
7 from gaworkflow.util import makebed
8 from gaworkflow.util import opener
9
10 from django.http import HttpResponse
11 from django.template.loader import get_template
12 from django.template import Context
13
14 import StringIO
15 import logging
16 import os
17
18 #from django.db.models import base 
19 LANE_LIST = [1,2,3,4,5,6,7,8]
20
21 def create_library_list():
22     """
23     Create a list of libraries that includes how many lanes were run
24     """
25     library_list = []
26     for lib in Library.objects.all():
27        summary = {}
28        summary['library_id'] = lib.library_id
29        summary['library_name'] = lib.library_name
30        summary['species_name' ] = lib.library_species.scientific_name
31        lanes_run = 0
32        for lane_id in LANE_LIST:
33            lane = getattr(lib, 'lane_%d_library' % (lane_id,))
34            lanes_run += len( lane.all() )
35        summary['lanes_run'] = lanes_run
36        library_list.append(summary)
37     return library_list
38
39 def library(request):
40     library_list = create_library_list()
41     t = get_template('library.html')
42     c = Context({'library_list': library_list })
43     return HttpResponse( t.render(c) )
44
45 def library_to_flowcells(request, lib_id):
46     """
47     Display information about all the flowcells a library has been run on.
48     """
49     t = get_template("summary_stats.html")
50     
51     try:
52       lib = Library.objects.get(library_id=lib_id)
53     except:
54       return HttpResponse("Library %s does not exist" % (lib_id))
55     
56     output = []
57     
58     output.append('<b>Library ID:</b> %s' % (lib.library_id))
59     output.append('<b>Name:</b> %s' % (lib.library_name))
60     output.append('<b>Species:</b> %s' % (lib.library_species.scientific_name))
61     output.append('')
62     
63     output.append('<b>FLOWCELL - LANE:</b>')
64     
65     output.extend([ '%s - Lane 1 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 1)) for fc in lib.lane_1_library.all() ])
66     output.extend([ '%s - Lane 2 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 2)) for fc in lib.lane_2_library.all() ])
67     output.extend([ '%s - Lane 3 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 3)) for fc in lib.lane_3_library.all() ])
68     output.extend([ '%s - Lane 4 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 4)) for fc in lib.lane_4_library.all() ])
69     output.extend([ '%s - Lane 5 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 5)) for fc in lib.lane_5_library.all() ])
70     output.extend([ '%s - Lane 6 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 6)) for fc in lib.lane_6_library.all() ])
71     output.extend([ '%s - Lane 7 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 7)) for fc in lib.lane_7_library.all() ])
72     output.extend([ '%s - Lane 8 %s' % (fc.flowcell_id, _files(fc.flowcell_id, 8)) for fc in lib.lane_8_library.all() ])
73     
74     record_count = lib.lane_1_library.count() + \
75                     lib.lane_2_library.count() + \
76                     lib.lane_3_library.count() + \
77                     lib.lane_4_library.count() + \
78                     lib.lane_5_library.count() + \
79                     lib.lane_6_library.count() + \
80                     lib.lane_7_library.count() + \
81                     lib.lane_8_library.count()
82     
83     flowcell_list = []
84     flowcell_list.extend([ (fc.flowcell_id, 1) for fc in lib.lane_1_library.all() ])
85     flowcell_list.extend([ (fc.flowcell_id, 2) for fc in lib.lane_2_library.all() ])
86     flowcell_list.extend([ (fc.flowcell_id, 3) for fc in lib.lane_3_library.all() ])
87     flowcell_list.extend([ (fc.flowcell_id, 4) for fc in lib.lane_4_library.all() ])
88     flowcell_list.extend([ (fc.flowcell_id, 5) for fc in lib.lane_5_library.all() ])
89     flowcell_list.extend([ (fc.flowcell_id, 6) for fc in lib.lane_6_library.all() ])
90     flowcell_list.extend([ (fc.flowcell_id, 7) for fc in lib.lane_7_library.all() ])
91     flowcell_list.extend([ (fc.flowcell_id, 8) for fc in lib.lane_8_library.all() ])
92     flowcell_list.sort()
93     
94     lane_summary_list = []
95     for fc, lane in flowcell_list:
96         lane_summary, err_list = _summary_stats(fc, lane)
97         
98         lane_summary_list.extend(lane_summary)
99     
100         for err in err_list:    
101             output.append(err)
102    
103     logging.error("len lane summary %d" % (len(lane_summary_list)))
104     output.append('<br />')
105     output.append(t.render(Context({'lane_summary_list': lane_summary_list})))
106     output.append('<br />')
107     
108     if record_count == 0:
109         output.append("None Found")
110     
111     return HttpResponse('<br />\n'.join(output))
112
113
114 def summaryhtm_fc_cnm(request, fc_id, cnm):
115     """
116     returns a Summary.htm file if it exists.
117     """
118     fc_id = flowcellIdStrip(fc_id)
119     d = get_flowcell_result_dict(fc_id)
120     
121     if d is None:
122         return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
123     
124     if cnm not in d:
125         return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
126     
127     summary_filepath = d[cnm]['summary']
128     
129     if summary_filepath is None:
130         return HttpResponse('<b>Summary.htm for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
131     
132     f = open(summary_filepath, 'r')
133     
134     return HttpResponse(f)
135
136
137 def result_fc_cnm_eland_lane(request, fc_id, cnm, lane):
138     """
139     returns an eland_file upon calling.
140     """
141     fc_id = flowcellIdStrip(fc_id)
142     d = get_flowcell_result_dict(fc_id)
143     
144     if d is None:
145         return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
146     
147     if cnm not in d:
148         return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
149     
150     erd = d[cnm]['eland_results']
151     lane = int(lane)
152     
153     if lane not in erd:
154         return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
155     
156     filepath = erd[lane]
157     
158     f = opener.autoopen(filepath, 'r')
159     
160     return HttpResponse(f, mimetype="application/x-elandresult")
161
162
163 def bedfile_fc_cnm_eland_lane_ucsc(request, fc_id, cnm, lane):
164     """
165     returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane (ucsc compatible)
166     """
167     return bedfile_fc_cnm_eland_lane(request, fc_id, cnm, lane, ucsc_compatible=True)
168
169
170 def bedfile_fc_cnm_eland_lane(request, fc_id, cnm, lane, ucsc_compatible=False):
171     """
172     returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane
173     """
174     fc_id = flowcellIdStrip(fc_id)
175     d = get_flowcell_result_dict(fc_id)
176     
177     if d is None:
178         return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
179     
180     if cnm not in d:
181         return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
182     
183     erd = d[cnm]['eland_results']
184     lane = int(lane)
185     
186     if lane not in erd:
187         return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
188     
189     filepath = erd[lane]
190     
191     # Eland result file
192     fi = opener.autoopen(filepath, 'r')
193     # output memory file
194     
195     
196     name, description = makebed.make_description(settings.DATABASE_NAME,
197                                                  fc_id,
198                                                  lane)
199     
200     bedgen = makebed.make_bed_from_eland_stream_generator(fi, name, description)
201     
202     if ucsc_compatible:
203         return HttpResponse(bedgen)
204     else:
205         return HttpResponse(bedgen, mimetype="application/x-bedfile")
206
207
208 def _summary_stats(flowcell_id, lane_id):
209     """
210     Return the summary statistics for a given flowcell, lane, and end.
211     """
212     fc_id = flowcellIdStrip(flowcell_id)
213     fc_result_dict = get_flowcell_result_dict(fc_id)
214
215     summary_list = []
216     err_list = []
217     
218     if fc_result_dict is None:
219         err_list.append('Results for Flowcell %s not found.' % (fc_id))
220         return (summary_list, err_list)
221
222     for cycle_width in fc_result_dict:
223         xmlpath = fc_result_dict[cycle_width]['run_xml']
224         
225         if xmlpath is None:
226             err_list.append('Run xml for Flowcell %s(%s) not found.' % (fc_id, cnm))
227             continue
228         
229         tree = ElementTree.parse(xmlpath).getroot()
230         try:
231             runs = runfolder.PipelineRun(pathname='', xml=tree)
232             gerald_summary = runs.gerald.summary.lane_results
233             for end in range(len(gerald_summary)):
234                 eland_summary = runs.gerald.eland_results.results[end][lane_id]
235                 # add information to lane_summary
236                 eland_summary.flowcell_id = flowcell_id
237                 eland_summary.clusters = gerald_summary[end][lane_id].cluster
238                 eland_summary.cycle_width = cycle_width
239                 eland_summary.summarized_reads = runfolder.summarize_mapped_reads(eland_summary.mapped_reads)
240                 summary_list.append(eland_summary)
241
242         except Exception, e:
243             summary_list.append("Summary report needs to be updated.")
244             logging.error("Exception: " + str(e))
245     
246     return (summary_list, err_list)
247
248 def _summary_stats_old(flowcell_id, lane):
249     """
250     return a dictionary of summary stats for a given flowcell_id & lane.
251     """
252     fc_id = flowcellIdStrip(flowcell_id)
253     fc_result_dict = get_flowcell_result_dict(fc_id)
254     
255     dict_list = []
256     err_list = []
257     summary_list = []
258     
259     if fc_result_dict is None:
260         err_list.append('Results for Flowcell %s not found.' % (fc_id))
261         return (dict_list, err_list, summary_list)
262     
263     for cnm in fc_result_dict:
264     
265         xmlpath = fc_result_dict[cnm]['run_xml']
266         
267         if xmlpath is None:
268             err_list.append('Run xml for Flowcell %s(%s) not found.' % (fc_id, cnm))
269             continue
270         
271         tree = ElementTree.parse(xmlpath).getroot()
272         results = runfolder.PipelineRun(pathname='', xml=tree)
273         try:
274             lane_report = runfolder.summarize_lane(results.gerald, lane)
275             summary_list.append(os.linesep.join(lane_report))
276         except Exception, e:
277             summary_list.append("Summary report needs to be updated.")
278             logging.error("Exception: " + str(e))
279        
280         print "----------------------------------"
281         print "-- DOES NOT SUPPORT PAIRED END ---"
282         print "----------------------------------"
283         lane_results = results.gerald.summary[0][lane]
284         lrs = lane_results
285         
286         d = {}
287         
288         d['average_alignment_score'] = lrs.average_alignment_score
289         d['average_first_cycle_intensity'] = lrs.average_first_cycle_intensity
290         d['cluster'] = lrs.cluster
291         d['lane'] = lrs.lane
292         d['flowcell'] = flowcell_id
293         d['cnm'] = cnm
294         d['percent_error_rate'] = lrs.percent_error_rate
295         d['percent_intensity_after_20_cycles'] = lrs.percent_intensity_after_20_cycles
296         d['percent_pass_filter_align'] = lrs.percent_pass_filter_align
297         d['percent_pass_filter_clusters'] = lrs.percent_pass_filter_clusters
298         
299         #FIXME: function finished, but need to take advantage of
300         #   may need to take in a list of lanes so we only have to
301         #   load the xml file once per flowcell rather than once
302         #   per lane.
303         dict_list.append(d)
304     
305     return (dict_list, err_list, summary_list)
306     
307     
308
309     
310 def _files(flowcell_id, lane):
311     """
312     Sets up available files for download
313     """
314     flowcell_id = flowcellIdStrip(flowcell_id)
315     d = get_flowcell_result_dict(flowcell_id)
316     
317     if d is None:
318         return ''
319     
320     output = []
321     
322     # c_name == 'CN-M' (i.e. C1-33)
323     for c_name in d:
324         
325         if d[c_name]['summary'] is not None:
326             output.append('<a href="/results/%s/%s/summary/">summary(%s)</a>' \
327                           % (flowcell_id, c_name, c_name))
328         
329         erd = d[c_name]['eland_results']
330         
331         if int(lane) in erd:
332             output.append('<a href="/results/%s/%s/eland_result/%s">eland_result(%s)</a>' % (flowcell_id, c_name, lane, c_name))
333             output.append('<a href="/results/%s/%s/bedfile/%s">bedfile(%s)</a>' % (flowcell_id, c_name, lane, c_name))
334     
335     if len(output) == 0:
336         return ''
337     
338     return '(' + '|'.join(output) + ')'
339