grnsight 6.0.7 → 7.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.
Files changed (67) hide show
  1. package/.eslintrc.yml +4 -4
  2. package/.github/workflows/node.js.yml +35 -0
  3. package/README.md +1 -1
  4. package/database/README.md +218 -97
  5. package/database/constants.py +42 -0
  6. package/database/filter_update.py +168 -0
  7. package/database/grnsettings-database/README.md +52 -0
  8. package/database/grnsettings-database/schema.sql +4 -0
  9. package/database/loader.py +30 -0
  10. package/database/loader_update.py +36 -0
  11. package/database/network-database/scripts/generate_network.py +15 -23
  12. package/database/network-database/scripts/generate_new_network_version.py +17 -24
  13. package/database/protein-protein-database/README.md +71 -0
  14. package/database/protein-protein-database/schema.sql +37 -0
  15. package/database/protein-protein-database/scripts/generate_protein_network.py +227 -0
  16. package/database/protein-protein-database/scripts/remove_duplicates.sh +4 -0
  17. package/database/utils.py +418 -0
  18. package/package.json +3 -2
  19. package/server/app.js +2 -0
  20. package/server/config/config.js +4 -4
  21. package/server/controllers/additional-sheet-parser.js +2 -1
  22. package/server/controllers/constants.js +5 -0
  23. package/server/controllers/custom-workbook-controller.js +4 -3
  24. package/server/controllers/demo-workbooks.js +1462 -6
  25. package/server/controllers/export-constants.js +3 -2
  26. package/server/controllers/exporters/sif.js +6 -1
  27. package/server/controllers/exporters/xlsx.js +8 -3
  28. package/server/controllers/expression-sheet-parser.js +0 -6
  29. package/server/controllers/grnsettings-database-controller.js +17 -0
  30. package/server/controllers/importers/sif.js +30 -11
  31. package/server/controllers/network-database-controller.js +2 -2
  32. package/server/controllers/network-sheet-parser.js +54 -12
  33. package/server/controllers/protein-database-controller.js +18 -0
  34. package/server/controllers/sif-constants.js +11 -4
  35. package/server/controllers/spreadsheet-controller.js +44 -1
  36. package/server/controllers/workbook-constants.js +21 -4
  37. package/server/dals/expression-dal.js +4 -4
  38. package/server/dals/grnsetting-dal.js +49 -0
  39. package/server/dals/network-dal.js +14 -15
  40. package/server/dals/protein-dal.js +106 -0
  41. package/test/additional-sheet-parser-tests.js +1 -1
  42. package/test/export-tests.js +136 -9
  43. package/test/import-sif-tests.js +67 -13
  44. package/test/test.js +1 -1
  45. package/test-files/additional-sheet-test-files/optimization-parameters-default.xlsx +0 -0
  46. package/test-files/demo-files/18_proteins_81_edges_PPI.xlsx +0 -0
  47. package/test-files/expression-data-test-sheets/expression_sheet_missing_data_ok_export_exact.xlsx +0 -0
  48. package/web-client/config/config.js +4 -4
  49. package/web-client/public/js/api/grnsight-api.js +18 -3
  50. package/web-client/public/js/constants.js +27 -12
  51. package/web-client/public/js/generateNetwork.js +170 -72
  52. package/web-client/public/js/graph.js +424 -161
  53. package/web-client/public/js/grnsight.js +25 -4
  54. package/web-client/public/js/grnstate.js +4 -1
  55. package/web-client/public/js/iframe-coordination.js +3 -3
  56. package/web-client/public/js/setup-handlers.js +76 -61
  57. package/web-client/public/js/setup-load-and-import-handlers.js +32 -7
  58. package/web-client/public/js/update-app.js +119 -28
  59. package/web-client/public/js/upload.js +142 -85
  60. package/web-client/public/js/warnings.js +25 -0
  61. package/web-client/public/lib/bootstrap.file-input/bootstrap.file-input.js +0 -1
  62. package/web-client/public/stylesheets/grnsight.styl +40 -16
  63. package/web-client/views/components/demo.pug +7 -5
  64. package/web-client/views/upload.pug +64 -50
  65. package/database/network-database/scripts/filter_genes.py +0 -76
  66. package/database/network-database/scripts/loader.py +0 -79
  67. package/database/network-database/scripts/loader_updates.py +0 -99
@@ -1,13 +1,34 @@
1
+ /* eslint-disable func-style */
1
2
  import { displayStatistics } from "./graph-statistics"; // eslint-disable-line no-unused-vars
2
3
  import { upload } from "./upload";
3
4
  import { generateNetwork } from "./generateNetwork";
4
5
 
5
6
  import { grnState } from "./grnstate";
7
+ import { queryDefaultDataset } from "./api/grnsight-api.js";
6
8
  import { updateApp } from "./update-app";
7
9
  import { setupHandlers } from "./setup-handlers";
8
10
 
