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.
- package/.eslintrc.yml +4 -4
- package/.github/workflows/node.js.yml +35 -0
- package/README.md +1 -1
- package/database/README.md +218 -97
- package/database/constants.py +42 -0
- package/database/filter_update.py +168 -0
- package/database/grnsettings-database/README.md +52 -0
- package/database/grnsettings-database/schema.sql +4 -0
- package/database/loader.py +30 -0
- package/database/loader_update.py +36 -0
- package/database/network-database/scripts/generate_network.py +15 -23
- package/database/network-database/scripts/generate_new_network_version.py +17 -24
- package/database/protein-protein-database/README.md +71 -0
- package/database/protein-protein-database/schema.sql +37 -0
- package/database/protein-protein-database/scripts/generate_protein_network.py +227 -0
- package/database/protein-protein-database/scripts/remove_duplicates.sh +4 -0
- package/database/utils.py +418 -0
- package/package.json +3 -2
- package/server/app.js +2 -0
- package/server/config/config.js +4 -4
- package/server/controllers/additional-sheet-parser.js +2 -1
- package/server/controllers/constants.js +5 -0
- package/server/controllers/custom-workbook-controller.js +4 -3
- package/server/controllers/demo-workbooks.js +1462 -6
- package/server/controllers/export-constants.js +3 -2
- package/server/controllers/exporters/sif.js +6 -1
- package/server/controllers/exporters/xlsx.js +8 -3
- package/server/controllers/expression-sheet-parser.js +0 -6
- package/server/controllers/grnsettings-database-controller.js +17 -0
- package/server/controllers/importers/sif.js +30 -11
- package/server/controllers/network-database-controller.js +2 -2
- package/server/controllers/network-sheet-parser.js +54 -12
- package/server/controllers/protein-database-controller.js +18 -0
- package/server/controllers/sif-constants.js +11 -4
- package/server/controllers/spreadsheet-controller.js +44 -1
- package/server/controllers/workbook-constants.js +21 -4
- package/server/dals/expression-dal.js +4 -4
- package/server/dals/grnsetting-dal.js +49 -0
- package/server/dals/network-dal.js +14 -15
- package/server/dals/protein-dal.js +106 -0
- package/test/additional-sheet-parser-tests.js +1 -1
- package/test/export-tests.js +136 -9
- package/test/import-sif-tests.js +67 -13
- package/test/test.js +1 -1
- package/test-files/additional-sheet-test-files/optimization-parameters-default.xlsx +0 -0
- package/test-files/demo-files/18_proteins_81_edges_PPI.xlsx +0 -0
- package/test-files/expression-data-test-sheets/expression_sheet_missing_data_ok_export_exact.xlsx +0 -0
- package/web-client/config/config.js +4 -4
- package/web-client/public/js/api/grnsight-api.js +18 -3
- package/web-client/public/js/constants.js +27 -12
- package/web-client/public/js/generateNetwork.js +170 -72
- package/web-client/public/js/graph.js +424 -161
- package/web-client/public/js/grnsight.js +25 -4
- package/web-client/public/js/grnstate.js +4 -1
- package/web-client/public/js/iframe-coordination.js +3 -3
- package/web-client/public/js/setup-handlers.js +76 -61
- package/web-client/public/js/setup-load-and-import-handlers.js +32 -7
- package/web-client/public/js/update-app.js +119 -28
- package/web-client/public/js/upload.js +142 -85
- package/web-client/public/js/warnings.js +25 -0
- package/web-client/public/lib/bootstrap.file-input/bootstrap.file-input.js +0 -1
- package/web-client/public/stylesheets/grnsight.styl +40 -16
- package/web-client/views/components/demo.pug +7 -5
- package/web-client/views/upload.pug +64 -50
- package/database/network-database/scripts/filter_genes.py +0 -76
- package/database/network-database/scripts/loader.py +0 -79
- package/database/network-database/scripts/loader_updates.py +0 -99
|
@@ -37,8 +37,9 @@ module.exports = {
|
|
|
37
37
|
warningCode: "INCORRECT_NETWORK_SHEET_EXPORT_WARNING",
|
|
38
38
|
errorDescription: "GRNsight has detected that the 'network' sheet or the 'network_optimized_weights'" +
|
|
39
39
|
" sheet is improperly formattedPlease look over your exported workbook and ensure that network" +
|
|
40
|
-
" sheets have cell A1 as 'cols regulators/rows targets'
|
|
41
|
-
" conventions listed at:
|
|
40
|
+
" sheets have cell A1 as 'cols regulators/rows targets' or 'cols protein1/ rows protein2' exactly" +
|
|
41
|
+
" and all gene are using the naming conventions listed at:" +
|
|
42
|
+
" \nhttps://dondi.github.io/GRNsight/documentation.html."
|
|
42
43
|
},
|
|
43
44
|
// Missing Source Genes
|
|
44
45
|
MISSING_SOURCE_GENES_EXPORT_WARNING: {
|
|
@@ -7,7 +7,12 @@ var exportEdges = function (workbook, gene, geneIndex) {
|
|
|
7
7
|
if (link.source === geneIndex) {
|
|
8
8
|
result += [
|
|
9
9
|
gene.name,
|
|
10
|
-
workbook.sheetType === constants.
|
|
10
|
+
workbook.sheetType === constants.WEIGHTED ?
|
|
11
|
+
link.value : (workbook.meta) ?
|
|
12
|
+
(workbook.meta.data.workbookType === constants.NETWORK_PPI_MODE ?
|
|
13
|
+
"pp" : "pd") :
|
|
14
|
+
workbook.workbookType === constants.NETWORK_PPI_MODE ?
|
|
15
|
+
"pp" : "pd",
|
|
11
16
|
workbook.genes[link.target].name
|
|
12
17
|
].join("\t") + "\n";
|
|
13
18
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// const { meta } = require("eslint/lib/rules/*");
|
|
2
2
|
const xlsx = require("node-xlsx");
|
|
3
|
+
const { CELL_A1_GRN, CELL_A1_PPI, NETWORK_GRN_MODE } = require("../constants");
|
|
3
4
|
|
|
4
5
|
const buildGeneNameArray = function (genes) {
|
|
5
6
|
const geneNameArray = genes.map(gene => gene["name"]);
|
|
@@ -10,7 +11,7 @@ const createArrayWithZeroes = function (length) {
|
|
|
10
11
|
return Array.apply(null, Array(length)).map(() => 0);
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
const buildNetworkSheet = function (genes, links) {
|
|
14
|
+
const buildNetworkSheet = function (genes, links, workbookType) {
|
|
14
15
|
const geneNameArray = buildGeneNameArray(genes);
|
|
15
16
|
// The +1 to length is because we ALSO add the gene name to each of the network sheet arrays.
|
|
16
17
|
const networkSheet = genes.map(() => createArrayWithZeroes(genes.length + 1));
|
|
@@ -18,7 +19,11 @@ const buildNetworkSheet = function (genes, links) {
|
|
|
18
19
|
// Place the gene name in the beginning of the network sheet array.
|
|
19
20
|
// EX: ["CIN5", 0, 0, 1]
|
|
20
21
|
Object.keys(geneNameArray).forEach(index => networkSheet[index][0] = geneNameArray[index]);
|
|
21
|
-
|
|
22
|
+
if (workbookType === NETWORK_GRN_MODE) {
|
|
23
|
+
geneNameArray.unshift(CELL_A1_GRN);
|
|
24
|
+
} else {
|
|
25
|
+
geneNameArray.unshift(CELL_A1_PPI);
|
|
26
|
+
}
|
|
22
27
|
|
|
23
28
|
links.forEach((link) => {
|
|
24
29
|
networkSheet[link.target][link.source + 1] = link.value;
|
|
@@ -115,7 +120,7 @@ const buildXlsxSheet = function (workbook) {
|
|
|
115
120
|
{
|
|
116
121
|
"name": network,
|
|
117
122
|
"data": buildNetworkSheet(workbook.exportSheets.networks[network].genes,
|
|
118
|
-
workbook.exportSheets.networks[network].links)
|
|
123
|
+
workbook.exportSheets.networks[network].links, workbook.meta.data.workbookType)
|
|
119
124
|
}
|
|
120
125
|
);
|
|
121
126
|
}
|
|
@@ -154,17 +154,11 @@ module.exports = function (workbook) {
|
|
|
154
154
|
warnings: [],
|
|
155
155
|
errors: []
|
|
156
156
|
};
|
|
157
|
-
var expCount = 0;
|
|
158
157
|
|
|
159
158
|
workbook.forEach(function (sheet) {
|
|
160
159
|
if (isExpressionSheet(sheet.name)) {
|
|
161
160
|
output["expression"][sheet.name] = parseExpressionSheet(sheet);
|
|
162
|
-
expCount++;
|
|
163
161
|
}
|
|
164
162
|
});
|
|
165
|
-
|
|
166
|
-
if (expCount <= 0) {
|
|
167
|
-
addExpWarning(output, constants.warnings.missingExpressionWarning());
|
|
168
|
-
}
|
|
169
163
|
return output;
|
|
170
164
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
var grnsettingDal = require(__dirname + "/../dals/grnsetting-dal");
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module.exports = function (app) {
|
|
6
|
+
|
|
7
|
+
app.get("/grnsettingsdb", function (req, res) {
|
|
8
|
+
try {
|
|
9
|
+
return grnsettingDal.queryDefaultDataset(req, res);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
res.json({error: e.stack});
|
|
12
|
+
res.json({error: e.name});
|
|
13
|
+
res.json({error: e.message});
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -44,7 +44,7 @@ module.exports = function (sif) {
|
|
|
44
44
|
sifEntries.forEach(function (entry) {
|
|
45
45
|
if (entry.length > TARGET) {
|
|
46
46
|
if (!isNumber(entry[RELATIONSHIP])) {
|
|
47
|
-
if (entry[RELATIONSHIP] !== "pd") {
|
|
47
|
+
if (entry[RELATIONSHIP] !== "pd" && entry[RELATIONSHIP] !== "pp") {
|
|
48
48
|
unweightedRelationshipTypeErrorDetected = true;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -54,6 +54,25 @@ module.exports = function (sif) {
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
let hasNumbers = relationships.some(isNumber);
|
|
58
|
+
let allNumbers = relationships.every(isNumber);
|
|
59
|
+
|
|
60
|
+
let workbookType;
|
|
61
|
+
if (allNumbers) {
|
|
62
|
+
workbookType = constants.NETWORK_GRN_MODE;
|
|
63
|
+
} else {
|
|
64
|
+
let stringRelationships = relationships.filter(function (relationship) {
|
|
65
|
+
return !isNumber(relationship);
|
|
66
|
+
});
|
|
67
|
+
if (stringRelationships.every(rel => rel === "pp")) {
|
|
68
|
+
workbookType = constants.NETWORK_PPI_MODE;
|
|
69
|
+
} else if (stringRelationships.every(rel => rel === "pd")) {
|
|
70
|
+
workbookType = constants.NETWORK_GRN_MODE;
|
|
71
|
+
} else if (stringRelationships.every(rel => rel === "pp" || rel === "pd")) {
|
|
72
|
+
errors.push(sifConstants.errors.SIF_MIXED_RELATIONSHIP_TYPE_ERROR);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
57
76
|
if (unweightedRelationshipTypeErrorDetected) {
|
|
58
77
|
errors.push(sifConstants.errors.SIF_UNWEIGHTED_RELATIONSHIP_TYPE_ERROR);
|
|
59
78
|
}
|
|
@@ -62,9 +81,8 @@ module.exports = function (sif) {
|
|
|
62
81
|
errors.push(sifConstants.errors.SIF_MISSING_DATA_ERROR);
|
|
63
82
|
}
|
|
64
83
|
|
|
65
|
-
var hasNumbers = relationships.some(isNumber);
|
|
66
|
-
var allNumbers = relationships.every(isNumber);
|
|
67
84
|
return {
|
|
85
|
+
workbookType: workbookType,
|
|
68
86
|
sheetType: allNumbers ? constants.WEIGHTED : constants.UNWEIGHTED,
|
|
69
87
|
warnings: hasNumbers && !allNumbers ? constants.warnings.EDGES_WITHOUT_WEIGHTS : null,
|
|
70
88
|
errors: errors
|
|
@@ -77,7 +95,7 @@ module.exports = function (sif) {
|
|
|
77
95
|
|
|
78
96
|
var genes = [];
|
|
79
97
|
var links = [];
|
|
80
|
-
var
|
|
98
|
+
var workbookMeta = "unweighted";
|
|
81
99
|
|
|
82
100
|
var nullEntries = entries.filter(function (entry) {
|
|
83
101
|
return entry === null;
|
|
@@ -92,13 +110,13 @@ module.exports = function (sif) {
|
|
|
92
110
|
}
|
|
93
111
|
});
|
|
94
112
|
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
warnings.push(
|
|
113
|
+
workbookMeta = sifWorkbookType(entries);
|
|
114
|
+
if (workbookMeta.warnings) {
|
|
115
|
+
warnings.push(workbookMeta.warnings);
|
|
98
116
|
}
|
|
99
117
|
|
|
100
|
-
if (
|
|
101
|
-
|
|
118
|
+
if (workbookMeta.errors) {
|
|
119
|
+
workbookMeta.errors.forEach(function (error) {
|
|
102
120
|
errors.push(error);
|
|
103
121
|
});
|
|
104
122
|
}
|
|
@@ -117,7 +135,7 @@ module.exports = function (sif) {
|
|
|
117
135
|
source: sourceIndex,
|
|
118
136
|
target: targetIndex
|
|
119
137
|
};
|
|
120
|
-
if (
|
|
138
|
+
if (workbookMeta.sheetType === constants.WEIGHTED) {
|
|
121
139
|
link.value = +entry[RELATIONSHIP];
|
|
122
140
|
}
|
|
123
141
|
links.push(link);
|
|
@@ -133,7 +151,8 @@ module.exports = function (sif) {
|
|
|
133
151
|
links: links,
|
|
134
152
|
errors: errors,
|
|
135
153
|
warnings: warnings,
|
|
136
|
-
sheetType:
|
|
154
|
+
sheetType: workbookMeta.sheetType,
|
|
155
|
+
workbookType: workbookMeta.workbookType,
|
|
137
156
|
positiveWeights: [],
|
|
138
157
|
negativeWeights: [],
|
|
139
158
|
meta: {},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
var
|
|
2
|
+
var networkDal = require(__dirname + "/../dals/network-dal");
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
module.exports = function (app) {
|
|
6
6
|
|
|
7
7
|
app.get("/networkdb", function (req, res) {
|
|
8
8
|
try {
|
|
9
|
-
return
|
|
9
|
+
return networkDal.queryNetworkDatabase(req, res);
|
|
10
10
|
} catch (e) {
|
|
11
11
|
res.json({error: e.stack});
|
|
12
12
|
res.json({error: e.name});
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// var path = require("path");
|
|
3
3
|
// var demoWorkbooks = require(__dirname + "/demo-workbooks");
|
|
4
4
|
|
|
5
|
+
const { NETWORK_PPI_MODE, NETWORK_GRN_MODE, CELL_A1_GRN, CELL_A1_PPI } = require("./constants");
|
|
5
6
|
const { initWorkbook } = require("./helpers");
|
|
6
7
|
|
|
7
8
|
var semanticChecker = require(__dirname + "/semantic-checker");
|
|
8
9
|
|
|
9
10
|
var constants = require(__dirname + "/workbook-constants");
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
// const NETWORK_SHEET_NAMES = ["network", "network_optimized_weights"];
|
|
13
13
|
|
|
14
14
|
// const isNetworkSheet = (sheetName) => {
|
|
@@ -94,9 +94,26 @@ var parseNetworkSheet = function (sheet, network) {
|
|
|
94
94
|
var rowData = [];
|
|
95
95
|
|
|
96
96
|
// check for “cols regulators/rows targets” in cell A1
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
let cellA1 = "";
|
|
98
|
+
try {
|
|
99
|
+
cellA1 = sheet.data[0][0];
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const row = 0;
|
|
102
|
+
const column = 0;
|
|
103
|
+
addError(network, constants.errors.missingValueError(row, column));
|
|
104
|
+
return network;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// TODO There are now 2 valid values for cellA1. One indicates GRN, the other is PPI.
|
|
108
|
+
// If neither, then we continue with the warning.
|
|
109
|
+
|
|
110
|
+
// Depending on the value of cellA1, we want to make a new property `networkType` which
|
|
111
|
+
// will indicate the network type. THe web app then reads this to decide what to do next.
|
|
112
|
+
if (cellA1 !== CELL_A1_GRN && cellA1 !== CELL_A1_PPI) {
|
|
113
|
+
addWarning(
|
|
114
|
+
network,
|
|
115
|
+
constants.warnings.incorrectCellA1WorkbookWarning(sheet.name)
|
|
116
|
+
);
|
|
100
117
|
}
|
|
101
118
|
|
|
102
119
|
// Get Source Genes
|
|
@@ -275,27 +292,52 @@ var parseNetworkSheet = function (sheet, network) {
|
|
|
275
292
|
return semanticChecker(network);
|
|
276
293
|
};
|
|
277
294
|
|
|
295
|
+
/*
|
|
296
|
+
* This method detect the network type of the workbook file either grn or protein-protein-physical-interactions
|
|
297
|
+
* If cellA1 = "cols regulators/ row targets" -> workbookType = grn
|
|
298
|
+
* If cellA1 = "cols protein1/ rows protein2" -> workbookType = "protein-protein-physical-interaction"
|
|
299
|
+
* else undefined
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
exports.workbookType = function (workbookFile) {
|
|
303
|
+
let workbookType;
|
|
304
|
+
for (const sheet of workbookFile) {
|
|
305
|
+
if (sheet.name.toLowerCase() === "network") {
|
|
306
|
+
const cellA1 = sheet.data[0][0];
|
|
307
|
+
|
|
308
|
+
if (cellA1 === CELL_A1_GRN) {
|
|
309
|
+
workbookType = NETWORK_GRN_MODE;
|
|
310
|
+
} else if (cellA1 === CELL_A1_PPI) {
|
|
311
|
+
workbookType = NETWORK_PPI_MODE;
|
|
312
|
+
} else {
|
|
313
|
+
workbookType = undefined;
|
|
314
|
+
}
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return workbookType;
|
|
319
|
+
};
|
|
278
320
|
|
|
279
|
-
|
|
321
|
+
exports.networks = function (workbookFile) {
|
|
280
322
|
const networks = {
|
|
281
323
|
network: {},
|
|
282
324
|
networkOptimizedWeights: {},
|
|
283
325
|
networkWeights: {},
|
|
284
326
|
};
|
|
285
327
|
|
|
286
|
-
for (
|
|
328
|
+
for (const element of workbookFile) {
|
|
287
329
|
// === 'network' for backwards compatibility of test files
|
|
288
|
-
if (
|
|
330
|
+
if (element.name.toLowerCase() === "network") {
|
|
289
331
|
// Here we have found a network sheet containing simple data. We keep looking
|
|
290
332
|
// in case there is also a network sheet with optimized weights
|
|
291
|
-
networks.network = parseNetworkSheet(
|
|
292
|
-
} else if (
|
|
333
|
+
networks.network = parseNetworkSheet(element, initWorkbook({ sheetType: "unweighted" }));
|
|
334
|
+
} else if (element.name.toLowerCase() === "network_optimized_weights" ) {
|
|
293
335
|
// We found a network sheet with optimized weights, which is the ideal data source.
|
|
294
|
-
networks.networkOptimizedWeights = parseNetworkSheet(
|
|
336
|
+
networks.networkOptimizedWeights = parseNetworkSheet(element,
|
|
295
337
|
initWorkbook({ sheetType: "weighted" }));
|
|
296
|
-
} else if (
|
|
338
|
+
} else if (element.name.toLowerCase() === "network_weights") {
|
|
297
339
|
// We found a network_weights sheet to preserve existing network type sheet data
|
|
298
|
-
networks.networkWeights = parseNetworkSheet(
|
|
340
|
+
networks.networkWeights = parseNetworkSheet(element, initWorkbook({ sheetType: "weighted" }));
|
|
299
341
|
}
|
|
300
342
|
}
|
|
301
343
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
var proteinDal = require(__dirname + "/../dals/protein-dal");
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module.exports = function (app) {
|
|
6
|
+
|
|
7
|
+
app.get("/proteindb", function (req, res) {
|
|
8
|
+
try {
|
|
9
|
+
return proteinDal.queryProteinDatabase(req, res);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
res.json({error: e.stack});
|
|
12
|
+
res.json({error: e.name});
|
|
13
|
+
res.json({error: e.message});
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
};
|
|
@@ -13,10 +13,10 @@ module.exports = {
|
|
|
13
13
|
SIF_UNWEIGHTED_RELATIONSHIP_TYPE_ERROR: {
|
|
14
14
|
errorCode: "SIF_UNWEIGHTED_RELATIONSHIP_TYPE_ERROR",
|
|
15
15
|
possibleCause: "The SIF importer detects an unweighted network with an unsupported relationship type.",
|
|
16
|
-
suggestedFix: "SIF files accepted by GRNsight must use 'pd' as the text string for the
|
|
17
|
-
" type in unweighted networks. Please review the SIF input documentation.
|
|
18
|
-
" error may be have been caused by missing data in your file, which caused
|
|
19
|
-
" incorrectly interpret a source or target as the relationship."
|
|
16
|
+
suggestedFix: "SIF files accepted by GRNsight must use 'pd' or 'pp' as the text string for the" +
|
|
17
|
+
" relationship type in unweighted networks. Please review the SIF input documentation." +
|
|
18
|
+
" Additionally, this error may be have been caused by missing data in your file, which caused " +
|
|
19
|
+
"the importer to incorrectly interpret a source or target as the relationship."
|
|
20
20
|
},
|
|
21
21
|
|
|
22
22
|
SIF_MISSING_DATA_ERROR: {
|
|
@@ -32,5 +32,12 @@ module.exports = {
|
|
|
32
32
|
possibleCause: "GRNsight has detected stray data and/or extraneous blank rows in your SIF file. ",
|
|
33
33
|
suggestedFix: "Please review the data and delete extraneous data from the file."
|
|
34
34
|
},
|
|
35
|
+
|
|
36
|
+
SIF_MIXED_RELATIONSHIP_TYPE_ERROR: {
|
|
37
|
+
errorCode: "SIF_MIXED_RELATIONSHIP_TYPE_ERROR",
|
|
38
|
+
possibleCause: "The SIF importer detects a SIF file with mixed relationship types.",
|
|
39
|
+
suggestedFix: ["GRNsight only supports networks with a single relationship type.",
|
|
40
|
+
"Please review the relationships for consistency."].join(" ")
|
|
41
|
+
},
|
|
35
42
|
},
|
|
36
43
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
var multiparty = require("multiparty");
|
|
2
2
|
var xlsx = require("node-xlsx");
|
|
3
3
|
var path = require("path");
|
|
4
|
+
const { NETWORK_GRN_MODE, NETWORK_PPI_MODE } = require("./constants");
|
|
4
5
|
var parseAdditionalSheets = require(__dirname + "/additional-sheet-parser");
|
|
5
6
|
var parseExpressionSheets = require(__dirname + "/expression-sheet-parser");
|
|
6
7
|
var parseNetworkSheet = require(__dirname + "/network-sheet-parser");
|
|
@@ -21,6 +22,11 @@ var SPECIES = [
|
|
|
21
22
|
"Saccharomyces cerevisiae",
|
|
22
23
|
];
|
|
23
24
|
|
|
25
|
+
const WORKBOOK_TYPES = [
|
|
26
|
+
NETWORK_GRN_MODE,
|
|
27
|
+
NETWORK_PPI_MODE
|
|
28
|
+
];
|
|
29
|
+
|
|
24
30
|
var TAXON_ID = ["3702", "6293", "7227", "9606", "10090", "4932", "559292"];
|
|
25
31
|
|
|
26
32
|
var isExpressionSheet = function (sheetName) {
|
|
@@ -43,6 +49,15 @@ var doesSpeciesExist = function (speciesInfo) {
|
|
|
43
49
|
return false;
|
|
44
50
|
};
|
|
45
51
|
|
|
52
|
+
var supportWorkbookType = function (type) {
|
|
53
|
+
for (var t in WORKBOOK_TYPES) {
|
|
54
|
+
if (WORKBOOK_TYPES[t] === type) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
|
|
46
61
|
var addMessageToArray = function (messageArray, message) {
|
|
47
62
|
messageArray.push(message);
|
|
48
63
|
};
|
|
@@ -106,7 +121,8 @@ var crossSheetInteractions = function (workbookFile) {
|
|
|
106
121
|
|
|
107
122
|
// Refactored the parseNetworkSheet function to preserve all network type sheets including "network",
|
|
108
123
|
// "network_optimized_weights",and "network_weights" restructuring workbook object as a result
|
|
109
|
-
|
|
124
|
+
|
|
125
|
+
var networks = parseNetworkSheet.networks(workbookFile);
|
|
110
126
|
|
|
111
127
|
// Parse expression and 2-column data, then add to workbook object
|
|
112
128
|
// Eventually, will split this up into parsing for each type of sheet.
|
|
@@ -180,6 +196,20 @@ var crossSheetInteractions = function (workbookFile) {
|
|
|
180
196
|
}
|
|
181
197
|
}
|
|
182
198
|
|
|
199
|
+
additionalData.meta.data.workbookType = parseNetworkSheet.workbookType(workbookFile);
|
|
200
|
+
if (additionalData.meta.data.workbookType === undefined) {
|
|
201
|
+
addWarning(workbook, constants.warnings.noWorkbookTypeDetected);
|
|
202
|
+
additionalData.meta.data.workbookType = NETWORK_GRN_MODE;
|
|
203
|
+
} else if (!supportWorkbookType(additionalData.meta.data.workbookType)) {
|
|
204
|
+
addWarning(
|
|
205
|
+
workbook,
|
|
206
|
+
constants.warnings.unsupportedWorkbookTypeDetected(
|
|
207
|
+
additionalData.meta.data.workbookType
|
|
208
|
+
)
|
|
209
|
+
);
|
|
210
|
+
additionalData.meta.data.workbookType = NETWORK_GRN_MODE;
|
|
211
|
+
}
|
|
212
|
+
|
|
183
213
|
if (additionalData.meta.data.species === undefined && additionalData.meta.data.taxon_id === undefined) {
|
|
184
214
|
addWarning(workbook, constants.warnings.noSpeciesInformationDetected);
|
|
185
215
|
additionalData.meta.data.species = "Saccharomyces cerevisiae";
|
|
@@ -203,6 +233,11 @@ var crossSheetInteractions = function (workbookFile) {
|
|
|
203
233
|
// FUTURE IMPROVEMENT: not all expression sheets are specifically named 'wt_log2_expression.'
|
|
204
234
|
// We need to account for all the different possible expression sheet names.
|
|
205
235
|
if (expressionData) {
|
|
236
|
+
if (additionalData.meta.data.workbookType === constants.NETWORK_GRN_MODE) {
|
|
237
|
+
if (expressionData["expression"] && Object.keys(expressionData["expression"]).length === 0) {
|
|
238
|
+
addWarning(expressionData, constants.warnings.missingExpressionWarning());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
206
241
|
if (expressionData.errors !== undefined) {
|
|
207
242
|
expressionData.errors.forEach(data => workbook.errors.push(data));
|
|
208
243
|
}
|
|
@@ -411,6 +446,14 @@ module.exports = function (app) {
|
|
|
411
446
|
app
|
|
412
447
|
);
|
|
413
448
|
});
|
|
449
|
+
|
|
450
|
+
app.get("/demo/ppi", function (req, res) {
|
|
451
|
+
return demoWorkbooks(
|
|
452
|
+
"test-files/demo-files/18_proteins_81_edges_PPI.xlsx",
|
|
453
|
+
res,
|
|
454
|
+
app
|
|
455
|
+
);
|
|
456
|
+
});
|
|
414
457
|
}
|
|
415
458
|
|
|
416
459
|
// exporting parseNetworkSheet for use in testing. Do not remove!
|
|
@@ -102,7 +102,8 @@ module.exports = {
|
|
|
102
102
|
return {
|
|
103
103
|
warningCode: "MISLABELED_NETWORK_CELL_A1",
|
|
104
104
|
errorDescription: `The top left cell of the ${sheetName} sheet is mislabeled.
|
|
105
|
-
Replace the incorrect label with \'cols regulators/rows targets\'
|
|
105
|
+
Replace the incorrect label with \'cols regulators/ rows targets\' or \'cols
|
|
106
|
+
protein1/ rows protein2'\ exactly.`
|
|
106
107
|
};
|
|
107
108
|
},
|
|
108
109
|
|
|
@@ -178,8 +179,7 @@ module.exports = {
|
|
|
178
179
|
noSpeciesInformationDetected: {
|
|
179
180
|
warningCode: "MISSING_SPECIES_INFORMATION",
|
|
180
181
|
errorDescription: "No species information was detected in your input file." +
|
|
181
|
-
" GRNsight defaults to Saccharomyces cerevisiae.
|
|
182
|
-
" selection in the Species menu or panel."
|
|
182
|
+
" GRNsight defaults to Saccharomyces cerevisiae."
|
|
183
183
|
},
|
|
184
184
|
|
|
185
185
|
unknownSpeciesDetected: function (workbookSpecies, workbookTaxon) {
|
|
@@ -188,7 +188,24 @@ module.exports = {
|
|
|
188
188
|
errorDescription: "GRNsight detected the species " + workbookSpecies +
|
|
189
189
|
" and the taxon " + workbookTaxon + " in your input file." +
|
|
190
190
|
" This is not one of the supported species, or was formatted incorrectly" +
|
|
191
|
-
"
|
|
191
|
+
" GRNsight defaults to Saccharomyces cerevisiae."
|
|
192
|
+
};
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
noWorkbookTypeDetected : {
|
|
196
|
+
warningCode: "MISSING_WORKBOOK_TYPE_INFORMATION",
|
|
197
|
+
errorDescription: "No workbook type was detected in your input file." +
|
|
198
|
+
" GRNsight defaults to a gene regulatory network. You can change the workbook type" +
|
|
199
|
+
" selection in the Network menu or panel."
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
unsupportedWorkbookTypeDetected: function (workbookType) {
|
|
203
|
+
return {
|
|
204
|
+
warningCode: "UNKNOWN_WORKBOOK_TYPE_DETECTED",
|
|
205
|
+
errorDescription: "GRNsight detected the workbook type " + workbookType +
|
|
206
|
+
" in your input file. This is not one of the supported workbook types, or was formatted" +
|
|
207
|
+
" incorrectly. GRNsight defaults to a gene regulatory network. You can change the workbook type" +
|
|
208
|
+
" selection in the Network menu or panel."
|
|
192
209
|
};
|
|
193
210
|
},
|
|
194
211
|
|
|
@@ -4,8 +4,8 @@ var env = process.env.NODE_ENV || "development";
|
|
|
4
4
|
var config = require("../config/config")[env];
|
|
5
5
|
var sequelize = new Sequelize(
|
|
6
6
|
config.databaseName,
|
|
7
|
-
process.env.
|
|
8
|
-
process.env.
|
|
7
|
+
process.env.DB_USERNAME,
|
|
8
|
+
process.env.DB_PASSWORD,
|
|
9
9
|
{
|
|
10
10
|
host: config.databaseHost,
|
|
11
11
|
dialect: config.databaseDialect,
|
|
@@ -20,7 +20,7 @@ var sequelize = new Sequelize(
|
|
|
20
20
|
const buildExpressionGenesQuery = function (geneString) {
|
|
21
21
|
let genes = "";
|
|
22
22
|
let geneList = geneString.split(",");
|
|
23
|
-
geneList.forEach(x => genes += ( `(gene_expression.gene.display_gene_id
|
|
23
|
+
geneList.forEach(x => genes += ( `(LOWER(gene_expression.gene.display_gene_id) = LOWER(\'${x}\')) OR `));
|
|
24
24
|
return genes.substring(0, genes.length - 4);
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -62,7 +62,7 @@ const buildExpressionQuery = function (query) {
|
|
|
62
62
|
const listExpressionGeneData = function (gene, totalOutput) {
|
|
63
63
|
let listOfData = [];
|
|
64
64
|
totalOutput.forEach(function (x) {
|
|
65
|
-
if (x.display_gene_id === gene) {
|
|
65
|
+
if (x.display_gene_id.toLowerCase() === gene.toLowerCase()) {
|
|
66
66
|
listOfData.push(Number(x.expression));
|
|
67
67
|
}
|
|
68
68
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const Sequelize = require("sequelize");
|
|
2
|
+
require("dotenv").config();
|
|
3
|
+
var env = process.env.NODE_ENV || "development";
|
|
4
|
+
var config = require("../config/config")[env];
|
|
5
|
+
var sequelize = new Sequelize(
|
|
6
|
+
config.databaseName,
|
|
7
|
+
process.env.DB_USERNAME,
|
|
8
|
+
process.env.DB_PASSWORD,
|
|
9
|
+
{
|
|
10
|
+
host: config.databaseHost,
|
|
11
|
+
dialect: config.databaseDialect,
|
|
12
|
+
pool: {
|
|
13
|
+
max: 5,
|
|
14
|
+
min: 0,
|
|
15
|
+
idle: 10000
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const buildGetDefaultDataset = function () {
|
|
21
|
+
return `
|
|
22
|
+
SELECT grnsettings.expression_dataset FROM settings.grnsettings;`;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const DefaultDatasetToJSON = (totalOutput) => {
|
|
26
|
+
const JSONOutput = {
|
|
27
|
+
defaultDataset : []
|
|
28
|
+
};
|
|
29
|
+
for (let dataset of totalOutput) {
|
|
30
|
+
JSONOutput.defaultDataset.push(dataset.expression_dataset);
|
|
31
|
+
}
|
|
32
|
+
return JSONOutput;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
queryDefaultDataset: function (req, res) {
|
|
38
|
+
return sequelize.query(buildGetDefaultDataset(),
|
|
39
|
+
{ type: sequelize.QueryTypes.SELECT })
|
|
40
|
+
.then(function (stdname) {
|
|
41
|
+
const convertToJSON = {
|
|
42
|
+
"DefaultDataset" : () => DefaultDatasetToJSON(stdname)
|
|
43
|
+
};
|
|
44
|
+
const type = req.query.type;
|
|
45
|
+
return (Object.keys(convertToJSON).includes(type)) ? res.send(convertToJSON[type]()) :
|
|
46
|
+
res.status(500).send({ errors: "Something went wrong." });
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
2
1
|
const Sequelize = require("sequelize");
|
|
3
2
|
require("dotenv").config();
|
|
4
3
|
var env = process.env.NODE_ENV || "development";
|
|
5
4
|
var config = require("../config/config")[env];
|
|
6
5
|
var sequelize = new Sequelize(
|
|
7
6
|
config.databaseName,
|
|
8
|
-
process.env.
|
|
9
|
-
process.env.
|
|
7
|
+
process.env.DB_USERNAME,
|
|
8
|
+
process.env.DB_PASSWORD,
|
|
10
9
|
{
|
|
11
10
|
host: config.databaseHost,
|
|
12
11
|
dialect: config.databaseDialect,
|
|
@@ -19,14 +18,13 @@ var sequelize = new Sequelize(
|
|
|
19
18
|
);
|
|
20
19
|
|
|
21
20
|
const buildNetworkSourceQuery = function () {
|
|
22
|
-
return "SELECT * FROM gene_regulatory_network.source ORDER BY time_stamp;";
|
|
21
|
+
return "SELECT * FROM gene_regulatory_network.source ORDER BY time_stamp DESC;";
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
const buildNetworkGeneFromSourceQuery = function (gene
|
|
26
|
-
return `SELECT DISTINCT gene_id, display_gene_id FROM
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
(gene.gene_id = network.regulator_gene_id OR gene.gene_id = network.target_gene_id);`;
|
|
24
|
+
const buildNetworkGeneFromSourceQuery = function (gene) {
|
|
25
|
+
return `SELECT DISTINCT gene_id, display_gene_id FROM
|
|
26
|
+
gene_regulatory_network.gene WHERE (gene.gene_id ='${gene}'
|
|
27
|
+
OR gene.display_gene_id ='${gene}')`;
|
|
30
28
|
};
|
|
31
29
|
|
|
32
30
|
const buildNetworkGenesQuery = function (geneString) {
|
|
@@ -49,7 +47,7 @@ const buildGenerateNetworkQuery = function (genes, source, timestamp) {
|
|
|
49
47
|
const buildQueryByType = function (queryType, query) {
|
|
50
48
|
const networkQueries = {
|
|
51
49
|
"NetworkSource": () => buildNetworkSourceQuery(),
|
|
52
|
-
"NetworkGeneFromSource": () => buildNetworkGeneFromSourceQuery(query.gene
|
|
50
|
+
"NetworkGeneFromSource": () => buildNetworkGeneFromSourceQuery(query.gene),
|
|
53
51
|
"GenerateNetwork": () => buildGenerateNetworkQuery(query.genes, query.source, query.timestamp)
|
|
54
52
|
};
|
|
55
53
|
if (Object.keys(networkQueries).includes(query.type)) {
|
|
@@ -57,16 +55,17 @@ const buildQueryByType = function (queryType, query) {
|
|
|
57
55
|
}
|
|
58
56
|
};
|
|
59
57
|
|
|
58
|
+
// const response = convertResponseToJSON(req.query.type, req.query, stdname);
|
|
60
59
|
const convertResponseToJSON = function (queryType, query, totalOutput) {
|
|
61
60
|
let JSONOutput = {};
|
|
62
61
|
switch (queryType) {
|
|
63
62
|
case "NetworkSource":
|
|
64
63
|
JSONOutput.sources = {};
|
|
65
|
-
totalOutput.forEach(function (
|
|
66
|
-
const timestamp =
|
|
67
|
-
const source =
|
|
68
|
-
const displayName =
|
|
69
|
-
JSONOutput.sources[`${displayName}
|
|
64
|
+
totalOutput.forEach(function (connection) {
|
|
65
|
+
const timestamp = connection.time_stamp;
|
|
66
|
+
const source = connection.source;
|
|
67
|
+
const displayName = connection.display_name;
|
|
68
|
+
JSONOutput.sources[`${displayName}: ${timestamp.toISOString().split("T")[0]}`] = {timestamp, source};
|
|
70
69
|
});
|
|
71
70
|
return JSONOutput;
|
|
72
71
|
case "NetworkGeneFromSource":
|