sequenceserver 1.1.0.beta6 → 1.1.0.beta7

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.

Potentially problematic release.


This version of sequenceserver might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da64719d5d51834a93bd4071cf01f7dd9f45dfce
4
- data.tar.gz: 071fa0cfc1d276a53d613b43fab36e85180a3e8e
3
+ metadata.gz: 596bc25ee4cb80b8fad1de7a63b7677f291a0743
4
+ data.tar.gz: bb5bda8278682fb5a79526542023d3addfce8933
5
5
  SHA512:
6
- metadata.gz: 6f5486cf92ad273fd348fcd3d2dbcf4656b6bccd70f4040e2013e787b4ee68cd9c2d0c26473eb21a4ba2c0eb0d240d6f2f955110cd3f1442ddb37df94a8f5fc9
7
- data.tar.gz: bdaf284e009ee77987e2c89652fcdbe3501d783c5cdb0a568dac29535072dde48db28c716b6371ee6eb2dd31cdac364954033a58d886ce2b9eb9d30f941943cf
6
+ metadata.gz: e71d8f58e66599466f5149043f20e1ab5e1490857a557a71005889fdbd70ac46ac3649b18ff5b04037154f9b49ca98a3f37bbccfcef614786c3fc963222424b5
7
+ data.tar.gz: faaa045609c7009b1dae99175da8da6adbf8bb7a01439a2f2dbbd21d6a64f353ac76a5fe5c276051d96c7dbf9f9041c2ae2f90355ea002d1c37b112bfa8a772e
@@ -1,4 +1,4 @@
1
1
  # Define version number.
2
2
  module SequenceServer
3
- VERSION = '1.1.0.beta6'
3
+ VERSION = '1.1.0.beta7'
4
4
  end
data/public/js/circos.js CHANGED
@@ -316,10 +316,10 @@ class Graph {
316
316
  .attr('transform','translate('+this.svgContainer.width() / 2+','+this.svgContainer.height()/2+')')
317
317
  .append('text')
318
318
  .attr('text-anchor','start')
319
- .attr('dy','0.75em')
320
- .attr('x', -50)
321
- .attr('y', 2)
322
- .text('Sorry no Circos generated')
319
+ .attr('dy','-0.25em')
320
+ .attr('x', -175)
321
+ .style("font-size", "14px")
322
+ .text('Circos looks great with less than 16 queries')
323
323
  }
324
324
 
325
325
  layoutReset() {
File without changes
@@ -388,5 +388,5 @@ class Graph {
388
388
  }
389
389
  }
390
390
 
391
- var AlignmentOverview = Grapher(Graph);
392
- export default AlignmentOverview;
391
+ var HitsOverview = Grapher(Graph);
392
+ export default HitsOverview;
@@ -19,11 +19,11 @@ import * as Helpers from './visualisation_helpers';
19
19
 
