quorum 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,274 +2,350 @@
2
2
  // QUORUM
3
3
  //---------------------------------------------------------------------------//
4
4
 
5
- var QUORUM = {
6
-
7
- //
8
- // Supported algorithms.
9
- //
10
- algorithms: ["blastn", "blastx", "tblastn", "blastp"],
11
-
12
- //
13
- // Poll quorum search results asynchronously and insert them into
14
- // the DOM via #blast_template.
15
- //
16
- pollResults: function(id, interval, algos) {
17
-
18
- // Set the default poll interval to 5 seconds.
19
- interval = interval || 5000;
20
-
21
- // Algorithms
22
- algos = algos || QUORUM.algorithms;
23
-
24
- _.each(algos, function(a) {
25
- $.getJSON(
26
- '/quorum/jobs/' + id + '/get_quorum_search_results.json?algo=' + a,
27
- function(data) {
28
- if (data.length === 0) {
29
- setTimeout(function() {
30
- QUORUM.pollResults(id, interval, [a]);
31
- }, interval);
5
+ var QUORUM = QUORUM || {};
6
+
7
+ //
8
+ // Supported algorithms.
9
+ //
10
+ QUORUM.algorithms = ["blastn", "blastx", "tblastn", "blastp"];
11
+
12
+ //
13
+ // Poll search results asynchronously.
14
+ //
15
+ // Allow user to define callback / callback_obj. If callback is
16
+ // undefined, render buildTemplate.
17
+ //
18
+ QUORUM.pollResults = function(id, callback, callback_obj, interval, algos) {
19
+
20
+ var self = this,
21
+ interval = interval || 5000,
22
+ algos = algos || self.algorithms;
23
+
24
+ // Render default view.
25
+ function buildTemplate(data, a) {
26
+ $('#' + a + '-results').empty();
27
+ var temp = _.template(
28
+ $('#blast_template').html(), {
29
+ data: data,
30
+ algo: a
31
+ }
32
+ );
33
+ $('#' + a + '-results').html(temp);
34
+ }
35
+
36
+ _.each(algos, function(a) {
37
+ $.getJSON(
38
+ '/quorum/jobs/' + id + '/get_quorum_search_results.json?algo=' + a,
39
+ function(data) {
40
+ if (data.length === 0) {
41
+ // Continue to check until results are returned.
42
+ setTimeout(function() {
43
+ self.pollResults(id, callback, callback_obj, interval, [a]);
44
+ }, interval);
45
+ } else {
46
+ if (typeof callback === "function") {
47
+ callback.call(callback_obj, id, data, a);
32
48
  } else {
33
- $('#' + a + '-results').empty();
34
- var temp = _.template(
35
- $('#blast_template').html(), {
36
- data: data,
37
- algo: a
38
- }
39
- );
40
- $('#' + a + '-results').html(temp);
41
- return;
49
+ buildTemplate(data, a);
42
50
  }
43
51
  }
52
+ }
53
+ );
54
+ });
55
+
56
+ };
57
+
58
+ //
59
+ // Display jQuery UI modal box containing detailed report of all hits
60
+ // to the same query. After the modal box is inserted into the DOM,
61
+ // automatically scroll to the highlighted hit.
62
+ //
63
+ QUORUM.viewDetailedReport = function(id, focus_id, query, algo) {
64
+
65
+ var self = this;
66
+
67
+ // Create the modal box.
68
+ $('#detailed_report_dialog').html(
69
+ "<p class='center'>" +
70
+ "Loading... <img src='/assets/quorum/loading.gif' alt='Loading'>" +
71
+ "</p>"
72
+ ).dialog({
73
+ modal: true,
74
+ width: 850,
75
+ position: 'top'
76
+ });
77
+
78
+ $.getJSON(
79
+ '/quorum/jobs/' + id + '/get_quorum_search_results.json?algo=' + algo +
80
+ '&query=' + query,
81
+ function(data) {
82
+ var temp = _.template(
83
+ $('#detailed_report_template').html(), {
84
+ data: data,
85
+ query: query,
86
+ algo: algo
87
+ }
44
88
  );
45
- });
46
- },
47
-
48
- //
49
- // Display jQuery UI modal box containing detailed report of all hits
50
- // to the same query. After the modal box is inserted into the DOM,
51
- // automatically scroll to the highlighted hit.
52
- //
53
- viewDetailedReport: function(id, focus_id, query, algo) {
54
- // Create the modal box.
55
- $('#detailed_report_dialog').html(
56
- "<p class='center'>" +
57
- "Loading... <img src='/assets/quorum/loading.gif' alt='Loading'>" +
58
- "</p>"
59
- ).dialog({
60
- modal: true,
61
- width: 850,
62
- position: 'top'
63
- });
64
89
 
65
- $.getJSON(
66
- '/quorum/jobs/' + id + '/get_quorum_search_results.json?algo=' + algo +
67
- '&query=' + query,
68
- function(data) {
69
- var temp = _.template(
70
- $('#detailed_report_template').html(), {
71
- data: data,
72
- query: query,
73
- algo: algo
74
- }
75
- );
90
+ // Insert the detailed report data.
91
+ $('#detailed_report_dialog').empty().html(temp);
76
92
 
77
- // Insert the detailed report data.
78
- $('#detailed_report_dialog').empty().html(temp);
93
+ // Add tipsy to the sequence data.
94
+ $('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
79
95
 
80
- // Add tipsy to the sequence data.
81
- $('a[rel=quorum-tipsy]').tipsy({ gravity: 's' });
96
+ // Highlight the selected id.
97
+ $('#' + focus_id).addClass("ui-state-highlight");
82
98
 
83
- // Highlight the selected id.
84
- $('#' + focus_id).addClass("ui-state-highlight");
99
+ // Automatically scroll to the selected id.
100
+ self.autoScroll(focus_id, false);
101
+ }
102
+ );
85
103
 
86
- // Automatically scroll to the selected id.
87
- QUORUM.autoScroll(focus_id, false);
88
- }
89
- );
90
- },
91
-
92
- //
93
- // Helper to add title sequence position attribute for tipsy.
94
- //
95
- // If from > to decrement index; otherwise increment.
96
- // If the algo is tblastn and type is hit OR algo is blastx and type is query,
97
- // increment / decrement by 3; otherwise increment / decrement by 1.
98
- //
99
- addBaseTitleIndex: function(bases, from, to, algo, type) {
100
- var forward = true;
101
- var value = 1;
102
- var index = from;
103
-
104
- if (from > to) {
105
- forward = false;
104
+ };
105
+
106
+ //
107
+ // Helper to add title sequence position attribute for tipsy.
108
+ //
109
+ // If from > to decrement index; otherwise increment.
110
+ // If the algo is tblastn and type is hit OR algo is blastx and type is query,
111
+ // increment / decrement by 3; otherwise increment / decrement by 1.
112
+ //
113
+ QUORUM.addBaseTitleIndex = function(bases, from, to, algo, type) {
114
+
115
+ var self = this,
116
+ forward = true,
117
+ value = 1,
118
+ index = from;
119
+
120
+ if (from > to) {
121
+ forward = false;
122
+ }
123
+
124
+ // Set value to 3 for the below.
125
+ if ((type === "hit" && algo === "tblastn") ||
126
+ (type === "query" && algo === "blastx")) {
127
+ value = 3;
128
+ }
129
+
130
+ // Add tipsy to each base.
131
+ return _.map(bases.split(''), function(c) {
132
+ var str = "<a rel='quorum-tipsy' title=" + index + ">" + c + "</a>";
133
+ forward ? index += value : index -= value;
134
+ return str;
135
+ }).join('');
136
+
137
+ };
138
+
139
+ //
140
+ // Format sequence data for detailed report.
141
+ //
142
+ // If q_from > q_to or h_from > h_to, subtract by increment; otherwise add
143
+ // by increment.
144
+ //
145
+ // If algo is tblastn or blastx, multiple increment by 3.
146
+ //
147
+ QUORUM.formatSequenceReport = function(qseq, midline, hseq, q_from, q_to, h_from, h_to, algo) {
148
+
149
+ var self = this,
150
+ max = qseq.length, // max length
151
+ increment = 60, // increment value
152
+ s = 0, // start position
153
+ e = increment, // end position
154
+ seq = "\n"; // seq string to return
155
+
156
+ while(true) {
157
+ seq += "qseq " + self.addBaseTitleIndex(qseq.slice(s, e), q_from, q_to, algo, 'query') + "\n";
158
+ seq += " " + midline.slice(s, e) + "\n";
159
+ seq += "hseq " + self.addBaseTitleIndex(hseq.slice(s, e), h_from, h_to, algo, 'hit') + "\n\n";
160
+
161
+ if (e >= max) {
162
+ break;
106
163
  }
107
164
 
108
- // Set value to 3 for the below.
109
- if ((type === "hit" && algo === "tblastn") ||
110
- (type === "query" && algo === "blastx")) {
111
- value = 3;
165
+ s += increment;
166
+ e += increment;
167
+
168
+ // If the algorithm is blastx, increment * 3 only for qseq.
169
+ if (algo === "blastx") {
170
+ q_from < q_to ? q_from += (increment * 3) : q_from -= (increment * 3);
171
+ } else {
172
+ q_from < q_to ? q_from += increment : q_from -= increment;
112
173
  }
113
174
 
114
- // Add tipsy to each base.
115
- return _.map(bases.split(''), function(c) {
116
- var str = "<a rel='quorum-tipsy' title=" + index + ">" + c + "</a>";
117
- forward ? index += value : index -= value;
118
- return str;
119
- }).join('');
120
- },
121
-
122
- //
123
- // Format sequence data for detailed report.
124
- //
125
- // If q_from > q_to or h_from > h_to, subtract by increment; otherwise add
126
- // by increment.
127
- //
128
- // If algo is tblastn or blastx, multiple increment by 3.
129
- //
130
- formatSequenceReport: function(qseq, midline, hseq, q_from, q_to, h_from, h_to, algo) {
131
- var max = qseq.length; // max length
132
- var increment = 60; // increment value
133
- var s = 0; // start position
134
- var e = increment; // end position
135
- var seq = "\n"; // seq string to return
136
-
137
- while(true) {
138
- seq += "qseq " + QUORUM.addBaseTitleIndex(qseq.slice(s, e), q_from, q_to, algo, 'query') + "\n";
139
- seq += " " + midline.slice(s, e) + "\n";
140
- seq += "hseq " + QUORUM.addBaseTitleIndex(hseq.slice(s, e), h_from, h_to, algo, 'hit') + "\n\n";
141
-
142
- if (e >= max) {
143
- break;
144
- }
175
+ // If the algorithm is tblastn, increment * 3 only for hseq.
176
+ if (algo === "tblastn") {
177
+ h_from < h_to ? h_from += (increment * 3) : h_from -= (increment * 3);
178
+ } else {
179
+ h_from < h_to ? h_from += increment : h_from -= increment;
180
+ }
181
+ }
182
+ return "<p class='small'>Alignment (Mouse over for positions):</p>" +
183
+ "<span class='small'><pre>" + seq + "</pre></span>";
145
184
 
146
- s += increment;
147
- e += increment;
185
+ };
148
186
 
149
- // If the algorithm is blastx, increment * 3 only for qseq.
150
- if (algo === "blastx") {
151
- q_from < q_to ? q_from += (increment * 3) : q_from -= (increment * 3);
152
- } else {
153
- q_from < q_to ? q_from += increment : q_from -= increment;
154
- }
187
+ //
188
+ // Format Query and Hit Strand.
189
+ //
190
+ // If query_frame or hit_frame < 0, print 'reverse'; print 'forward' otherwise.
191
+ //
192
+ QUORUM.formatStrand = function(qstrand, hstrand) {
193
+
194
+ var self = this,
195
+ q = "",
196
+ h = "";
197
+
198
+ qstrand < 0 ? q = "reverse" : q = "forward";
199
+ hstrand < 0 ? h = "reverse" : h = "forward";
200
+
201
+ return q + " / " + h;
155
202
 
156
- // If the algorithm is tblastn, increment * 3 only for hseq.
157
- if (algo === "tblastn") {
158
- h_from < h_to ? h_from += (increment * 3) : h_from -= (increment * 3);
203
+ };
204
+
205
+ //
206
+ // Format Blast E-value.
207
+ //
208
+ QUORUM.formatEvalue = function(evalue) {
209
+
210
+ var self = this,
211
+ index,
212
+ f,
213
+ e,
214
+ formatted;
215
+
216
+ if (_.isUndefined(evalue) || _.isNull(evalue) || evalue === "") {
217
+ return "";
218
+ }
219
+
220
+ index = evalue.indexOf('e');
221
+
222
+ if (index > -1) {
223
+ f = parseFloat(evalue.slice(0, index)).toPrecision(2);
224
+ e = evalue.slice(index).replace('e', '');
225
+
226
+ formatted = f + " x 10<sup>" + e + "</sup>";
227
+ } else {
228
+ formatted = parseFloat(evalue).toPrecision(2);
229
+ }
230
+
231
+ return formatted;
232
+
233
+ };
234
+
235
+ //
236
+ // Display links to Hsps in the same group.
237
+ //
238
+ QUORUM.displayHspLinks = function(focus, group, data) {
239
+
240
+ var self = this,
241
+ str = "",
242
+ ids,
243
+ selected;
244
+
245
+ if (!_.isNull(group)) {
246
+ str = "Related <a onclick=\"(QUORUM.openWindow(" +
247
+ "'http://www.ncbi.nlm.nih.gov/books/NBK62051/def-item/blast_glossary.HSP'," +
248
+ "'HSP', 800, 300))\">HSPs</a>: ";
249
+
250
+ ids = _.map(group.split(","), function(i) { return parseInt(i, 10); });
251
+
252
+ selected = _(data).chain()
253
+ .reject(function(d) { return !_.include(ids, d.id); })
254
+ .sortBy(function(d) { return d.id; })
255
+ .value();
256
+
257
+ _.each(selected, function(e) {
258
+ if (e.id !== focus) {
259
+ str += "<a onclick='(QUORUM.autoScroll(" + e.id + ", true))'>" + e.hsp_num + "</a> ";
159
260
  } else {
160
- h_from < h_to ? h_from += increment : h_from -= increment;
261
+ str += e.hsp_num + " ";
161
262
  }
263
+ });
264
+ }
265
+
266
+ return str;
267
+
268
+ };
269
+
270
+ //
271
+ // Download Blast hit sequence.
272
+ //
273
+ QUORUM.downloadSequence = function(id, algo_id, algo, el) {
274
+
275
+ var self = this;
276
+
277
+ $(el).html('Fetching sequence...');
278
+
279
+ $.getJSON(
280
+ "/quorum/jobs/" + id + "/get_quorum_blast_hit_sequence.json?algo_id=" +
281
+ algo_id + "&algo=" + algo,
282
+ function(data) {
283
+ self.getSequenceFile(id, data[0].meta_id, el);
162
284
  }
163
- return "<p class='small'>Alignment (Mouse over for positions):</p>" +
164
- "<span class='small'><pre>" + seq + "</pre></span>";
165
- },
166
-
167
- //
168
- // Format Query and Hit Strand.
169
- //
170
- // If query_frame or hit_frame < 0, print 'reverse'; print 'forward' otherwise.
171
- //
172
- formatStrand: function(qstrand, hstrand) {
173
- var q = "";
174
- var h = "";
175
-
176
- qstrand < 0 ? q = "reverse" : q = "forward";
177
- hstrand < 0 ? h = "reverse" : h = "forward";
178
-
179
- return q + " / " + h;
180
- },
181
-
182
- //
183
- // Display links to Hsps in the same group.
184
- //
185
- displayHspLinks: function(focus, group, data) {
186
- if (group !== null) {
187
- var str = "Related <a onclick=\"(QUORUM.openWindow(" +
188
- "'http://www.ncbi.nlm.nih.gov/books/NBK62051/def-item/blast_glossary.HSP'," +
189
- "'HSP', 800, 300))\">HSPs</a>: ";
190
-
191
- var ids = _.map(group.split(","), function(i) { return parseInt(i, 10); });
192
-
193
- var selected = _(data).chain()
194
- .reject(function(d) { return !_.include(ids, d.id); })
195
- .sortBy(function(d) { return d.id; })
196
- .value();
197
-
198
- _.each(selected, function(e) {
199
- if (e.id !== focus) {
200
- str += "<a onclick='(QUORUM.autoScroll(" + e.id + ", true))'>" + e.hsp_num + "</a> ";
201
- } else {
202
- str += e.hsp_num + " ";
203
- }
204
- });
205
- return str;
206
- }
207
- },
285
+ );
208
286
 
209
- //
210
- // Download Blast hit sequence.
211
- //
212
- downloadSequence: function(id, algo_id, algo, el) {
213
- $(el).html('Fetching sequence...');
287
+ };
214
288
 
215
- $.getJSON(
216
- "/quorum/jobs/" + id + "/get_quorum_blast_hit_sequence.json?algo_id=" +
217
- algo_id + "&algo=" + algo,
218
- function(data) {
219
- QUORUM.getSequenceFile(id, data[0].meta_id, el);
220
- }
221
- );
222
- },
223
-
224
- //
225
- // Poll application for Blast hit sequence.
226
- //
227
- getSequenceFile: function(id, meta_id, el) {
228
- var url = "/quorum/jobs/" + id +
229
- "/send_quorum_blast_hit_sequence?meta_id=" + meta_id;
230
- $.get(
231
- url,
232
- function(data) {
233
- if (data.length === 0) {
234
- setTimeout(function() { QUORUM.getSequenceFile(id, meta_id, el) }, 2500);
289
+ //
290
+ // Poll application for Blast hit sequence.
291
+ //
292
+ QUORUM.getSequenceFile = function(id, meta_id, el) {
293
+
294
+ var self = this,
295
+ url;
296
+
297
+ url = "/quorum/jobs/" + id +
298
+ "/send_quorum_blast_hit_sequence?meta_id=" + meta_id;
299
+ $.get(
300
+ url,
301
+ function(data) {
302
+ if (data.length === 0) {
303
+ setTimeout(function() { self.getSequenceFile(id, meta_id, el) }, 2500);
304
+ } else {
305
+ if (data.indexOf("error") !== -1) {
306
+ // Print error message.
307
+ $(el).addClass('ui-state-error').html(data);
235
308
  } else {
236
- if (data.indexOf("error") !== -1) {
237
- // Print error message.
238
- $(el).addClass('ui-state-error').html(data);
239
- } else {
240
- // Force browser to download file via iframe.
241
- $(el).addClass('ui-state-highlight').html('Sequence Downloaded Successfully');
242
- $('.quorum_sequence_download').remove();
243
- $('body').append('<iframe class="quorum_sequence_download"></iframe>');
244
- $('.quorum_sequence_download').attr('src', url).hide();
245
- }
309
+ // Force browser to download file via iframe.
310
+ $(el).addClass('ui-state-highlight').html('Sequence Downloaded Successfully');
311
+ $('.quorum_sequence_download').remove();
312
+ $('body').append('<iframe class="quorum_sequence_download"></iframe>');
313
+ $('.quorum_sequence_download').attr('src', url).hide();
246
314
  }
247
315
  }
248
- );
249
- },
250
-
251
- //
252
- // Autoscroll to given div id.
253
- //
254
- autoScroll: function(id, highlight) {
255
- $('html, body').animate({
256
- scrollTop: $('#' + id).offset().top
257
- }, 1000);
258
-
259
- if (highlight) {
260
- $('#' + id).effect("highlight", {}, 4000);
261
316
  }
262
- },
317
+ );
318
+
319
+ };
263
320
 
264
- //
265
- // Open URL in new window.
266
- //
267
- openWindow: function(url, name, width, height) {
321
+ //
322
+ // Autoscroll to given div id.
323
+ //
324
+ QUORUM.autoScroll = function(id, highlight) {
268
325
 
269
- var windowSize = "width=" + width + ",height=" + height + ",scrollbars=yes";
326
+ var self = this;
270
327
 
271
- window.open(url, name, windowSize);
328
+ $('html, body').animate({
329
+ scrollTop: $('#' + id).offset().top
330
+ }, 1000);
331
+
332
+ if (highlight) {
333
+ $('#' + id).effect("highlight", {}, 4000);
272
334
  }
273
335
 
274
336
  };
275
337
 
338
+ //
339
+ // Open URL in new window.
340
+ //
341
+ QUORUM.openWindow = function(url, name, width, height) {
342
+
343
+ var self = this,
344
+ windowSize;
345
+
346
+ windowSize = "width=" + width + ",height=" + height + ",scrollbars=yes";
347
+
348
+ window.open(url, name, windowSize);
349
+
350
+ };
351
+
@@ -115,15 +115,15 @@ module Quorum
115
115
  def send_quorum_blast_hit_sequence
116
116
  data = Workers::System.get_meta(params[:meta_id])
117
117
  if data.succeeded?
118
- unless data.result.downcase.include?("error")
118
+ if data.result.downcase.include?("error")
119
+ render :text => data.result
120
+ return
121
+ else
119
122
  send_data data.result,
120
123
  :filename => "#{params[:meta_id]}.fa",
121
124
  :type => "text/plain",
122
125
  :disposition => "attachment"
123
126
  return
124
- else
125
- render :text => data.result
126
- return
127
127
  end
128
128
  end
129
129
  render :text => ""
@@ -200,7 +200,7 @@ module Quorum
200
200
  "-a #{ActiveRecord::Base.configurations[::Rails.env.to_s]['adapter']} " <<
201
201
  "-k #{ActiveRecord::Base.configurations[::Rails.env.to_s]['host']} " <<
202
202
  "-u #{ActiveRecord::Base.configurations[::Rails.env.to_s]['username']} " <<
203
- "-p #{ActiveRecord::Base.configurations[::Rails.env.to_s]['password']} "
203
+ "-p '#{ActiveRecord::Base.configurations[::Rails.env.to_s]['password']}' "
204
204
  end
205
205
 
206
206
  end
@@ -11,26 +11,26 @@
11
11
  <div>
12
12
  <%= f.file_field :sequence_file %>
13
13
  </div>
14
- <!-- Search Algorithms -->
15
- <!-- Comment out an algorithm below to remove it from the form. -->
14
+ <%# Search Algorithms %>
15
+ <%# Comment out an algorithm below to remove it from the form. %>
16
16
 
17
- <!-- blastn -->
17
+ <%# blastn %>
18
18
  <%= render :partial => "quorum/jobs/form/blastn_form", :locals => {
19
19
  :f => f, :blast_dbs => @blast_dbs } %>
20
20
 
21
- <!-- blastx -->
21
+ <%# blastx %>
22
22
  <%= render :partial => "quorum/jobs/form/blastx_form", :locals => {
23
23
  :f => f, :blast_dbs => @blast_dbs } %>
24
24
 
25
- <!-- tblastn -->
25
+ <%# tblastn %>
26
26
  <%= render :partial => "quorum/jobs/form/tblastn_form", :locals => {
27
27
  :f => f, :blast_dbs => @blast_dbs } %>
28
28
 
29
- <!-- blastp -->
29
+ <%# blastp %>
30
30
  <%= render :partial => "quorum/jobs/form/blastp_form", :locals => {
31
31
  :f => f, :blast_dbs => @blast_dbs } %>
32
32
 
33
- <!-- End Search Algorithms -->
33
+ <%# End Search Algorithms %>
34
34
  <div>
35
35
  <%= f.submit "Submit" %>&nbsp;&nbsp;
36
36
  <%= submit_tag "Reset", :name => "reset",