Friday, 18 November 2011

Displaying pharmacophores from Pharao in Avogadro

Following on from the equivalent post for Pharmer, here is an extended Avogadro plugin that works for both Pharmer and Pharao generated pharmacophores.

The plugin allows the user to click through all of the pharmacophores defined in a file and display them one by one. See install instructions in the previous post. The code is kinda rough-and-ready so be prepared to hack around if you need to sort something out:
import os
from PyQt4.Qt import *
import Avogadro as avo
from numpy import array
# Get JSON from my own Python installation
import sys
sys.path.append("C:\\Python26\\Lib\\site-packages")
sys.path.append("C:\\Python26\\lib")
import json
colorlookup = {
'Hydrophobic': [0, 139, 69],
'HydrogenAcceptor': [255, 165, 0],
'HydrogenDonor': [211, 211, 211],
'Aromatic': [205, 0, 205],
'PositiveIon': [0, 0, 238],
'NegativeIon': [255, 0, 0],
'HybridAromLipo': [205./2., 139/2., (69+205.)/2.]
}
pharaolookup = {
"HYBL": "HybridAromLipo",
"HDON": "HydrogenDonor",
"HACC": "HydrogenAcceptor",
"NEGC": "NegativeIon",
"POSC": "PositiveIon",
"LIPO": "Hydrophobic",
"AROM": "Aromatic",
"HYBH": "HyrogenAcceptor"
}
def debug(text):
return
filename = os.path.join("C:\\", "Users", "Noel", "Desktop", "tmp.txt")
output = open(filename, "a")
print >> output, text
output.close()
def readpharmacophore(filename):
NONE, PHARAO, PHARMER = range(3)
software = NONE
pharmas = []
# Detect whether Pharmer or Pharao
with open(filename) as f:
line = f.next()
if line[0] == "{":
software = PHARMER
else:
software = PHARAO
with open(filename) as f:
if software == PHARMER:
query = json.load(f)
pharmas.append(("No title", [x for x in query['points'] if x['enabled']]))
else:
for line in f:
pharma = []
title = line
line = f.next()
while line.rstrip() != "$$$$":
broken = line.rstrip().split()
data = {}
data["name"] = pharaolookup[broken[0]]
for a, b in zip(["x", "y", "z"], broken[1:4]):
data[a] = float(b)
data["radius"] = float(broken[4])
if broken[5] == "1":
tmp = {}
for a, b in zip(["x", "y", "z"], broken[6:9]):
tmp[a] = (float(b) - data[a])*2.5 + data[a] # Increase length
data["vector"] = tmp
data["vector_on"] = True
pharma.append(data)
line = f.next()
pharmas.append((title, pharma))
if software == PHARMER:
pharma = pharmas[0]
if len(pharma) > 0:
x = y = z =0
for p in pharma:
x += p['x']
y += p['y']
z += p['z']
x /= len(pharma)
y /= len(pharma)
z /= len(pharma)
for p in pharma:
p['x'] -= x
p['y'] -= y
p['z'] -= z
return pharmas
class Engine(QObject):
# declare the changed() signal
__pyqtSignals__ = ("changed()",)
# constructor
def __init__(self):
QObject.__init__(self)
self.widget = None
self.textbox = None
self.filename = ""
self.pharmas = []
def name(self):
return "Pharmacophore"
def flags(self):
return avo.EngineFlags.NoFlags
@pyqtSignature("")
def browse(self):
self.filename = str(QFileDialog.getOpenFileName())
if not self.filename:
return
self.textbox.setText(self.filename)
self.pharmas = readpharmacophore(self.filename)
self.allpharmas.setRowCount(len(self.pharmas))
for i, pharma in enumerate(self.pharmas):
newItem = QTableWidgetItem(pharma[0])
self.allpharmas.setItem(0, i, newItem)
self.chosenpharma = 0
self.allpharmas.setCurrentCell(0, self.chosenpharma, QItemSelectionModel.ClearAndSelect)
self.emit(SIGNAL("changed()"))
@pyqtSignature("")
def clear(self):
self.filename = ""
self.textbox.setText(self.filename)
self.pharmas = []
self.emit(SIGNAL("changed()"))
@pyqtSignature("")
def myupdate(self):
self.pharmas = readpharmacophore(self.filename)
self.allpharmas.setRowCount(len(self.pharmas))
for i, pharma in enumerate(self.pharmas):
newItem = QTableWidgetItem(pharma[0])
self.allpharmas.setItem(0, i, newItem)
if self.chosenphara > len(self.pharmas):
self.chosenpharma = len(self.pharmas) - 1
self.emit(SIGNAL("changed()"))
@pyqtSignature("int, int, int, int")
def myotherupdate(self, x, y, a, b):
debug("value: %d" % self.allpharmas.currentRow())
debug("values: %d %d %d %d" % (x, y, a, b))
self.chosenpharma = self.allpharmas.currentRow()
debug("chosenpharma: %d N pharmas: %d" % (self.chosenpharma, len(self.pharmas)))
if self.chosenpharma > len(self.pharmas):
self.chosenpharma = len(self.pharmas) - 1
self.emit(SIGNAL("changed()"))
def settingsWidget(self):
self.widget = QWidget()
layout = QVBoxLayout(self.widget)
self.textbox = QLineEdit(self.filename)
self.textbox.setReadOnly(True)
layout.addWidget(self.textbox)
self.allpharmas = QTableWidget(self.widget)
self.allpharmas.setAlternatingRowColors(True)
self.allpharmas.setSelectionMode(QAbstractItemView.SingleSelection)
layout.addWidget(self.allpharmas)
self.allpharmas.clear()
self.allpharmas.setRowCount(1)
self.allpharmas.setColumnCount(1)
self.allpharmas.horizontalHeader().setResizeMode(QHeaderView.Stretch)
self.allpharmas.setHorizontalHeaderLabels(["Pharmacophore Title"])
buttons = QHBoxLayout(self.widget)
layout.addLayout(buttons)
self.browsebtn = QPushButton("Browse")
self.updatebtn = QPushButton("Reload")
self.clearbtn = QPushButton("Clear")
buttons.addWidget(self.browsebtn)
buttons.addWidget(self.updatebtn)
buttons.addWidget(self.clearbtn)
QObject.connect(self.browsebtn,SIGNAL("clicked()"),self, SLOT("browse()"))
QObject.connect(self.clearbtn, SIGNAL("clicked()"),self, SLOT("clear()"))
QObject.connect(self.updatebtn,SIGNAL("clicked()"),self, SLOT("myupdate()"))
QObject.connect(self.allpharmas,
SIGNAL("currentCellChanged(int, int, int, int)"),
self, SLOT("myotherupdate(int,int,int,int)"))
debug("End of widget 2")
return self.widget
def renderOpaque(self, pd):
if len(self.pharmas) == 0:
return
# Painter
painter = pd.painter
# Molecule
molecule = pd.molecule
# Color
color = pd.colorMap
for point in self.pharmas[self.chosenpharma][1]:
if point['name'] in colorlookup:
colvals = [float(x) / 255. for x in colorlookup[point['name']]] + [1.0]
color.setFromRgba(*colvals)
else:
color.setFromRgba(0.3, 0.6, 1.0, 1.0)
painter.setColor(color)
r = point['radius']
x, y, z = point['x'], point['y'], point['z']
painter.drawSphere(array([x, y, z]), r)
if "vector" in point and point.get("vector_on") != False:
v = point['vector']
a, b, c = v['x'], v['y'], v['z']
painter.drawCylinder(array([x, y, z]), array([a, b, c]), 0.2)
painter.drawCone(array([a, b, c]),
array([(a-x)*0.1+a,(b-y)*0.1+b,(c-z)*0.1+c]), 0.3)

No comments: