Skip to content

Commit 7585752

Browse files
committed
bugs fixes, piechart added
1 parent a64d355 commit 7585752

File tree

4 files changed

+270
-113
lines changed

4 files changed

+270
-113
lines changed

app/tools/ml/layout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ export default function MLLayout({ children }) {
153153

154154

155155
{/* ---------------- Children get taskType prop ---------------- */}
156-
{children}
156+
<details open = {!hasResults}>
157+
<summary>{hasResults && <>Reveal ML Forms</>}</summary>
158+
{children}
159+
</details>
157160

158161
{/* ---------------- Scatterplot or barplot ---------------- */}
159162
{hasResults && (
Lines changed: 162 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,205 @@
1-
import { useContext, useState } from "react";
1+
import { useContext, useState, useEffect, useRef } from "react";
22
import TargetContext from "../../context/TargetContext";
33
import LigandContext from "../../context/LigandContext";
44
import Link from "next/link";
55
import FAQComp from "../ui-comps/FAQComp";
6-
import { Button, Progress, Select } from "@mantine/core";
6+
import { Button, Progress, Select, Grid, Paper } from "@mantine/core";
7+
import PieChart from "../tools/toolViz/PieChart";
78

89
export default function CompoundGetter() {
910
const [unit, setUnit] = useState("Ki");
1011
const [binding, setBinding] = useState("B");
12+
const [pieData, setPieData] = useState<any[]>([]);
1113
const { target, setTarget } = useContext(TargetContext);
1214
const { ligand, setLigand } = useContext(LigandContext);
1315
const [ligandSearch, setLigandSearch] = useState(false);
1416
const [loading, setLoading] = useState(false);
1517
const [progress, setProgress] = useState(0);
1618

19+
// -----------------------------
20+
// Fetch pie aggregation data
21+
// -----------------------------
22+
useEffect(() => {
23+
if (!target?.target_id) return;
24+
25+
const esQuery = {
26+
index_name: "chembl_activity",
27+
es_query: JSON.stringify({
28+
size: 0,
29+
query: { query_string: { query: `target_chembl_id:${target.target_id}` } },
30+
aggs: { main_agg: { terms: { field: "standard_type", size: 20, missing: "N/A", order: { _count: "desc" } } } }
31+
})
32+
};
33+
34+
const base64Encoded = btoa(
35+
unescape(encodeURIComponent(JSON.stringify(esQuery)))
36+
);
37+
38+
fetch(
39+
`https://www.ebi.ac.uk/chembl/interface_api/es_proxy/es_data/get_es_data/${base64Encoded}`
40+
)
41+
.then((res) => res.json())
42+
.then((data) => {
43+
const buckets =
44+
data?.es_response?.aggregations?.main_agg?.buckets ?? [];
45+
setPieData(
46+
buckets.map((b: any) => ({
47+
key: b.key,
48+
value: b.doc_count,
49+
}))
50+
);
51+
})
52+
.catch(console.error);
53+
}, [target?.target_id]);
54+
55+
// -----------------------------
56+
// Fetch activity data
57+
// -----------------------------
1758
async function getFullActivityData(url: string) {
1859
setLigandSearch(false);
1960
setLoading(true);
2061

2162
const chembl_url = "https://www.ebi.ac.uk";
22-
const results = [{}];
23-
63+
const results: any[] = [];
2464
let nextUrl = chembl_url + url;
2565

2666
while (nextUrl !== chembl_url + "null") {
2767
const response = await fetch(nextUrl);
2868
const data = await response.json();
29-
results.push(...data.activities);
3069

70+
results.push(...data.activities);
3171
nextUrl = chembl_url + data.page_meta.next;
3272

33-
const newProgress = (results.length / data.page_meta.total_count) * 100;
73+
const newProgress =
74+
(results.length / data.page_meta.total_count) * 100;
3475
setProgress(newProgress);
3576
}
77+
3678
setLigandSearch(true);
37-
return results.slice(1);
79+
setLoading(false);
80+
return results;
3881
}
3982

40-
function hehe() {
83+
function fetchData() {
4184
getFullActivityData(
42-
`/chembl/api/data/activity?format=json&target_chembl_id=${target.target_id}&type=${unit}&target_organism=Homo%20sapiens&assay_type=${binding}&relation==`,
85+
`/chembl/api/data/activity?format=json&target_chembl_id=${target.target_id}&type=${unit}&target_organism=Homo%20sapiens&assay_type=${binding}&relation==`
4386
).then((data) => {
44-
data.map((x) => {
45-
x[unit] = x["standard_value"];
46-
x["id"] = x["molecule_chembl_id"];
47-
delete x["standard_value"];
48-
return x;
87+
data.forEach((x: any) => {
88+
x[unit] = x.standard_value;
89+
x.id = x.molecule_chembl_id;
90+
delete x.standard_value;
4991
});
5092
setLigand(data);
5193
});
52-
setTarget({ ...target, activity_columns: [unit], data_source: "chembl"});
94+
95+
setTarget({
96+
...target,
97+
activity_columns: [unit],
98+
data_source: "chembl",
99+
});
53100
}
54101

102+
// -----------------------------
103+
// Layout
104+
// -----------------------------
55105
return (
56-
<div
57-
style={{
58-
width: "inherit",
59-
gap: "10px",
60-
display: "flex",
61-
flexDirection: "column",
62-
alignContent: "center",
63-
justifyContent: "center",
64-
}}
65-
>
66-
<h2>Small Molecule Getter</h2>
67-
<FAQComp>
68-
For your specific target select, small molecules will be searched that
69-
have been tested in assays against your target is filtered. You could
70-
select the type of assay they have been tested in and the units
71-
provided. Generally speaking it is best to avoid&nbsp;
72-
<a href="https://pubs.acs.org/doi/full/10.1021/acs.jcim.4c00049">
73-
mixing various forms of data types
74-
</a>
75-
. Since, Binding Assays are more prevalent with Ki being the preferred
76-
unit, they are the default.
77-
</FAQComp>
78-
<label htmlFor="input-assay-type">Assay Type</label>
79-
<Select
80-
className="input"
81-
value={binding}
82-
onChange={(value: string | null) => {
83-
if (value !== null) setBinding(value);
84-
}}
85-
data={[
86-
{ value: "B", label: "B (Binding)" },
87-
{ value: "F", label: "F (Functional)" },
88-
{ value: "ADMET", label: "ADMET (ADME Data)" },
89-
{ value: "T", label: "T (Toxicity)" },
90-
{ value: "P", label: "P (Physiochemical)" },
91-
{ value: "U", label: "U (Unclassified)" },
92-
]}
93-
/>
94-
<label htmlFor="input-unit">Unit Type</label>
95-
<Select
96-
className="input"
97-
value={unit}
98-
onChange={(value: string | null) => {
99-
if (value !== null) setUnit(value);
100-
}}
101-
data={[
102-
{ value: "Ki", label: "Ki" },
103-
{ value: "IC50", label: "IC50" },
104-
{ value: "XC50", label: "XC50" },
105-
{ value: "EC50", label: "EC50" },
106-
{ value: "AC50", label: "AC50" },
107-
{ value: "Kd", label: "Kd" },
108-
{ value: "Potency", label: "Potency" },
109-
{ value: "ED50", label: "ED50" },
110-
]}
111-
/>
112-
<Button className="button" onClick={hehe}>
113-
Fetch Data
114-
</Button>
115-
{loading && (
116-
<div>
117-
<Progress
118-
value={progress}
119-
style={{ width: "100%", marginBottom: "10px" }}
120-
></Progress>
121-
<br></br>
122-
<span style={{ textAlign: "center" }}>
123-
{Math.min(progress, 100).toFixed(2)} %
124-
</span>
125-
</div>
126-
)}
127-
<br></br>
128-
{ligand.length > 0 ? (
129-
<div style={{ marginTop: "10px" }}>
130-
<Link className="button" href="/tools/preprocess/">
131-
Process Molecules
132-
</Link>
133-
</div>
134-
) : (
135-
<span>
136-
{ligandSearch &&
137-
"There are zero compounds for this target using this filtration criteria"}
138-
</span>
139-
)}
106+
<div style={{ maxWidth: 1200, margin: "0 auto", padding: 20 }}>
107+
<h2 style={{ textAlign: "center", marginBottom: 30 }}>
108+
Small Molecule Getter
109+
</h2>
110+
111+
<Grid gutter="xl">
112+
{/* PIE CHART */}
113+
<Grid.Col span={{ xs: 12, md: 6 }}>
114+
<Paper shadow="sm" p="md">
115+
<h3 style={{ textAlign: "center", marginBottom: 20 }}>
116+
Associated Bioactivities
117+
</h3>
118+
119+
{pieData.length === 0 ? (
120+
<p style={{ textAlign: "center" }}>Loading chart...</p>
121+
) : (
122+
<PieChart data={pieData} />
123+
)}
124+
</Paper>
125+
</Grid.Col>
126+
127+
{/* FORM */}
128+
<Grid.Col span={{ xs: 12, md: 6 }}>
129+
<Paper shadow="sm" p="md">
130+
<FAQComp>
131+
For your specific target select, small molecules will be searched that
132+
have been tested in assays against your target is filtered. You could
133+
select the type of assay they have been tested in and the units
134+
provided. Generally speaking it is best to avoid&nbsp;
135+
<a href="https://pubs.acs.org/doi/full/10.1021/acs.jcim.4c00049">
136+
mixing various forms of data types
137+
</a>
138+
. Since, Binding Assays are more prevalent with Ki being the preferred
139+
unit, they are the default.
140+
</FAQComp>
141+
142+
<Select
143+
label="Assay Type"
144+
value={binding}
145+
onChange={(v) => v && setBinding(v)}
146+
data={[
147+
{ value: "B", label: "Binding" },
148+
{ value: "F", label: "Functional" },
149+
{ value: "ADMET", label: "ADMET" },
150+
{ value: "T", label: "Toxicity" },
151+
{ value: "P", label: "Physiochemical" },
152+
{ value: "U", label: "Unclassified" },
153+
]}
154+
mb="md"
155+
/>
156+
157+
<Select
158+
label="Unit Type"
159+
value={unit}
160+
onChange={(v) => v && setUnit(v)}
161+
data={[
162+
{ value: "Ki", label: "Ki" },
163+
{ value: "IC50", label: "IC50" },
164+
{ value: "XC50", label: "XC50" },
165+
{ value: "EC50", label: "EC50" },
166+
{ value: "AC50", label: "AC50" },
167+
{ value: "Kd", label: "Kd" },
168+
{ value: "Potency", label: "Potency" },
169+
{ value: "ED50", label: "ED50" },
170+
]}
171+
mb="lg"
172+
/>
173+
174+
<Button fullWidth onClick={fetchData}>
175+
Fetch Data
176+
</Button>
177+
178+
{loading && (
179+
<>
180+
<Progress value={progress} mt="md" />
181+
<div style={{ textAlign: "center", marginTop: 8 }}>
182+
{Math.min(progress, 100).toFixed(1)}%
183+
</div>
184+
</>
185+
)}
186+
187+
{ligand.length > 0 && (
188+
<Link href="/tools/preprocess/" passHref>
189+
<Button fullWidth mt="md">
190+
Process Molecules
191+
</Button>
192+
</Link>
193+
)}
194+
195+
{ligandSearch && ligand.length === 0 && (
196+
<p style={{ textAlign: "center", marginTop: 20 }}>
197+
No compounds found.
198+
</p>
199+
)}
200+
</Paper>
201+
</Grid.Col>
202+
</Grid>
140203
</div>
141204
);
142205
}

components/dataloader/TargetGetter.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export default function TargetGetter() {
2222
)
2323
.then((response) => response.json())
2424
.then((data) => {
25-
let target_data = data.targets;
25+
let target_data = data.targets || [];
2626
setTargetDetails(target_data);
2727
setLoading(false);
2828
})
@@ -53,7 +53,6 @@ export default function TargetGetter() {
5353
<Input
5454
placeholder="Search for relevant words to your Target"
5555
onChange={(e) => setTargetQuery(e.target.value)}
56-
defaultValue={target.target_name}
5756
required={true}
5857
pattern=".{3,}"
5958
/>
@@ -64,16 +63,9 @@ export default function TargetGetter() {
6463
value="Search for your Target"
6564
/>
6665
</form>
67-
<div
68-
style={{
69-
overflow: "scroll",
70-
height: "300px",
71-
display: "flex",
72-
justifyContent: "center",
73-
}}
74-
>
66+
7567
{loading ? (
76-
<Loader size={30} />
68+
<Loader size={100} />
7769
) : (
7870
<Table>
7971
<Table.Thead>
@@ -96,6 +88,8 @@ export default function TargetGetter() {
9688
pre_processed: false,
9789
});
9890
open();
91+
setTargetDetails(dummyData.targets);
92+
setTargetQuery("");
9993
}}
10094
>
10195
<Table.Td>{tars.pref_name}</Table.Td>
@@ -106,8 +100,7 @@ export default function TargetGetter() {
106100
</Table.Tbody>
107101
</Table>
108102
)}
109-
</div>
110-
<Modal opened={opened} onClose={() => {
103+
<Modal size = "70%" opened={opened} onClose={() => {
111104
close();
112105
resetAll();
113106
}}>

0 commit comments

Comments
 (0)