Skip to content

Commit 841d4e9

Browse files
committed
graphology removed
1 parent e4e3dc2 commit 841d4e9

File tree

5 files changed

+91
-78
lines changed

5 files changed

+91
-78
lines changed

app/tools/scaff_net/page.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import ScaffoldNetworkWholeGraph from "../../../components/tools/toolComp/Scaffo
66
import ScaffNetDets from "../../../components/tools/toolComp/ScaffNetDets";
77
import ScaffoldSettings from "../../../components/tools/toolComp/ScaffoldSettings";
88
import TargetContext from "../../../context/TargetContext";
9-
import { graph_molecule_image_generator } from "../../../components/utils/rdkit_loader";
9+
import { deserializeGraph, graph_molecule_image_generator } from "../../../components/utils/rdkit_loader";
1010
import RDKitContext from "../../../context/RDKitContext";
11-
import { MultiDirectedGraph } from "graphology";
1211
import { Tabs } from "@mantine/core";
1312

1413
export default function DisplayGraph() {
@@ -22,15 +21,15 @@ export default function DisplayGraph() {
2221
if (target.scaffold_network != "") {
2322
setLoaded(false);
2423
setTimeout(() => {
25-
let network_graph = new MultiDirectedGraph();
26-
network_graph.import(target.scaffold_network);
27-
let image_graph = graph_molecule_image_generator(rdkit, network_graph);
24+
// Replace graphology with plain object
25+
const network_graph = deserializeGraph(target.scaffold_network);
26+
const image_graph = graph_molecule_image_generator(rdkit, network_graph);
2827
setGraph(image_graph);
29-
}, 100)
28+
}, 100);
3029
setLoaded(true);
31-
setDefaultTab(1)
30+
setDefaultTab(1);
3231
}
33-
}, [])
32+
}, []);
3433

