Skip to content

Commit 221b691

Browse files
committed
implemented atom-level report
- the report of multi-atom interactions resolves to individual atoms - import optimizations - adds test methods
1 parent 2d995f8 commit 221b691

11 files changed

+4859
-28
lines changed

CHANGES.txt

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
Changelog
22
---------
3+
# 2.1.8
4+
* report of individual binding site atoms
5+
6+
# 2.1.7
7+
* bug fixes
8+
39
# 2.1.6
410
* fetch URL for PDB files updated to avoid issues with RCSB API changes
511

plip/exchange/report.py

+40-22
Original file line numberDiff line numberDiff line change
@@ -191,64 +191,76 @@ def __init__(self, plcomplex):
191191
################
192192

193193
self.saltbridge_features = (
194-
'RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST', 'PROTISPOS',
194+
'RESNR', 'RESTYPE', 'RESCHAIN', 'PROT_IDX_LIST', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST',
195+
'PROTISPOS',
195196
'LIG_GROUP',
196197
'LIG_IDX_LIST',
197198
'LIGCOO', 'PROTCOO')
198199
self.saltbridge_info = []
199200
for sb in self.complex.saltbridge_lneg + self.complex.saltbridge_pneg:
200201
if sb.protispos:
201-
group, ids = sb.negative.fgroup, [str(x) for x in sb.negative.atoms_orig_idx]
202-
self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, sb.resnr_l, sb.restype_l, sb.reschain_l,
202+
group, ligand_atom_ids = sb.negative.fgroup, [str(x) for x in sb.negative.atoms_orig_idx]
203+
protein_atom_ids = [str(x) for x in sb.positive.atoms_orig_idx]
204+
self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, ",".join(protein_atom_ids), sb.resnr_l,
205+
sb.restype_l, sb.reschain_l,
203206
'%.2f' % sb.distance, sb.protispos,
204-
group.capitalize(), ",".join(ids),
207+
group.capitalize(), ",".join(ligand_atom_ids),
205208
tuple(sb.negative.center), tuple(sb.positive.center)))
206209
else:
207-
group, ids = sb.positive.fgroup, [str(x) for x in sb.positive.atoms_orig_idx]
208-
self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, sb.resnr_l, sb.restype_l, sb.reschain_l,
210+
group, ligand_atom_ids = sb.positive.fgroup, [str(x) for x in sb.positive.atoms_orig_idx]
211+
protein_atom_ids = [str(x) for x in sb.negative.atoms_orig_idx]
212+
self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, ",".join(protein_atom_ids), sb.resnr_l,
213+
sb.restype_l, sb.reschain_l,
209214
'%.2f' % sb.distance, sb.protispos,
210-
group.capitalize(), ",".join(ids),
215+
group.capitalize(), ",".join(ligand_atom_ids),
211216
tuple(sb.positive.center), tuple(sb.negative.center)))
212217

213218
###############
214219
# PI-STACKING #
215220
###############
216221

217222
self.pistacking_features = (
218-
'RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'CENTDIST', 'ANGLE', 'OFFSET',
223+
'RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'PROT_IDX_LIST', 'CENTDIST',
224+
'ANGLE', 'OFFSET',
219225
'TYPE',
220226
'LIG_IDX_LIST', 'LIGCOO', 'PROTCOO')
221227
self.pistacking_info = []
222228
for stack in self.complex.pistacking:
223-
ids = [str(x) for x in stack.ligandring.atoms_orig_idx]
229+
ligand_atom_ids = [str(x) for x in stack.ligandring.atoms_orig_idx]
230+
protein_atom_ids = [str(x) for x in stack.proteinring.atoms_orig_idx]
224231
self.pistacking_info.append((stack.resnr, stack.restype, stack.reschain, stack.resnr_l, stack.restype_l,
225-
stack.reschain_l, '%.2f' % stack.distance,
226-
'%.2f' % stack.angle, '%.2f' % stack.offset, stack.type, ",".join(ids),
232+
stack.reschain_l, ",".join(protein_atom_ids), '%.2f' % stack.distance,
233+
'%.2f' % stack.angle, '%.2f' % stack.offset, stack.type,
234+
",".join(ligand_atom_ids),
227235
tuple(stack.ligandring.center), tuple(stack.proteinring.center)))
228236

229237
##########################
230238
# PI-CATION INTERACTIONS #
231239
##########################
232240

