diff options
author | Navan Chauhan <navanchauhan@gmail.com> | 2020-10-17 18:22:35 +0530 |
---|---|---|
committer | Navan Chauhan <navanchauhan@gmail.com> | 2020-10-17 18:22:35 +0530 |
commit | 426d6e460b36690e8fbbc0d09ad34e7bacade61a (patch) | |
tree | 4c9d293e68bd106c4c53eb06e76c634d585beb8c | |
parent | 16316fa24cbc9b66a1dbcf9fd8e18506c35d7b91 (diff) |
added Molecule Properties and Alerts
-rw-r--r-- | app/misc.ini | 13 | ||||
-rw-r--r-- | app/templates/base.html | 9 | ||||
-rw-r--r-- | app/templates/home.html | 10 | ||||
-rw-r--r-- | app/templates/mol-characteristics.html | 66 | ||||
-rw-r--r-- | app/views.py | 90 |
5 files changed, 184 insertions, 4 deletions
diff --git a/app/misc.ini b/app/misc.ini index c474556..9587e56 100644 --- a/app/misc.ini +++ b/app/misc.ini @@ -13,4 +13,15 @@ DB02 = Unknown Hostname, failed to connect to the database. CW01 = Looks like an invalid PDB ID -PC00 = Could not find any compound on PubChem matching the query.
\ No newline at end of file +PC00 = Could not find any compound on PubChem matching the query. + +RD00 = Failed to import RDKit. +RD01 = Could not convert SMILES to molecule, please check the SMILES + +[ALERT_SMARTS] +ESTER = [#6][CX3](=O)[OX2H0][#6] +ANILINE = [NX3][$(C=C),$(cc)] + +[ALERT_DESCRIPTION] +ESTER = The given compound contains Ester. For more details read the paper. +ANILINE = None
\ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index e4ae447..0936f80 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -29,6 +29,15 @@ <li class="{{ 'nav-item active' if active_page == 'about' else 'nav-item' }}"> <a class="nav-link" href="{{ url_for('about') }}">About</a> </li> + <li class="{{ 'nav-item dropdown active' if active_page == 'analyse' else 'nav-item dropdown' }}"> + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Analyse + </a> + <div class="dropdown-menu" aria-labelledby="navbarDropdown"> + <a class="dropdown-item" href="{{ url_for('propalert') }}">Property and Alerts</a> + <a class="dropdown-item" href="#">Druggability</a> + </div> + </li> <li class="{{ 'nav-item dropdown active' if active_page == 'dock' else 'nav-item dropdown' }}"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Dock and Report diff --git a/app/templates/home.html b/app/templates/home.html index 7e0e352..d67cac7 100644 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -5,7 +5,7 @@ <h2>Curie Web Demo</h2> <p>Curie-Web is a part of The Curie Project which aims to make the process of Computer-Aided Drug Design as fast as possible.</p> <p>The following are the currently active modules</p> - <h3>Docking</h3> + <h3>Dock and Generate Reports</h3> <ul> <li><a href="{{ url_for('dock_manual') }}">Dock and Report (Manual)</a> - You can enter your AutoDock Vina configuration, upload the PDBQT files and it will perform the molecular docking and generate a PDF with proper visualisations and protein-interaction profillings (Using PLIP) </li> <li><a href="{{ url_for('dock_automatic') }}">Dock and Report (Automatic)</a> - You just enter in the PDB Code, target compound's SMILES structure and name, it will automatically find a binding location and then perform docking and report generation</li> @@ -16,13 +16,19 @@ <li><a href="{{ url_for('generate') }}">Generate</a> - You can use this to generate completely new compounds</li> </ul> - <h3>Researching</h3> + <h3>Research</h3> <ul> <li><a href="{{ url_for('pubmed') }}">PubMed Search</a> - Handy PubMed search with direct download links</li> <li><a href="{{url_for('pubchem')}}">PubChem Search</a> - Get Compound SMILES</li> <li>Qrious App - You can enter a question for a set of papers (e.g. ChemRxiv preprints) and it uses AI to answer it for each individual paper based on their abstract</li> </ul> + <h3>Analyse</h3> + <ul> + <li><a href="{{ url_for('propalert') }}">Chemical Properties and Alerts</a> - Find Chemical properties and check structure for alerts.</li> + <li><a href="#">Druggability</a> - Classify druggability of a compound using a ML Model.</li> + </ul> + <h3>Misc.</h3> <ul> <li>API - <a href="/docs">Swagger UI</a> or <a href="/redoc">ReDoc</a> - API access for the server</li> diff --git a/app/templates/mol-characteristics.html b/app/templates/mol-characteristics.html new file mode 100644 index 0000000..c7fc945 --- /dev/null +++ b/app/templates/mol-characteristics.html @@ -0,0 +1,66 @@ +{% extends 'base.html' %} +{% set active_page = "analyse" %} +{% block main %} + <h1>Chemical Properties and Alerts</h1> + <form action="{{ url_for('propalert') }}" method="post" enctype="multipart/form-data"> + {% include 'flash_messages.html' %} + {{ form.csrf_token }} + <div class="form-row"> + {{ form.query.label }} + {{ form.query(class="form-control")}} + </div> + <!--<div class="form-row"> + {\{ form.modelSelection.label }} + {\{ form.modelSelection(class="form-control")}} + </div>--> + <br> + <div class="form-row"> + <button type="submit" class="btn btn-primary">Search</button> + </div> + </form> + + {% if complete %} + <br> + <h3>Properties</h3> + + <table class="table table-dark"> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col">Value</th> + </tr> + </thead> + {% for x in prop %} + <tbody> + <tr> + <th scope="row">{{x}}</th> + <td>{{prop[x]}}</td> + </tr> + </tbody> + {% endfor %} + </table> + + {% if perfect %} + <h3>No alerts for the given compound.</h3> + {% endif %} + + <div class="card-deck row-cols-2"> + {% for x in range(result|length) %} + + <div class="card" style="width: 18rem;"> + <div class="card-img-top"> + {{result[x]["SVG"] | safe }} + </div> + <div class="card-body"> + <h5 class="card-title">{{result[x]["Name"]}}</h5> + <p class="card-text">{{result[x]["Description"]}}</p> + <a href="#" class="btn btn-primary">Read Paper</a> + </div> + </div> + {% endfor %} + </div> + {% endif %} + + + +{% endblock %}
\ No newline at end of file diff --git a/app/views.py b/app/views.py index 47a37ac..bf2d401 100644 --- a/app/views.py +++ b/app/views.py @@ -17,6 +17,8 @@ import subprocess import mysql.connector as con from mysql.connector.errors import InterfaceError,DatabaseError + + import requests import logging @@ -31,6 +33,8 @@ import configparser misc = configparser.ConfigParser() misc.read('app/misc.ini') errors = misc['ERRORS'] +AlertSMARTS = misc['ALERT_SMARTS'] +AlertDescription = misc['ALERT_DESCRIPTION'] base = os.getcwd() @@ -121,6 +125,47 @@ def pubchem(): return render_template('search-pubchem.html',result=search,form=form) return render_template('search-pubchem.html',form=form) +@app.route('/Properties',methods=['GET','POST']) +def propalert(): + form = PyMedSearch() + + if request.method == 'POST' and form.validate_on_submit(): + q = form.query.data + result = [] + perfect = False + complete = False + + try: + from rdkit import Chem + except ImportError: + return render_template('error.html',code="RD00",description=errors["RD00"]) + + if Chem.MolFromSmiles(q.strip()) is None: + print("invalid smiles") + return render_template('error.html',code="RD01",description=errors["RD01"]) + + for alert in AlertSMARTS: + print("Checking",alert,AlertSMARTS[alert]) + records = {} + records['Name'] = alert + try: + records['SVG'] = get_svg(q,AlertSMARTS[alert]) + except: + continue + records['Description'] = AlertDescription[alert] + result.append(records) + + prop = get_prop(q) + print(prop) + + complete = True + + if len(result) == 0: + perfect = True + + return render_template('mol-characteristics.html',complete=complete,result=result,form=form,perfect=perfect,prop=prop) + return render_template('mol-characteristics.html',form=form) + @app.route('/Status',methods=['GET','POST']) def status(): taskStatusForm = statusForm() @@ -426,4 +471,47 @@ def page_not_found(error): if __name__ == '__main__': - app.run(debug=True, host="0.0.0.0", port="8080")
\ No newline at end of file + app.run(debug=True, host="0.0.0.0", port="8080") + +def get_svg(base,pattern): + try: + from rdkit.Chem.Draw import rdMolDraw2D + from rdkit import Chem + except: + return None # Need to add logic + + mol = Chem.MolFromSmiles(base) + patt = Chem.MolFromSmarts(pattern) + hit_ats = list(mol.GetSubstructMatch(patt)) + hit_bonds = [] + for bond in patt.GetBonds(): + aid1 = hit_ats[bond.GetBeginAtomIdx()] + aid2 = hit_ats[bond.GetEndAtomIdx()] + hit_bonds.append(mol.GetBondBetweenAtoms(aid1,aid2).GetIdx()) + d = rdMolDraw2D.MolDraw2DSVG(500, 500) + rdMolDraw2D.PrepareAndDrawMolecule(d, mol, highlightAtoms=hit_ats, highlightBonds=hit_bonds) + return d.GetDrawingText().replace("width='500' height='500'","").replace("width='500px' height='500px'","") + +def get_prop(base): + try: + from rdkit import Chem + from rdkit.Chem import Crippen + from rdkit.Chem import Descriptors + from rdkit.Chem import rdMolDescriptors + from rdkit.Chem import Lipinski + except: + return None # Need to add logic + result = {} + + mol = Chem.MolFromSmiles(base) + result["cLogP"] = Crippen.MolLogP(mol) + result["Molecular Weight"] = Descriptors.MolWt(mol) + result["TPSA"] = rdMolDescriptors.CalcTPSA(mol) + result["Hydrogen Bond Acceptors"] = Lipinski.NumHAcceptors(mol) + result["Hydrogen Bond Donors"] = Lipinski.NumHDonors(mol) + result["Rotable Bonds"] = Lipinski.NumRotatableBonds(mol) + result["Fraction SP3"] = Lipinski.FractionCSP3(mol) + + + return result + |