Skip to content

Commit

Permalink
Network graph (#782)
Browse files Browse the repository at this point in the history
* setup for vis-network

* suppress error

* wip - new graph component

* fit graph

* notes
  • Loading branch information
qu-y authored Nov 15, 2024
1 parent c86baad commit 78238d4
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 38 deletions.
14 changes: 6 additions & 8 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
let plugins = []
let plugins = [];

if (process.env.NODE_ENV === 'production') {
plugins.push('transform-remove-console')
if (process.env.NODE_ENV === "production") {
plugins.push("transform-remove-console");
}

module.exports = {
presets: [
'@vue/app'
],
plugins
}
presets: ["@vue/app", "@babel/preset-env"],
plugins,
};
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"tabix-reader": "^1.0.1",
"trapi-client": "^0.0.3",
"url-parse": "^1.5.10",
"vis-data": "^7.1.9",
"vis-network": "^9.1.9",
"vis-data": "7.1.6",
"vis-network": "9.1.6",
"vis-util": "^5.0.7",
"vue": "^2.7.16",
"vue-async-computed": "^3.9.0",
Expand All @@ -48,11 +48,12 @@
"yaml": "^1.10.2"
},
"devDependencies": {
"@babel/preset-env": "^7.23.8",
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@vue/babel-preset-app": "^4.5.19",
"@vue/cli-plugin-babel": "^4.5.19",
"@vue/cli-service": "^4.5.19",
"babel-loader": "^8.3.0",
"babel-loader": "^8.4.1",
"babel-plugin-transform-remove-console": "^6.9.4",
"cache-loader": "^4.1.0",
"eslint-config-prettier": "^8.10.0",
Expand Down
185 changes: 185 additions & 0 deletions src/components/NetworkGraph.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<template>
<div class="network-container">
<div
v-show="!loading && !stabilizing"
ref="networkContainer"
class="vis-network"
></div>
<div v-if="loading" class="loading">Loading data...</div>
<div v-if="stabilizing" class="stabilization-progress">
<div class="progress-bar">
<div
class="progress-fill"
:style="{ width: `${stabilizationProgress}%` }"
></div>
</div>
<div class="progress-text">
Stabilizing: {{ Math.round(stabilizationProgress) }}%
</div>
</div>
</div>
</template>
<script>
import Vue from "vue";
import { Network } from "vis-network";
import { DataSet } from "vis-data";
export default Vue.component("NetworkGraph", {
//props: phenotype, sigma and geneset size
data() {
return {
network: null,
loading: false,
stabilizing: false,
stabilizationProgress: 0,
nodes: new DataSet([]),
edges: new DataSet([]),
};
},
async mounted() {
await this.$nextTick();
await this.fetchGraphData();
},
beforeDestroy() {
if (this.network) {
this.network.destroy();
}
},
methods: {
async fetchGraphData() {
this.loading = true;
try {
const response = await fetch(
"https://bioindex-dev.hugeamp.org/api/bio/query/pigean-graph?q=T2D,2,small"
);
const data = await response.json();
this.nodes.clear();
this.edges.clear();
this.nodes.add(data.data[0].nodes);
this.edges.add(data.data[0].edges);
await this.$nextTick();
await this.initNetwork();
// Initial fit after data load
if (this.network) {
this.network.fit({
animation: false,
});
}
} catch (error) {
console.error("Error:", error);
} finally {
this.loading = false;
}
},
initNetwork() {
if (!this.$refs.networkContainer) return;
const container = this.$refs.networkContainer;
const data = {
nodes: this.nodes,
edges: this.edges,
};
const options = {
physics: {
enabled: true,
stabilization: {
enabled: true,
iterations: 100,
updateInterval: 50,
fit: true,
},
},
};
this.network = new Network(container, data, options);
// Add stabilization events
this.network.on("startStabilizing", () => {
this.stabilizing = true;
});
this.network.on("stabilizationProgress", (params) => {
this.stabilizationProgress =
(params.iterations / params.total) * 100;
});
this.network.on("stabilizationIterationsDone", () => {
this.stabilizing = false;
this.stabilizationProgress = 100;
this.network.setOptions({ physics: false });
// Final fit after stabilization with animation
setTimeout(() => {
if (this.network) {
this.network.fit({
animation: {
duration: 1000,
easingFunction: "easeInOutQuad",
},
scale: 1.2, // Zoom out slightly more
});
}
}, 500);
});
},
},
});
</script>

<style scoped>
.network-container {
position: relative;
width: 100%;
height: 400px;
}
.stabilization-progress {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
text-align: center;
background: rgba(255, 255, 255, 0.9);
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.progress-bar {
width: 100%;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
margin-bottom: 10px;
}
.progress-fill {
height: 100%;
background: #4caf50;
transition: width 0.3s ease;
}
.progress-text {
color: #333;
font-size: 14px;
}
.vis-network {
width: 100%;
height: 100%;
border: 1px solid #ddd;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
53 changes: 30 additions & 23 deletions src/views/PIGEAN/Phenotype/Template.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,18 @@

<div class="card mdkp-card">
<div class="card-body">
<h4 class="card-title">
Genes with genetic support
</h4>
<div style="margin-bottom: 1rem;">
<h4 class="card-title">Network Graph</h4>
<network-graph></network-graph>
</div>
</div>

<div class="card mdkp-card">
<div class="card-body">
<h4 class="card-title">Genes with genetic support</h4>
<div style="margin-bottom: 1rem">
Combined genetic support is composed of direct support
(from GWAS associations near the gene) and indirect support
(membership in gene sets with genetic support).
(from GWAS associations near the gene) and indirect
support (membership in gene sets with genetic support).
Units are log-odds of probability.
</div>
<criterion-function-group>
Expand Down Expand Up @@ -146,11 +151,11 @@
<h4 class="card-title">
Gene sets that affect genetic support
</h4>
<div style="margin-bottom: 1rem;">
Gene sets affect the log-odds of the probability
that a gene is involved in a trait. Effect sizes are
calculated for the gene set in isolation (marginal)
and in a joint model with all gene sets together (joint).
<div style="margin-bottom: 1rem">
Gene sets affect the log-odds of the probability that a
gene is involved in a trait. Effect sizes are calculated
for the gene set in isolation (marginal) and in a joint
model with all gene sets together (joint).
</div>
<criterion-function-group>
<filter-enumeration-control
Expand Down Expand Up @@ -210,31 +215,33 @@
</tooltip-documentation>
</h4>
<div>
Mechanisms are determined by latent factorization
of the membership matrix of significant genes and gene sets.
Mechanisms are determined by latent factorization of the
membership matrix of significant genes and gene sets.
</div>
<criterion-function-group>
<div class="col filter-col-md">
<div class="label">P-value (<=)</div>
<input type="number"
<input
type="number"
class="form-control"
v-model.lazy="$parent.heatmapMaxP"/>
v-model.lazy="$parent.heatmapMaxP"
/>
</div>
</criterion-function-group>
<heatmap
v-if="$store.state.pigeanTopPhewas.data.length > 0"
:heatmapData="$parent.heatmapData"
:renderConfig="$parent.heatmapConfig"
:sectionId="`${$store.state.phenotype.name}_topPhewas`"
>
>
</heatmap>
<pigean-table
v-if="$parent.plotReady"
:pigeanData="$store.state.pigeanFactor.data"
:config="$parent.factorTableConfig"
:phewasRenderConfig="$parent.renderConfig"
>
</pigean-table>
<pigean-table
v-if="$parent.plotReady"
:pigeanData="$store.state.pigeanFactor.data"
:config="$parent.factorTableConfig"
:phewasRenderConfig="$parent.renderConfig"
>
</pigean-table>
</div>
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/views/PIGEAN/Phenotype/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import FilterEnumeration from "@/components/criterion/FilterEnumeration.vue";
import FilterGreaterLess from "@/components/criterion/FilterGreaterLess.vue";
import FilterPValue from "@/components/criterion/FilterPValue.vue";
import TooltipDocumentation from "@/components/TooltipDocumentation.vue";
import NetworkGraph from "@/components/NetworkGraph.vue";
import { pageMixin } from "@/mixins/pageMixin.js";
new Vue({
store,
Expand All @@ -42,6 +43,7 @@ new Vue({
Heatmap,
ResearchHeatmap,
FilterPValue,
NetworkGraph,
},
mixins: [pageMixin],
data() {
Expand Down Expand Up @@ -415,8 +417,8 @@ new Vue({
let data = structuredClone(originalData);
let mechanisms = this.mechanismMap;
for (let i = 0; i < data.length; i++) {
let label = mechanisms[data[i].factor].label;
let score = mechanisms[data[i].factor].score;
let label = mechanisms[data[i].factor].label || "";
let score = mechanisms[data[i].factor].score || "";
data[i].mechanism = `${score}___${label}`;
}
return data;
Expand Down
18 changes: 17 additions & 1 deletion vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,6 @@ module.exports = {
});

// add the transform rule for bioindex
// Helen 2021-06-17
config.module.rules.push({
test: /bioIndexUtils\.js$/,
loader: "string-replace-loader",
Expand All @@ -389,6 +388,23 @@ module.exports = {
},
});

// Add the rule for handling .js files with babel-loader
config.module.rules.push({
test: /\.js$/,
include: [/node_modules\/vis-network/, /node_modules\/vis-data/],
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: ["@babel/plugin-transform-runtime"],
},
},
});
config.resolve.alias = {
...config.resolve.alias,
"vis-network": "vis-network/standalone/umd/vis-network.min.js",
"vis-data": "vis-data/standalone/umd/vis-data.min.js",
};
// create inline maps for dev builds
if (process.env.NODE_ENV !== "production") {
//config.devtool = "inline-source-map";
Expand Down

0 comments on commit 78238d4

Please sign in to comment.