sequenceserver 3.1.2 → 3.2.0
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.
- checksums.yaml +4 -4
- data/lib/sequenceserver/api_errors.rb +18 -0
- data/lib/sequenceserver/blast/hit.rb +1 -2
- data/lib/sequenceserver/blast/job.rb +15 -5
- data/lib/sequenceserver/blast/report.rb +5 -1
- data/lib/sequenceserver/blast/tasks.rb +1 -1
- data/lib/sequenceserver/database.rb +5 -1
- data/lib/sequenceserver/job.rb +26 -10
- data/lib/sequenceserver/makeblastdb.rb +2 -1
- data/lib/sequenceserver/routes.rb +38 -13
- data/lib/sequenceserver/version.rb +1 -1
- data/lib/sequenceserver/zip_file_generator.rb +1 -1
- data/lib/sequenceserver.rb +1 -1
- data/public/404.html +8 -16
- data/public/css/app.css +794 -111
- data/public/css/app.min.css +1 -1
- data/public/css/sequenceserver.min.css +1 -8
- data/public/js/alignment_exporter.js +16 -28
- data/public/js/circos.js +103 -96
- data/public/{packages/circosJS@1.7.0.js → js/circosjs.js} +156 -778
- data/public/js/cloud_share_modal.js +95 -98
- data/public/js/collapse_preferences.js +13 -15
- data/public/js/databases.js +4 -3
- data/public/js/databases_tree.js +51 -30
- data/public/js/error_modal.js +35 -22
- data/public/js/exporter.js +2 -0
- data/public/js/form.js +55 -17
- data/public/js/grapher.js +94 -92
- data/public/js/hit.js +24 -22
- data/public/js/hits.js +283 -0
- data/public/js/hits_overview.js +8 -27
- data/public/js/hsp.js +140 -144
- data/public/js/jquery_world.js +25 -16
- data/public/js/kablammo.js +14 -10
- data/public/js/length_distribution.js +23 -37
- data/public/js/mailto.js +1 -3
- data/public/js/null_plugins/report_plugins.js +4 -5
- data/public/js/options.js +19 -25
- data/public/js/query.js +36 -35
- data/public/js/report/alignment_results.js +18 -0
- data/public/js/report/graphical_overview.js +38 -0
- data/public/js/report/report_header.js +28 -0
- data/public/js/report/run_summary.js +43 -0
- data/public/js/report.js +124 -348
- data/public/js/report_root.js +10 -8
- data/public/js/search.js +31 -11
- data/public/js/search_button.js +85 -78
- data/public/js/sequence.js +169 -180
- data/public/js/sequence_modal.js +58 -65
- data/public/js/share_url.js +5 -5
- data/public/js/sidebar.js +152 -89
- data/public/js/svgExporter.js +8 -3
- data/public/js/tests/alignment_exporter.spec.js +38 -0
- data/public/js/tests/cloud_share_modal.spec.js +75 -0
- data/public/js/tests/form.spec.js +1 -1
- data/public/js/tests/report.spec.js +37 -15
- data/public/js/tests/visualisation_helpers.spec.js +28 -0
- data/public/js/visualisation_helpers.js +24 -27
- data/public/packages/jquery-ui@1.13.3.js +19070 -0
- data/public/sequenceserver-report.min.js +3 -2481
- data/public/sequenceserver-report.min.js.LICENSE.txt +213 -0
- data/public/sequenceserver-report.min.js.map +1 -0
- data/public/sequenceserver-search.min.js +3 -2382
- data/public/sequenceserver-search.min.js.LICENSE.txt +262 -0
- data/public/sequenceserver-search.min.js.map +1 -0
- data/views/error.erb +1 -1
- data/views/layout.erb +122 -133
- data/views/report.erb +3 -2
- data/views/search.erb +10 -14
- metadata +21 -28
- data/public/config.js +0 -147
- data/public/css/fonts.css +0 -31
- data/public/css/grapher.css +0 -670
- data/public/css/sequenceserver.css +0 -527
- data/public/packages/jquery-ui@1.11.4.js +0 -16624
- data/public/vendor/github/mbostock/d3@3.5.6/d3.js +0 -9506
- data/public/vendor/github/mbostock/d3@3.5.6.js +0 -1
- data/views/search_layout.erb +0 -153
data/public/js/hits.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
import _ from 'underscore';
|
|
4
|
+
|
|
5
|
+
import { ReportQuery } from './query';
|
|
6
|
+
import Hit from './hit';
|
|
7
|
+
import HSP from './hsp';
|
|
8
|
+
import AlignmentExporter from './alignment_exporter';
|
|
9
|
+
/* eslint-enable no-unused-vars */
|
|
10
|
+
|
|
11
|
+
class Hits extends Component {
|
|
12
|
+
constructor(props) {
|
|
13
|
+
super(props);
|
|
14
|
+
this.numUpdates = 0;
|
|
15
|
+
this.nextQuery = 0;
|
|
16
|
+
this.nextHit = 0;
|
|
17
|
+
this.nextHSP = 0;
|
|
18
|
+
this.maxHSPs = 10; // max HSPs to render in a cycle
|
|
19
|
+
this.state = props.state;
|
|
20
|
+
this.state.pluginResults = [];
|
|
21
|
+
this.prepareAlignmentOfSelectedHits = this.prepareAlignmentOfSelectedHits.bind(this);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
componentDidMount() {
|
|
25
|
+
this.props.plugins.init(this.onPluginResultsFetched.bind(this));
|
|
26
|
+
this.componentDidUpdate(this.props, this.state);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
onPluginResultsFetched(pluginResults) {
|
|
30
|
+
this.setState({ pluginResults: pluginResults });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
replacePluginResults(pluginResults) {
|
|
34
|
+
if (!pluginResults) return;
|
|
35
|
+
|
|
36
|
+
const updatedResults = this.props.plugins.replacePluginResults(this.state.results, pluginResults);
|
|
37
|
+
this.setState({ results: updatedResults, pluginResults: pluginResults });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Called for the first time after as BLAST results have been retrieved from
|
|
42
|
+
* the server and added to this.state by fetchResults. Only summary overview
|
|
43
|
+
* and circos would have been rendered at this point. At this stage we kick
|
|
44
|
+
* start iteratively adding 1 HSP to the page every 25 milli-seconds.
|
|
45
|
+
*/
|
|
46
|
+
componentDidUpdate(_prevProps, prevState) {
|
|
47
|
+
// Log to console how long the last update take?
|
|
48
|
+
// console.log((Date.now() - this.lastTimeStamp) / 1000);
|
|
49
|
+
|
|
50
|
+
// Queue next update if we have not rendered all results yet.
|
|
51
|
+
if (this.nextQuery < this.state.queries.length) {
|
|
52
|
+
// setTimeout is used to clear call stack and space out
|
|
53
|
+
// the updates giving the browser a chance to respond
|
|
54
|
+
// to user interactions.
|
|
55
|
+
setTimeout(() => this.updateState(), 25);
|
|
56
|
+
} else {
|
|
57
|
+
this.props.componentFinishedUpdating();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.state.pluginResults.length > 0 && prevState.pluginResults.length == 0) {
|
|
61
|
+
this.replacePluginResults(this.state.pluginResults);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isFirstUpdate() {
|
|
66
|
+
return this.nextQuery == 0 && this.nextHit == 0 && this.nextHSP == 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* eslint complexity: ["error", 6] */
|
|
70
|
+
/* ---------------------
|
|
71
|
+
* Push next slice of results to React for rendering.
|
|
72
|
+
*/
|
|
73
|
+
updateState() {
|
|
74
|
+
var results = { items: [], numHSPsProcessed: 0 };
|
|
75
|
+
this.processQueries(results);
|
|
76
|
+
|
|
77
|
+
// Push the components to react for rendering.
|
|
78
|
+
this.numUpdates++;
|
|
79
|
+
this.lastTimeStamp = Date.now();
|
|
80
|
+
this.setState({
|
|
81
|
+
results: this.state.results.concat(results.items),
|
|
82
|
+
veryBig: this.numUpdates >= 250,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
processQueries(results) {
|
|
87
|
+
while (this.nextQuery < this.state.queries.length) {
|
|
88
|
+
var query = this.state.queries[this.nextQuery];
|
|
89
|
+
|
|
90
|
+
// We may see a query multiple times during rendering because only
|
|
91
|
+
// 10 hsps are rendered in each cycle, but we want to create the
|
|
92
|
+
// corresponding Query component only the first time we see it.
|
|
93
|
+
if (this.nextHit == 0 && this.nextHSP == 0) {
|
|
94
|
+
results.items.push(this.renderReportQuery(query));
|
|
95
|
+
results.items.push(this.props.plugins.queryResult(query, this.state.pluginResults));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.processHits(results, query);
|
|
99
|
+
this.iterateLoops(['nextQuery', 'nextHit'], query.hits.length);
|
|
100
|
+
if (results.numHSPsProcessed == this.maxHSPs) break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
processHits(results, query) {
|
|
105
|
+
while (this.nextHit < query.hits.length) {
|
|
106
|
+
var hit = query.hits[this.nextHit];
|
|
107
|
+
// We may see a hit multiple times during rendering because only
|
|
108
|
+
// 3 hsps are rendered in each cycle, but we want to create the
|
|
109
|
+
// corresponding Hit component only the first time we see it.
|
|
110
|
+
if (this.nextHSP == 0) results.items.push(this.renderHit(query, hit));
|
|
111
|
+
|
|
112
|
+
this.processHSPS(results, query, hit);
|
|
113
|
+
this.iterateLoops(['nextHit', 'nextHSP'], hit.hsps.length);
|
|
114
|
+
if (results.numHSPsProcessed == this.maxHSPs) break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
processHSPS(results, query, hit) {
|
|
119
|
+
while (this.nextHSP < hit.hsps.length) {
|
|
120
|
+
// Get nextHSP and increment the counter.
|
|
121
|
+
var hsp = hit.hsps[this.nextHSP++];
|
|
122
|
+
results.items.push(
|
|
123
|
+
this.renderHsp(query, hit, hsp)
|
|
124
|
+
);
|
|
125
|
+
results.numHSPsProcessed++;
|
|
126
|
+
if (results.numHSPsProcessed == this.maxHSPs) break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
* this function check if 2nd argument is reach end of it
|
|
132
|
+
*/
|
|
133
|
+
iterateLoops(args, length) {
|
|
134
|
+
if (this[args[1]] != length) return;
|
|
135
|
+
|
|
136
|
+
this[args[0]]++;
|
|
137
|
+
this[args[1]] = 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
renderHsp(query, hit, hsp) {
|
|
141
|
+
return (
|
|
142
|
+
<HSP
|
|
143
|
+
key={
|
|
144
|
+
'Query_' +
|
|
145
|
+
query.number +
|
|
146
|
+
'_Hit_' +
|
|
147
|
+
hit.number +
|
|
148
|
+
'_HSP_' +
|
|
149
|
+
hsp.number
|
|
150
|
+
}
|
|
151
|
+
query={query}
|
|
152
|
+
hit={hit}
|
|
153
|
+
hsp={hsp}
|
|
154
|
+
algorithm={this.state.program}
|
|
155
|
+
showHSPNumbers={hit.hsps.length > 1}
|
|
156
|
+
{...this.props}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
renderHit(query, hit) {
|
|
162
|
+
return (
|
|
163
|
+
<Hit
|
|
164
|
+
key={'Query_' + query.number + '_Hit_' + hit.number}
|
|
165
|
+
query={query}
|
|
166
|
+
hit={hit}
|
|
167
|
+
algorithm={this.state.program}
|
|
168
|
+
querydb={this.state.querydb}
|
|
169
|
+
selectHit={this.selectHit}
|
|
170
|
+
imported_xml={this.state.imported_xml}
|
|
171
|
+
non_parse_seqids={this.state.non_parse_seqids}
|
|
172
|
+
showQueryCrumbs={this.state.queries.length > 1}
|
|
173
|
+
showHitCrumbs={query.hits.length > 1}
|
|
174
|
+
veryBig={this.state.veryBig}
|
|
175
|
+
onChange={this.prepareAlignmentOfSelectedHits}
|
|
176
|
+
{...this.props}
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
renderReportQuery(query) {
|
|
182
|
+
return (
|
|
183
|
+
<ReportQuery
|
|
184
|
+
key={'Query_' + query.id}
|
|
185
|
+
query={query}
|
|
186
|
+
program={this.state.program}
|
|
187
|
+
querydb={this.state.querydb}
|
|
188
|
+
showQueryCrumbs={this.state.queries.length > 1}
|
|
189
|
+
non_parse_seqids={this.state.non_parse_seqids}
|
|
190
|
+
imported_xml={this.state.imported_xml}
|
|
191
|
+
veryBig={this.state.veryBig}
|
|
192
|
+
/>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* eslint complexity: ["error", 6] */
|
|
197
|
+
/* -----------------------------------
|
|
198
|
+
* Event-handler when hit is selected
|
|
199
|
+
* Adds border-seqorange to hit component.
|
|
200
|
+
* Updates number of Fasta that can be downloaded
|
|
201
|
+
*/
|
|
202
|
+
selectHit(id) {
|
|
203
|
+
var checkbox = $('#' + id);
|
|
204
|
+
var num_checked = $('.hit-links :checkbox:checked').length;
|
|
205
|
+
|
|
206
|
+
if (!checkbox || !checkbox.val()) return;
|
|
207
|
+
|
|
208
|
+
var $hit = $(checkbox.data('target'));
|
|
209
|
+
|
|
210
|
+
// Highlight selected hit and enable 'Download FASTA/Alignment of
|
|
211
|
+
// selected' links.
|
|
212
|
+
if (checkbox.is(':checked')) {
|
|
213
|
+
$hit.addClass('border-seqorange');
|
|
214
|
+
$hit.next('.hsp').addClass('border-seqorange');
|
|
215
|
+
$hit.removeClass('border-transparent');
|
|
216
|
+
$hit.next('.hsp').removeClass('border-transparent');
|
|
217
|
+
$('.download-fasta-of-selected').enable();
|
|
218
|
+
$('.download-alignment-of-selected').enable();
|
|
219
|
+
} else {
|
|
220
|
+
$hit.removeClass('border-seqorange');
|
|
221
|
+
$hit.next('.hsp').removeClass('border-seqorange');
|
|
222
|
+
$hit.addClass('border-transparent');
|
|
223
|
+
$hit.next('.hsp').addClass('border-transparent');
|
|
224
|
+
$('.download-fasta-of-selected').attr('href', '#').removeAttr('download');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var $a = $('.download-fasta-of-selected');
|
|
228
|
+
var $b = $('.download-alignment-of-selected');
|
|
229
|
+
|
|
230
|
+
if (num_checked >= 1) {
|
|
231
|
+
$a.find('.font-bold').html(num_checked);
|
|
232
|
+
$b.find('.font-bold').html(num_checked);
|
|
233
|
+
$a.find('.font-bold').addClass('px-1').removeClass('px-0.5');
|
|
234
|
+
$b.find('.font-bold').addClass('px-1').removeClass('px-0.5');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (num_checked == 0) {
|
|
238
|
+
$a.addClass('disabled').find('.font-bold').html('');
|
|
239
|
+
$b.addClass('disabled').find('.font-bold').html('');
|
|
240
|
+
$a.find('.font-bold').removeClass('px-1').addClass('px-0.5');
|
|
241
|
+
$b.find('.font-bold').removeClass('px-1').addClass('px-0.5');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
prepareAlignmentOfSelectedHits() {
|
|
246
|
+
var sequence_ids = $('.hit-links :checkbox:checked').map(function () {
|
|
247
|
+
return this.value;
|
|
248
|
+
}).get();
|
|
249
|
+
|
|
250
|
+
if(!sequence_ids.length){
|
|
251
|
+
// remove attributes from link if sequence_ids array is empty
|
|
252
|
+
$('.download-alignment-of-selected').attr('href', '#').removeAttr('download');
|
|
253
|
+
return;
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
if(this.state.alignment_blob_url){
|
|
257
|
+
// always revoke existing url if any because this method will always create a new url
|
|
258
|
+
window.URL.revokeObjectURL(this.state.alignment_blob_url);
|
|
259
|
+
}
|
|
260
|
+
var hsps_arr = [];
|
|
261
|
+
var aln_exporter = new AlignmentExporter();
|
|
262
|
+
const self = this;
|
|
263
|
+
_.each(this.state.queries, _.bind(function (query) {
|
|
264
|
+
_.each(query.hits, function (hit) {
|
|
265
|
+
if (_.indexOf(sequence_ids, hit.id) != -1) {
|
|
266
|
+
hsps_arr = hsps_arr.concat(self.props.populate_hsp_array(hit, query.id));
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}, this));
|
|
270
|
+
const filename = 'alignment-' + sequence_ids.length + '_hits.txt';
|
|
271
|
+
const blob_url = aln_exporter.prepare_alignments_for_export(hsps_arr, filename);
|
|
272
|
+
// set required download attributes for link
|
|
273
|
+
$('.download-alignment-of-selected').attr('href', blob_url).attr('download', filename);
|
|
274
|
+
// track new url for future removal
|
|
275
|
+
this.setState({alignment_blob_url: blob_url});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
render() {
|
|
279
|
+
return this.state.results;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export default Hits;
|
data/public/js/hits_overview.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import d3 from 'd3';
|
|
1
|
+
import * as d3 from 'd3';
|
|
2
2
|
import _ from 'underscore';
|
|
3
3
|
import Grapher from 'grapher';
|
|
4
4
|
import * as Helpers from './visualisation_helpers';
|
|
@@ -58,13 +58,6 @@ class Graph {
|
|
|
58
58
|
return hits;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
setupTooltip() {
|
|
62
|
-
this.svg_container.find('[data-toggle="tooltip"]').tooltip({
|
|
63
|
-
'placement': 'top', 'container': 'body', 'html': 'true',
|
|
64
|
-
'delay': 0, 'white-space': 'nowrap'
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
61
|
setupClick($graphDiv) {
|
|
69
62
|
$('a', $graphDiv).click(function (evt) {
|
|
70
63
|
evt.preventDefault();
|
|
@@ -87,7 +80,7 @@ class Graph {
|
|
|
87
80
|
$graphDiv
|
|
88
81
|
.append(
|
|
89
82
|
$('<button/>')
|
|
90
|
-
.addClass('btn btn-link more')
|
|
83
|
+
.addClass('btn btn-link text-sm text-seqblue hover:text-seqorange cursor-pointer more')
|
|
91
84
|
.attr('type', 'button')
|
|
92
85
|
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
93
86
|
.html('View More ')
|
|
@@ -97,7 +90,7 @@ class Graph {
|
|
|
97
90
|
.addClass('fa fa-angle-double-down')
|
|
98
91
|
),
|
|
99
92
|
$('<button/>')
|
|
100
|
-
.addClass('btn btn-link less')
|
|
93
|
+
.addClass('btn btn-link text-sm text-seqblue hover:text-seqorange cursor-pointer less')
|
|
101
94
|
.attr('type', 'button')
|
|
102
95
|
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
103
96
|
.html('View Less ')
|
|
@@ -143,7 +136,6 @@ class Graph {
|
|
|
143
136
|
countHits();
|
|
144
137
|
this.graphIt($queryDiv, $graphDiv, shownHits, MIN_HITS_TO_SHOW, opts, hits);
|
|
145
138
|
initButtons();
|
|
146
|
-
this.setupTooltip();
|
|
147
139
|
e.stopPropagation();
|
|
148
140
|
},this));
|
|
149
141
|
|
|
@@ -161,7 +153,6 @@ class Graph {
|
|
|
161
153
|
this.graphIt($queryDiv, $graphDiv, shownHits, MIN_HITS_TO_SHOW - shownHits, opts, hits);
|
|
162
154
|
initButtons();
|
|
163
155
|
}
|
|
164
|
-
this.setupTooltip();
|
|
165
156
|
e.stopPropagation();
|
|
166
157
|
},this));
|
|
167
158
|
}
|
|
@@ -262,9 +253,7 @@ class Graph {
|
|
|
262
253
|
.append('g')
|
|
263
254
|
.attr('transform', 'translate(' + options.margin / 2 + ', ' + (1.5 * options.margin) + ')');
|
|
264
255
|
|
|
265
|
-
var x = d3.
|
|
266
|
-
.linear()
|
|
267
|
-
.range([0, width - options.margin]);
|
|
256
|
+
var x = d3.scaleLinear().range([0, width - options.margin]);
|
|
268
257
|
|
|
269
258
|
x.domain([1, queryLen]);
|
|
270
259
|
|
|
@@ -274,10 +263,7 @@ class Graph {
|
|
|
274
263
|
var _tValues = x.ticks(11);
|
|
275
264
|
_tValues.pop();
|
|
276
265
|
|
|
277
|
-
var xAxis = d3.
|
|
278
|
-
.axis()
|
|
279
|
-
.scale(x)
|
|
280
|
-
.orient('top')
|
|
266
|
+
var xAxis = d3.axisBottom(x)
|
|
281
267
|
.tickValues(_tValues.concat([1, queryLen]))
|
|
282
268
|
.tickFormat(formatter);
|
|
283
269
|
|
|
@@ -294,16 +280,14 @@ class Graph {
|
|
|
294
280
|
.attr('y','2px')
|
|
295
281
|
.attr('transform','rotate(-90)');
|
|
296
282
|
|
|
297
|
-
var y = d3.
|
|
298
|
-
.
|
|
299
|
-
.rangeBands([0, height - 3 * options.margin - 2 * options.legend], 0.3);
|
|
283
|
+
var y = d3.scaleBand()
|
|
284
|
+
.range([0, height - 3 * options.margin - 2 * options.legend], 0.3);
|
|
300
285
|
|
|
301
286
|
y.domain(hits.map(function (d) {
|
|
302
287
|
return d.hitId;
|
|
303
288
|
}));
|
|
304
289
|
|
|
305
|
-
var gradScale = d3.
|
|
306
|
-
.log()
|
|
290
|
+
var gradScale = d3.scaleLog()
|
|
307
291
|
.domain([
|
|
308
292
|
d3.min([1e-5, d3.min(hits.map(function (d) {
|
|
309
293
|
if (parseFloat(d.hitEvalue) === 0.0) return undefined;
|
|
@@ -369,7 +353,6 @@ class Graph {
|
|
|
369
353
|
d3.select(this)
|
|
370
354
|
.attr('xlink:href', '#' + q_i + '_hit_' + (i+1))
|
|
371
355
|
.append('rect')
|
|
372
|
-
.attr('data-toggle', 'tooltip')
|
|
373
356
|
.attr('title', alt_tooltip)
|
|
374
357
|
.attr('class','bar')
|
|
375
358
|
.attr('x', function (d) {
|
|
@@ -393,8 +376,6 @@ class Graph {
|
|
|
393
376
|
if (index === 0) {
|
|
394
377
|
this.graphControls($queryDiv, $graphDiv, true, opts, inhits);
|
|
395
378
|
}
|
|
396
|
-
// Refresh tooltip each time graph is redrawn.
|
|
397
|
-
this.setupTooltip();
|
|
398
379
|
// Ensure clicking on 'rect' takes user to the relevant hit on all
|
|
399
380
|
// browsers.
|
|
400
381
|
this.setupClick($graphDiv);
|