diff --git a/index.html b/index.html index 25ae1b37..fc7263e5 100644 --- a/index.html +++ b/index.html @@ -1,665 +1,456 @@ - + + + + FunMap Hierarchical Organization + + + + + - + input, + output { + display: inline-block; + font-size: 1em; + font-size: 1vw; + line-height: var(--leading); + font-family: var(--font); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 400; + box-sizing: border-box; + width: 100%; + height: 2.5rem; + margin-top: 0; + padding: 5px; + border: 2px solid var(--color-body); + border-radius: 0; + appearance: none; + } - -
-
-
Legend
-
Search
- -
-
- -

Visualize and interact with the hierarchical structure of FunMap.

Click on - collapsed nodes to view children. Hover over nodes to see more information about the module.

-

Legend

-
    -
  • Collapsed node
  • -
  • Expanded node
  • -
  • Fill Color - Signed log10 meta-p value
  • -
  • Edge Color - Cancer hallmark
  • -
+ button, + input[type="submit"], + input[type="button"], + input[type="reset"] { + width: auto; + height: 1.5em; + background-color: var(--color-secondary); + border: 2px solid transparent; + box-shadow: var(--color-body) 0 2px 0 0; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: var(--font); + font-size: 1em; + font-size: 1vw; + font-weight: 400; + line-height: 1; + margin-bottom: 1%; + margin-top: 0; + text-align: center; + vertical-align: 100%; + -moz-appearance: none; + -moz-osx-font-smoothing: grayscale; + padding: 1%; + } + button:hover, + input[type="submit"]:hover { + background: var(--color-secondary-hover); + } + + + + +
+
+
Legend
+
Search
+ -
-
-
-

Search for Module Containing Gene

- - - +
+
+ +

+ Visualize and interact with the hierarchical structure + of + FunMap.

+ Click on collapsed nodes to view children. Hover over + nodes to see more information about the module. +

+

Legend

+
    +
  • + + Collapsed node +
  • +
  • + + Expanded node +
  • +
  • Fill Color - Signed log10 meta-p value
  • +
  • Edge Color - Cancer hallmark
  • +
+
-
-
-
-
+
+
+

+ Search for Module Containing Gene +

+ + + +
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- - + container.style[direction] = closed_container_pos; + tab.style[direction] = closed_tab_pos; + }, + timeout, + timeout_id, + ); + }); + + // New event listener for handling the tab hover + tab.addEventListener("mouseenter", () => { + container.style[direction] = open_container_pos; + tab.style[direction] = open_tab_pos; + }); + }; + + registerMouseEvents( + legendContainer, + legendTabContainer, + legend_timeout, + "left", + "-22.2%", + "-1.15%", + "0", + "20.85%", + ); + registerMouseEvents( + searchContainer, + searchTabContainer, + search_timeout, + "right", + "-23.2%", + "-1.15%", + "0", + "21.85%", + ); + registerMouseEvents( + dagContainer, + dagTabContainer, + dag_timeout, + "right", + "-35.2%", + "-1.15%", + "0", + "33.95%", + ); + funmap(echarts); + + diff --git a/js/funmap.js b/js/funmap.js new file mode 100644 index 00000000..51545ca5 --- /dev/null +++ b/js/funmap.js @@ -0,0 +1,410 @@ +function uncollapse_children(node, valid_names) { + let collapseParent = valid_names.includes(node.name); + if (node.children && node.children.length > 0) { + let collapse_this_node = false; + for (let i = 0; i < node.children.length; i++) { + if (valid_names.includes(node.children[i].name)) { + x = uncollapse_children(node.children[i], valid_names); + node.children[i] = x[0]; + collapse_this_node = collapse_this_node || x[1]; + } + } + if (collapse_this_node) { + node.collapsed = false; + } + } + return [node, collapseParent]; +} + +function toTitleCase(str) { + return str.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); +} + +function funmap(echarts, config = {}) { + let gene_json = config.gene_json || "data/genes.json"; + let gene_element = config.gene_element || "genes"; + let gene_to_module_json = config.gene_to_module || "data/gene_to_module.json"; + let go_json = config.go_json || "data/go.json"; + let funmap_json = config.funmap_json || "data/funmap.json"; + let main_element = config.main_chart || "chart"; + let pie_element = config.pie_chart || "pie_chart"; + fetch(gene_json) + .then((res) => res.json()) + .then((gene_data) => { + genelist = document.getElementById(gene_element); + for (let i = 0; i < gene_data.length; i++) { + let option = document.createElement("option"); + option.value = gene_data[i]; + genelist.appendChild(option); + } + }) + .then(() => { + fetch(gene_to_module_json) + .then((res) => res.json()) + .then((gene_to_module) => { + fetch(go_json) + .then((res) => res.json()) + .then((go_data) => { + fetch(funmap_json) + .then((res) => res.json()) + .then((chartData) => { + var chartOptions = { + title: { + text: "FunMap Hierarchical Organization", + left: "center", + textStyle: { + fontSize: 30, + fontWeight: "bolder", + color: "#333", + }, + }, + tooltip: { + trigger: "item", + triggerOn: "mousemove", + formatter: function (params, ticket, callback) { + node_go = go_data[params.name]; + let hallmark_string = ""; + if ("hallmarks" in params.data) { + for ( + let i = 0; + i < params.data.hallmarks.length; + i++ + ) { + hallmark_string += + toTitleCase(params.data.hallmarks[i]) + ", "; + } + hallmark_string = hallmark_string.slice(0, -2); + } + + if (hallmark_string == "") { + hallmark_string = "No Hallmarks"; + } + var content = `

