Skip to content

Commit

Permalink
an attempt at SDF File parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
syedzayyan committed May 27, 2024
1 parent 74a5fc8 commit 6870fd0
Show file tree
Hide file tree
Showing 14 changed files with 397 additions and 146 deletions.
2 changes: 1 addition & 1 deletion app/tools/activity/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function Activity() {
return (
<div className="tools-container">
<Histogram data={data} xLabel={target.activity_columns[0]} yLabel="Count" toolTipData={ligand}>
<span>Mean : {round(mean(data), 2) } || Median : {round(median(data), 2)} || Mode : {round(mode(data), 2)}</span>
<span>Mean : {round(mean(data), 2) || ""} || Median : {round(median(data), 2) || ""} || Mode : {round(mode(data), 2) || ""}</span>
</Histogram>
</div>
)
Expand Down
21 changes: 13 additions & 8 deletions app/tools/ml/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,20 @@ export default function MLLayout({ children }) {
</MLResultsContext.Provider>
{screenData.length > 0 && (
<>
<input style={{ width: "40%" }} className="input" onChange={(e) => setOneOffSmiles(e.target.value)} placeholder="Input Your SMILES string here"></input>
&nbsp;
<Dropdown buttonText="Draw the molecule">
<JSME width="300px" height="300px" onChange={(smiles) => setOneOffSmiles(smiles)} id="jsme_comp_1" />
</Dropdown>
&nbsp;
<button className="button" onClick={oneOffPred}>Predict Activity of SMILES</button>
<br />
<span>Predicted {target.activity_columns[0]}: {oneOffSMILESResult}</span>
<div style={{ borderColor: "10px solid black", margin: "20px 0", gap: "10px" }}>
<h2>Predict the activity of a single molecule</h2>
<input style={{ width: "40%" }} className="input" onChange={(e) => setOneOffSmiles(e.target.value)} placeholder="Input Your SMILES string here"></input>
<br />
<Dropdown buttonText="Draw the molecule">
<JSME width="300px" height="300px" onChange={(smiles) => setOneOffSmiles(smiles)} id="jsme_comp_1" />
</Dropdown>
<br />
<button className="button" onClick={oneOffPred}>Predict Activity of SMILES</button>
<br />
<span>Predicted {target.activity_columns[0]}: {oneOffSMILESResult}</span>
</div>

<GroupedBarChart mae={screenData[0]} r2={screenData[1]}>
<span>Mean MAE: {round(mean(screenData[0]), 2)} || Mean R-Squared: {round(mean(screenData[1]), 2)}</span>
</GroupedBarChart>
Expand Down
52 changes: 45 additions & 7 deletions app/tools/toc/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
"use client"

import { useContext } from "react";
import { useContext, useState } from "react";
import Table from "../../../components/ui-comps/PaginatedTables";
import LigandContext from "../../../context/LigandContext";
import { usePapaParse } from 'react-papaparse';
import TargetContext from "../../../context/TargetContext";
import JSME from "../../../components/tools/toolViz/JSMEComp";
import Dropdown from "../../../components/tools/toolViz/DropDown";
import RDKitContext from "../../../context/RDKitContext";
import { isEmpty } from "lodash";

export default function TOC(){
export default function TOC() {
const { ligand } = useContext(LigandContext);
const { target } = useContext(TargetContext);
const { jsonToCSV } = usePapaParse();
const { rdkit } = useContext(RDKitContext);


const [searchSmi, setSearchSmi] = useState('');
const [searchRes, setSearchRes] = useState(ligand);

const results = jsonToCSV(ligand, { delimiter: ';' });

function downloadCSV(csv: any){
function downloadCSV(csv: any) {
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
Expand All @@ -22,11 +33,38 @@ export default function TOC(){
a.click();
document.body.removeChild(a);
}

return(

function searchSubst() {
let searchResults = [];
let query = rdkit.get_mol(searchSmi);
ligand.map((lig) => {
let mol = rdkit.get_mol(lig.canonical_smiles);
let substructRes = mol.get_substruct_match(query);
var substructResJson = JSON.parse(substructRes);
if (!isEmpty(substructResJson)){
searchResults.push(lig);
}
mol.delete();
})
query.delete();
setSearchRes(searchResults);
}


return (
<div className="tools-container">
<button className="button" onClick={() => downloadCSV(results)}>Download Ligand Data as CSV</button>
<Table data = {ligand} rowsPerPage={30}/>
<div >
<button className="button" onClick={() => downloadCSV(results)}>Download Ligand Data as CSV</button>
<br />
<input className = "input" type="text" placeholder="Search By Substructure/SMILES" onChange={(e) => setSearchSmi(e.target.value)}/>
&nbsp;
<Dropdown buttonText="Draw the molecule">
<JSME width="300px" height="300px" onChange={(smiles) => setSearchSmi(smiles)} id="jsme_comp_2" />
</Dropdown>
&nbsp;
<button className="button" onClick={() => searchSubst()}>Substructure Search molecule</button>
</div>
<Table data={searchRes} rowsPerPage={30} act_column={target.activity_columns} />
</div>
)
}
16 changes: 12 additions & 4 deletions components/dataloader/DataLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useRouter } from "next/navigation";
import ErrorContext from "../../context/ErrorContext";
import ModalComponent from "../ui-comps/ModalComponent";
import TabWrapper, { Tabs } from "../ui-comps/TabbedComponents";
import SDFFileLoader from "./SDFFileLoader";

export default function DataLoader() {
const { ligand, setLigand } = useContext(LigandContext);
Expand Down Expand Up @@ -59,13 +60,20 @@ export default function DataLoader() {
<div>
<TabWrapper>
<Tabs title="ChEMBL">
<TargetGetter />
<TargetGetter />
</Tabs>
<Tabs title="External File (CSV)">
<CSVLoader callofScreenFunction={onSubmit} csvSetter={setLigand} />
<Tabs title="External File">
<TabWrapper>
<Tabs title="Upload CSV">
<CSVLoader callofScreenFunction={onSubmit} csvSetter={setLigand} />
</Tabs>
<Tabs title="Upload SDF">
<SDFFileLoader />
</Tabs>
</TabWrapper>
</Tabs>
<Tabs title="QITB JSON">
<LoadFromWork />
<LoadFromWork />
</Tabs>
</TabWrapper>
</div>
Expand Down
3 changes: 2 additions & 1 deletion components/dataloader/DataPreProcessToolKit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type FingerPrintSettings = {
const DataPreProcessToolKit = () => {
const [loaded, setLoaded] = useState(true);
const [stage, setStage] = useState('choose'); // Initial stage is 'choose'
const [selection, setSelection] = useState(null);
const [selection, setSelection] = useState('express');
const { ligand, setLigand } = useContext(LigandContext);
const { rdkit } = useContext(RDKitContext);
const { target, setTarget } = useContext(TargetContext);
Expand Down Expand Up @@ -100,6 +100,7 @@ const DataPreProcessToolKit = () => {
value="express"
className='custom-radio'
onChange={(e) => setSelection(e.target.value)}
defaultChecked = {true}
/>
Express
</label>
Expand Down
155 changes: 155 additions & 0 deletions components/dataloader/SDFFileLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { useContext, useState } from "react";
import LigandContext from "../../context/LigandContext";
import TargetContext from "../../context/TargetContext";
import { useRouter } from "next/navigation";
import ErrorContext from "../../context/ErrorContext";
import sdfFileParser from "../utils/sdfFileParser";
import { useForm } from "react-hook-form";


export type Inputs = {
id_column: string;
act_column?: string;
};

export default function SDFFileLoader() {
const { ligand, setLigand } = useContext(LigandContext);
const { target, setTarget } = useContext(TargetContext);
const { setErrors } = useContext(ErrorContext);
const [stage, setStage] = useState(false);
const [isHovered, setIsHovered] = useState(false);

const router = useRouter();

const {
register,
handleSubmit,
formState: { errors },
} = useForm<Inputs>();

const handleFileChange = (event) => {
const input = event.target;
const file = input.files?.[0];
if (file && file.name.endsWith(".sdf")) {
handleFile(file);
} else {
setErrors("Hey, please upload a valid SDF File");
}
};

const handleFileDrop = (event) => {
event.preventDefault();
const file = event.dataTransfer.files?.[0];
if (file) {
handleFile(file);
}
};

const handleFile = (file) => {
console.log("File uploaded successfully:", file.name);
const reader = new FileReader();
reader.onload = (e) => {
try {
const sdfContent = e.target?.result as string;
const molecules = sdfContent.split('$$$$').filter(molecule => molecule.trim() !== '');
const parsedMolecules = molecules.map(molecule => sdfFileParser(molecule));
setLigand(parsedMolecules);
setStage(true)
} catch (error) {
setErrors("Please upload a valid QITB JSON File");
}
};
reader.readAsText(file);
};

const handleDragOver = (event) => {
event.preventDefault();
setIsHovered(true);
};

const handleDragExit = () => {
setIsHovered(false);
};

function fileSubmitHandler(data){
let while_process_var = ligand.map((x) => {
x["id"] = x[data.id_column];
x["canonical_smiles"] = x.molData;
x[data.act_column] = parseFloat(x[data.act_column]);
delete x[data.id_column], x[data.smi_column];
return x;
});
console.log(while_process_var)
setLigand(while_process_var);
setTarget({...target, data_source: "sdf", activity_columns: [data.act_column]});
router.push("/tools/preprocess/");
}

if (stage) {
return (
<div className="container" style={{ minHeight: "15vh" }}>
<form
onSubmit={handleSubmit(fileSubmitHandler)}
style={{ display: "flex", flexDirection: "column" }}
>
<label htmlFor="id_column">ID Column: </label>
<select
id="id_column"
className="input"
defaultValue="test"
{...register("id_column")}
>
{Object.keys(ligand[0]).map((head, key) => (
<option key={key}>{head}</option>
))}
</select>
<br />

<label htmlFor="act_column">Activity Column: </label>
<select
id="smi_column"
className="input"
{...register("act_column")}
>
{Object.keys(ligand[0]).map((head, key) => (
<option key={key}>{head}</option>
))}
</select>
<br />

<input
type="submit"
className="button"
value="Pre-Process Molecules"
/>
</form>
</div>
)
}

return (
<div className="container" style={{ minHeight: "15vh" }}>
<div
onDrop={handleFileDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragExit}
onClick={() => {
const fileInput = document.getElementById("fileInput");
if (fileInput) {
fileInput.click();
}
}}
className={`zone ${isHovered ? "zoneHover" : ""}`}
>
<p>Upload Your SDF File Here With Molecules.
You could also drag and drop the file here or Click to browse.</p>
<input
type="file"
id="fileInput"
style={{ display: "none" }}
onChange={handleFileChange}
/>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion components/dataloader/TargetGetter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default function TargetGetter() {
{loading ? (
<Loader />
) : (
<table className="custom-table" style = {{marginLeft : "0"}}>
<table className="table target-table" style = {{marginLeft : "0"}}>
<thead>
<tr>
<th>Target Name</th>
Expand Down
43 changes: 0 additions & 43 deletions components/tools/toolViz/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,6 @@ const Dropdown = ({ buttonText, children }) => {
<div className={`dropdown-content ${isVisible ? 'visible' : ''}`}>
{children}
</div>
<style>
{
`
.dropdown-container {
position: relative;
display: inline-block;
}
.dropdown-icon {
background-color: var(--accent-color);
border: none;
color: white;
padding: 12px;
margin:5px;
font-size: 16px;
cursor: pointer;
}
.dropdown-icon:hover {
background-color: #3e8e41;
}
.dropdown-content {
display: none;
position: absolute;
z-index: 1;
top: 100%; /* Position it below the button */
left: 50%;
transform: translateX(-50%); /* Center it horizontally */
}
.dropdown-content.visible {
display: block;
}
// .dropdown-content div {
// padding: 12px 16px;
// text-decoration: none;
// display: block;
// }
`
}
</style>
</div>
);
};
Expand Down
Loading

0 comments on commit 6870fd0

Please sign in to comment.