UNPKG

grnsight

Version:

Web app and service for visualizing models of gene regulatory networks

329 lines (320 loc) 17.1 kB
/* eslint-disable max-len */ import { CREATE_NETWORK_CLASS, CREATE_NETWORK_MODAL, NETWORK_PPI_MODE, NETWORK_GRN_MODE} from "./constants"; import { queryNetworkDatabase, queryProteinProteinDatabase, uploadCustomWorkbook } from "./api/grnsight-api"; import { grnState } from "./grnstate"; export const generateNetwork = function () { const GENE_EXCEPTIONS = { "DUR1,2" : "DUR12", "IMP2'" : "IMP21", "ARG5,6" : "ARG56", "ADE5,7" : "ADE57", "MF(ALPHA)1" : "YPL187W", "MF(ALPHA)2" : "YGL089C" }; const createHTMLforForm = (sources, source, networkType) => { const geneProtein = networkType === NETWORK_PPI_MODE ? "protein" : "gene"; let result = ` <div id=\'generateNetworkFormContainer\' '> <h2 id=\'generateNetwork\'>Generate Network</h2> <p>Warning: changing network type or source will clear the list of selected genes or proteins below.</p> <div class=\'form-group\' id=\'getNetworkTypeForm\'> <label for=\'network-type\' id=\'network-type-label\'>Network Type</label> <select class=\'network-dropdown btn btn-default\' id=\'network-type\'> <option value=\'grn\' ${geneProtein === "gene" ? "selected=\'true\'" : "" }>Gene Regulatory</option> <option value=\'protein-protein-physical-interaction\' ${geneProtein === "protein" ? "selected=\'true\'" : "" }>Protein-Protein Physical Interactions</option> </select> </div> <div class=\'form-group\' id=\'getNetworkSourceForm\'> <label for=\'network-source\' id=\'network-source-label\'>Network Source</label> <select class=\'network-dropdown btn btn-default\' id=\'network-source\'> `; if (sources.length !== 1) { for (let source in sources) { result += ` <option value=\'${sources[source]}\' ${source === sources[source] ? "\'selected=\'true" : "" }\'>${sources[source]}</option> `; } } else { result += ` <option value=\'${sources[0]}\' selected=\'true\' disabled hidden>${sources[0]}</option> `; } result += `</select> </div> <div class=\'form-group\' id=\'getNetworkGenesForm\'> <form id=\'getNetworkGenesForm\' class=\'NetworkGenesForm\' > <label for=\'network-search-bar\' id=\'network-source-label\'>Select ${geneProtein}</label> <input type=\'text\' id=\'network-search-bar\' name=\'network-search-bar\'></input> <button id=\'enter-search\' type=\'submit\' class=\'search-button btn btn-default\'> <span class=\'glyphicon glyphicon-search\'></span> </button> </form> </div> <div id=\'selected-genes-container\'> <p>Added ${geneProtein}s go below! Click on a ${geneProtein} to remove it.</p> <div id=\'selected-genes\'> </div> `; return result; }; const createGeneButtons = function () { let result = `<div id=\'selected-genes\'> <div id=\'custom-network-genes-container\'> `; for (let gene in grnState.customWorkbook.genes) { const primaryName = grnState.customWorkbook.type === NETWORK_GRN_MODE ? grnState.customWorkbook.genes[gene] : gene; const secondaryName = grnState.customWorkbook.type === NETWORK_GRN_MODE ? gene : `${grnState.customWorkbook.genes[gene].displayGeneID} | ${grnState.customWorkbook.genes[gene].geneID}`; result += ` <div class=\'custom-network-gene\' id=${gene}> <p class=\'custom-network-gene-display-id\'> ${primaryName} </p> <p class=\'custom-network-gene-id\'> (${secondaryName}) </p> </div> `; } result += "</div></div>"; return result; }; const displayCurrentGenes = function () { $("#selected-genes").remove(); $("#selected-genes-container").append(createGeneButtons()); for (let gene in grnState.customWorkbook.genes) { $(`#${gene}`).on("click", (ev) => { ev.stopPropagation(); $(`#${gene}`).remove(); delete grnState.customWorkbook.genes[gene]; }); } }; const validGene = function (gene) { if (/^[A-Z0-9_-]{1,12}$/.test(gene)) { return gene; } if (Object.keys(GENE_EXCEPTIONS).includes(gene)) { return GENE_EXCEPTIONS[gene]; } return ""; }; const addGene = function () { const userGeneProtein = grnState.customWorkbook.type === NETWORK_GRN_MODE ? "Gene" : "Protein"; const searchGeneProtein = `${$("#network-search-bar").val()}`; $("#network-search-bar").val(""); const geneProtein = validGene(searchGeneProtein.toUpperCase()); if (geneProtein === "") { alert(`${userGeneProtein}: "${searchGeneProtein}" is not to GRNsight specifications. ${userGeneProtein}s must be 12 characters or less, containing "-", "_", and alpha-numeric characters only`); } else { let source = grnState.customWorkbook.source; if (grnState.customWorkbook.type === NETWORK_GRN_MODE) { let headers = { type:"NetworkGeneFromSource", gene: geneProtein, source:grnState.customWorkbook.sources.geneRegulation[source].source, timestamp:grnState.customWorkbook.sources.geneRegulation[source].timestamp }; queryNetworkDatabase(headers).then(function (response) { if (response.geneId && response.displayGeneId ) { grnState.customWorkbook.genes[response.geneId] = response.displayGeneId; displayCurrentGenes(); } else { alert( `${userGeneProtein}: "${searchGeneProtein}" was not found in this database. Please check for any typos and try again.` ); } }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); } else if (grnState.customWorkbook.type === NETWORK_PPI_MODE) { let headers = { type:"NetworkFromGeneProtein", geneProtein: geneProtein, source:grnState.customWorkbook.sources.proteinProteinInteractions[source].source, timestamp:grnState.customWorkbook.sources.proteinProteinInteractions[source].timestamp }; queryProteinProteinDatabase(headers).then(function (response) { if (response.standardName && response.displayGeneId && response.geneId) { grnState.customWorkbook.genes[response.standardName] = {displayGeneID: response.displayGeneId, geneID: response.geneId}; displayCurrentGenes(); } else { alert( `${userGeneProtein}: "${searchGeneProtein}" was not found in this database. Please check for any typos and try again.` ); } }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); } } }; const createHTMLforModalButtons = () => { return ` <div id=\'generateNetworkFooter\' class=\'modal-footer-div\'> <div> <input type=\'button\' class=\'btn btn-default\' id=\'submit-network\' value=\'Generate Network\'/> <input type=\'button\' class=\'btn btn-default\' data-dismiss=\'modal\' value=\'Cancel\' /> </div> </div> `; }; const displayGenerateNetworkModal = function () { $("#generateNetworkFormContainer").remove(); $("#generateNetworkFooter").remove(); $("#generateNetworkFooter-container").append(createHTMLforModalButtons()); grnState.customWorkbook = { genes : {}, type: NETWORK_GRN_MODE, source : null, sources : { proteinProteinInteractions : null, geneRegulation: null } }; // get sources from database queryProteinProteinDatabase({type:"NetworkSource"}).then(function (response) { grnState.customWorkbook.sources.proteinProteinInteractions = response.sources; }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); queryNetworkDatabase({type:"NetworkSource"}).then(function (response) { grnState.customWorkbook.sources.geneRegulation = response.sources; grnState.customWorkbook.source = Object.keys(response.sources).length >= 1 ? Object.keys(response.sources)[0] : null; $("#generateNetworkQuestions-container").append(createHTMLforForm(Object.keys(response.sources), grnState.customWorkbook.source, grnState.customWorkbook.type)); }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); $(CREATE_NETWORK_MODAL).modal("show"); }; $("body").on("click", CREATE_NETWORK_CLASS, function (event) { event.preventDefault(); event.stopPropagation(); displayGenerateNetworkModal(); }); $("body").on("change", "#network-type", function (event) { grnState.customWorkbook.type = $("#network-type").val(); grnState.customWorkbook.genes = {}; if (grnState.customWorkbook.type === NETWORK_PPI_MODE) { grnState.customWorkbook.source = Object.keys(grnState.customWorkbook.sources.proteinProteinInteractions).length >= 1 ? Object.keys(grnState.customWorkbook.sources.proteinProteinInteractions)[0] : null; $("#generateNetworkFormContainer").remove(); $("#generateNetworkQuestions-container").append(createHTMLforForm(Object.keys(grnState.customWorkbook.sources.proteinProteinInteractions), grnState.customWorkbook.source, grnState.customWorkbook.type)); } else if (grnState.customWorkbook.type === NETWORK_GRN_MODE) { grnState.customWorkbook.source = Object.keys(grnState.customWorkbook.sources.proteinProteinInteractions).length >= 1 ? Object.keys(grnState.customWorkbook.sources.geneRegulation)[0] : null; $("#generateNetworkFormContainer").remove(); $("#generateNetworkQuestions-container").append(createHTMLforForm(Object.keys(grnState.customWorkbook.sources.geneRegulation), grnState.customWorkbook.source, grnState.customWorkbook.type)); } event.stopPropagation(); displayCurrentGenes(); }); $("body").on("change", "#network-source", function (event) { grnState.customWorkbook.source = $("#network-source").val(); grnState.customWorkbook.genes = {}; event.stopPropagation(); displayCurrentGenes(); }); $("body").on("click", "#submit-network", function () { let genesAmount = Object.keys(grnState.customWorkbook.genes).length; if (genesAmount === 0 ) { alert("Network must have at least 1 gene"); } else if (genesAmount > 75) { alert(`GRNsight is only capable of handling 75 genes at most. Your proposed network contains ${genesAmount} genes. Please remove some genes from your proposed network.`); } else { if (grnState.customWorkbook.type === NETWORK_GRN_MODE) { const genes = Object.keys(grnState.customWorkbook.genes); const displayGenes = Object.keys(grnState.customWorkbook.genes).map(g => grnState.customWorkbook.genes[g]); const source = grnState.customWorkbook.source; const headers = { type:"GenerateNetwork", genes: genes.join(","), source:grnState.customWorkbook.sources.geneRegulation[source].source, timestamp:grnState.customWorkbook.sources.geneRegulation[source].timestamp }; queryNetworkDatabase(headers).then(function (response) { grnState.customWorkbook.links = response.links; const links = Object.entries(grnState.customWorkbook.links); const genesAmount = genes.length; const edgesAmount = links.flatMap( (entry) => entry[1].map((target) => [entry[0], target])).length; if (edgesAmount > 100) { alert(`GRNsight is only capable of handling 100 edges at most. Your proposed network contains ${edgesAmount} regulatory connections. Please remove some genes from your proposed network.`); } else { const name = `GRN (${grnState.customWorkbook.source}; ${genesAmount} genes, ${edgesAmount} edges)`; const l = []; for (let link of links) { const r = link[0]; for (let t of link[1]) { l.push(`${grnState.customWorkbook.genes[r]}->${grnState.customWorkbook.genes[t]}`); } } const workbook = {name, genes: displayGenes, links : l.join(","), networkType: grnState.customWorkbook.type}; uploadCustomWorkbook(workbook, grnState); $(CREATE_NETWORK_MODAL).modal("hide"); } }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); } else if (grnState.customWorkbook.type === NETWORK_PPI_MODE) { const proteins = Object.keys(grnState.customWorkbook.genes); const source = grnState.customWorkbook.source; const headers = { type:"GenerateProteinNetwork", proteins: proteins.join(","), source:grnState.customWorkbook.sources.proteinProteinInteractions[source].source, timestamp:grnState.customWorkbook.sources.proteinProteinInteractions[source].timestamp }; queryProteinProteinDatabase(headers).then(function (response) { grnState.customWorkbook.links = response.links; const links = Object.entries(grnState.customWorkbook.links); const proteinsAmount = proteins.length; const edgesAmount = links.flatMap( (entry) => entry[1].map((target) => [entry[0], target])).length; if (edgesAmount > 100) { alert(`GRNsight is only capable of handling 100 edges at most. Your proposed network contains ${edgesAmount} physical interactions. Please remove some proteins from your proposed network.`); } else { const name = `Protein-Protein-Physical Interaction Network (${grnState.customWorkbook.source}; ${proteinsAmount} proteins, ${edgesAmount} edges)`; const l = []; for (let link of links) { const p1 = link[0]; for (let p2 of link[1]) { l.push(`${p1}->${p2}`); } } const workbook = {name, genes: proteins, links : l.join(","), networkType: grnState.customWorkbook.type}; uploadCustomWorkbook(workbook, grnState); $(CREATE_NETWORK_MODAL).modal("hide"); } }).catch(function (error) { console.log(error.stack); console.log(error.name); console.log(error.message); }); } } }); $("body").on("click", "#enter-search", function (event) { try { event.preventDefault(); event.stopPropagation(); addGene(); } catch (error) { console.log(error); } }); };