${params.name}

Cancer Hallmarks: ${hallmark_string}


Top GO Terms

GO CategoryGO IDNamep-Value
Biological Process${node_go["gobp"]["id"]}${node_go["gobp"]["name"]}${node_go["gobp"]["p"]}
Cellular Component${node_go["gocc"]["id"]}${node_go["gocc"]["name"]}${node_go["gocc"]["p"]}
Molecular Function${node_go["gomf"]["id"]}${node_go["gomf"]["name"]}${node_go["gomf"]["p"]}
`; + let el = document.createElement("div"); + el.innerHTML = content; + return el; + }, + }, + toolbox: { + show: true, + feature: { + restore: {}, + saveAsImage: {}, + }, + }, + series: [ + { + type: "tree", + roam: true, + name: "FunMap", + data: [chartData], + top: "10%", + bottom: "10%", + left: "10%", + right: "10%", + layout: "radial", + symbol: (_value, params) => { + node = params.data; + if ( + node.children && + node.children.length > 0 && + params.collapsed + ) { + return "diamond"; + } else { + return "circle"; + } + }, + + symbolSize: 20, + initialTreeDepth: 1, + label: { + position: "top", + verticalAlign: "middle", + align: "right", + fontSize: 12, + }, + leaves: { + label: { + position: "bottom", + verticalAlign: "middle", + align: "left", + }, + }, + animationDuration: 550, + animationDurationUpdate: 750, + lineStyle: { + width: 7, + color: "yellow", + }, + itemStyle: { + borderWidth: 1, + color: "yellow", + borderColor: "black", + }, + emphasis: { + focus: "ancestor", + }, + }, + ], + visualMap: { + type: "continuous", + min: -165, + max: 165, + seriesIndex: 0, + title: { + text: "Signed log10 meta-p", + left: "center", + top: "bottom", + }, + text: [ + "Signed log10 meta-p\n\nHigher in Tumor compared to Normal", + "Lower in Tumor compared to Normal", + ], + precision: 3, + inRange: { + color: [ + "#67001f", + "#b2182b", + "#d6604d", + "#f4a582", + "#fddbc7", + "#f7f7f7", + "#d1e5f0", + "#92c5de", + "#4393c3", + "#2166ac", + "#053061", + ].reverse(), + }, + }, + }; + + // Initialize the chart + var chart = echarts.init( + document.getElementById(main_element), + ); + chart.setOption(chartOptions); + window.addEventListener("resize", function () { + chart.resize(); + }); + + var pieChartDom = document.getElementById(pie_element); + var pie_chart = echarts.init(pieChartDom); + var option; + + option = { + title: { + text: "Hallmark Key", + left: "center", + }, + series: [ + { + animationDuration: 0, + animationDurationUpdate: 0, + name: "Hallmark Key", + type: "pie", + radius: ["40%", "70%"], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 10, + borderColor: "#fff", + borderWidth: 2, + }, + label: { + show: false, + position: "center", + }, + emphasis: { + animationDuration: 50, + label: { + show: true, + width: 200, + fontSize: 18, + fontWeight: "bold", + overflow: "break", + }, + }, + labelLine: { + show: false, + }, + // Think about making this not hard coded + data: [ + { + name: "EVADING GROWTH SUPPRESSORS", + value: 1, + itemStyle: { color: "rgba(96, 50, 2, 0.55)" }, + }, + { + name: "AVOIDING IMMUNE DESTRUCTION", + value: 1, + itemStyle: { color: "rgba(194, 0, 126, 0.55)" }, + }, + { + name: "ENABLING REPLICATIVE IMMORTALITY", + value: 1, + itemStyle: { color: "rgba(13, 104, 161, 0.55)" }, + }, + { + name: "TUMOR PROMOTING INFLAMMATION", + value: 1, + itemStyle: { color: "rgba(213, 101, 23, 0.55)" }, + }, + { + name: "ACTIVATING INVASION AND METASTASIS", + value: 1, + itemStyle: { color: "rgba(25, 23, 24, 0.55)" }, + }, + { + name: "INDUCING ANGIOGENESIS", + value: 1, + itemStyle: { color: "rgba(232, 35, 40, 0.55)" }, + }, + { + name: "GENOME INSTABILITY AND MUTATION", + value: 1, + itemStyle: { color: "rgba(21, 41, 132, 0.55)" }, + }, + { + name: "RESISTING CELL DEATH", + value: 1, + itemStyle: { color: "rgba(112, 125, 134, 0.55)" }, + }, + { + name: "DEREGULATING CELLULAR ENERGETICS", + value: 1, + itemStyle: { color: "rgba(106, 42, 133, 0.55)" }, + }, + { + name: "SUSTAINING PROLIFERATIVE SIGNALING", + value: 1, + itemStyle: { color: "rgba(21, 143, 72, 0.55)" }, + }, + { + name: "NONE", + value: 1, + itemStyle: { color: "rgba(220, 211, 182, 0.55)" }, + }, + ], + }, + ], + }; + + option && pie_chart.setOption(option); + + let dag = create_dag("dense_modules", "C195", "dag"); + let dag_chart = null; + dag.then((res) => { + dag_chart = res; + chart.on("mouseover", function (params) { + update_dag_chart(params.name); + }); + }); + + update_dag_chart = function (clique_id, gene = null) { + let res = update_dag( + dag_chart, + "hierarchal_modules", + clique_id, + ); + res.then((result) => { + if (!!result) { + dag_chart = result; + if (!has_shown_dag) { + dagTabContainer.style.display = "block"; + dagContainer.style.display = "block"; + has_shown_dag = true; + } + dagTabContainer.dispatchEvent(new Event("mouseenter")); + setTimeout(() => { + timeout_id += 1; + dagTabContainer.dispatchEvent( + new Event("mouseleave"), + ); + }, 1000); + if (gene != null) { + dag_chart.dispatchAction({ + type: "highlight", + seriesIndex: 0, + name: gene, + }); + } + } else { + dagTabContainer.style.display = "none"; + dagContainer.style.display = "none"; + dagContainer.style.right = "-35.2%"; // Hide + dagTabContainer.style.right = "-1.15%"; + has_shown_dag = false; + } + }); + }; + + function resize_pie_chart() { + pie_chart.resize({ + width: pieChartDom.clientWidth, + height: pieChartDom.clientHeight, + animation: { + duration: 500, + }, + }); + setTimeout(() => { + pie_chart.clear(); + pie_chart.setOption(option, true); + }, 1); + } + new ResizeObserver(resize_pie_chart).observe(pieChartDom); + pie_chart.on("mouseover", function (params) { + let indices = []; + for ( + let i = 0; + i < chartOptions.series[0].data[0].children.length; + i++ + ) { + if ( + chartOptions.series[0].data[0].children[i] + .hallmarks[0] == params.name + ) { + indices.push( + chartOptions.series[0].data[0].children[i].name, + ); + } else if ( + params.name == "NONE" && + chartOptions.series[0].data[0].children[i].hallmarks + .length == 0 + ) { + indices.push( + chartOptions.series[0].data[0].children[i].name, + ); + } + } + chart.dispatchAction({ + type: "highlight", + seriesIndex: 0, + name: indices, + }); + }); + let search_button = document.getElementById("search_button"); + search_button.addEventListener("click", function (e) { + let gene = document.getElementById("gene_search").value; + if (gene in gene_to_module) { + let modules = gene_to_module[gene]; + let node = chartOptions.series[0].data[0]; + node = uncollapse_children(node, modules)[0]; + let newChartOptions = chartOptions; + newChartOptions.series[0].data[0] = node; + chart.setOption(newChartOptions); + chart.dispatchAction({ + type: "highlight", + seriesIndex: 0, + name: modules, + }); + update_dag_chart(modules[modules.length - 1], gene); + } + }); + }); + }); + }); + }); +}