233241
self.pication_features = (
234-
'RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST', 'OFFSET', 'PROTCHARGED',
235-
'LIG_GROUP',
236-
'LIG_IDX_LIST', 'LIGCOO', 'PROTCOO')
242+
'RESNR', 'RESTYPE', 'RESCHAIN', 'PROT_IDX_LIST', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST',
243+
'OFFSET',
244+
'PROTCHARGED', 'LIG_GROUP', 'LIG_IDX_LIST', 'LIGCOO', 'PROTCOO')
237245
self.pication_info = []
238246
for picat in self.complex.pication_laro + self.complex.pication_paro:
239247
if picat.protcharged:
240-
ids = [str(x) for x in picat.ring.atoms_orig_idx]
248+
ligand_atom_ids = [str(x) for x in picat.ring.atoms_orig_idx]
249+
protein_atom_ids = [str(x) for x in picat.charge.atoms_orig_idx]
241250
group = 'Aromatic'
242-
self.pication_info.append((picat.resnr, picat.restype, picat.reschain, picat.resnr_l, picat.restype_l,
251+
self.pication_info.append((picat.resnr, picat.restype, picat.reschain, ",".join(protein_atom_ids),
252+
picat.resnr_l, picat.restype_l,
243253
picat.reschain_l, '%.2f' % picat.distance,
244-
'%.2f' % picat.offset, picat.protcharged, group, ",".join(ids),
254+
'%.2f' % picat.offset, picat.protcharged, group, ",".join(ligand_atom_ids),
245255
tuple(picat.ring.center), tuple(picat.charge.center)))
246256
else:
247-
ids = [str(x) for x in picat.charge.atoms_orig_idx]
257+
ligand_atom_ids = [str(x) for x in picat.charge.atoms_orig_idx]
258+
protein_atom_ids = [str(x) for x in picat.ring.atoms_orig_idx]
248259
group = picat.charge.fgroup
249-
self.pication_info.append((picat.resnr, picat.restype, picat.reschain, picat.resnr_l, picat.restype_l,
260+
self.pication_info.append((picat.resnr, picat.restype, picat.reschain, ",".join(protein_atom_ids),
261+
picat.resnr_l, picat.restype_l,
250262
picat.reschain_l, '%.2f' % picat.distance,
251-
'%.2f' % picat.offset, picat.protcharged, group, ",".join(ids),
263+
'%.2f' % picat.offset, picat.protcharged, group, ",".join(ligand_atom_ids),
252264
tuple(picat.charge.center), tuple(picat.ring.center)))
253265

254266
#################
@@ -451,9 +463,15 @@ def format_interactions(element_name, features, interaction_information):
451463
new_contact = et.SubElement(interaction, element_name[:-2], id=str(j + 1))
452464
for i, feature in enumerate(single_contact):
453465
# Just assign the value unless it's an atom list, use subelements in this case
454-
if features[i] == 'LIG_IDX_LIST':
466+
if features[i] == 'LIG_IDX_LIST' or features[i] == 'PROT_IDX_LIST':
455467
feat = et.SubElement(new_contact, features[i].lower())
456-
for k, atm_idx in enumerate(feature.split(',')):
468+
split = list()
469+
# check whether multiple atoms are contained in the atom group
470+
if isinstance(feature, str):
471+
split = feature.split(',')
472+
else:
473+
split = [feature]
474+
for k, atm_idx in enumerate(split):
457475
idx = et.SubElement(feat, 'idx', id=str(k + 1))
458476
idx.text = str(atm_idx)
459477
elif features[i].endswith('COO'):

plip/exchange/xml.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from lxml import etree
22

3-
from urllib.request import urlopen
4-
53

64
class XMLStorage:
75
"""Generic class for storing XML data from PLIP XML files."""
@@ -109,6 +107,8 @@ def __init__(self, sbridge_part):
109107
self.lig_group = self.getdata(sbridge_part, 'lig_group', force_string=True)
110108
self.lig_idx_list = [int(tagpart.text) for tagpart in
111109
sbridge_part.xpath('lig_idx_list/idx')]
110+
self.prot_idx_list = [int(tagpart.text) for tagpart in
111+
sbridge_part.xpath('prot_idx_list/idx')]
112112

113113

114114
class PiStacking(Interaction):
@@ -123,6 +123,8 @@ def __init__(self, pistack_part):
123123
self.type = self.getdata(pistack_part, 'type')
124124
self.lig_idx_list = [int(tagpart.text) for tagpart in
125125
pistack_part.xpath('lig_idx_list/idx')]
126+
self.prot_idx_list = [int(tagpart.text) for tagpart in
127+
pistack_part.xpath('prot_idx_list/idx')]
126128

127129

128130
class PiCation(Interaction):
@@ -233,7 +235,7 @@ def __init__(self, bindingsite, pdbid):
233235
self.halogens = [HalogenBond(x) for x in interactions.xpath('halogen_bonds/halogen_bond')]
234236
self.metal_complexes = [MetalComplex(x) for x in interactions.xpath('metal_complexes/metal_complex')]
235237
self.num_contacts = len(self.hydrophobics) + len(self.hbonds) + len(self.wbridges) + len(self.sbridges) + \
236-
len(self.pi_stacks) + len(self.pi_cations) + len(self.halogens) + len(self.metal_complexes)
238+
len(self.pi_stacks) + len(self.pi_cations) + len(self.halogens) + len(self.metal_complexes)
237239
self.has_interactions = self.num_contacts > 0
238240

239241
self.get_atom_mapping()
@@ -260,7 +262,8 @@ def get_counts(self):
260262
'pications': len(self.pi_cations), 'halogens': len(self.halogens), 'metal': len(self.metal_complexes),
261263
'hbond_back': hbondsback, 'hbond_nonback': (len(self.hbonds) - hbondsback)}
262264
counts['total'] = counts['hydrophobics'] + counts['hbonds'] + counts['wbridges'] + \
263-
counts['sbridges'] + counts['pistacks'] + counts['pications'] + counts['halogens'] + counts['metal']
265+
counts['sbridges'] + counts['pistacks'] + counts['pications'] + counts['halogens'] + counts[
266+
'metal']
264267
return counts
265268

266269

@@ -284,4 +287,4 @@ def __init__(self, xmlfile):
284287

285288
def load_data(self, xmlfile):
286289
"""Loads/parses an XML file and saves it as a tree if successful."""
287-
self.doc = etree.parse(xmlfile)
290+
self.doc = etree.parse(xmlfile)

0 commit comments

Comments
 (0)