9
- setupHandlers(grnState);
10
- updateApp(grnState);
11
+ async function updateDefaultDataset () {
12
+ try {
13
+ const response = await queryDefaultDataset({type:"DefaultDataset"});
14
+ grnState.database = response;
15
+ return response.defaultDataset.join();
16
+ } catch (error) {
17
+ console.log(error.stack);
18
+ console.log(error.name);
19
+ console.log(error.message);
20
+ }
21
+ }
11
22
 
12
- upload();
13
- generateNetwork();
23
+ async function initializeGrnsight () {
24
+ const defaultDataset = await updateDefaultDataset();
25
+ grnState.defaultDataset = defaultDataset;
26
+
27
+ setupHandlers(grnState);
28
+ updateApp(grnState);
29
+
30
+ upload();
31
+ generateNetwork();
32
+ }
33
+
34
+ initializeGrnsight();
@@ -10,7 +10,8 @@ import {
10
10
  DEFAULT_MAX_LOG_FOLD_CHANGE,
11
11
  DEFAULT_ZOOM_VALUE,
12
12
  FORCE_GRAPH,
13
- VIEWPORT_INIT
13
+ VIEWPORT_INIT,
14
+ NETWORK_GRN_MODE
14
15
  } from "./constants";
15
16
  let currentWorkbook = null;
16
17
 
@@ -41,6 +42,7 @@ const annotateLinks = workbook => {
41
42
  };
42
43
 
