Skip to content

Commit e14e86f

Browse files
committed
scaffold network parallelised
1 parent 841d4e9 commit e14e86f

File tree

10 files changed

+249
-157
lines changed

10 files changed

+249
-157
lines changed

app/tools/layout.tsx

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default function DashboardLayout({
3737
setRDKit(rdkitWorker);
3838
setPyodide(pyodideWorker);
3939
if (ligand.length < 1) {
40-
pushNotification({"message": "Data Loading Done!"});
40+
pushNotification({ "message": "Data Loading Done!" });
4141
router.push("/tools/load_data");
4242
}
4343
}, []);
@@ -55,66 +55,93 @@ export default function DashboardLayout({
5555
}, [notifications]);
5656

5757

58-
if (rdkit) {
59-
rdkit.onmessage = (event) => {
60-
const { message, id, error, ...data } = event.data;
58+
if (rdkit) {
59+
rdkit.onmessage = (event) => {
60+
const { message, id, error, ...data } = event.data;
6161

62-
// Handle simple string messages (progress, etc.)
63-
if (message && typeof message === 'string') {
64-
pushNotification({ message, autoClose: true, duration: 2000, id: id || undefined });
65-
return;
66-
}
67-
68-
// Handle errors
69-
if (error) {
70-
pushNotification({ message: `Error: ${error}`, type: 'error' });
71-
rdkit.terminate();
72-
return;
73-
}
62+
// Handle simple string messages (progress, etc.)
63+
if (message && typeof message === 'string') {
64+
pushNotification({ message, autoClose: true, duration: 2000, id: id || undefined });
65+
return;
66+
}
7467

75-
// Handle function results
76-
if (id && data.function) {
77-
switch (data.function) {
78-
case 'fingerprint':
79-
if (data.settings) {
80-
localStorage.setItem("fingerprint", data.settings.fingerprint);
81-
localStorage.setItem("path", data.settings.radius.toString());
82-
localStorage.setItem("nBits", data.settings.nBits.toString());
83-
}
84-
pushNotification({ message: "Molecule Pre-processing Done! Going to Activity Distribution Tool..." });
85-
setTimeout(() => {
68+
// Handle errors
69+
if (error) {
70+
pushNotification({ message: `Error: ${error}`, type: 'error' });
71+
rdkit.terminate();
72+
return;
73+
}
74+
// Handle function results
75+
if (id && data.function) {
76+
77+
switch (data.function) {
78+
case 'fingerprint':
79+
if (data.settings) {
80+
localStorage.setItem("fingerprint", data.settings.fingerprint);
81+
localStorage.setItem("path", data.settings.radius.toString());
82+
localStorage.setItem("nBits", data.settings.nBits.toString());
83+
}
84+
pushNotification({ message: "Molecule Pre-processing Done! Going to Activity Distribution Tool..." });
85+
setTimeout(() => {
86+
setLigand(data.data);
87+
setTarget({ ...target, activity_columns: data.activity_columns, pre_processed: true });
88+
router.push("/tools/activity");
89+
}, 200);
90+
break;
91+
92+
case 'mma':
93+
pushNotification({ message: "Massive Molecular Analysis Done! Going to Scaffold Analysis Tool..." });
94+
setTarget({ ...target, scaffCores: data.data });
95+
break;
96+
97+
case 'tanimoto':
98+
pushNotification({ message: "Tanimoto Similarity Calculation Done!" });
8699
setLigand(data.data);
87-
setTarget({ ...target, activity_columns: data.activity_columns, pre_processed: true });
88-
router.push("/tools/activity");
89-
}, 200);
90-
break;
91-
92-
case 'mma':
93-
pushNotification({ message: "Massive Molecular Analysis Done! Going to Scaffold Analysis Tool..." });
94-
setTarget({ ...target, scaffCores: data.data });
95-
break;
96-
97-
case 'tanimoto':
98-
pushNotification({ message: "Tanimoto Similarity Calculation Done!" });
99-
setLigand(data.data);
100-
break;
101-
102-
case 'only_fingerprint':
103-
setLigand(data.results);
104-
pushNotification({ message: "Fingerprints generated successfully!" });
105-
break;
106-
107-
case 'substructure_search':
108-
setLigand(data.results);
109-
pushNotification({ message: `Found ${data.results.length} matching substructures` });
110-
break;
111-
112-
default:
113-
console.warn('Unknown function:', data.function);
100+
break;
101+
102+
case 'only_fingerprint':
103+
// if (data.id.includes("ml_screen_")) {
104+
// // Handle ML screen fingerprints
105+
// if (data.function === "only_fingerprint") {
106+
// let mol_fp = data.results.map(x => x["fingerprint"]);
107+
// pyodide.postMessage({
108+
// id: "job-123",
109+
// opts: target.machine_learning_inference_type === "regression" ? 1 : 2,
110+
// fp: mol_fp,
111+
// func: "ml-screen"
112+
// })
113+
// pyodide.onmessage = async (event) => {
114+
// console.log("Received message from Pyodide:", event.data);
115+
// if (event.data.success == "ok") {
116+
// let fp_mols = event.data.results;
117+
// newScreenData = await newScreenData.map((x, i) => {
118+
// x["predictions"] = fp_mols[i];
119+
// return x
120+
// });
121+
// setScreenData(newScreenData);
122+
// pushNotification({ message: "ML Model run complete" });
123+
// }
124+
// }
125+
// }
126+
// }
127+
setLigand(data.results);
128+
pushNotification({ message: "Fingerprints generated successfully!" });
129+
break;
130+
131+
case 'substructure_search':
132+
setLigand(data.results);
133+
pushNotification({ message: `Found ${data.results.length} matching substructures` });
134+
break;
135+
case 'scaffold_network':
136+
pushNotification({ message: "Scaffold Network Generation Done!" });
137+
setTarget({ ...target, scaffold_network: data.data });
138+
break;
139+
default:
140+
console.warn('Unknown function:', data.function);
141+
}
114142
}
115-
}
116-
};
117-
}
143+
};
144+
}
118145

119146

120147
if (pyodide) {

app/tools/scaff_net/page.tsx

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"use client";
22

3-
import { useContext, useEffect, useState } from "react";
4-
import Loader from "../../../components/ui-comps/Loader";
3+
import { useContext, useEffect } from "react";
54
import ScaffoldNetworkWholeGraph from "../../../components/tools/toolComp/ScaffoldNetworkWholeGraph";
65
import ScaffNetDets from "../../../components/tools/toolComp/ScaffNetDets";
76
import ScaffoldSettings from "../../../components/tools/toolComp/ScaffoldSettings";
@@ -11,33 +10,18 @@ import RDKitContext from "../../../context/RDKitContext";
1110
import { Tabs } from "@mantine/core";
1211

1312
export default function DisplayGraph() {
14-
const [loaded, setLoaded] = useState(true);
15-
const [graph, setGraph] = useState<any>();
16-
const [defaultTab, setDefaultTab] = useState(0);
1713
const { target } = useContext(TargetContext);
1814
const { rdkit } = useContext(RDKitContext);
1915

20-
useEffect(() => {
21-
if (target.scaffold_network != "") {
22-
setLoaded(false);
23-
setTimeout(() => {
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);
27-
setGraph(image_graph);
28-
}, 100);
29-
setLoaded(true);
30-
setDefaultTab(1);
31-
}
32-
}, []);
33-
34-
if (!loaded) {
35-
return (
36-
<div className="tools-container">
37-
<Loader loadingText="Networking is hard..." />
38-
</div>
39-
);
40-
}
16+
// useEffect(() => {
17+
// if (target.scaffold_network != undefined) {
18+
// setTimeout(() => {
19+
// // Replace graphology with plain object
20+
// const network_graph = deserializeGraph(target.scaffold_network);
21+
// const image_graph = graph_molecule_image_generator(rdkit, network_graph);
22+
// }, 100);
23+
// }
24+
// }, []);
4125

4226
return (
4327
<div className="tools-container">
@@ -62,18 +46,15 @@ export default function DisplayGraph() {
6246

6347
<Tabs.Panel value="Network_Settings">
6448
<ScaffoldSettings
65-
setGraph={setGraph}
66-
setLoaded={setLoaded}
67-
activeTabChange={setDefaultTab}
6849
/>
6950
</Tabs.Panel>
7051

7152
<Tabs.Panel value="Network_Details">
72-
{graph != undefined && <ScaffNetDets graph={graph} />}
53+
{target.scaffold_network != undefined && <ScaffNetDets />}
7354
</Tabs.Panel>
7455

7556
<Tabs.Panel value="Whole_Network">
76-
{graph != undefined && <ScaffoldNetworkWholeGraph graph={graph} imageSize={200} />}
57+
{target.scaffold_network != undefined && <ScaffoldNetworkWholeGraph imageSize={200} />}
7758
</Tabs.Panel>
7859
</Tabs>
7960
</div >

app/tools/screen/layout.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export default function ScreenLayout({ children }) {
2121
const { pyodide } = useContext(PyodideContext);
2222
const { target } = useContext(TargetContext);
2323
let newScreenData = screenData;
24-
const requestId = `fingerprint_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
2524

2625
async function callofScreenFunction(data) {
2726
pushNotification({ message: "Running ML Model on Ligands" });
@@ -34,7 +33,7 @@ export default function ScreenLayout({ children }) {
3433

3534
rdkit.postMessage({
3635
function: 'only_fingerprint',
37-
id: requestId,
36+
id: `ml_screen_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
3837
mol_data: newScreenData,
3938
formStuff: {
4039
fingerprint: localStorage.getItem("fingerprint"),

components/tools/toolComp/ScaffNetDets.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import React, { useState, useEffect } from "react";
1+
import React, { useState, useEffect, useContext } from "react";
22
import TagComponent from "../../ui-comps/Tags";
33
import ScaffoldNetworkWholeGraph from "./ScaffoldNetworkWholeGraph";
44
import { useDisclosure } from "@mantine/hooks";
55
import { Button, Card, Grid, Group, Modal } from "@mantine/core";
66
import { ScaffoldGraph } from "../../../types/GraphData";
7+
import TargetContext from "../../../context/TargetContext";
78

8-
const GraphComponent: React.FC<any> = ({ graph }) => {
9+
const GraphComponent: React.FC<any> = () => {
910
const [opened, { open, close }] = useDisclosure(false);
11+
const { target } = useContext(TargetContext);
1012

1113
// Function to get nodes connected to a specific label in the graph
1214
function getNodesConnectedToLabel(graph: ScaffoldGraph, label: string) {
@@ -18,7 +20,7 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
1820
// Update the display nodes array based on selected tags
1921
function updateFilterFragments(tags: string) {
2022
if (tags !== 'All') {
21-
const nodesConnectedToConnectionLabel = getNodesConnectedToLabel(graph, tags);
23+
const nodesConnectedToConnectionLabel = getNodesConnectedToLabel(target.scaffold_network, tags);
2224
const newDisplayArray = nodesConnectedToConnectionLabel.map(index => nodesArray[index]);
2325
setDisplayNodesArray(newDisplayArray);
2426
} else {
@@ -33,7 +35,7 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
3335

3436
// Effect to update nodesArray and displayNodesArray when graph changes
3537
useEffect(() => {
36-
const tempNodesArray = graph.nodes.map(node => ({
38+
const tempNodesArray = target.scaffold_network.nodes.map(node => ({
3739
node: node.id,
3840
smiles: node.smiles,
3941
size: node.molCounts,
@@ -42,7 +44,7 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
4244
tempNodesArray.sort((a, b) => b.size - a.size);
4345
setNodesArray(tempNodesArray);
4446
setDisplayNodesArray(tempNodesArray);
45-
}, [graph]);
47+
}, [target.scaffold_network]);
4648

4749
// Constants for pagination
4850
const nodesPerPage = 12; // Adjust as needed
@@ -87,12 +89,12 @@ const GraphComponent: React.FC<any> = ({ graph }) => {
8789
function filterNodes(nodeEnquired: string, attr, depthSet: number) {
8890
// Get neighbors (nodes connected to this node)
8991
const connectedNodeIds = new Set([nodeEnquired]);
90-
graph.edges.forEach(edge => {
92+
target.scaffold_network.edges.forEach(edge => {
9193
if (edge.source === nodeEnquired) connectedNodeIds.add(edge.target);
9294
if (edge.target === nodeEnquired) connectedNodeIds.add(edge.source);
9395
});
9496

95-
const filteredGraph = getSubgraph(graph, Array.from(connectedNodeIds));
97+
const filteredGraph = getSubgraph(target.scaffold_network, Array.from(connectedNodeIds));
9698
setGraph(filteredGraph);
9799
open();
98100
}

components/tools/toolComp/ScaffoldNetworkWholeGraph.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
import React, { useEffect, useRef } from 'react';
1+
import React, { useContext, useEffect, useRef } from 'react';
22
import * as d3 from 'd3';
33
import ScaffEdgeLegend from './ScaffLegend';
4+
import TargetContext from '../../../context/TargetContext';
45

5-
const ScaffoldNetworkWholeGraph = ({ graph, imageSize = 120, width = 928, height = 680 }) => {
6+
const ScaffoldNetworkWholeGraph = ({ imageSize = 120, width = 928, height = 680, graph = null }) => {
67
const svgRef = useRef(null);
8+
9+
const { target } = useContext(TargetContext);
10+
11+
let graphData;
12+
13+
if (graph) {
14+
graphData = graph;
15+
} else {
16+
graphData = target.scaffold_network;
17+
}
718

819
useEffect(() => {
920
// Clear previous SVG elements
@@ -14,9 +25,9 @@ const ScaffoldNetworkWholeGraph = ({ graph, imageSize = 120, width = 928, height
1425
const { nodes, links } = {
1526
nodes: [
1627
{ id: 'fakeRoot', children: [] },
17-
...graph.nodes.map(n => ({ id: n.id, ...n }))
28+
...graphData.nodes.map(n => ({ id: n.id, ...n }))
1829
],
19-
links: graph.edges.map(e => ({
30+
links: graphData.edges.map(e => ({
2031
source: e.source,
2132
target: e.target,
2233
...e
@@ -107,7 +118,7 @@ const ScaffoldNetworkWholeGraph = ({ graph, imageSize = 120, width = 928, height
107118
.on("end", dragended);
108119
}
109120

110-
}, [graph, imageSize]); // Ensure the effect runs only when `graph` or `imageSize` changes
121+
}, [target.scaffold_network, imageSize]); // Ensure the effect runs only when `graph` or `imageSize` changes
111122

112123
return (
113124
<>

0 commit comments

Comments
 (0)