1- import { useContext , useState } from "react" ;
1+ import { useContext , useState , useEffect , useRef } from "react" ;
22import TargetContext from "../../context/TargetContext" ;
33import LigandContext from "../../context/LigandContext" ;
44import Link from "next/link" ;
55import 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
89export 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
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
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}
0 commit comments