3534
if (!loaded) {
3635
return (

components/tools/toolComp/ScaffNetDets.tsx

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import React, { useState, useEffect } from "react";
22
import TagComponent from "../../ui-comps/Tags";
3-
import { subgraph } from "graphology-operators";
43
import ScaffoldNetworkWholeGraph from "./ScaffoldNetworkWholeGraph";
54
import { useDisclosure } from "@mantine/hooks";
65
import { Button, Card, Grid, Group, Modal } from "@mantine/core";
6+
import { ScaffoldGraph } from "../../../types/GraphData";
77

88
const GraphComponent: React.FC<any> = ({ graph }) => {
99
const [opened, { open, close }] = useDisclosure(false);
1010

1111
// Function to get nodes connected to a specific label in the graph
12-
function getNodesConnectedToLabel(graph, label) {
13-
const nodes = [];
14-
graph.forEachEdge((_, attributes, source, target) => {
15-
if (attributes.label === label) {
16-
nodes.push(parseInt(source));
17-
}
18-
});
19-
return nodes;
12+
function getNodesConnectedToLabel(graph: ScaffoldGraph, label: string) {
13+
return graph.edges
14+
.filter(e => e.label === label)
15+
.map(e => parseInt(e.source));
2016
}
2117

2218
// Update the display nodes array based on selected tags
@@ -37,10 +33,12 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
3733

3834
// Effect to update nodesArray and displayNodesArray when graph changes
3935
useEffect(() => {
40-
const tempNodesArray: { node: any, smiles: string, size: number, img: string }[] = [];
41-
graph.forEachNode((node, attributes) => {
42-
tempNodesArray.push({ node, smiles: attributes.smiles, size: attributes.molCounts, img: attributes.image });
43-
});
36+
const tempNodesArray = graph.nodes.map(node => ({
37+
node: node.id,
38+
smiles: node.smiles,
39+
size: node.molCounts,
40+
img: node.image,
41+
}));
4442
tempNodesArray.sort((a, b) => b.size - a.size);
4543
setNodesArray(tempNodesArray);
4644
setDisplayNodesArray(tempNodesArray);
@@ -78,8 +76,23 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
7876
};
7977

8078
const [subGraph, setGraph] = useState<any>();
79+
function getSubgraph(graph: ScaffoldGraph, nodeIds: string[]): ScaffoldGraph {
80+
const nodeIdSet = new Set(nodeIds);
81+
return {
82+
nodes: graph.nodes.filter(n => nodeIdSet.has(n.id)),
83+
edges: graph.edges.filter(e => nodeIdSet.has(e.source) && nodeIdSet.has(e.target)),
84+
};
85+
}
86+
// In filterNodes function:
8187
function filterNodes(nodeEnquired: string, attr, depthSet: number) {
82-
let filteredGraph = subgraph(graph, [nodeEnquired, ...graph.neighbors(nodeEnquired)]);;
88+
// Get neighbors (nodes connected to this node)
89+
const connectedNodeIds = new Set([nodeEnquired]);
90+
graph.edges.forEach(edge => {
91+
if (edge.source === nodeEnquired) connectedNodeIds.add(edge.target);
92+
if (edge.target === nodeEnquired) connectedNodeIds.add(edge.source);
93+
});
94+
95+
const filteredGraph = getSubgraph(graph, Array.from(connectedNodeIds));
8396
setGraph(filteredGraph);
8497
open();
8598
}

components/tools/toolComp/ScaffoldNetworkWholeGraph.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ const ScaffoldNetworkWholeGraph = ({ graph, imageSize = 120, width = 928, height
1111

1212
// Create a fake root node
1313
const fakeRoot = { id: 'fakeRoot', children: [] };
14-
const graph_ex = graph.export();
1514
const { nodes, links } = {
16-
nodes: [fakeRoot, ...graph_ex.nodes.map(n => ({ id: n.key, ...n.attributes }))],
17-
links: graph_ex.edges.map(e => ({
15+
nodes: [
16+
{ id: 'fakeRoot', children: [] },
17+
...graph.nodes.map(n => ({ id: n.id, ...n }))
18+
],
19+
links: graph.edges.map(e => ({
1820
source: e.source,
1921
target: e.target,
20-
...e.attributes
22+
...e
2123
}))
2224
};
2325

@@ -112,8 +114,8 @@ const ScaffoldNetworkWholeGraph = ({ graph, imageSize = 120, width = 928, height
112114
<ScaffEdgeLegend />
113115
<svg ref={svgRef} height="600px" width="100%" />
114116
</>
115-
116-
);
117+
118+
);
117119
};
118120

119121
export default ScaffoldNetworkWholeGraph;

components/tools/toolComp/ScaffoldSettings.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
graph_molecule_image_generator,
77
initRDKit,
88
scaffold_net_chunking_method,
9+
serializeGraph,
910
} from "../../utils/rdkit_loader";
1011

1112
import {
@@ -122,13 +123,10 @@ export default function ScaffoldSettings({ setGraph, setLoaded, activeTabChange
122123

123124
// Collect smiles and call your scaffold function
124125
const smiles_list = ligand.map((x: any) => x.canonical_smiles);
125-
126-
// NOTE: your original code had two calls; preserve behavior but await the chunked net
127126
const network_graph = scaffold_net_chunking_method(smiles_list, 600, rdkit, params);
128-
// you previously had another call with 50; if needed uncomment:
129-
// scaffold_net_chunking_method(smiles_list, 50, rdkit, params);
130127

131-
const serialised_graph = await network_graph.export();
128+
// Serialize as plain JSON
129+
const serialised_graph = serializeGraph(network_graph);
132130
await setTarget({ ...target, scaffold_network: serialised_graph });
133131

134132
const image_graph = graph_molecule_image_generator(rdkit, network_graph);

components/utils/rdkit_loader.ts

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import _ from "lodash";
2-
import { MultiDirectedGraph } from "graphology";
2+
import { GraphEdge, GraphNode, ScaffoldGraph } from "../../types/GraphData";
33

44
function colorOfEdge(edge: string) {
5-
if (edge === "Fragment") {
6-
return "#99ccff"; // Muted Blue
7-
} else if (edge === "Generic") {
8-
return "#ff9999"; // Muted Red
9-
} else if (edge === "GenericBond") {
10-
return "#99ff99"; // Muted Green
11-
} else if (edge === "RemoveAttachment") {
12-
return "#666666"; // Dark Gray
13-
} else {
14-
return "#cccc66"; // Muted Yellow
15-
}
5+
if (edge === "Fragment") return "#99ccff";
6+
if (edge === "Generic") return "#ff9999";
7+
if (edge === "GenericBond") return "#99ff99";
8+
if (edge === "RemoveAttachment") return "#666666";
9+
return "#cccc66";
1610
}
1711

18-
1912
export function molListFromSmiArray(smiArray, rdkit) {
2013
const molList = new rdkit.MolList();
2114
smiArray.forEach((smiName) => {
@@ -38,8 +31,9 @@ export function scaffold_net_chunking_method(
3831
params,
3932
) {
4033
var scaffold_net_ins = new rdkit.ScaffoldNetwork();
41-
scaffold_net_ins.set_scaffold_params(JSON.stringify(params))
34+
scaffold_net_ins.set_scaffold_params(JSON.stringify(params));
4235
let network;
36+
4337
for (let i = 0; i < array.length; i += chunkSize) {
4438
let smiles_mol_list;
4539
try {
@@ -54,69 +48,77 @@ export function scaffold_net_chunking_method(
5448
smiles_mol_list?.delete();
5549
}
5650
}
57-
5851
scaffold_net_ins?.delete();
59-
var graph = new MultiDirectedGraph();
60-
52+
53+
// Return plain object instead of graphology Graph
54+
const nodes: GraphNode[] = [];
6155
for (let i = 0; i < network.nodes.size(); i++) {
6256
try {
6357
var smiles_string = network.nodes.get(i);
64-
graph.addNode(i.toString(), {
65-
molCounts: network.molCounts.get(i),
58+
nodes.push({
59+
id: i.toString(),
6660
smiles: smiles_string,
61+
molCounts: network.molCounts.get(i),
6762
nodeType: array.includes(smiles_string) ? "whole" : "fragment",
6863
});
6964
} catch (e) {
70-
console.error("Error in adding node to graph: ", e);
65+
console.error("Error in adding node: ", e);
7166
}
7267
}
68+
69+
const edges: GraphEdge[] = [];
7370
for (let i = 0; i < network.edges.size(); i++) {
7471
try {
7572
let network_edge = network.edges.get(i);
76-
graph.addEdgeWithKey(
77-
i.toString(),
78-
network_edge.beginIdx,
79-
network_edge.endIdx,
80-
{
81-
label: network_edge.type,
82-
color: colorOfEdge(network_edge.type),
83-
},
84-
);
73+
edges.push({
74+
id: i.toString(),
75+
source: network_edge.beginIdx.toString(),
76+
target: network_edge.endIdx.toString(),
77+
label: network_edge.type,
78+
color: colorOfEdge(network_edge.type),
79+
});
8580
} catch (e) {
86-
console.error("Error in adding edge to graph: ", e);
81+
console.error("Error in adding edge: ", e);
8782
}
8883
}
89-
90-
return graph;
84+
85+
return { nodes, edges };
9186
}
9287

93-
export function graph_molecule_image_generator(rdkit, graph, svgSize = 120){
94-
let new_graph = graph;
95-
try{
96-
new_graph.forEachNode((node, attr) => {
97-
var mol = rdkit.get_mol(attr.smiles);
88+
export function graph_molecule_image_generator(rdkit, graphData, svgSize = 120) {
89+
try {
90+
graphData.nodes.forEach((node) => {
91+
var mol = rdkit.get_mol(node.smiles);
9892
var svg_string = mol.get_svg(svgSize, svgSize);
9993
var blob_link = new Blob([svg_string], { type: "image/svg+xml" });
100-
new_graph.setNodeAttribute(node, 'image', URL.createObjectURL(blob_link))
94+
node.image = URL.createObjectURL(blob_link);
10195
mol?.delete();
102-
})
103-
}catch(e){
104-
console.error(e)
96+
});
97+
} catch (e) {
98+
console.error(e);
10599
}
106-
return new_graph;
100+
return graphData;
101+
}
102+
103+
// Serialize plain object to JSON (works in workers)
104+
export function serializeGraph(graph: ScaffoldGraph) {
105+
return JSON.stringify(graph);
106+
}
107+
108+
// Deserialize from JSON
109+
export function deserializeGraph(json: string): ScaffoldGraph {
110+
return JSON.parse(json);
107111
}
108112

109113
export const initRDKit = (() => {
110114
let rdkitLoadingPromise: Promise<any>;
111-
112115
return (): Promise<any> => {
113116
if (!rdkitLoadingPromise) {
114117
rdkitLoadingPromise = new Promise((resolve, reject) => {
115118
const script = document.createElement("script");
116119
script.src = "/rdkit/RDKit_minimal.js";
117120
script.async = true;
118121
document.body.appendChild(script);
119-
120122
script.addEventListener("load", () => {
121123
globalThis
122124
.initRDKitModule()
@@ -129,7 +131,6 @@ export const initRDKit = (() => {
129131
});
130132
});
131133
}
132-
133134
return rdkitLoadingPromise;
134135
};
135136
})();

0 commit comments

Comments
 (0)