-from htsworkflow.frontend.experiments.models import FlowCell, DataRun, ClusterStation, Sequencer, Lane
+from htsworkflow.frontend.experiments.models import \
+ FlowCell, DataRun, DataFile, FileType, ClusterStation, Sequencer, Lane
from django.contrib import admin
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.forms import ModelForm
from django.forms.widgets import TextInput
from django.utils.translation import ugettext_lazy as _
+class DataFileForm(ModelForm):
+ class Meta:
+ model = DataFile
+
+class DataFileInline(admin.TabularInline):
+ model = DataFile
+ form = DataFileForm
+ raw_id_fields = ('library',)
+ extra = 0
+
class DataRunOptions(admin.ModelAdmin):
search_fields = [
+ 'flowcell_id',
'run_folder',
'run_note',
- 'config_params', ]
+ ]
list_display = [
- 'run_folder',
- 'Flowcell_Info',
+ 'runfolder_name',
+ 'result_dir',
'run_start_time',
- 'main_status',
- 'run_note',
]
- list_filter = ('run_status', 'run_start_time')
+ fieldsets = (
+ (None, {
+ 'fields': (('flowcell', 'run_status'),
+ ('runfolder_name', 'cycle_start', 'cycle_stop'),
+ ('result_dir',),
+ ('last_update_time'),
+ ('comment',))
+ }),
+ )
+ inlines = [ DataFileInline ]
+ #list_filter = ('run_status', 'run_start_time')
+admin.site.register(DataRun, DataRunOptions)
+
+class FileTypeAdmin(admin.ModelAdmin):
+ list_display = ('name', 'mimetype', 'regex')
+admin.site.register(FileType, FileTypeAdmin)
+
# lane form setup needs to come before Flowcell form config
# as flowcell refers to the LaneInline class
class LaneForm(ModelForm):
'fields': ('comment', )
}),
)
+admin.site.register(Lane, LaneOptions)
class FlowCellOptions(admin.ModelAdmin):
date_hierarchy = "run_date"
if db_field.name == "notes":
field.widget.attrs["rows"] = "3"
return field
+admin.site.register(FlowCell, FlowCellOptions)
class ClusterStationOptions(admin.ModelAdmin):
list_display = ('name', )
fieldsets = ( ( None, { 'fields': ( 'name', ) } ), )
+admin.site.register(ClusterStation, ClusterStationOptions)
class SequencerOptions(admin.ModelAdmin):
list_display = ('name', )
fieldsets = ( ( None, { 'fields': ( 'name', ) } ), )
-
-
-#admin.site.register(DataRun, DataRunOptions)
-admin.site.register(FlowCell, FlowCellOptions)
-admin.site.register(ClusterStation, ClusterStationOptions)
admin.site.register(Sequencer, SequencerOptions)
-admin.site.register(Lane, LaneOptions)
--- /dev/null
+[
+ { "model": "experiments.FileType",
+ "pk": 1,
+ "fields": {
+ "name": "run_xml",
+ "mimetype": "application/vnd.htsworkflow-run-xml",
+ "regex": "run.*\\.xml\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 2,
+ "fields": {
+ "name": "Summary.htm",
+ "mimetype": "text/html",
+ "regex": "Summary\\.htm\\Z(?ms)"
+ }
+ },
+
+ { "model": "experiments.FileType",
+ "pk": 3,
+ "fields": {
+ "name": "IVC All",
+ "mimetype": "image/png",
+ "regex": "s_(?P<lane>[0-9])_all\\.png\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 4,
+ "fields": {
+ "name": "IVC Call",
+ "mimetype": "image/png",
+ "regex": "s_(?P<lane>[0-9])_call\\.png\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 5,
+ "fields": {
+ "name": "IVC Percent All",
+ "mimetype": "image/png",
+ "regex": "s_(?P<lane>[0-9])_percent_all\\.png\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 6,
+ "fields": {
+ "name": "IVC Percent Base",
+ "mimetype": "image/png",
+ "regex": "s_(?P<lane>[0-9])_percent_base\\.png\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 7,
+ "fields": {
+ "name": "IVC Percent Call",
+ "mimetype": "image/png",
+ "regex": "s_(?P<lane>[0-9])_percent_call\\.png\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 8,
+ "fields": {
+ "name": "GERALD Scores",
+ "regex": "scores\\.tar\\.bz2\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 9,
+ "fields": {
+ "name": "ELAND Result",
+ "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_result\\.txt\\.bz2\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 10,
+ "fields": {
+ "name": "ELAND Multi",
+ "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_multi\\.txt\\.bz2\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 11,
+ "fields": {
+ "name": "ELAND Extended",
+ "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_extended\\.txt\\.bz2\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 12,
+ "fields": {
+ "name": "ELAND Export",
+ "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_export\\.txt\\.bz2\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 13,
+ "fields": {
+ "name": "SRF",
+ "regex": ".*_(?P<lane>[1-8])\\.srf\\Z(?ms)"
+ }
+ },
+ { "model": "experiments.FileType",
+ "pk": 14,
+ "fields": {
+ "name": "QSEQ tarfile",
+ "regex": ".*_l(?P<lane>[1-8])_r(?P<end>[1-4])\\.tar\\.bz2\\Z(?ms)"
+ }
+ }
+
+]
\ No newline at end of file
{"pk": 153, "model": "experiments.flowcell",
"fields": {
"paired_end": true,
- "run_date": "2009-09-11 22:12:13",
- "read_length": 75,
+ "run_date": "2007-09-27 22:12:13",
+ "read_length": 36,
"notes": "",
"advanced_run": false,
"control_lane": 2,
"cluster_station": 3,
"sequencer": 2,
- "flowcell_id": "303TUAAXX"
+ "flowcell_id": "FC12150"
}
},
{"pk": 1193, "model": "experiments.lane",
+import datetime
+import glob
import logging
+import os
+import re
+import types
+import uuid
+from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core import urlresolvers
from django.db import models
+from django.db.models.signals import post_init
-from htsworkflow.frontend.samples.models import *
-#from htsworkflow.frontend.settings import options
-from django.conf import settings
+from htsworkflow.frontend.samples.models import Library
+from htsworkflow.frontend.samples.results import parse_flowcell_id
+from htsworkflow.pipelines import runfolder
+
+default_pM = 5
+try:
+ default_pM = int(settings.DEFAULT_PM)
+except ValueError,e:
+ logging.error("invalid value for frontend.default_pm")
+
+RUN_STATUS_CHOICES = (
+ (0, 'Sequencer running'), ##Solexa Data Pipeline Not Yet Started'),
+ (1, 'Data Pipeline Started'),
+ (2, 'Data Pipeline Interrupted'),
+ (3, 'Data Pipeline Finished'),
+ (4, 'Collect Results Started'),
+ (5, 'Collect Results Finished'),
+ (6, 'QC Started'),
+ (7, 'QC Finished'),
+ (255, 'DONE'),
+ )
+RUN_STATUS_REVERSE_MAP = dict(((v,k) for k,v in RUN_STATUS_CHOICES))
class ClusterStation(models.Model):
name = models.CharField(max_length=50, unique=True)
def __unicode__(self):
return unicode(self.name)
-default_pM = 5
-try:
- default_pM = int(settings.DEFAULT_PM)
-except ValueError,e:
- logging.error("invalid value for frontend.default_pm")
-
class FlowCell(models.Model):
-
flowcell_id = models.CharField(max_length=20, unique=True, db_index=True)
run_date = models.DateTimeField()
advanced_run = models.BooleanField(default=False)
paired_end = models.BooleanField(default=False)
read_length = models.IntegerField(default=32) #Stanford is currenlty 25
- control_lane = models.IntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(0,'All Lanes')], null=True)
+ control_lane = models.IntegerField(choices=[(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(0,'All Lanes')], null=True, blank=True)
cluster_station = models.ForeignKey(ClusterStation, default=3)
sequencer = models.ForeignKey(Sequencer, default=1)
def __unicode__(self):
return unicode(self.flowcell_id)
- def Create_LOG(self):
- str = ''
- str +='<a target=_balnk href="/experiments/'+self.flowcell_id+'" title="Create XLS like sheet for this Flowcell ..." ">Create LOG</a>'
- try:
- t = DataRun.objects.get(fcid=self.id)
- str +='<br/><a target=_self href="/admin/experiments/datarun/?q='+self.flowcell_id+'" title="Check Data Runs ..." ">DataRun ..</a>'
- except ObjectDoesNotExist:
- str += '<br/><span style="color:red">not sequenced</span>'
- return str
- Create_LOG.allow_tags = True
-
def Lanes(self):
- library_url = '/admin/samples/library/%s'
html = ['<table>']
- #for i in range(1,9):
for lane in self.lane_set.all():
cluster_estimate = lane.cluster_estimate
if cluster_estimate is not None:
library_id = lane.library_id
library = lane.library
element = '<tr><td>%d</td><td><a href="%s">%s</a></td><td>%s</td></tr>'
- expanded_library_url = library_url %(library_id,)
- html.append(element % (lane.lane_number, expanded_library_url, library, cluster_estimate))
+ html.append(element % (lane.lane_number,
+ library.get_admin_url(),
+ library,
+ cluster_estimate))
html.append('</table>')
return "\n".join(html)
Lanes.allow_tags = True
def get_admin_url(self):
# that's the django way... except it didn't work
- #return urlresolvers.reverse('admin_experiments_FlowCell_change', args=(self.id,))
- return '/admin/experiments/flowcell/%s/' % (self.id,)
+ return urlresolvers.reverse('admin:experiments_flowcell_change',
+ args=(self.id,))
def flowcell_type(self):
"""
return ('htsworkflow.frontend.experiments.views.flowcell_detail',
[str(self.flowcell_id)])
-### -----------------------
-class DataRun(models.Model):
- ConfTemplate = "CONFIG PARAMS WILL BE GENERATED BY THE PIPELINE SCRIPT.\nYOU'LL BE ABLE TO EDIT AFTER IF NEEDED."
- run_folder = models.CharField(max_length=50,unique=True, db_index=True)
- fcid = models.ForeignKey(FlowCell,verbose_name="Flowcell Id")
- config_params = models.TextField(default=ConfTemplate)
- run_start_time = models.DateTimeField()
- RUN_STATUS_CHOICES = (
- (0, 'Sequencer running'), ##Solexa Data Pipeline Not Yet Started'),
- (1, 'Data Pipeline Started'),
- (2, 'Data Pipeline Interrupted'),
- (3, 'Data Pipeline Finished'),
- (4, 'CollectReads Started'),
- (5, 'CollectReads Finished'),
- (6, 'QC Finished'),
- (7, 'DONE'),
- )
- run_status = models.IntegerField(choices=RUN_STATUS_CHOICES, default=0)
- run_note = models.TextField(blank=True)
-
-
- def main_status(self):
- str = '<div'
- if self.run_status >= 5:
- str += ' style="color:green">'
- str += '<b>'+self.RUN_STATUS_CHOICES[self.run_status][1]+'</b>'
- str += '<br/><br/>' #<span style="color:red;font-size:80%;">New!</span>'
- str +='<br/><a target=_balnk href="'+settings.TASKS_PROJS_SERVER+'/Flowcells/'+self.fcid.flowcell_id+'/'+self.fcid.flowcell_id+'_QC_Summary.html" title="View QC Summaries of this run ..." ">View QC Page</a>'
- else:
- str += '>'+self.RUN_STATUS_CHOICES[self.run_status][1]
+ def get_raw_data_directory(self):
+ """Return location of where the raw data is stored"""
+ flowcell_id, status = parse_flowcell_id(self.flowcell_id)
- str += '</div>'
- return str
- main_status.allow_tags = True
+ return os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
- main_status.allow_tags = True
+ def update_data_runs(self):
+ result_root = self.get_raw_data_directory()
+ if result_root is None:
+ return
- def Flowcell_Info(self):
- str = '<b>'+self.fcid.__str__()+'</b>'
- str += ' (c: '+self.fcid.cluster_mac_id+', s: '+self.fcid.seq_mac_id+')'
- str += '<div style="margin-top:5px;">'
- str +='<a title="View Lane List here ..." onClick="el = document.getElementById(\'LanesOf'+self.fcid.__str__()+'\');if(el) (el.style.display==\'none\'?el.style.display=\'block\':el.style.display=\'none\')" style="cursor:pointer;color: #5b80b2;">View/hide lanes</a>'
- str += '<div id="LanesOf'+self.fcid.__str__()+'" style="display:block;border:solid #cccccc 1px;width:350px">'
- LanesList = '1: '+self.fcid.lane_1_library.__str__()+' ('+self.fcid.lane_1_library.library_species.use_genome_build+')<br/>2: '+self.fcid.lane_2_library.__str__()+' ('+self.fcid.lane_2_library.library_species.use_genome_build+')<br/>3: '+self.fcid.lane_3_library.__str__()+' ('+self.fcid.lane_3_library.library_species.use_genome_build+')<br/>4: '+self.fcid.lane_4_library.__str__()+' ('+self.fcid.lane_4_library.library_species.use_genome_build+')<br/>5: '+self.fcid.lane_5_library.__str__()+' ('+self.fcid.lane_5_library.library_species.use_genome_build+')<br/>6: '+self.fcid.lane_6_library.__str__()+' ('+self.fcid.lane_6_library.library_species.use_genome_build+')<br/>7: '+self.fcid.lane_7_library.__str__()+' ('+self.fcid.lane_7_library.library_species.use_genome_build+')<br/>8: '+self.fcid.lane_8_library.__str__()+' ('+self.fcid.lane_8_library.library_species.use_genome_build+')'
- str += LanesList ## self.fcid.Lanes()
- str += '</div>'
- str += '<div><a title="open Flowcell record" href="/admin/exp_track/flowcell/'+self.fcid.id.__str__()+'/" target=_self>Edit Flowcell record</a>'
- #str += '<span style="color:red;font-size:80%;margin-left:15px;margin-right:3px">New!</span>'
- str +='<a style="margin-left:15px;" target=_balnk href="/exp_track/'+self.fcid.flowcell_id+'" title="View XLS like sheet for this Flowcell LOG ..." ">GA LOG Page</a>'
- str += '</div>'
- str += '</div>'
- return str
- Flowcell_Info.allow_tags = True
+ result_home_dir = os.path.join(settings.RESULT_HOME_DIR,'')
+ run_xml_re = re.compile(glob.fnmatch.translate('run*.xml'))
+
+ dataruns = self.datarun_set.all()
+ datarun_result_dirs = [ x.result_dir for x in dataruns ]
+
+ result_dirs = []
+ for dirpath, dirnames, filenames in os.walk(result_root):
+ for filename in filenames:
+ if run_xml_re.match(filename):
+ # we have a run directory
+ relative_pathname = get_relative_pathname(dirpath)
+ if relative_pathname not in datarun_result_dirs:
+ self.import_data_run(relative_pathname, filename)
+
+ def import_data_run(self, relative_pathname, run_xml_name):
+ """Given a result directory import files"""
+ run_dir = get_absolute_pathname(relative_pathname)
+ run_xml_path = os.path.join(run_dir, run_xml_name)
+ run_xml_data = runfolder.load_pipeline_run_xml(run_xml_path)
+
+ run = DataRun()
+ run.flowcell = self
+ run.status = RUN_STATUS_REVERSE_MAP['DONE']
+ run.result_dir = relative_pathname
+ run.runfolder_name = run_xml_data.runfolder_name
+ run.cycle_start = run_xml_data.image_analysis.start
+ run.cycle_stop = run_xml_data.image_analysis.stop
+ run.run_start_time = run_xml_data.image_analysis.date
+ run.last_update_time = datetime.datetime.now()
+ run.save()
+
+ run.update_result_files()
+
+# FIXME: should we automatically update dataruns?
+# Or should we expect someone to call update_data_runs?
+#def update_flowcell_dataruns(sender, instance, *args, **kwargs):
+# """Update our dataruns
+# """
+# if not os.path.exists(settings.RESULT_HOME_DIR):
+# return
+#
+# instance.update_data_runs()
+#post_init.connect(update_flowcell_dataruns, sender=FlowCell)
+
+
LANE_STATUS_CODES = [(0, 'Failed'),
(1, 'Marginal'),
def get_absolute_url(self):
return ('htsworkflow.frontend.experiments.views.flowcell_lane_detail',
[str(self.flowcell.flowcell_id), str(self.lane_number)])
+
+
+### -----------------------
+class DataRun(models.Model):
+ flowcell = models.ForeignKey(FlowCell,verbose_name="Flowcell Id")
+ runfolder_name = models.CharField(max_length=50)
+ result_dir = models.CharField(max_length=255)
+ last_update_time = models.DateTimeField()
+ run_start_time = models.DateTimeField()
+ cycle_start = models.IntegerField(null=True, blank=True)
+ cycle_stop = models.IntegerField(null=True, blank=True)
+ run_status = models.IntegerField(choices=RUN_STATUS_CHOICES,
+ null=True, blank=True)
+ comment = models.TextField(blank=True)
+
+ def update_result_files(self):
+ abs_result_dir = get_absolute_pathname(self.result_dir)
+
+ for dirname, dirnames, filenames in os.walk(abs_result_dir):
+ for filename in filenames:
+ pathname = os.path.join(dirname, filename)
+ relative_pathname = get_relative_pathname(pathname)
+ datafiles = self.datafile_set.filter(
+ data_run = self,
+ relative_pathname=relative_pathname)
+ if len(datafiles) > 0:
+ continue
+
+ metadata = find_file_type_metadata_from_filename(filename)
+ if metadata is not None:
+ metadata['filename'] = filename
+ newfile = DataFile()
+ newfile.data_run = self
+ newfile.file_type = metadata['file_type']
+ newfile.relative_pathname = relative_pathname
+
+ lane_number = metadata.get('lane', None)
+ if lane_number is not None:
+ lane = self.flowcell.lane_set.get(lane_number = lane_number)
+ newfile.library = lane.library
+
+ self.datafile_set.add(newfile)
+
+ self.last_update_time = datetime.datetime.now()
+
+ def lane_files(self):
+ lanes = {}
+
+ for datafile in self.datafile_set.all():
+ metadata = datafile.attributes
+ if metadata is not None:
+ lane = metadata.get('lane', None)
+ if lane is not None:
+ lane_file_set = lanes.setdefault(lane, {})
+ lane_file_set[datafile.file_type.normalized_name] = datafile
+ return lanes
+
+ def ivc_plots(self, lane):
+ ivc_name = ['IVC All', 'IVC Call',
+ 'IVC Percent Base', 'IVC Percent All', 'IVC Percent Call']
+
+ plots = {}
+ for rel_filename, metadata in self.get_result_files():
+ if metadata.file_type.name in ivc_name:
+ plots[metadata.file_type.name] = (rel_filename, metadata)
+
+class FileType(models.Model):
+ """Represent potential file types
+
+ regex is a pattern used to detect if a filename matches this type
+ data run currently assumes that there may be a (?P<lane>) and
+ (?P<end>) pattern in the regular expression.
+ """
+ name = models.CharField(max_length=50)
+ mimetype = models.CharField(max_length=50, null=True, blank=True)
+ # regular expression from glob.fnmatch.translate
+ regex = models.CharField(max_length=50, null=True, blank=True)
+
+ def parse_filename(self, pathname):
+ """Does filename match our pattern?
+
+ Returns None if not, or dictionary of match variables if we do.
+ """
+ path, filename = os.path.split(pathname)
+ if len(self.regex) > 0:
+ match = re.match(self.regex, filename)
+ if match is not None:
+ # These are (?P<>) names we know about from our default regexes.
+ results = match.groupdict()
+
+ # convert int parameters
+ for attribute_name in ['lane', 'end']:
+ value = results.get(attribute_name, None)
+ if value is not None:
+ results[attribute_name] = int(value)
+
+ return results
+
+ def _get_normalized_name(self):
+ """Crush data file name into identifier friendly name"""
+ return self.name.replace(' ', '_').lower()
+ normalized_name = property(_get_normalized_name)
+
+ def __unicode__(self):
+ #return u"<FileType: %s>" % (self.name,)
+ return self.name
+
+
+class DataFile(models.Model):
+ """Store map from random ID to filename"""
+ random_key = models.CharField(max_length=16,
+ db_index=True,
+ default=uuid.uuid1)
+ data_run = models.ForeignKey(DataRun, db_index=True)
+ library = models.ForeignKey(Library, db_index=True, null=True, blank=True)
+ file_type = models.ForeignKey(FileType)
+ relative_pathname = models.CharField(max_length=255, db_index=True)
+
+ def _get_attributes(self):
+ return self.file_type.parse_filename(self.relative_pathname)
+ attributes = property(_get_attributes)
+
+ def _get_pathname(self):
+ return get_absolute_pathname(self.relative_pathname)
+ pathname = property(_get_pathname)
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('htsworkflow.frontend.experiments.views.read_result_file',
+ (), {'key': self.random_key })
+
+def find_file_type_metadata_from_filename(pathname):
+ path, filename = os.path.split(pathname)
+ result = None
+ for file_type in FileType.objects.all():
+ result = file_type.parse_filename(filename)
+ if result is not None:
+ result['file_type'] = file_type
+ return result
+
+ return None
+
+def get_relative_pathname(abspath):
+ """Strip off the result home directory from a path
+ """
+ result_home_dir = os.path.join(settings.RESULT_HOME_DIR,'')
+ relative_pathname = abspath.replace(result_home_dir,'')
+ return relative_pathname
+
+def get_absolute_pathname(relative_pathname):
+ """Attach relative path to results home directory"""
+ return os.path.join(settings.RESULT_HOME_DIR, relative_pathname)
+
except ImportError, e:
import simplejson as json
import os
+import shutil
import sys
+import tempfile
+from django.conf import settings
from django.core import mail
from django.core.exceptions import ObjectDoesNotExist
from django.test import TestCase
from htsworkflow.frontend.experiments import experiments
from htsworkflow.frontend.auth import apidata
+from htsworkflow.pipelines.test.simulate_runfolder import TESTDATA_DIR
+
LANE_SET = range(1,9)
class ExperimentsTestCases(TestCase):
fixtures = ['test_flowcells.json']
def setUp(self):
- pass
+ self.tempdir = tempfile.mkdtemp(prefix='htsw-test-experiments-')
+ settings.RESULT_HOME_DIR = self.tempdir
+
+ self.fc1_id = 'FC12150'
+ self.fc1_root = os.path.join(self.tempdir, self.fc1_id)
+ os.mkdir(self.fc1_root)
+ self.fc1_dir = os.path.join(self.fc1_root, 'C1-37')
+ os.mkdir(self.fc1_dir)
+ runxml = 'run_FC12150_2007-09-27.xml'
+ shutil.copy(os.path.join(TESTDATA_DIR, runxml),
+ os.path.join(self.fc1_dir, runxml))
+ for i in range(1,9):
+ shutil.copy(
+ os.path.join(TESTDATA_DIR,
+ 'woldlab_070829_USI-EAS44_0017_FC11055_1.srf'),
+ os.path.join(self.fc1_dir,
+ 'woldlab_070829_SERIAL_FC12150_%d.srf' %(i,))
+ )
+
+ self.fc2_dir = os.path.join(self.tempdir, '42JTNAAXX')
+ os.mkdir(self.fc2_dir)
+ os.mkdir(os.path.join(self.fc2_dir, 'C1-25'))
+ os.mkdir(os.path.join(self.fc2_dir, 'C1-37'))
+ os.mkdir(os.path.join(self.fc2_dir, 'C1-37', 'Plots'))
+
+ def tearDown(self):
+ shutil.rmtree(self.tempdir)
def test_flowcell_information(self):
"""
Check the code that packs the django objects into simple types.
"""
- for fc_id in [u'303TUAAXX', u"42JTNAAXX", "42JU1AAXX"]:
+ for fc_id in [u'FC12150', u"42JTNAAXX", "42JU1AAXX"]:
fc_dict = experiments.flowcell_information(fc_id)
fc_django = models.FlowCell.objects.get(flowcell_id=fc_id)
self.failUnlessEqual(fc_dict['flowcell_id'], fc_id)
"""
Require logging in to retrieve meta data
"""
- response = self.client.get(u'/experiments/config/303TUAAXX/json')
+ response = self.client.get(u'/experiments/config/FC12150/json')
self.failUnlessEqual(response.status_code, 403)
def test_library_id(self):
"""
Library IDs should be flexible, so make sure we can retrive a non-numeric ID
"""
- response = self.client.get('/experiments/config/303TUAAXX/json', apidata)
+ response = self.client.get('/experiments/config/FC12150/json', apidata)
self.failUnlessEqual(response.status_code, 200)
flowcell = json.loads(response.content)
self.failUnlessEqual(response.status_code, 404)
+ def test_raw_data_dir(self):
+ """Raw data path generator check"""
+ flowcell_id = self.fc1_id
+ raw_dir = os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
+
+ fc = models.FlowCell.objects.get(flowcell_id=flowcell_id)
+ self.failUnlessEqual(fc.get_raw_data_directory(), raw_dir)
+
+ fc.flowcell_id = flowcell_id + " (failed)"
+ self.failUnlessEqual(fc.get_raw_data_directory(), raw_dir)
+
+
+ def test_data_run_import(self):
+ srf_file_type = models.FileType.objects.get(name='SRF')
+ runxml_file_type = models.FileType.objects.get(name='run_xml')
+ flowcell_id = self.fc1_id
+ flowcell = models.FlowCell.objects.get(flowcell_id=flowcell_id)
+ flowcell.update_data_runs()
+ self.failUnlessEqual(len(flowcell.datarun_set.all()), 1)
+
+ run = flowcell.datarun_set.all()[0]
+ result_files = run.datafile_set.all()
+ result_dict = dict(((rf.relative_pathname, rf) for rf in result_files))
+
+ srf4 = result_dict['FC12150/C1-37/woldlab_070829_SERIAL_FC12150_4.srf']
+ self.failUnlessEqual(srf4.file_type, srf_file_type)
+ self.failUnlessEqual(srf4.library_id, '11060')
+ self.failUnlessEqual(srf4.data_run.flowcell.flowcell_id, 'FC12150')
+ self.failUnlessEqual(
+ srf4.data_run.flowcell.lane_set.get(lane_number=4).library_id,
+ '11060')
+ self.failUnlessEqual(
+ srf4.pathname,
+ os.path.join(settings.RESULT_HOME_DIR, srf4.relative_pathname))
+
+ lane_files = run.lane_files()
+ self.failUnlessEqual(lane_files[4]['srf'], srf4)
+
+ runxml= result_dict['FC12150/C1-37/run_FC12150_2007-09-27.xml']
+ self.failUnlessEqual(runxml.file_type, runxml_file_type)
+ self.failUnlessEqual(runxml.library_id, None)
+
+
+ def test_read_result_file(self):
+ """make sure we can return a result file
+ """
+ flowcell_id = self.fc1_id
+ flowcell = models.FlowCell.objects.get(flowcell_id=flowcell_id)
+ flowcell.update_data_runs()
+
+ #self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
+
+ result_files = flowcell.datarun_set.all()[0].datafile_set.all()
+ for f in result_files:
+ url = '/experiments/file/%s' % ( f.random_key,)
+ response = self.client.get(url)
+ self.failUnlessEqual(response.status_code, 200)
+ mimetype = f.file_type.mimetype
+ if mimetype is None:
+ mimetype = 'application/octet-stream'
+
+ self.failUnlessEqual(mimetype, response['content-type'])
+
+class TestFileType(TestCase):
+ def test_file_type_unicode(self):
+ file_type_objects = models.FileType.objects
+ name = 'QSEQ tarfile'
+ file_type_object = file_type_objects.get(name=name)
+ self.failUnlessEqual(u"<FileType: QSEQ tarfile>",
+ unicode(file_type_object))
+
+class TestFileType(TestCase):
+ def test_find_file_type(self):
+ file_type_objects = models.FileType.objects
+ cases = [('woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
+ 'QSEQ tarfile', 7, 1),
+ ('woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
+ 'SRF', 1, None),
+ ('s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
+ ('s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
+ ('s_3_eland_result.txt.bz2','ELAND Result', 3, None),
+ ('s_1_export.txt.bz2','ELAND Export', 1, None),
+ ('s_1_percent_call.png', 'IVC Percent Call', 1, None),
+ ('s_2_percent_base.png', 'IVC Percent Base', 2, None),
+ ('s_3_percent_all.png', 'IVC Percent All', 3, None),
+ ('s_4_call.png', 'IVC Call', 4, None),
+ ('s_5_all.png', 'IVC All', 5, None),
+ ('Summary.htm', 'Summary.htm', None, None),
+ ('run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
+ ]
+ for filename, typename, lane, end in cases:
+ ft = models.find_file_type_metadata_from_filename(filename)
+ self.failUnlessEqual(ft['file_type'],
+ file_type_objects.get(name=typename))
+ self.failUnlessEqual(ft.get('lane', None), lane)
+ self.failUnlessEqual(ft.get('end', None), end)
+
+ def test_assign_file_type_complex_path(self):
+ file_type_objects = models.FileType.objects
+ cases = [('/a/b/c/woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
+ 'QSEQ tarfile', 7, 1),
+ ('foo/woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
+ 'SRF', 1, None),
+ ('../s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
+ ('/bleem/s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
+ ('/qwer/s_3_eland_result.txt.bz2','ELAND Result', 3, None),
+ ('/ty///1/s_1_export.txt.bz2','ELAND Export', 1, None),
+ ('/help/s_1_percent_call.png', 'IVC Percent Call', 1, None),
+ ('/bored/s_2_percent_base.png', 'IVC Percent Base', 2, None),
+ ('/example1/s_3_percent_all.png', 'IVC Percent All', 3, None),
+ ('amonkey/s_4_call.png', 'IVC Call', 4, None),
+ ('fishie/s_5_all.png', 'IVC All', 5, None),
+ ('/random/Summary.htm', 'Summary.htm', None, None),
+ ('/notrandom/run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
+ ]
+ for filename, typename, lane, end in cases:
+ result = models.find_file_type_metadata_from_filename(filename)
+ self.failUnlessEqual(result['file_type'],
+ file_type_objects.get(name=typename))
+ self.failUnlessEqual(result.get('lane',None), lane)
+ self.failUnlessEqual(result.get('end', None), end)
+
class TestEmailNotify(TestCase):
fixtures = ['test_flowcells.json']
self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
response = self.client.get('/experiments/started/153/')
self.failUnlessEqual(response.status_code, 200)
- self.failUnless(re.search('Flowcell 303TUAAXX', response.content))
+ self.failUnless(re.search('Flowcell FC12150', response.content))
# require that navigation back to the admin page exists
self.failUnless(re.search('<a href="/admin/experiments/flowcell/153/">[^<]+</a>', response.content))
#(r'^(?P<run_folder>.+)/$', 'gaworkflow.frontend.experiments.views.detail'),
(r'^config/(?P<fc_id>.+)/json$', 'htsworkflow.frontend.experiments.experiments.flowcell_json'),
(r'^lanes_for/(?P<username>.+)/json$', 'htsworkflow.frontend.experiments.experiments.lanes_for_json'),
- (r'^fcsheet/(?P<fcid>.+)/$', 'htsworkflow.frontend.experiments.views.makeFCSheet'),
- (r'^updStatus$', 'htsworkflow.frontend.experiments.experiments.updStatus'),
- (r'^getConfile$', 'htsworkflow.frontend.experiments.experiments.getConfile'),
- (r'^getLanesNames$', 'htsworkflow.frontend.experiments.experiments.getLaneLibs'),
- # for the following two URLS I have to pass in the primary key
- # because I link to the page from an overridden version of the admin change_form
- # which only makes the object primary key available in the form.
- # (Or at least as far as I could tell)
+ (r'^file/(?P<key>.+)/?$', 'htsworkflow.frontend.experiments.views.read_result_file'),
(r'^started/(?P<pk>.+)/$', 'htsworkflow.frontend.experiments.views.startedEmail'),
(r'^finished/(?P<pk>.+)/$', 'htsworkflow.frontend.experiments.views.finishedEmail'),
+
)
# Create your views here.
from datetime import datetime
+import os
#from django.template import Context, loader
#shortcut to the above modules
from django.contrib.auth.decorators import user_passes_test
+from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import EmailMessage, mail_managers
from django.http import HttpResponse
from django.template import RequestContext
from django.template.loader import get_template
-from htsworkflow.frontend.experiments.models import *
+from htsworkflow.frontend.experiments.models import DataRun, DataFile, FlowCell
from htsworkflow.frontend.experiments.experiments import \
estimateFlowcellDuration, \
estimateFlowcellTimeRemaining, \
def flowcell_detail(request, flowcell_id):
fc = get_object_or_404(FlowCell, flowcell_id=flowcell_id)
+ fc.update_data_runs()
context = RequestContext(request,
{'flowcell': fc})
def flowcell_lane_detail(request, flowcell_id, lane_number):
fc = get_object_or_404(FlowCell, flowcell_id=flowcell_id)
lane = get_object_or_404(fc.lane_set, lane_number=lane_number)
+
+ fc.update_data_runs()
context = RequestContext(request,
{'lib': lane.library,
return render_to_response('experiments/flowcell_lane_detail.html',
context)
+
+def read_result_file(self, key):
+ """Return the contents of filename if everything is approved
+ """
+ data_file = get_object_or_404(DataFile, random_key = key)
+
+ mimetype = 'application/octet-stream'
+ if data_file.file_type.mimetype is not None:
+ mimetype = data_file.file_type.mimetype
+
+ if os.path.exists(data_file.pathname):
+ return HttpResponse(open(data_file.pathname,'r'),
+ mimetype=mimetype)
+
+ raise Http404
+
+
import urlparse
from django.db import models
from django.contrib.auth.models import User, UserManager
+from django.core import urlresolvers
from django.db.models.signals import pre_save, post_save
from django.db import connection
from htsworkflow.frontend.reports.libinfopar import *
-
-# Create your models here.
logger = logging.getLogger(__name__)
class Antibody(models.Model):
def get_absolute_url(self):
return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
+ def get_admin_url(self):
+ return urlresolvers.reverse('admin:samples_library_change',
+ args=(self.id,))
class HTSUser(User):
"""
eland_results = []
for fc, lane_number in flowcell_list:
lane_summary, err_list = _summary_stats(fc, lane_number)
-
- eland_results.extend(_make_eland_results(fc, lane_number, flowcell_run_results))
lane_summary_list.extend(lane_summary)
+
+ eland_results.extend(_make_eland_results(fc, lane_number, flowcell_run_results))
context = {
'page_name': 'Library Details',
flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
#pm_field = 'lane_%d_pM' % (lane_id)
lane_obj = flowcell.lane_set.get(lane_number=lane_id)
- eland_summary.successful_pm = lane_obj.pM
+ eland_summary.flowcell = flowcell
+ eland_summary.lane = lane_obj
summary_list.append(eland_summary)
return (summary_list, err_list)
-def _summary_stats_old(flowcell_id, lane):
- """
- return a dictionary of summary stats for a given flowcell_id & lane.
- """
- fc_id, status = parse_flowcell_id(flowcell_id)
- fc_result_dict = get_flowcell_result_dict(fc_id)
-
- dict_list = []
- err_list = []
- summary_list = []
-
- if fc_result_dict is None:
- err_list.append('Results for Flowcell %s not found.' % (fc_id))
- return (dict_list, err_list, summary_list)
-
- for cnm in fc_result_dict:
-
- xmlpath = fc_result_dict[cnm]['run_xml']
-
- if xmlpath is None:
- err_list.append('Run xml for Flowcell %s(%s) not found.' % (fc_id, cnm))
- continue
-
- tree = ElementTree.parse(xmlpath).getroot()
- results = runfolder.PipelineRun(pathname='', xml=tree)
- try:
- lane_report = runfolder.summarize_lane(results.gerald, lane)
- summary_list.append(os.linesep.join(lane_report))
- except Exception, e:
- summary_list.append("Summary report needs to be updated.")
- logging.error("Exception: " + str(e))
-
- print >>sys.stderr, "----------------------------------"
- print >>sys.stderr, "-- DOES NOT SUPPORT PAIRED END ---"
- print >>sys.stderr, "----------------------------------"
- lane_results = results.gerald.summary[0][lane]
- lrs = lane_results
-
- d = {}
-
- d['average_alignment_score'] = lrs.average_alignment_score
- d['average_first_cycle_intensity'] = lrs.average_first_cycle_intensity
- d['cluster'] = lrs.cluster
- d['lane'] = lrs.lane
- d['flowcell'] = flowcell_id
- d['cnm'] = cnm
- d['percent_error_rate'] = lrs.percent_error_rate
- d['percent_intensity_after_20_cycles'] = lrs.percent_intensity_after_20_cycles
- d['percent_pass_filter_align'] = lrs.percent_pass_filter_align
- d['percent_pass_filter_clusters'] = lrs.percent_pass_filter_clusters
-
- #FIXME: function finished, but need to take advantage of
- # may need to take in a list of lanes so we only have to
- # load the xml file once per flowcell rather than once
- # per lane.
- dict_list.append(d)
-
- return (dict_list, err_list, summary_list)
-
def get_eland_result_type(pathname):
"""
margin: 0;
}
- div.htswdetail h4,
- div.htswdetail h5,
- div.htswdetail ul,
- div.htswdetail ol,
- div.htswdetail li
- {
- list-style: none;
- margin: 0;
- }
+div.htswdetail h4,
+div.htswdetail h5,
+div.htswdetail ul,
+div.htswdetail ol,
+div.htswdetail li
+{
+ list-style: none;
+ margin: 0;
+}
+
+div.htswdetail ul,
+div.htswdetail ol
+{
+ margin-bottom: .5em;
+}
- div.htswdetail ul,
- div.htswdetail ol
- {
- margin-bottom: .5em;
+/* style library detail headers */
+div#librarydetail {
+ margin: 0;
+ padding: 0;
+}
+div#librarydetail table, div#librarydetail td {
+ border-style: solid;
+}
+div#librarydetail table {
+ border-width: 0 0 1px 1px;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+div#librarydetail td {
+ margin: 0;
+ padding: 3px;
+ border-width: 1px 1px 0 0;
+}
+div#librarydetail thead {
+ text-align: center;
}
- /* ]]> */
-</style>
+div#librarydetail tbody {
+ text-align: right;
+}
+div#librarydetail h1,
+div#librarydetail h2
+{
+ font-size: 150%;
+}
+
+div#librarydetail h3 {
+ font-size: 125%;
+ margin: 0;
+}
+
+div#librarydetail h4,
+div#librarydetail h5,
+div#librarydetail ul,
+div#librarydetail ol,
+div#librarydetail li
+{
+ list-style: none;
+ margin: 0;
+}
+
+div#librarydetail ul,
+div#librarydetail ol
+{
+ margin-bottom: .5em;
+}
+
+div.library_identity {
+ float: left; margin: 5px; }
+div.library_sample_detail { float: left; margin: 5px; }
+div.library_library_detail { float: left; margin: 5px; }
+div.library_statistics { clear: both; border: 1px; }
+
<span property="libns:control_lane">{{flowcell.control_lane}}</span><br/>
<b>Notes</b>:
- <p property="libns:flowcell_notes">{{flowcell.notes}}</p>
+ <pre property="libns:flowcell_notes">{{flowcell.notes}}</pre>
<div class="htswdetail">
<h2>Lanes</h2>
<table>
</tbody>
</table>
</div>
+ <div class="htsw_flowcell_ivc">
+ {% for run in flowcell.datarun_set.all %}
+ <h2>Run {{ run.runfolder_name }}</h2>
+ <table>
+ <thead>
+ <tr>
+ <td>Lane</td>
+ <td>IVC All</td>
+ <td>IVC Call</td>
+ <td>IVC Percent Base</td>
+ <td>IVC Percent Base All</td>
+ <td>IVC Percent Base Called</td>
+ </thead>
+ <tbody>
+ {% for lane_id, lane_file_set in run.lane_files.items %}
+ <tr>
+ <td>{{ lane_id }}</td>
+ <td>
+ <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
+ </a>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endfor %}
+ </div>
</div>
{% endblock %}
{% endblock %}
{% block content %}
-<div id="lane_detail">
+<div id="lane_detail" class="htswdetail">
<h2>About this lane</h2>
<div rel="libns:flowcell" resource="{{flowcell.get_absolute_url}}">
<b>Flowcell</b>:
</div>
<b>Lane</b>:
<span property="libns:lane_number" datatype="xsd:decimal">{{lane.lane_number}}</span><br/>
+ <b>Cycles</b>:
+ <span property="libns:read_length">{{lane.flowcell.read_length}}</span><br/>
<b>pM</b>
<span property="libns:pM" datatype="xsd:decimal">{{ lane.pM }}</span><br/>
<b>Cluster Estimate</b>
<span property="libns:status">{{ lane.status }}</span><br/>
<b>Comment</b>:
<span property="libns:comment">{{ lane.comment }}</span><br/>
-
-
- <div rel="libns:library" resource="{{lib.get_absolute_url}}">
- <h2>About the library</h2>
- <b>Library ID</b>:
- <a href="{{lib.get_absolute_url}}" property="libns:library_id">{{ lib.id }}</a><br/>
- <b>Name</b>:
- <span property="libns:name">{{ lib.library_name }}</span>
- <br/>
- <b>Species</b>:
- <a href="{{lib.library_species.get_absolute_url}}" rel="libns:species"><span property="libns:species_name">{{ lib.library_species.scientific_name }}</span></a>
- <br/>
- <b>Concentration</b>:
- <span property="libns:concentration">{{ lib.undiluted_concentration }} ng/µl</span>
- <br/>
- <b>Gel Cut Size</b>:
- <span property="libns:gel_cut">{{ lib.gel_cut_size }}</span>
- <br/>
- <b>Insert Size</b>:
- <span property="libns:insert_size">{{ lib.insert_size }}</span>
- <br/>
- <b>Background or Cell Line</b>:
- <span property="libns:cell_line">{{ lib.cell_line }}</span>
- <br/>
- <b>Replicate</b>:
- <span property="libns:replicate">{{ lib.replicate }}</span>
- <br/>
- <b>Library Type</b>:
- <span property="libns:library_type">{{ lib.library_type }}</span>
- <br/>
- <b>Experiment Type</b>:
- <span property="libns:experiment_type">{{ lib.experiment_type }}</span>
- <br/>
- <b>Made By</b>:
- <span property="libns:made_by">{{ lib.made_by }}</span>
- <br/>
- <b>Creation Date</b>
- <span property="libns:date" content="{{lib.creation_date|date:'Y-m-d'}}T00:00:00" datatype="xsd:dateTime">{{ lib.creation_date }}</span>
- <br/>
- <b>Protocol Stopping Point</b>
- <span property="libns:stopping_point">{{ lib.stopping_point_name }}</span>
- <br/>
- <b>Affiliations</b>:
- <ul>
- {% for individual in lib.affiliations.all %}
- <li property="libns:affliation" content="{{individual.name}}">
- {{ individual.name }} ( {{ individual.contact }} )
- </li>
- {% endfor %}
- </ul>
+ <hr/>
+ {% include "sample_header.html" %}
+ <hr/>
+ <div class="htsw_flowcell_ivc">
+ {% for run in flowcell.datarun_set.all %}
+ <h2>Run {{ run.runfolder_name }}</h2>
+ <table>
+ <thead>
+ <tr>
+ <td>Lane</td>
+ <td>IVC All</td>
+ <td>IVC Call</td>
+ <td>IVC Percent Base</td>
+ <td>IVC Percent Base All</td>
+ <td>IVC Percent Base Called</td>
+ </thead>
+ <tbody>
+ {% for lane_id, lane_file_set in run.lane_files.items %}
+ {% if lane_id == lane.lane_number %}
+ <tr>
+ <td>{{lane_id}}</td>
+ <td>
+ <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
+ </a>
+ </td>
+ <td>
+ <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
+ <img height="84" width="126" src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
+ </a>
+ </td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endfor %}
</div>
-</div>
{% endblock %}
--- /dev/null
+<div id="librarydetail">
+ <div class="library_identity">
+ <h2>Library Name</h2>
+ <b>Library ID</b>: <a href="{{lib.get_absolute_url}}">{{ lib.id }}</a><br/>
+ <b>Name</b>:
+ <span property="libns:name">{{ lib.library_name }}</span>
+ <br/>
+ <b>Affiliations</b>:
+ <ul>
+ {% for individual in lib.affiliations.all %}
+ <li property="libns:affiliation" content="{{individual.name}}">
+ {{ individual.name }} ( {{ individual.contact }} )
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="library_sample_detail">
+ <h2>Sample Details</h2>
+ <b>Species</b>:
+ <a href="{{lib.library_species.get_absolute_url}}" property="libns:species">{{ lib.library_species.scientific_name }}</a>
+ <br/>
+ <b>Experiment Type</b>:
+ <span property="libns:experiment_type">{{ lib.experiment_type }}</span>
+ <br/>
+ {% if lib.antibody %}
+ <b>Antibody</b>:
+ <span property="libns:antibody">{{ lib.antibody.antibodies }}</span>
+ {% if lib.antibody.antibodies.nuckname %}
+ (<span property="libns:antibody_term">{{ lib.antibody.nickname }}</span>)
+ {% endif %}
+ <br/>
+ {% endif %}
+ {% if lib.cell_line %}
+ <b>Background or Cell Line</b>:
+ <span property="libns:cell_line">{{ lib.cell_line }}</span>
+ <br/>
+ {% endif %}
+ {% if lib.condition %}
+ <b>Condition</b>:
+ <span property="libns:condition">{{ lib.condition.condition_name }}</span>
+ {% if lib.condition.nickname %}
+ (<span property="libns:condition_term">{{ lib.condition.nickname }}</span>)
+ {% endif %}
+ <br/>
+ {% endif %}
+ {% if lib.replicate %}
+ <b>Replicate</b>:
+ <span property="libns:replicate">{{ lib.replicate }}</span>
+ <br/>
+ {% endif %}
+ </div>
+ <div class="library_library_detail">
+ <h2>Library Details</h2>
+ <b>Library Type</b>:
+ <span property="libns:library_type">{{ lib.library_type }}</span>
+ <br/>
+ <b>Creation Date</b>
+ <span property="libns:date" content="{{lib.creation_date|date:'Y-m-d'}}T00:00:00" datatype="xsd:dateTime">{{ lib.creation_date }}</span>
+ <br/>
+ <b>Made By</b>:
+ <span property="libns:made_by">{{ lib.made_by }}</span>
+ <br/>
+ {% if lib.gel_cut_size %}
+ <b>Gel Cut Size</b>:
+ <span property="libns:gel_cut">{{ lib.gel_cut_size }}</span>
+ <br/>
+ {% endif %}
+ {% if lib.insert_size %}
+ <b>Insert Size</b>:
+ <span property="libns:insert_size">{{ lib.insert_size }}</span>
+ <br/>
+ {% endif %}
+ {% if lib.undiluted_concentration %}
+ <b>Concentration</b>:
+ <span property="libns:concentration">{{ lib.undiluted_concentration }} ng/µl</span>
+ <br/>
+ {% endif %}
+ {% if lib.stopping_point_name %}
+ <b>Protocol Stopping Point</b>
+ <span property="libns:stopping_point">{{ lib.stopping_point_name }}</span>
+ <br/>
+ {% endif %}
+ </div>
{% block additional_javascript %}
{% endblock %}
-
-<style type="text/css">
- /* <![CDATA[ */
- div#librarydetail {
- margin: 0;
- padding: 0;
- }
- div#librarydetail table, div#librarydetail td {
- border-style: solid;
- }
- div#librarydetail table {
- border-width: 0 0 1px 1px;
- border-spacing: 0;
- border-collapse: collapse;
- }
- div#librarydetail td {
- margin: 0;
- padding: 3px;
- border-width: 1px 1px 0 0;
- }
- div#librarydetail thead {
- text-align: center;
- }
- div#librarydetail tbody {
- text-align: right;
- }
- div#librarydetail h1,
- div#librarydetail h2
- {
- font-size: 150%;
- }
-
- div#librarydetail h3 {
- font-size: 125%;
- margin: 0;
- }
-
- div#librarydetail h4,
- div#librarydetail h5,
- div#librarydetail ul,
- div#librarydetail ol,
- div#librarydetail li
- {
- list-style: none;
- margin: 0;
- }
-
- div#librarydetail ul,
- div#librarydetail ol
- {
- margin-bottom: .5em;
- }
-
- div.library_identity {
- float: left; margin: 5px; }
- div.library_sample_detail { float: left; margin: 5px; }
- div.library_library_detail { float: left; margin: 5px; }
- div.library_statistics { clear: both; border: 1px; }
- /* ]]> */
-</style>
{% endblock %}
{% block content %}
-<div id="librarydetail">
- <div class="library_identity">
- <h2>Library Name</h2>
- <b>Library ID</b>: {{ lib.id }}<br/>
- <b>Name</b>:
- <span property="libns:name">{{ lib.library_name }}</span>
- <br/>
- <b>Affiliations</b>:
- <ul>
- {% for individual in lib.affiliations.all %}
- <li property="libns:affiliation" content="{{individual.name}}">
- {{ individual.name }} ( {{ individual.contact }} )
- </li>
- {% endfor %}
- </ul>
- </div>
- <div class="library_sample_detail">
- <h2>Sample Details</h2>
- <b>Species</b>:
- <span property="libns:species">{{ lib.library_species.scientific_name }}</span>
- <br/>
- <b>Experiment Type</b>:
- <span property="libns:experiment_type">{{ lib.experiment_type }}</span>
- <br/>
- {% if lib.antibody %}
- <b>Antibody</b>:
- <span property="libns:antibody">{{ lib.antibody.antibodies }}</span>
- {% if lib.antibody.antibodies.nuckname %}
- (<span property="libns:antibody_term">{{ lib.antibody.nickname }}</span>)
- {% endif %}
- <br/>
- {% endif %}
- {% if lib.cell_line %}
- <b>Background or Cell Line</b>:
- <span property="libns:cell_line">{{ lib.cell_line }}</span>
- <br/>
- {% endif %}
- {% if lib.condition %}
- <b>Condition</b>:
- <span property="libns:condition">{{ lib.condition.condition_name }}</span>
- {% if lib.condition.nickname %}
- (<span property="libns:condition_term">{{ lib.condition.nickname }}</span>)
- {% endif %}
- <br/>
- {% endif %}
- {% if lib.replicate %}
- <b>Replicate</b>:
- <span property="libns:replicate">{{ lib.replicate }}</span>
- <br/>
- {% endif %}
- </div>
- <div class="library_library_detail">
- <h2>Library Details</h2>
- <b>Library Type</b>:
- <span property="libns:library_type">{{ lib.library_type }}</span>
- <br/>
- <b>Creation Date</b>
- <span property="libns:date" content="{{lib.creation_date|date:'Y-m-d'}}T00:00:00" datatype="xsd:dateTime">{{ lib.creation_date }}</span>
- <br/>
- <b>Made By</b>:
- <span property="libns:made_by">{{ lib.made_by }}</span>
- <br/>
- {% if lib.gel_cut_size %}
- <b>Gel Cut Size</b>:
- <span property="libns:gel_cut">{{ lib.gel_cut_size }}</span>
- <br/>
- {% endif %}
- {% if lib.insert_size %}
- <b>Insert Size</b>:
- <span property="libns:insert_size">{{ lib.insert_size }}</span>
- <br/>
- {% endif %}
- {% if lib.undiluted_concentration %}
- <b>Concentration</b>:
- <span property="libns:concentration">{{ lib.undiluted_concentration }} ng/µl</span>
- <br/>
- {% endif %}
- {% if lib.stopping_point_name %}
- <b>Protocol Stopping Point</b>
- <span property="libns:stopping_point">{{ lib.stopping_point_name }}</span>
- <br/>
- {% endif %}
- </div>
+ {% include "sample_header.html" %}
+ <hr/>
<div class="library_statistics">
<h2>Raw Result Files</h2>
<table>
</thead>
<tbody>
- {% for lane in lane_summary_list %}
- <tr about="/flowcell/{{lane.flowcell_id}}/{{lane.lane_id}}/{% if lane.end %}#end{{ lane.end }}{% endif %}">
- <td>{{ lane.cycle_width }}</td>
- <td>{{ lane.flowcell_id }}</td>
- <td>{{ lane.lane_id }}</td>
- <td>{% if lane.end %}{{ lane.end }}{% endif %}</td>
- <td>{{ lane.clusters.0|intcomma }}</td>
- <td>{{ lane.successful_pm }}</td>
- <td>{{ lane.reads|intcomma }}</td>
- <td>{{ lane.no_match|intcomma }}</td>
- <td>{{ lane.no_match_percent|stringformat:".2f" }}</td>
- <td>{{ lane.qc_failed|intcomma }}</td>
- <td>{{ lane.qc_failed_percent|stringformat:".2f" }}</td>
- <td>{{ lane.match_codes.U0|intcomma }}</td>
- <td>{{ lane.match_codes.U1|intcomma }}</td>
- <td>{{ lane.match_codes.U2|intcomma }}</td>
- <td {% if lane.unique_reads %}property="libns:total_unique_locations" content="{{lane.unique_reads}}" datatype="xsd:decimal"{% endif %}>{{ lane.unique_reads|intcomma }}</td>
- <td>{{ lane.match_codes.R0|intcomma }}</td>
- <td>{{ lane.match_codes.R1|intcomma }}</td>
- <td>{{ lane.match_codes.R2|intcomma }}</td>
- <td>{{ lane.repeat_reads|intcomma }}</td>
+ {# ls short for lane summary #}
+ {% for ls in lane_summary_list %}
+ <tr about="{{ls.lane.get_absolute_url">
+ <td>{{ ls.cycle_width }}</td>
+ <td><a href="{{ls.flowcell.get_absolute_url}}">{{ ls.flowcell_id }}</a></td>
+ <td><a href="{{ls.lane.get_absolute_url}}">{{ ls.lane_id }}</a></td>
+ <td>{% if ls.end %}{{ ls.end }}{% endif %}</td>
+ <td>{{ ls.clusters.0|intcomma }}</td>
+ <td>{{ ls.successful_pm }}</td>
+ <td>{{ ls.reads|intcomma }}</td>
+ <td>{{ ls.no_match|intcomma }}</td>
+ <td>{{ ls.no_match_percent|stringformat:".2f" }}</td>
+ <td>{{ ls.qc_failed|intcomma }}</td>
+ <td>{{ ls.qc_failed_percent|stringformat:".2f" }}</td>
+ <td>{{ ls.match_codes.U0|intcomma }}</td>
+ <td>{{ ls.match_codes.U1|intcomma }}</td>
+ <td>{{ ls.match_codes.U2|intcomma }}</td>
+ <td {% if ls.unique_reads %}property="libns:total_unique_locations" content="{{ls.unique_reads}}" datatype="xsd:decimal"{% endif %}>{{ ls.unique_reads|intcomma }}</td>
+ <td>{{ ls.match_codes.R0|intcomma }}</td>
+ <td>{{ ls.match_codes.R1|intcomma }}</td>
+ <td>{{ ls.match_codes.R2|intcomma }}</td>
+ <td>{{ ls.repeat_reads|intcomma }}</td>
</tr>
{% endfor %}
</tbody>
# Flowcell:
(r'^flowcell/(?P<flowcell_id>\w+)/(?P<lane_number>\w+)/',
'htsworkflow.frontend.experiments.views.flowcell_lane_detail'),
- (r'^flowcell/(?P<flowcell_id>\w+)/',
+ (r'^flowcell/(?P<flowcell_id>\w+)/$',
'htsworkflow.frontend.experiments.views.flowcell_detail'),
# AnalysTrack:
#(r'^analysis/', include('htsworkflow.frontend.analysis.urls')),
pass
def test_format_gerald(self):
- flowcell_request = self.client.get('/experiments/config/303TUAAXX/json', apidata)
+ flowcell_request = self.client.get('/experiments/config/FC12150/json', apidata)
self.failUnlessEqual(flowcell_request.status_code, 200)
print dir(flowcell_request)
flowcell_info = json.loads(flowcell_request.content)
- options = getCombinedOptions(['-f','303TUAAXX','-g',os.getcwd()])
+ options = getCombinedOptions(['-f','FC12150','-g',os.getcwd()])
genome_map = {u'Homo sapiens': '/tmp/hg18' }
config = format_gerald_config(options, flowcell_info, genome_map)