43
44
  export const grnState = {
45
+ mode: NETWORK_GRN_MODE, // GRNsight will display GRN view unless specified
44
46
  name: null,
45
47
  simulation: undefined,
46
48
  newWorkbook: false,
@@ -83,6 +85,7 @@ export const grnState = {
83
85
  lastDataset: null,
84
86
  bottomDataSameAsTop: true,
85
87
  nodeColoringOptions: [],
88
+ ppiNodeColorWarningDisplayed: false,
86
89
  },
87
90
 
88
91
 
@@ -11,7 +11,7 @@
11
11
  * loaded into the web browser when this script executes.
12
12
  */
13
13
  iFrameResize({
14
- checkOrigin: ["https://dondi.github.io", "https://grnsight.cs.lmu.edu"],
14
+ checkOrigin: ["https://dondi.github.io", "https://grnsight.lmucs.org"],
15
15
  widthCalculationMethod: "taggedElement",
16
16
  heightCalculationMethod: "taggedElement",
17
17
  sizeWidth: true,
@@ -40,7 +40,7 @@ const sendDimensions = (destination, origin) => {
40
40
  };
41
41
 
42
42
  window.addEventListener("message", event => {
43
- if (event.origin.indexOf("https://grnsight.cs.lmu.edu") !== 0) {
43
+ if (event.origin.indexOf("https://grnsight.lmucs.org") !== 0) {
44
44
  // Ignore any message that did not originate from the GRNsight web client server.
45
45
  return;
46
46
  }
@@ -51,5 +51,5 @@ window.addEventListener("message", event => {
51
51
  });
52
52
 
53
53
  window.addEventListener("resize", () => sendDimensions(
54
- document.querySelector("iframe.embedded-demo").contentWindow, "https://grnsight.cs.lmu.edu"
54
+ document.querySelector("iframe.embedded-demo").contentWindow, "https://grnsight.lmucs.org"
55
55
  ));
@@ -94,13 +94,11 @@ export const setupHandlers = grnState => {
94
94
  window.document.body.appendChild(emptySvg);
95
95
  var emptySvgDeclarationComputed = getComputedStyle(emptySvg);
96
96
 
97
- const traverse = svg => {
98
- var tree = [];
99
- tree.push(svg);
100
- // implement DFS
101
- const visit = (node) => {
102
- if (node && node.hasChildNodes()) {
103
- var child = node.firstChild;
97
+ const traverse = (node) => {
98
+ const tree = [];
99
+ const visit = (currentNode) => {
100
+ if (currentNode && currentNode.hasChildNodes()) {
101
+ let child = currentNode.firstChild;
104
102
  while (child) {
105
103
  if (child.nodeType === 1 && child.nodeName !== "SCRIPT") {
106
104
  tree.push(child);
@@ -110,38 +108,39 @@ export const setupHandlers = grnState => {
110
108
  }
111
109
  }
112
110
  };
113
- visit(svg);
111
+ visit(node);
114
112
  return tree;
115
113
  };
116
114
 
117
115
  const explicitlySetStyle = element => {
118
- const cSSStyleDeclarationComputed = window.getComputedStyle(element);
119
- let i;
120
- let len;
121
- let key;
122
- let value;
123
- let computedStyleStr = "";
124
-
125
- for (i = 0, len = cSSStyleDeclarationComputed.length; i < len; i++) {
126
- key = cSSStyleDeclarationComputed[i];
127
- value = cSSStyleDeclarationComputed.getPropertyValue(key);
116
+ const cssStyleDeclarationComputed = window.getComputedStyle(element);
117
+ const computedStyleObj = {};
118
+
119
+
120
+ for (let i = 0; i < cssStyleDeclarationComputed.length; i++) {
121
+ const key = cssStyleDeclarationComputed[i];
122
+ const value = cssStyleDeclarationComputed.getPropertyValue(key);
128
123
  if (value !== emptySvgDeclarationComputed.getPropertyValue(key)) {
129
124
  // Don't set computed style of width and height. Makes SVG elmements disappear.
130
125
  if ((key !== "height") && (key !== "width")) {
131
- computedStyleStr += key + ":" + value + ";";
126
+ computedStyleObj[key] = value;
132
127
  }
133
128
 
134
129
  }
135
130
  }
136
- element.setAttribute("style", computedStyleStr);
131
+
132
+ if (element.classList.contains("weight")) {
133
+ computedStyleObj["visibility"] = "hidden";
134
+ }
135
+
136
+ if (computedStyleObj) {
137
+ Object.assign(element.style, computedStyleObj);
138
+ }
137
139
  };
138
140
 
139
141
  // hardcode computed css styles inside svg
140
142
  var allElements = traverse(svg);
141
- var i = allElements.length;
142
- while (i--) {
143
- explicitlySetStyle(allElements[i]);
144
- }
143
+ allElements.forEach(explicitlySetStyle);
145
144
  };
146
145
 
147
146
  const sourceAttributeSetter = (svg) => {
@@ -160,7 +159,7 @@ export const setupHandlers = grnState => {
160
159
  };
161
160
 
162
161
  const exportSVG = (svgElement, name) => {
163
- let source = svgElement;
162
+ let source = svgElement.cloneNode(true);
164
163
 
165
164
  sourceAttributeSetter(source);
166
165
  setInlineStyles(source);
@@ -185,10 +184,30 @@ export const setupHandlers = grnState => {
185
184
  const imgData = canvas.toDataURL("image/png");
186
185
 
187
186
  const pdf = new jsPDF("l", "mm", "letter");
188
- const width = pdf.internal.pageSize.getWidth();
189
- const height = pdf.internal.pageSize.getHeight();
187
+ const pdfWidth = pdf.internal.pageSize.getWidth();
188
+ const pdfHeight = pdf.internal.pageSize.getHeight();
190
189
 
191
- pdf.addImage(imgData, "PNG", 0, 0, width, height);
190
+ const svgWidth = canvas.width;
191
+ const svgHeight = canvas.height;
192
+
193
+ const aspectRatio = svgWidth / svgHeight;
194
+ let scaledWidth = pdfWidth;
195
+ // ratio = width/height --> height = width/ratio
196
+ let scaledHeight = scaledWidth / aspectRatio;
197
+
198
+ if (scaledHeight > pdfHeight) {
199
+ scaledHeight = pdfHeight;
200
+ scaledWidth = pdfHeight * aspectRatio;
201
+ }
202
+
203
+ pdf.addImage(
204
+ imgData,
205
+ "PNG",
206
+ (pdfWidth - scaledWidth) / 2,
207
+ (pdfHeight - scaledHeight) / 2,
208
+ scaledWidth,
209
+ scaledHeight
210
+ );
192
211
  pdf.save(name);
193
212
  };
194
213
 
@@ -209,7 +228,7 @@ export const setupHandlers = grnState => {
209
228
  $(EXPORT_TO_PNG).click(() => {
210
229
  var svgContainer = document.getElementById("exportContainer");
211
230
  var editedName = grnState.name.replace(determineFileType(grnState.name), "") + ".png";
212
- saveSvgAsPng(svgContainer, editedName);
231
+ saveSvgAsPng(svgContainer, editedName, { backgroundColor: "white"});
213
232
  });
214
233
 
215
234
  $(EXPORT_TO_SVG).click(() => {
@@ -225,29 +244,40 @@ export const setupHandlers = grnState => {
225
244
  });
226
245
 
227
246
  // Node Coloring
228
- $(NODE_COLORING_TOGGLE_CLASS).click(() => {
229
- grnState.nodeColoring.nodeColoringEnabled = !grnState.nodeColoring.nodeColoringEnabled;
230
- updateApp(grnState);
231
- });
232
-
233
- $(TOP_DATASET_SELECTION_SIDEBAR).change(() => {
234
- var selection = $(TOP_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
247
+ const updateTopDatasetSelection = (selection) => {
235
248
  grnState.nodeColoring.topDataset = selection;
236
249
  if (grnState.nodeColoring.bottomDataSameAsTop) {
237
250
  grnState.nodeColoring.bottomDataset = selection;
238
251
  }
239
252
  updateApp(grnState);
240
- });
253
+ };
241
254
 
242
- $(TOP_DATASET_SELECTION_MENU).click(() => {
243
- var selection = $(this).attr("value");
244
- grnState.nodeColoring.topDataset = selection;
245
- if (grnState.nodeColoring.bottomDataSameAsTop) {
255
+ const updateBottomDatasetSelection = (selection) => {
256
+ grnState.nodeColoring.bottomDataset = selection;
257
+ if (selection === "Same as Top Dataset") {
258
+ grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
259
+ grnState.nodeColoring.bottomDataSameAsTop = true;
260
+ } else {
261
+ grnState.nodeColoring.bottomDataSameAsTop = false;
246
262
  grnState.nodeColoring.bottomDataset = selection;
247
263
  }
248
264
  updateApp(grnState);
265
+ };
266
+
267
+ $(NODE_COLORING_TOGGLE_CLASS).click(() => {
268
+ grnState.nodeColoring.nodeColoringEnabled = !grnState.nodeColoring.nodeColoringEnabled;
269
+ updateApp(grnState);
249
270
  });
250
271
 
272
+ $(TOP_DATASET_SELECTION_SIDEBAR).change(() => {
273
+ const selection = $(TOP_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
274
+ updateTopDatasetSelection(selection);
275
+ });
276
+
277
+ $(TOP_DATASET_SELECTION_MENU).click((event) => {
278
+ const selection = event.target.dataset.expression;
279
+ updateTopDatasetSelection(selection);
280
+ });
251
281
  $(AVG_REPLICATE_VALS_TOP_SIDEBAR).change(() => {
252
282
  grnState.nodeColoring.averageTopDataset = !grnState.nodeColoring.averageTopDataset;
253
283
  updateApp(grnState);
@@ -259,28 +289,13 @@ export const setupHandlers = grnState => {
259
289
  });
260
290
 
261
291
  $(BOTTOM_DATASET_SELECTION_SIDEBAR).change(() => {
262
- var selection = $(BOTTOM_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
263
- grnState.nodeColoring.bottomDataset = selection;
264
- if (grnState.nodeColoring.bottomDataset === "Same as Top Dataset") {
265
- grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
266
- grnState.nodeColoring.bottomDataSameAsTop = true;
267
- } else {
268
- grnState.nodeColoring.bottomDataSameAsTop = false;
269
- }
270
- updateApp(grnState);
292
+ const selection = $(BOTTOM_DATASET_SELECTION_SIDEBAR).find(":selected").attr("value");
293
+ updateBottomDatasetSelection(selection);
271
294
  });
272
295
 
273
- $(BOTTOM_DATASET_SELECTION_MENU).click(() => {
274
- var selection = $(this).attr("value");
275
- grnState.nodeColoring.bottomDataset = selection;
276
- if (selection === "Same as Top Dataset") {
277
- grnState.nodeColoring.bottomDataset = grnState.nodeColoring.topDataset;
278
- grnState.nodeColoring.bottomDataSameAsTop = true;
279
- } else {
280
- grnState.nodeColoring.bottomDataSameAsTop = false;
281
- grnState.nodeColoring.bottomDataset = selection;
282
- }
283
- updateApp(grnState);
296
+ $(BOTTOM_DATASET_SELECTION_MENU).click((event) => {
297
+ const selection = event.target.dataset.expression;
298
+ updateBottomDatasetSelection(selection);
284
299
  });
285
300
 
286
301
  $(AVG_REPLICATE_VALS_BOTTOM_SIDEBAR).change(() => {
@@ -10,6 +10,11 @@ import {
10
10
  UNWEIGHTED_DEMO_NAME,
11
11
  SCHADE_INPUT_NAME,
12
12
  SCHADE_OUTPUT_NAME,
13
+ PPI_DEMO_PATH,
14
+ PPI_DEMO_NAME,
15
+ FORCE_GRAPH,
16
+ NETWORK_PPI_MODE,
17
+ NETWORK_GRN_MODE
13
18
  } from "./constants";
14
19
  import { getWorkbookFromForm, getWorkbookFromUrl } from "./api/grnsight-api";
15
20
 
@@ -19,6 +24,7 @@ const demoFiles = [
19
24
  WEIGHTED_DEMO_PATH,
20
25
  SCHADE_INPUT_PATH,
21
26
  SCHADE_OUTPUT_PATH,
27
+ PPI_DEMO_PATH
22
28
  ];
23
29
 
24
30
  const submittedFilename = ($upload) => {
@@ -133,9 +139,21 @@ export const setupLoadAndImportHandlers = (grnState) => {
133
139
  break;
134
140
  case SCHADE_OUTPUT_PATH:
135
141
  grnState.name = SCHADE_OUTPUT_NAME;
142
+ break;
143
+ case PPI_DEMO_PATH:
144
+ grnState.name = PPI_DEMO_NAME;
145
+ break;
136
146
  }
137
147
  }
138
148
  grnState.workbook = workbook;
149
+
150
+ if (grnState.name.includes(".sif")) {
151
+ grnState.mode = workbook.workbookType;
152
+ } else if (grnState.name.includes(".graphml")) {
153
+ grnState.mode = NETWORK_GRN_MODE;
154
+ } else {
155
+ grnState.mode = workbook.meta.data.workbookType;
156
+ }
139
157
  grnState.workbook.expressionNames = Object.keys(workbook.expression);
140
158
  if (uploadRoute !== "upload") {
141
159
  grnState.annotateLinks();
@@ -153,8 +171,8 @@ export const setupLoadAndImportHandlers = (grnState) => {
153
171
  * for helping to resolve this.
154
172
  */
155
173
 
156
- // $(".upload").change(uploadHandler(loadGrn));
157
174
  $("body").on("change", ".upload", uploadHandler(loadGrn));
175
+
158
176
  const loadDemo = (url, value) => {
159
177
  $("#demoSourceDropdown option[value='" + value.substring(1) + "']").prop(
160
178
  "selected",
@@ -162,14 +180,16 @@ export const setupLoadAndImportHandlers = (grnState) => {
162
180
  );
163
181
  loadGrn(url);
164
182
  reloader = () => loadGrn(url);
165
-
183
+ grnState.graphLayout = FORCE_GRAPH;
166
184
  $("a.upload > input[type=file]").val("");
167
185
  };
168
186
 
169
187
  const initializeDemoFile = (demoClass, demoPath, demoName) => {
170
- // Deleted parameter `event`
171
- $(demoClass).on("click", () => {
172
- loadDemo(demoPath, demoClass, demoName);
188
+ $(".dropdown-menu li a").on("click", (event) => {
189
+ const selected = event.target.dataset.expression;
190
+ if (`.${selected}` === demoClass) {
191
+ loadDemo(demoPath, demoClass, demoName);
192
+ }
173
193
  });
174
194
  $("#demoSourceDropdown").on("change", () => {
175
195
  const selected = `.${$("#demoSourceDropdown").val()}`;
@@ -200,11 +220,16 @@ export const setupLoadAndImportHandlers = (grnState) => {
200
220
  export const responseCustomWorkbookData = (grnState, queryURL, name) => {
201
221
  const uploadRoute = queryURL;
202
222
  getWorkbookFromUrl(uploadRoute).done((workbook) => {
223
+ if (workbook.meta.data.workbookType === NETWORK_PPI_MODE) {
224
+ grnState.mode = workbook.meta.data.workbookType;
225
+ } else {
226
+ grnState.mode = NETWORK_GRN_MODE;
227
+ }
203
228
  grnState.name = name;
204
229
  grnState.workbook = workbook;
205
230
  // Reset the node coloring dataset selection
206
- grnState.nodeColoring.topDataset = undefined;
207
- grnState.nodeColoring.bottomDataset = undefined;
231
+ grnState.nodeColoring.topDataset = grnState.defaultDataset;
232
+ grnState.nodeColoring.bottomDataset = grnState.defaultDataset;
208
233
  grnState.annotateLinks();
209
234
  disableUpload(false);
210
235
  updateApp(grnState);
@@ -1,6 +1,6 @@
1
1
  import { drawGraph, updaters } from "./graph";
2
2
  import { uploadState } from "./upload";
3
- import { displayWarnings } from "./warnings";
3
+ import { displayWarnings, displayPPINodeColorWarning } from "./warnings";
4
4
  import { max } from "d3-array";
5
5
  import { grnState } from "./grnstate";
6
6
 
@@ -45,12 +45,11 @@ import {
45
45
  CHARGE_SLIDER_SIDEBAR,
46
46
  CHARGE_MENU,
47
47
  CHARGE_VALUE,
48
- GRID_LAYOUT_MENU,
49
- FORCE_GRAPH_MENU,
50
48
  LAYOUT_SIDEBAR_PANEL,
51
49
  NODE_COLORING_MENU,
52
50
  NODE_COLORING_TOGGLE_MENU,
53
51
  NODE_COLORING_MENU_CLASS,
52
+ NODE_COLORING_NAVBAR_OPTIONS,
54
53
  NODE_COLORING_SIDEBAR_BODY,
55
54
  NODE_COLORING_SIDEBAR_PANEL,
56
55
  NODE_COLORING_SIDEBAR_HEADER_LINK,
@@ -104,6 +103,13 @@ import {
104
103
  VIEWPORT_SIZE_L_SIDEBAR,
105
104
  VIEWPORT_SIZE_FIT_SIDEBAR,
106
105
  VIEWPORT_INIT,
106
+ NETWORK_MODE_DROPDOWN,
107
+ NETWORK_MODE_CLASS,
108
+ NETWORK_MODE_PROTEIN_PHYS,
109
+ NETWORK_MODE_GRN,
110
+ EXPORT_TO_UNWEIGHTED_GML_MENU,
111
+ NETWORK_GRN_MODE,
112
+ NETWORK_PPI_MODE,
107
113
  // EXPRESSION_SOURCE,
108
114
  } from "./constants";
109
115
 
@@ -128,7 +134,6 @@ const refreshApp = () => {
128
134
 
129
135
  const displayworkbook = (workbook, name) => {
130
136
  uploadState.currentWorkbook = workbook;
131
- // console.log("workbook: ", workbook); // Display the workbook in the console
132
137
  $("#graph-metadata").html(workbook.genes.length + " nodes<br>" + workbook.links.length + " edges");
133
138
 
134
139
  if (workbook.warnings.length > 0) {
@@ -379,6 +384,14 @@ const enableNodeColoringUI = function () {
379
384
  $(LOG_FOLD_CHANGE_MAX_VALUE_HEADER).removeClass("hidden");
380
385
  };
381
386
 
387
+ const adjustGeneNameForExpression = function (gene) {
388
+ const geneName = gene.name;
389
+ return grnState.workbook.meta.data.workbookType === NETWORK_PPI_MODE &&
390
+ geneName.endsWith("p")
391
+ ? geneName.slice(0, -1)
392
+ : geneName;
393
+ };
394
+
382
395
  const loadExpressionDatabase = function (isTopDataset) {
383
396
  const dataset = isTopDataset ? grnState.nodeColoring.topDataset : grnState.nodeColoring.bottomDataset;
384
397
  startLoadingIcon();
@@ -389,7 +402,9 @@ const loadExpressionDatabase = function (isTopDataset) {
389
402
  queryExpressionDatabase({
390
403
  type:"ExpressionData",
391
404
  dataset,
392
- genes : grnState.workbook.genes.map(x => {return x.name;}).join(","),
405
+ genes: grnState.workbook.genes
406
+ .map(adjustGeneNameForExpression)
407
+ .join(","),
393
408
  timepoints: timepointsResponse[dataset]
394
409
  }).then(function (response) {
395
410
  if (isTopDataset) {
@@ -417,13 +432,11 @@ const loadExpressionDatabase = function (isTopDataset) {
417
432
  const updateSliderState = slidersLocked => {
418
433
  const forceGraphDisabled = grnState.graphLayout === GRID_LAYOUT || slidersLocked;
419
434
  if (forceGraphDisabled) {
420
- $(`${LOCK_SLIDERS_MENU} span`).removeClass("invisible").addClass("glyphicon-ok");
421
435
  $(RESET_SLIDERS_MENU).parent().addClass("disabled");
422
436
  $(UNDO_SLIDERS_RESET_MENU).parent().addClass("disabled");
423
437
  $(LINK_DIST_CLASS).parent().addClass("disabled");
424
438
  $(CHARGE_CLASS).parent().addClass("disabled");
425
439
  } else {
426
- $(`${LOCK_SLIDERS_MENU} span`).removeClass("glyphicon-ok").addClass("invisible");
427
440
  $(RESET_SLIDERS_MENU).parent().removeClass("disabled");
428
441
  $(UNDO_SLIDERS_RESET_MENU).parent().removeClass("disabled");
429
442
  $(LINK_DIST_CLASS).parent().removeClass("disabled");
@@ -433,6 +446,17 @@ const updateSliderState = slidersLocked => {
433
446
  $(LINK_DIST_SLIDER_SIDEBAR).prop("disabled", forceGraphDisabled);
434
447
  $(CHARGE_SLIDER_SIDEBAR).prop("disabled", forceGraphDisabled);
435
448
  $(RESET_SLIDERS_SIDEBAR).prop("disabled", forceGraphDisabled);
449
+
450
+ if (slidersLocked) {
451
+ $(`${LOCK_SLIDERS_MENU} span`)
452
+ .removeClass("invisible")
453
+ .addClass("glyphicon-ok");
454
+ } else {
455
+ $(`${LOCK_SLIDERS_MENU} span`)
456
+ .removeClass("glyphicon-ok")
457
+ .addClass("invisible");
458
+ }
459
+
436
460
  $(LOCK_SLIDERS_BUTTON).prop("checked", slidersLocked);
437
461
 
438
462
  if (!grnState.showUndoReset) {
@@ -488,15 +512,13 @@ const toggleLayout = (on, off) => {
488
512
  }
489
513
  };
490
514
 
491
- const updatetoForceGraph = () => {
492
- $(LOCK_SLIDERS_BUTTON).removeAttr("disabled");
493
- toggleLayout(FORCE_GRAPH_MENU, GRID_LAYOUT_MENU);
515
+ export const hasExpressionData = (sheets) => {
516
+ return Object.keys(sheets).some(property => property.match(ENDS_IN_EXPRESSION_REGEXP));
494
517
  };
495
518
 
496
- const updatetoGridLayout = () => {
497
- $(LOCK_SLIDERS_BUTTON).attr("disabled", true);
498
- toggleLayout(GRID_LAYOUT_MENU, FORCE_GRAPH_MENU);
499
- };
519
+ const updatetoForceGraph = () => {};
520
+
521
+ const updatetoGridLayout = () => {};
500
522
 
501
523
  // Node Coloring Functions
502
524
  const showNodeColoringMenus = () => {
@@ -510,8 +532,8 @@ const showNodeColoringMenus = () => {
510
532
  const disableNodeColoringMenus = () => {
511
533
  $(NODE_COLORING_SIDEBAR_PANEL).addClass("disabled");
512
534
  $(NODE_COLORING_SIDEBAR_PANEL).removeClass("in");
513
- $(NODE_COLORING_MENU).addClass("disabled");
514
535
  $(NODE_COLORING_MENU_CLASS).addClass("disabled");
536
+ $(NODE_COLORING_MENU).addClass("disabled");
515
537
  $(NODE_COLORING_SIDEBAR_HEADER_LINK).attr("data-toggle", "");
516
538
  };
517
539
 
@@ -519,18 +541,67 @@ const isNewWorkbook = (name) => {
519
541
  return grnState.nodeColoring.lastDataset === null || grnState.nodeColoring.lastDataset !== name;
520
542
  };
521
543
 
522
- const shortenExpressionSheetName = (name) => {
523
- return (name.length > MAX_NUM_CHARACTERS_DROPDOWN) ?
524
- (name.slice(0, MAX_NUM_CHARACTERS_DROPDOWN) + "...") : name;
544
+ // Workbook Mode Functions
545
+ const updateModeViews = () =>{
546
+ // Select correct dropdown item
547
+ $(`${NETWORK_MODE_DROPDOWN} option`).removeAttr("selected");
548
+ $(`${NETWORK_MODE_DROPDOWN} option[value="${grnState.mode}"]`).prop("selected", true);
549
+ // Select the correct menu items
550
+ $(`${NETWORK_MODE_CLASS} option`).removeAttr("checked");
551
+ if (grnState.mode === NETWORK_GRN_MODE) {
552
+ toggleLayout(NETWORK_MODE_GRN, NETWORK_MODE_PROTEIN_PHYS);
553
+ } else if (grnState.mode === NETWORK_PPI_MODE) {
554
+ toggleLayout(NETWORK_MODE_PROTEIN_PHYS, NETWORK_MODE_GRN);
555
+ }
525
556
  };
526
557
 
527
- const hasExpressionData = (sheets) => {
528
- for (var property in sheets) {
529
- if (property.match(ENDS_IN_EXPRESSION_REGEXP)) {
530
- return true;
531
- }
558
+ const checkWorkbookModeSettings = () => {
559
+ const hasExpression = hasExpressionData(grnState.workbook.expression);
560
+
561
+ if (grnState.mode === NETWORK_PPI_MODE || !hasExpression) {
562
+ grnState.nodeColoring.nodeColoringEnabled = false;
563
+ grnState.nodeColoring.showMenu = true;
564
+ grnState.colorOptimal = false;
565
+ showNodeColoringMenus();
566
+ hideEdgeWeightOptions();
567
+ updateModeViews();
568
+ } else if (grnState.mode === NETWORK_GRN_MODE) {
569
+ grnState.nodeColoring.nodeColoringEnabled = true;
570
+ grnState.nodeColoring.showMenu = true;
571
+ grnState.colorOptimal = true;
572
+ showNodeColoringMenus();
573
+ showEdgeWeightOptions();
574
+ updateModeViews();
532
575
  }
533
- return false;
576
+ };
577
+
578
+ $("body").on("click", () => {
579
+ if (grnState.mode === NETWORK_PPI_MODE) {
580
+ $(EXPORT_TO_UNWEIGHTED_GML_MENU).addClass("disabled");
581
+ } else if (grnState.mode === NETWORK_GRN_MODE) {
582
+ $(EXPORT_TO_UNWEIGHTED_GML_MENU).removeClass("disabled");
583
+ }
584
+ });
585
+
586
+ $(NETWORK_MODE_DROPDOWN).on("change", () => {
587
+ grnState.mode = $(NETWORK_MODE_DROPDOWN).val();
588
+ checkWorkbookModeSettings();
589
+ refreshApp();
590
+ });
591
+ $(NETWORK_MODE_PROTEIN_PHYS).on("click", () => {
592
+ grnState.mode = NETWORK_PPI_MODE;
593
+ checkWorkbookModeSettings();
594
+ refreshApp();
595
+ });
596
+ $(NETWORK_MODE_GRN).on("click", () => {
597
+ grnState.mode = NETWORK_GRN_MODE;
598
+ checkWorkbookModeSettings();
599
+ refreshApp();
600
+ });
601
+
602
+ const shortenExpressionSheetName = (name) => {
603
+ return (name.length > MAX_NUM_CHARACTERS_DROPDOWN) ?
604
+ (name.slice(0, MAX_NUM_CHARACTERS_DROPDOWN) + "...") : name;
534
605
  };
535
606
 
536
607
  const updateSpeciesMenu = () => {
@@ -628,7 +699,7 @@ const resetDatasetDropdownMenus = (workbook) => {
628
699
  var createHTMLforDataset = function (name) {
629
700
  return `
630
701
  <li class=\"dataset-option node-coloring-menu\" value=\"${name}\">
631
- <a>
702
+ <a data-expression=\"${name}\">
632
703
  <span class=\"glyphicon\"></span>
633
704
  &nbsp;${name}
634
705
  </a>
@@ -716,7 +787,7 @@ if (!grnState.genePageData.identified) {
716
787
 
717
788
  export const updateApp = grnState => {
718
789
  if (grnState.newWorkbook) {
719
- grnState.nodeColoring.nodeColoringEnabled = true;
790
+ checkWorkbookModeSettings();
720
791
  grnState.normalizationMax = max(grnState.workbook.positiveWeights.concat(grnState.workbook.negativeWeights));
721
792
  displayworkbook(grnState.workbook, grnState.name);
722
793
  expandLayoutSidebar();
@@ -813,6 +884,12 @@ export const updateApp = grnState => {
813
884
  $(NODE_COLORING_TOGGLE_SIDEBAR).prop("checked", true);
814
885
  $(LOG_FOLD_CHANGE_MAX_VALUE_CLASS).val(DEFAULT_MAX_LOG_FOLD_CHANGE);
815
886
  $(NODE_COLORING_SIDEBAR_BODY).removeClass("hidden");
887
+ $(NODE_COLORING_MENU).removeClass("hidden");
888
+ $(NODE_COLORING_NAVBAR_OPTIONS).removeClass("hidden");
889
+ if (grnState.mode === NETWORK_PPI_MODE) {
890
+ displayPPINodeColorWarning(grnState.ppiNodeColorWarningDisplayed);
891
+ grnState.ppiNodeColorWarningDisplayed = true;
892
+ }
816
893
  if (grnState.database.expressionDatasets.includes(grnState.nodeColoring.topDataset) &&
817
894
  grnState.workbook.expression[grnState.nodeColoring.topDataset] === undefined) {
818
895
  if ($(NODE_COLORING_TOGGLE_SIDEBAR).prop("checked")) {
@@ -840,6 +917,12 @@ export const updateApp = grnState => {
840
917
  grnState.nodeColoring.topDataset : "Dahlquist_2018_wt";
841
918
  grnState.nodeColoring.bottomDataset = grnState.nodeColoring.bottomDataset ?
842
919
  grnState.nodeColoring.bottomDataset : "Dahlquist_2018_wt";
920
+ $(NODE_COLORING_TOGGLE_SIDEBAR).prop("checked", true);
921
+ $(`${NODE_COLORING_TOGGLE_MENU} span`).addClass("glyphicon-ok");
922
+ $(NODE_COLORING_SIDEBAR_BODY).removeClass("hidden");
923
+ $(NODE_COLORING_MENU).removeClass("hidden");
924
+ $(NODE_COLORING_NAVBAR_OPTIONS).removeClass("hidden");
925
+ $(LOG_FOLD_CHANGE_MAX_VALUE_CLASS).val(DEFAULT_MAX_LOG_FOLD_CHANGE);
843
926
  $(LOG_FOLD_CHANGE_MAX_VALUE_CLASS).addClass("hidden");
844
927
  $(LOG_FOLD_CHANGE_MAX_VALUE_SIDEBAR_BUTTON).addClass("hidden");
845
928
  $(LOG_FOLD_CHANGE_MAX_VALUE_HEADER).addClass("hidden");
@@ -866,13 +949,21 @@ export const updateApp = grnState => {
866
949
  // Investigate why a timeout is required in order for node coloring to take place
867
950
  // successfully in this case.
868
951
  setTimeout(() => updaters.renderNodeColoring(), 250);
869
-
952
+ }
953
+ if (grnState.mode === NETWORK_PPI_MODE) {
954
+ displayPPINodeColorWarning(grnState.ppiNodeColorWarningDisplayed);
955
+ grnState.ppiNodeColorWarningDisplayed = true;
870
956
  }
871
957
  }
872
958
  } else if (grnState.workbook !== null && !grnState.nodeColoring.nodeColoringEnabled) {
873
959
  $(NODE_COLORING_SIDEBAR_BODY).addClass("hidden");
960
+ $(NODE_COLORING_MENU).addClass("disabled");
961
+ $(NODE_COLORING_NAVBAR_OPTIONS).addClass("hidden");
874
962
  $(`${NODE_COLORING_TOGGLE_MENU} span`).removeClass("glyphicon-ok");
875
963
  $(NODE_COLORING_TOGGLE_SIDEBAR).prop("checked", false);
964
+ if (grnState.mode === NETWORK_PPI_MODE) {
965
+ grnState.ppiNodeColorWarningDisplayed = false;
966
+ }
876
967
  }
877
968
 
878
969
  if (grnState.workbook !== null && grnState.workbook.sheetType === "weighted") {
@@ -943,4 +1034,4 @@ export const updateApp = grnState => {
943
1034
  };
944
1035
 
945
1036
 
946
- export { stopLoadingIcon, startLoadingIcon};
1037
+ export { stopLoadingIcon, startLoadingIcon, adjustGeneNameForExpression};