quorum 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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",