Skip to content

Commit cdc197b

Browse files
author
Remi-Andre Olsen
authored
Merge pull request #61 from remiolsen/master
Finishing up bioinfo kpis
2 parents ad17ac1 + a5b51cd commit cdc197b

9 files changed

Lines changed: 187 additions & 13 deletions

File tree

make_dashboards/templates/internal/js/dashboard.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,10 @@ $(function () {
7676
'<span style="color:#258F0B">'+pl['hiseq_sequencing_l']+'H</span>, '+
7777
'<span style="color:#4c85bc">'+pl['hiseqX_sequencing_l']+'X</span> lanes in progress';
7878
make_balance_plot('#rc_finished_balance', pl_l['initial_qc_lanes'], pl['initial_qc_lanes'], undefined, pl['initial_qc_lanes']+' lanes in progress');
79-
console.log(pl['initial_qc_samples']);
8079
make_balance_plot('#rc_balance', pl_l['initial_qc_samples'], pl['initial_qc_samples'], undefined, pl['initial_qc_samples']+' samples in progress');
8180
make_balance_plot('#lp_balance', pl_l['library_prep'], pl['library_prep'], undefined, pl['library_prep']+' samples in progress');
82-
make_balance_plot('#seq_balance', pl_l['sequencing'], [pl['miseq_sequencing_l'], pl['hiseq_sequencing_l'], pl['hiseqX_sequencing_l']], undefined, sequencing_subtext);
8381
make_balance_plot('#bioinfo_balance', pl_l['bioinformatics'], pl['bioinformatics'], undefined, pl['bioinformatics']+' lanes in progress');
82+
make_balance_plot('#seq_balance', pl_l['sequencing'], [pl['miseq_sequencing_l'], pl['hiseq_sequencing_l'], pl['hiseqX_sequencing_l']], undefined, sequencing_subtext);
8483

8584
// Bottom row
8685
make_success_plot('#rc_success', suc['initial_qc']*100);
@@ -291,7 +290,6 @@ function make_balance_plot(target, aim, now, prev, subtext){
291290
}else{
292291
my_plotlines = Array();
293292
chroma_colors = chroma.scale(['#AF2323','#259F0B','#4c85cc']).colors(now.length);
294-
pl = [];
295293
for (i in now){
296294
my_plotlines.push({
297295
name:'serie'+i,

update_kpis/kpiupdater/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ class ProjectViewsIter:
1919
...,
2020
project_dates: projectsDB/project/summary_dates[summary.key],
2121
project_samples: projectsDB/project/samples[summary.key],
22-
worksets: worksetsDB/project/ws_proj[summary.key]
22+
worksets: worksetsDB/project/ws_proj[summary.key],
23+
bioinfo_lanes Bioinfo_analysisDB/genomics-dashboard/project_status_counts[summary.key]
2324
}
2425
"""
25-
def __init__(self, project_summary, project_samples, project_dates, worksets_proj, ofptype=None):
26+
def __init__(self, project_summary, project_samples, project_dates, worksets_proj, bioinfo_samples, ofptype=None):
2627
self.proj_key = None
2728
self.value = None
2829
self.ofptype = ofptype
2930
self.summary_iter = iter(project_summary.rows)
3031
self.project_samples = project_samples
3132
self.project_dates = project_dates
3233
self.worksets_proj = worksets_proj
34+
self.bioinfo_samples = bioinfo_samples
3335

3436
def __iter__(self):
3537
return self
@@ -64,6 +66,13 @@ def next(self):
6466
except:
6567
pass
6668

69+
try:
70+
self.value["bioinfo"] = []
71+
for row in self.bioinfo_samples[[self.proj_key]:[self.proj_key, u'\ufff0']].rows:
72+
self.value["bioinfo"].append((row["value"], row.key[1]))
73+
except:
74+
pass
75+
6776
return (self.proj_key, self.value)
6877

6978
def sequencing_success(num_days=30):

update_kpis/kpiupdater/kpi.py

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,42 @@ def _is_ongoing(doc):
2828
return False
2929

3030

31+
def _agregate_status(statuses):
32+
"""
33+
From https://github.com/SciLifeLab/genomics-status/blob/38e1b946b40cc4b25ff75621f4aa9ff63e0e7bb9/status/bioinfo_analysis.py#L195
34+
Helper function, agregates status from the lower levels
35+
"""
36+
37+
# my guess here agregation is already done from flowcell status
38+
# so this condition will most probably always be true
39+
if len(set(statuses)) == 1:
40+
status = statuses[0]
41+
elif 'Sequencing' in statuses:
42+
status = 'Sequencing'
43+
elif 'Demultiplexing' in statuses:
44+
status = 'Demulitplexing'
45+
elif 'Transferring' in statuses:
46+
status = 'Transferring'
47+
elif 'New' in statuses:
48+
status = 'New'
49+
elif 'QC-ongoing' in statuses:
50+
status = 'QC-ongoing'
51+
elif 'QC-done' in statuses:
52+
status = 'QC-done'
53+
elif 'BP-ongoing' in statuses:
54+
status = 'BP-ongoing'
55+
elif 'BP-done' in statuses:
56+
status = 'BP-done'
57+
elif 'Failed' in statuses:
58+
status = 'Failed'
59+
elif 'Delivered' in statuses:
60+
status = 'Delivered'
61+
else:
62+
pass
63+
# unknown status, if happens it will fail
64+
return status # may fail here, if somebody defined a new status without updating this function
65+
66+
3167
class KPIBase(object):
3268

3369
def __init__(self):
@@ -105,8 +141,44 @@ def __call__(self, doc):
105141
self.prep_passed += 1.0
106142

107143
def summary(self):
108-
return round(self.prep_passed / self.prep_finished, 2)
144+
if self.prep_finished > 0:
145+
return round(self.prep_passed / self.prep_finished, 2)
146+
else:
147+
return None
109148

149+
class SuccessBioinfo(KPIBase):
150+
"""
151+
Definition: Samples passed in final report/total samples
152+
Approximation Passed run-lane-samples passed / total run-lane-samples
153+
"""
154+
def __init__(self):
155+
super(SuccessBioinfo, self).__init__()
156+
self.failed = 0.0
157+
self.total = 0.0
158+
159+
def __call__(self, doc):
160+
details = doc.get("details",{})
161+
ptype = details.get("type", "")
162+
for sample, run_lane in doc.get("bioinfo", []):
163+
if sample.get("sample_status","") == "Delivered" and ptype == "Production":
164+
deliver_date = datetime.strptime(sample["datadelivered"], "%Y-%m-%d")
165+
if deliver_date > self.start_date:
166+
self.total += 1.0
167+
isfail = False
168+
for key, value in sample.get("qc", {}).items():
169+
if value == "Fail":
170+
isfail = True
171+
for key, value in sample.get("bp", {}).items():
172+
if value == "Fail":
173+
isfail = True
174+
if isfail:
175+
self.failed += 1.0
176+
177+
def summary(self):
178+
if self.total > 0:
179+
return round(1-(self.failed / self.total),2)
180+
else:
181+
return None
110182

111183
### Projects
112184

@@ -301,6 +373,56 @@ def __call__(self, doc):
301373

302374
self.state += sum(osamples.values())
303375

376+
class LoadBioinfoQueue(ProcessLoadBase):
377+
"""
378+
Definition: total number of lanes with lane QC, but no action in bioinformatic checklist
379+
Approximation: # project-run-lanes with status `Demultiplexing`, `New` or `Transferring`
380+
"""
381+
382+
def __call__(self, doc):
383+
super(LoadBioinfoQueue, self).__call__(doc)
384+
run_lanes = {}
385+
ongoing = 0
386+
if _is_ongoing(doc) and self.ptype == "Production":
387+
for sample, run_lane in doc.get("bioinfo", []):
388+
status = sample.get(u'sample_status', None)
389+
if run_lane in run_lanes.keys():
390+
run_lanes[run_lane].append(status)
391+
else:
392+
run_lanes[run_lane] = [status]
393+
394+
for run_lane, statuses in run_lanes.items():
395+
lane_status = _agregate_status(statuses)
396+
if lane_status in [u'Demultiplexing', u'New', u'Transferring']:
397+
ongoing += 1
398+
399+
self.state += ongoing
400+
401+
402+
class LoadBioinfo(ProcessLoadBase):
403+
"""
404+
Definition: Total number of lanes with an action taken in bioinformatic checklist, in projects without close date.
405+
Approximation: # project-run-lanes with status `BP-ongoing`, `BP-done`, `QC-ongoing`, `QC-done`
406+
"""
407+
408+
def __call__(self, doc):
409+
super(LoadBioinfo, self).__call__(doc)
410+
run_lanes = {}
411+
ongoing = 0
412+
if _is_ongoing(doc) and self.ptype == "Production":
413+
for sample, run_lane in doc.get("bioinfo", []):
414+
status = sample.get(u'sample_status', None)
415+
if run_lane in run_lanes.keys():
416+
run_lanes[run_lane].append(status)
417+
else:
418+
run_lanes[run_lane] = [status]
419+
420+
for run_lane, statuses in run_lanes.items():
421+
lane_status = _agregate_status(statuses)
422+
if lane_status in [u'BP-ongoing', u'BP-done', u'QC-ongoing', u'QC-done']:
423+
ongoing += 1
424+
425+
self.state += ongoing
304426

305427
### Turn-around times
306428

update_kpis/tests/data/processload.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ P0001:
3333
sequencing: "some_object"
3434
P0001_103:
3535
library_status: "FAILED"
36+
bioinfo:
37+
- !!python/tuple [{user: "taca", sample_status: "Demultiplexing"}, 170925_D12345_001_ABCD_1]
38+
- !!python/tuple [{qc: {basesq30: "Pass", fastq_screen: "Fail"}, sample_status: "QC-ongoing", user: "Frank Grimes"}, 170925_D12345_001_ABCD_2]
3639
P0002:
3740
open_date: "2015-12-12"
3841
no_samples: 2

update_kpis/tests/data/success.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
P0001:
2+
open_date: "2015-12-12"
3+
no_samples: 3
4+
details:
5+
queued: "2015-12-24"
6+
type: "Production"
7+
sample_type: "Other"
28
worksets:
39
WS160116:
410
date_run: "2016-01-16"
@@ -16,6 +22,9 @@ P0001:
1622
rec_ctrl:
1723
status: "FAILED"
1824
library_status: "PASSED"
25+
bioinfo:
26+
- !!python/tuple [{qc: {basesq30: "Pass", fastq_screen: "Pass"}, datadelivered: "2017-10-01", sample_status: "Delivered", user: "Frank Grimes"}, 170925_D12345_001_ABCD_2]
27+
- !!python/tuple [{qc: {basesq30: "Pass", fastq_screen: "Fail"}, datadelivered: "2017-10-01", sample_status: "Delivered", user: "Frank Grimes"}, 170925_D12345_001_ABCD_3]
1928
P0002:
2029
worksets:
2130
WS160105:

update_kpis/tests/data/turnaround.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ P0001:
33
close_date: "2016-01-20"
44
details:
55
queued: "2016-01-12"
6+
all_samples_sequenced: "2016-01-18"
67
type: "Production"
78
sample_type: "Finished Library"
89
project_dates:
9-
sequencing_start_date: "2016-01-15"
10+
sequencing_start_date: "2016-01-15"
1011
P0002:
1112
open_date: "2016-01-10"
1213
close_date: "2016-01-20"

update_kpis/tests/test_kpi.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,21 @@ def test_initialqc(self):
9090
self.assertIsInstance(s_initqc.summary(), float)
9191

9292
def test_libraryprep(self):
93-
s_libprep = SuccessLibraryPrep()
93+
s_libprep = SuccessLibraryPrep()
9494
s_libprep.start_date = datetime(2016, 1, 1, 0, 0)
9595
for doc in self.p_iter:
9696
s_libprep(doc)
9797
self.assertEqual(3.0, s_libprep.prep_finished)
9898
self.assertEqual(2.0, s_libprep.prep_passed)
9999
self.assertIsInstance(s_libprep.summary(), float)
100100

101+
def test_bioinfo(self):
102+
s_bioinfo = SuccessBioinfo()
103+
s_bioinfo.start_date = datetime(2016, 1, 1, 0, 0)
104+
for doc in self.p_iter:
105+
s_bioinfo(doc)
106+
self.assertEqual(0.5, s_bioinfo.summary())
107+
101108

102109
class TestProcessLoad(unittest.TestCase):
103110

@@ -130,6 +137,18 @@ def test_libraryprep(self):
130137
pl_libprep(doc)
131138
self.assertEqual(1, pl_libprep.summary())
132139

140+
def test_bioinfo_lanes(self):
141+
pl_bioinfo = LoadBioinfo()
142+
for doc in self.p_iter:
143+
pl_bioinfo(doc)
144+
self.assertEqual(1, pl_bioinfo.summary())
145+
146+
def test_bioinfo_queue(self):
147+
pl_bioinfoq = LoadBioinfoQueue()
148+
for doc in self.p_iter:
149+
pl_bioinfoq(doc)
150+
self.assertEqual(1, pl_bioinfoq.summary())
151+
133152

134153
class TestTurnAroundTimes(unittest.TestCase):
135154

@@ -167,6 +186,14 @@ def test_libraryprep(self):
167186
self.assertIsInstance(tat_libprep.summary(), float)
168187
self.assertIsInstance(tat_libprep_90th.summary(), float)
169188

189+
def test_bioinfo(self):
190+
tat_bioinfo = TaTBioinformatics()
191+
tat_bioinfo.start_date = self.start_date
192+
for doc in self.p_iter:
193+
tat_bioinfo(doc)
194+
self.assertEqual([2], tat_bioinfo.state)
195+
self.assertIsInstance(tat_bioinfo.summary(), float)
196+
170197
def test_libprep_project(self):
171198
tat_libprep_proj = TaTLibprepProj()
172199
tat_libprep_proj.start_date = self.start_date

update_kpis/update_kpis.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ def update_kpi(couch_user, password, couch_server):
4747
p_samples = projects_db.view('project/samples')
4848
p_dates = projects_db.view('project/summary_dates', group_level=1)
4949
w_proj = worksets_db.view('project/ws_proj')
50-
#TODO bioinfo
51-
#b_samples = bioinfo_db.view('latest_data/project_id')
50+
b_samples = bioinfo_db.view('genomics_dashboard/run_lane_sample_status')
5251

5352
kpis = {}
5453
kpis["s_initqc"] = SuccessInitialQC()
5554
kpis["s_libprep"] = SuccessLibraryPrep()
55+
kpis["s_bioinfo"] = SuccessBioinfo()
5656
kpis["p_finlib"] = ProjectsFinishedLib()
5757
kpis["p_libprep"] = ProjectsLibraryPrep()
5858
kpis["p_inprod"] = ProjectsInProduction()
@@ -65,6 +65,8 @@ def update_kpi(couch_user, password, couch_server):
6565
kpis["pl_rclanes"] = LoadInitialQCLanes()
6666
kpis["pl_libprepq"] = LoadLibraryPrepQueue()
6767
kpis["pl_libprep"] = LoadLibraryPrep()
68+
kpis["pl_bioinfoq"] = LoadBioinfoQueue()
69+
kpis["pl_bioinfo"] = LoadBioinfo()
6870
kpis["t_libprep"] = TaTLibprep()
6971
kpis["t_initqc"] = TaTInitialQC()
7072
kpis["t_libproj"] = TaTLibprepProj()
@@ -79,7 +81,7 @@ def update_kpi(couch_user, password, couch_server):
7981
kpis["t_bioinfo_90th"] = TaTBioinfo_90th()
8082

8183
logging.info("Generating KPIs")
82-
for proj_key, doc in ProjectViewsIter(p_summary, p_samples, p_dates, w_proj):
84+
for proj_key, doc in ProjectViewsIter(p_summary, p_samples, p_dates, w_proj, b_samples):
8385
logging.debug("Processing project: {}".format(proj_key))
8486
for kpiobj in kpis.values():
8587
try:
@@ -105,6 +107,8 @@ def update_kpi(couch_user, password, couch_server):
105107
"initial_qc_lanes": kpis["pl_rclanes"].summary(),
106108
"library_prep": kpis["pl_libprep"].summary(),
107109
"library_prep_queue": kpis["pl_libprepq"].summary(),
110+
"bioinformatics_queue": kpis["pl_bioinfoq"].summary(),
111+
"bioinformatics": kpis["pl_bioinfo"].summary(),
108112
"miseq_pooling_queue": pl_seq[0],
109113
"miseq_sequencing_queue_p": pl_seq[1],
110114
"miseq_sequencing_queue_l": pl_seq[2],
@@ -121,7 +125,8 @@ def update_kpi(couch_user, password, couch_server):
121125
out["success_rate"] = {
122126
"initial_qc": kpis["s_initqc"].summary(),
123127
"library_prep": kpis["s_libprep"].summary(),
124-
"sequencing": sequencing_success()
128+
"sequencing": sequencing_success(),
129+
"bioinformatics": kpis["s_bioinfo"].summary()
125130
}
126131
out["turnaround_times"] = {
127132
"library_prep": kpis["t_libprep"].summary(),

version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.5
1+
0.2.0

0 commit comments

Comments
 (0)