20
20
  class Graph {
21
21
  static name() {
22
- return 'query against hit';
22
+ return 'Matching region(s)';
23
23
  }
24
24
 
25
25
  static className() {
26
- return 'kablammo collapse in';
26
+ return 'kablammo';
27
27
  }
28
28
 
29
29
  static collapseId(props) {
@@ -9,7 +9,7 @@ import * as Helpers from './visualisation_helpers';
9
9
 
10
10
  class Graph {
11
11
  static name() {
12
- return 'Length Distribution';
12
+ return 'Length distribution of hits';
13
13
  }
14
14
 
15
15
  static className() {
data/public/js/report.js CHANGED
@@ -1,18 +1,16 @@
1
- import SequenceServer from './sequenceserver';
2
- import showErrorModal from './errormodal';
3
-
4
- import _ from 'underscore';
1
+ import './sequenceserver' // for custom $.tooltip function
5
2
  import React from 'react';
6
- import d3 from 'd3';
3
+ import _ from 'underscore';
7
4
 
8
- import * as Helpers from './visualisation_helpers';
9
- import GraphicalOverview from './alignmentsoverview';
10
- //import Kablammo from './kablammo';
11
- import './sequence';
12
- import AlignmentExporter from './alignment_exporter';
13
- import LengthDistribution from './lengthdistribution';
14
5
  import Circos from './circos';
6
+ import HitsOverview from './hits_overview';
7
+ import LengthDistribution from './length_distribution'; // length distribution of hits
8
+ import HSPOverview from './kablammo';
9
+ import AlignmentExporter from './alignment_exporter'; // to download textual alignment
10
+ import './sequence';
15
11
 
12
+ import * as Helpers from './visualisation_helpers'; // for toLetters
13
+ import showErrorModal from './error_modal';
16
14
 
17
15
  /**
18
16
  * Dynamically create form and submit.
@@ -514,9 +512,9 @@ var Hit = React.createClass({
514
512
  }, this))
515
513
  }
516
514
  </div>
517
- {/*
518
- <Kablammo key={"Kablammo"+this.props.query.id} query={this.props.query} hit={this.props.hit} algorithm={this.props.algorithm}/>
519
- */}
515
+ <HSPOverview key={"kablammo"+this.props.query.id}
516
+ query={this.props.query} hit={this.props.hit}
517
+ algorithm={this.props.algorithm}/>
520
518
  <table
521
519
  className="table hsps">
522
520
  <tbody>
@@ -678,7 +676,7 @@ var Query = React.createClass({
678
676
  {this.numhits() &&
679
677
  (
680
678
  <div className="section-content">
681
- <GraphicalOverview key={"GO_"+this.props.query.number} query={this.props.query} program={this.props.data.program} collapsed={this.props.data.veryBig}/>
679
+ <HitsOverview key={"GO_"+this.props.query.number} query={this.props.query} program={this.props.data.program} collapsed={this.props.data.veryBig}/>
682
680
  <LengthDistribution key={"LD_"+this.props.query.id} query={this.props.query} algorithm={this.props.data.program} collapsed="true"/>
683
681
  <HitsTable key={"HT_"+this.props.query.number} query={this.props.query}/>
684
682
  <div
@@ -921,65 +919,12 @@ var SideBar = React.createClass({
921
919
  */
922
920
  var Report = React.createClass({
923
921
 
924
- // Kind of public API //
925
-
926
- /**
927
- * Event-handler when hit is selected
928
- * Adds glow to hit component.
929
- * Updates number of Fasta that can be downloaded
930
- */
931
- selectHit: function (id) {
932
-
933
- var checkbox = $("#" + id);
934
- var num_checked = $('.hit-links :checkbox:checked').length;
935
-
936
- if (!checkbox || !checkbox.val()) {
937
- return;
938
- }
939
-
940
- var $hit = $(checkbox.data('target'));
941
-
942
- // Highlight selected hit and sync checkboxes if sequence viewer is open.
943
- if (checkbox.is(":checked")) {
944
- $hit
945
- .addClass('glow')
946
- .find(":checkbox").not(checkbox).check();
947
- var $a = $('.download-fasta-of-selected');
948
- var $b = $('.download-alignment-of-selected');
949
- $b.enable()
950
- var $n = $a.find('span');
951
- $a
952
- .enable()
953
- }
954
-
955
- else {
956
- $hit
957
- .removeClass('glow')
958
- .find(":checkbox").not(checkbox).uncheck();
959
- }
960
-
961
- if (num_checked >= 1)
962
- {
963
- var $a = $('.download-fasta-of-selected');
964
- var $b = $('.download-alignment-of-selected');
965
- $a.find('.text-bold').html(num_checked);
966
- $b.find('.text-bold').html(num_checked);
967
- }
968
-
969
- if (num_checked == 0) {
970
- var $a = $('.download-fasta-of-selected');
971
- var $b = $('.download-alignment-of-selected');
972
- $a.addClass('disabled').find('.text-bold').html('');
973
- $b.addClass('disabled').find('.text-bold').html('');
974
- }
975
- },
976
-
977
-
978
- // Internal helpers. //
979
-
980
- // Life-cycle methods. //
922
+ // Model //
981
923
 
982
924
  getInitialState: function () {
925
+ this.fetchResults();
926
+ this.updateCycle = 0;
927
+
983
928
  return {
984
929
  search_id: '',
985
930
  program: '',
@@ -991,17 +936,77 @@ var Report = React.createClass({
991
936
  };
992
937
  },
993
938
 
994
- render: function () {
995
- return (this.isResultAvailable() ? this.resultsJSX() : this.loadingJSX());
939
+ /**
940
+ * Fetch results.
941
+ */
942
+ fetchResults: function () {
943
+ var intervals = [200, 400, 800, 1200, 2000, 3000, 5000];
944
+
945
+ (function poll (comp) {
946
+ $.getJSON(location.pathname + '.json')
947
+ .complete(function (jqXHR) {
948
+ switch (jqXHR.status) {
949
+ case 202:
950
+ var interval;
951
+ if (intervals.length === 1) {
952
+ interval = intervals[0];
953
+ }
954
+ else {
955
+ interval = intervals.shift;
956
+ }
957
+ setTimeout(poll, interval);
958
+ break;
959
+ case 200:
960
+ comp.updateState(jqXHR.responseJSON);
961
+ break;
962
+ case 404:
963
+ case 400:
964
+ case 500:
965
+ showErrorModal(jqXHR.responseJSON);
966
+ break;
967
+ }
968
+ });
969
+ }(this));
996
970
  },
997
971
 
998
972
  /**
999
- * Returns true if results have been fetched.
1000
- *
1001
- * A holding message is shown till results are fetched.
973
+ * Incrementally update state so that the rendering process is
974
+ * not overwhelemed when there are too many queries.
1002
975
  */
1003
- isResultAvailable: function () {
1004
- return this.state.queries.length >= 1;
976
+ updateState: function(responseJSON) {
977
+ var queries = responseJSON.queries;
978
+
979
+ // Render results for first 50 queries and set flag if total queries is
980
+ // more than 250.
981
+ var numHits = 0;
982
+ responseJSON.veryBig = queries.length > 250;
983
+ //responseJSON.veryBig = !_.every(queries, (query) => {
984
+ //numHits += query.hits.length;
985
+ //return (numHits <= 500);
986
+ //});
987
+ responseJSON.queries = queries.splice(0, 50);
988
+ this.setState(responseJSON);
989
+
990
+ // Render results for remaining queries.
991
+ var update = function () {
992
+ if (queries.length > 0) {
993
+ this.setState({
994
+ queries: this.state.queries.concat(queries.splice(0, 50))
995
+ });
996
+ setTimeout(update.bind(this), 500);
997
+ }
998
+ else {
999
+ this.componentFinishedUpdating();
1000
+ }
1001
+ };
1002
+ setTimeout(update.bind(this), 500);
1003
+ },
1004
+
1005
+
1006
+ // View //
1007
+ render: function () {
1008
+ return this.isResultAvailable() ?
1009
+ this.resultsJSX() : this.loadingJSX();
1005
1010
  },
1006
1011
 
1007
1012
  /**
@@ -1049,9 +1054,11 @@ var Report = React.createClass({
1049
1054
  }
1050
1055
  <div className={this.shouldShowSidebar() ?
1051
1056
  'col-md-9' : 'col-md-12'}>
1052
- { this.overview() }
1053
- <Circos queries={this.state.queries}
1054
- program={this.state.program} collapsed="true"/>
1057
+ { this.overviewJSX() }
1058
+ { this.isHitsAvailable()
1059
+ ? <Circos queries={this.state.queries}
1060
+ program={this.state.program} collapsed="true"/>
1061
+ : <span></span> }
1055
1062
  {
1056
1063
  _.map(this.state.queries, _.bind(function (query) {
1057
1064
  return (
@@ -1065,31 +1072,10 @@ var Report = React.createClass({
1065
1072
  );
1066
1073
  },
1067
1074
 
1068
- /**
1069
- * Returns true if sidebar should be shown.
1070
- *
1071
- * Sidebar is not shown if there is only one query and there are no hits
1072
- * corresponding to the query.
1073
- */
1074
- shouldShowSidebar: function () {
1075
- return !(this.state.queries.length == 1 &&
1076
- this.state.queries[0].hits.length == 0);
1077
- },
1078
-
1079
- /**
1080
- * Returns true if index should be shown in the sidebar.
1081
- *
1082
- * Index is not shown in the sidebar if there are more than eight queries
1083
- * in total.
1084
- */
1085
- shouldShowIndex: function () {
1086
- return this.state.queries.length <= 8;
1087
- },
1088
-
1089
1075
  /**
1090
1076
  * Renders report overview.
1091
1077
  */
1092
- overview: function () {
1078
+ overviewJSX: function () {
1093
1079
  return (
1094
1080
  <div
1095
1081
  className="overview">
@@ -1104,8 +1090,8 @@ var Report = React.createClass({
1104
1090
  }).join(", ")
1105
1091
  }
1106
1092
  <br/>
1107
- Total: {this.state.stats.nsequences} sequences, {this.state
1108
- .stats.ncharacters} characters
1093
+ Total: {this.state.stats.nsequences} sequences,
1094
+ {this.state.stats.ncharacters} characters
1109
1095
  <br/>
1110
1096
  <br/>
1111
1097
  {
@@ -1118,106 +1104,86 @@ var Report = React.createClass({
1118
1104
  );
1119
1105
  },
1120
1106
 
1121
- componentDidMount: function () {
1122
- this.fetchResults();
1123
- },
1107
+
1108
+ // Controller //
1124
1109
 
1125
1110
  /**
1126
- * Fetch results.
1111
+ * Returns true if results have been fetched.
1112
+ *
1113
+ * A holding message is shown till results are fetched.
1127
1114
  */
1128
- fetchResults: function () {
1129
- var intervals = [200, 400, 800, 1200, 2000, 3000, 5000];
1130
-
1131
- $.getJSON(location.pathname + '.json')
1132
- .complete(_.bind(function (jqXHR) {
1133
- switch (jqXHR.status) {
1134
- case 202:
1135
- var interval;
1136
- if (intervals.length === 1) {
1137
- interval = intervals[0];
1138
- }
1139
- else {
1140
- interval = intervals.shift;
1141
- }
1142
- setTimeout(this.fetchResults, interval);
1143
- break;
1144
- case 200:
1145
- this.updatePage(jqXHR.responseJSON);
1146
- break;
1147
- case 404:
1148
- case 400:
1149
- case 500:
1150
- showErrorModal(jqXHR.responseJSON);
1151
- break;
1152
- }
1153
- }, this));
1115
+ isResultAvailable: function () {
1116
+ return this.state.queries.length >= 1;
1154
1117
  },
1155
1118
 
1156
- updatePage: function(responseJSON) {
1157
- var queries = responseJSON.queries;
1119
+ isHitsAvailable: function () {
1120
+ var cnt = 0;
1121
+ _.each(this.state.queries, function (query) {
1122
+ if(query.hits.length == 0) cnt++;
1123
+ });
1124
+ return !(cnt == this.state.queries.length);
1125
+ },
1158
1126
 
1159
- // Render results for first 50 queries and set flag if total queries is
1160
- // more than 250.
1161
- var numHits = 0;
1162
- responseJSON.veryBig = queries.length > 250;
1163
- //responseJSON.veryBig = !_.every(queries, (query) => {
1164
- //numHits += query.hits.length;
1165
- //return (numHits <= 500);
1166
- //});
1167
- responseJSON.queries = queries.splice(0, 50);
1168
- this.setState(responseJSON);
1127
+ /**
1128
+ * Returns true if sidebar should be shown.
1129
+ *
1130
+ * Sidebar is not shown if there is only one query and there are no hits
1131
+ * corresponding to the query.
1132
+ */
1133
+ shouldShowSidebar: function () {
1134
+ return !(this.state.queries.length == 1 &&
1135
+ this.state.queries[0].hits.length == 0);
1136
+ },
1169
1137
 
1170
- // Render results for remaining queries.
1171
- var update = function () {
1172
- if (queries.length > 0) {
1173
- this.setState({
1174
- queries: this.state.queries.concat(queries.splice(0, 50))
1175
- });
1176
- setTimeout(update.bind(this), 500);
1177
- }
1178
- else {
1179
- this.componentFinishedUpdating();
1180
- }
1181
- };
1182
- setTimeout(update.bind(this), 500);
1138
+ /**
1139
+ * Returns true if index should be shown in the sidebar.
1140
+ *
1141
+ * Index is not shown in the sidebar if there are more than eight queries
1142
+ * in total.
1143
+ */
1144
+ shouldShowIndex: function () {
1145
+ return this.state.queries.length <= 8;
1183
1146
  },
1184
1147
 
1185
1148
  /**
1186
- * Locks Sidebar in its position, prevents folding of hits during
1187
- * text-selection, etc.
1149
+ * Called after first call to render. The results may not be available at
1150
+ * this stage and thus results DOM cannot be scripted here, unless using
1151
+ * delegated events bound to the window, document, or body.
1188
1152
  */
1189
- componentFinishedUpdating: function () {
1190
- this.affixSidebar();
1191
- this.shouldShowIndex() && this.setupScrollSpy();
1192
- this.setupHitSelection();
1193
- this.setupDownloadLinks();
1153
+ componentDidMount: function () {
1154
+ // This sets up an event handler which enables users to select text
1155
+ // from hit header without collapsing the hit.
1156
+ this.preventCollapseOnSelection();
1194
1157
  },
1195
1158
 
1196
1159
  /**
1197
- * Affixes the sidebar.
1198
- *
1199
- * TODO: can't this be done with CSS?
1160
+ * Called after each state change. Only a part of results DOM may be
1161
+ * available after a state change.
1200
1162
  */
1201
- affixSidebar: function () {
1202
- var $sidebar = $('.sidebar');
1203
- $sidebar.affix({
1204
- offset: {
1205
- top: $sidebar.offset().top
1206
- }
1207
- });
1163
+ componentDidUpdate: function () {
1164
+ // We track the number of updates to the component.
1165
+ this.updateCycle += 1;
1166
+
1167
+ // Lock sidebar in its position on first update of
1168
+ // results DOM.
1169
+ if (this.updateCycle === 1 ) this.affixSidebar();
1208
1170
  },
1209
1171
 
1210
1172
  /**
1211
- * For the query in viewport, highlights corresponding entry in the index.
1173
+ * Prevents folding of hits during text-selection, etc.
1212
1174
  */
1213
- setupScrollSpy: function () {
1214
- $('body').scrollspy({target: '.sidebar'});
1175
+
1176
+ /**
1177
+ * Called after all results have been rendered.
1178
+ */
1179
+ componentFinishedUpdating: function () {
1180
+ this.shouldShowIndex() && this.setupScrollSpy();
1215
1181
  },
1216
1182
 
1217
1183
  /**
1218
1184
  * Prevents folding of hits during text-selection.
1219
1185
  */
1220
- setupHitSelection: function () {
1186
+ preventCollapseOnSelection: function () {
1221
1187
  $('body').on('mousedown', ".hit > .section-header > h4", function (event) {
1222
1188
  var $this = $(this);
1223
1189
  $this.on('mouseup mousemove', function handler(event) {
@@ -1234,28 +1200,74 @@ var Report = React.createClass({
1234
1200
  });
1235
1201
  },
1236
1202
 
1237
- // Download links.
1238
- //
1239
- // Handles downloading files referenced by links with class 'download'.
1240
- setupDownloadLinks: function () {
1241
- $(document).on('click', '.download', function (event) {
1242
- event.preventDefault();
1243
- event.stopPropagation();
1203
+ /**
1204
+ * Affixes the sidebar.
1205
+ */
1206
+ affixSidebar: function () {
1207
+ var $sidebar = $('.sidebar');
1208
+ $sidebar.affix({
1209
+ offset: {
1210
+ top: $sidebar.offset().top
1211
+ }
1212
+ });
1213
+ },
1244
1214
 
1245
- var $anchor = $(this);
1215
+ /**
1216
+ * For the query in viewport, highlights corresponding entry in the index.
1217
+ */
1218
+ setupScrollSpy: function () {
1219
+ $('body').scrollspy({target: '.sidebar'});
1220
+ },
1246
1221
 
1247
- if ($anchor.is(':disabled')) return;
1222
+ /**
1223
+ * Event-handler when hit is selected
1224
+ * Adds glow to hit component.
1225
+ * Updates number of Fasta that can be downloaded
1226
+ */
1227
+ selectHit: function (id) {
1248
1228
 
1249
- var url = $anchor.attr('href');
1229
+ var checkbox = $("#" + id);
1230
+ var num_checked = $('.hit-links :checkbox:checked').length;
1250
1231
 
1251
- $.get(url)
1252
- .done(function (data) {
1253
- window.location.href = url;
1254
- })
1255
- .fail(function (jqXHR, status, error) {
1256
- SequenceServer.showErrorModal(jqXHR, function () {});
1257
- });
1258
- });
1232
+ if (!checkbox || !checkbox.val()) {
1233
+ return;
1234
+ }
1235
+
1236
+ var $hit = $(checkbox.data('target'));
1237
+
1238
+ // Highlight selected hit and sync checkboxes if sequence viewer is open.
1239
+ if (checkbox.is(":checked")) {
1240
+ $hit
1241
+ .addClass('glow')
1242
+ .find(":checkbox").not(checkbox).check();
1243
+ var $a = $('.download-fasta-of-selected');
1244
+ var $b = $('.download-alignment-of-selected');
1245
+ $b.enable()
1246
+ var $n = $a.find('span');
1247
+ $a
1248
+ .enable()
1249
+ }
1250
+
1251
+ else {
1252
+ $hit
1253
+ .removeClass('glow')
1254
+ .find(":checkbox").not(checkbox).uncheck();
1255
+ }
1256
+
1257
+ if (num_checked >= 1)
1258
+ {
1259
+ var $a = $('.download-fasta-of-selected');
1260
+ var $b = $('.download-alignment-of-selected');
1261
+ $a.find('.text-bold').html(num_checked);
1262
+ $b.find('.text-bold').html(num_checked);
1263
+ }
1264
+
1265
+ if (num_checked == 0) {
1266
+ var $a = $('.download-fasta-of-selected');
1267
+ var $b = $('.download-alignment-of-selected');
1268
+ $a.addClass('disabled').find('.text-bold').html('');
1269
+ $b.addClass('disabled').find('.text-bold').html('');
1270
+ }
1259
1271
  },
1260
1272
  });
1261
1273