Skip to content
Commits on Source (3)
Changelog
---------
# 1.4.2
* Adds "--name" option to change name of output files
* Adds "--nopdbcanmap" option to skip calculation of canonical->PDB mapping which can lead to segfaults with OpenBabel
* Improved handling of ligand names
# 1.4.1
* Improved import of modules
* Corrections for README and documentation
......
......@@ -33,7 +33,7 @@ pymol 1VSN_NFT_A_283.pse
In your terminal, add the PLIP repository to your PYTHONPATH variable.
For our example, we also download a PDB file for testing.
```bash
export PYTHONPATH=~/pliptool/plip:${PYTHONPATH}
export PYTHONPATH=~/pliptool:${PYTHONPATH}
cd /tmp && wget http://files.rcsb.org/download/1EVE.pdb
python
```
......
plip (1.4.2+dfsg-1) unstable; urgency=medium
* New upstream version 1.4.2+dfsg
-- Alexandre Mestiashvili <mestia@debian.org> Thu, 07 Jun 2018 20:05:34 +0200
plip (1.4.1+dfsg-1) unstable; urgency=medium
* New upstream version 1.4.1+dfsg
......
......@@ -23,6 +23,8 @@ PEPTIDES = [] # Definition which chains should be considered as peptide ligands
INTRA = None
KEEPMOD = False
DNARECEPTOR = False
OUTPUTFILENAME = "report" # Naming for the TXT and XML report files
NOPDBCANMAP = False # Skip calculation of mapping canonical atom order: PDB atom order
# Configuration file for Protein-Ligand Interaction Profiler (PLIP)
# Set thresholds for detection of interactions
......
......@@ -53,10 +53,10 @@ class Interaction(XMLStorage):
def __init__(self, interaction_part):
self.id = interaction_part.get('id')
self.resnr = self.getdata(interaction_part, 'resnr')
self.restype = self.getdata(interaction_part, 'restype')
self.restype = self.getdata(interaction_part, 'restype', force_string=True)
self.reschain = self.getdata(interaction_part, 'reschain', force_string=True)
self.resnr_lig = self.getdata(interaction_part, 'resnr_lig')
self.restype_lig = self.getdata(interaction_part, 'restype_lig')
self.restype_lig = self.getdata(interaction_part, 'restype_lig', force_string=True)
self.reschain_lig = self.getdata(interaction_part, 'reschain_lig', force_string=True)
self.ligcoo = self.getcoordinates(interaction_part, 'ligcoo')
self.protcoo = self.getcoordinates(interaction_part, 'protcoo')
......@@ -87,8 +87,8 @@ class HydrogenBond(Interaction):
self.protisdon = self.getdata(hbond_part, 'protisdon')
self.donoridx = self.getdata(hbond_part, 'donoridx')
self.acceptoridx = self.getdata(hbond_part, 'acceptoridx')
self.donortype = self.getdata(hbond_part, 'donortype')
self.acceptortype = self.getdata(hbond_part, 'acceptortype')
self.donortype = self.getdata(hbond_part, 'donortype', force_string=True)
self.acceptortype = self.getdata(hbond_part, 'acceptortype', force_string=True)
class WaterBridge(Interaction):
......@@ -105,8 +105,8 @@ class WaterBridge(Interaction):
self.donor_idx = self.getdata(wbridge_part, 'donor_idx')
self.acceptor_idx = self.getdata(wbridge_part, 'acceptor_idx')
self.donortype = self.getdata(wbridge_part, 'donortype')
self.acceptortype = self.getdata(wbridge_part, 'acceptortype')
self.donortype = self.getdata(wbridge_part, 'donortype', force_string=True)
self.acceptortype = self.getdata(wbridge_part, 'acceptortype', force_string=True)
self.water_idx = self.getdata(wbridge_part, 'water_idx')
self.watercoo = self.getcoordinates(wbridge_part, 'watercoo')
......@@ -118,7 +118,7 @@ class SaltBridge(Interaction):
Interaction.__init__(self, sbridge_part)
self.dist = self.getdata(sbridge_part, 'dist')
self.protispos = self.getdata(sbridge_part, 'protispos')
self.lig_group = self.getdata(sbridge_part, 'lig_group')
self.lig_group = self.getdata(sbridge_part, 'lig_group', force_string=True)
self.lig_idx_list = [int(tagpart.text) for tagpart in
sbridge_part.xpath('lig_idx_list/idx')]
......@@ -157,8 +157,8 @@ class HalogenBond(Interaction):
self.dist = self.getdata(halogen_part, 'dist')
self.don_angle = self.getdata(halogen_part, 'don_angle')
self.acc_angle = self.getdata(halogen_part, 'acc_angle')
self.donortype = self.getdata(halogen_part, 'donortype')
self.acceptortype = self.getdata(halogen_part, 'acceptortype')
self.donortype = self.getdata(halogen_part, 'donortype', force_string=True)
self.acceptortype = self.getdata(halogen_part, 'acceptortype', force_string=True)
self.don_idx = self.getdata(halogen_part, 'don_idx')
self.acc_idx = self.getdata(halogen_part, 'acc_idx')
self.sidechain = self.getdata(halogen_part, 'sidechain')
......@@ -170,14 +170,14 @@ class MetalComplex(Interaction):
def __init__(self, metalcomplex_part):
Interaction.__init__(self, metalcomplex_part)
self.metal_idx = self.getdata(metalcomplex_part, 'metal_idx')
self.metal_type = self.getdata(metalcomplex_part, 'metal_type')
self.metal_type = self.getdata(metalcomplex_part, 'metal_type', force_string=True)
self.target_idx = self.getdata(metalcomplex_part, 'target_idx')
self.target_type = self.getdata(metalcomplex_part, 'target_type')
self.target_type = self.getdata(metalcomplex_part, 'target_type', force_string=True)
self.coordination = self.getdata(metalcomplex_part, 'coordination')
self.dist = self.getdata(metalcomplex_part, 'dist')
self.location = self.getdata(metalcomplex_part, 'location')
self.location = self.getdata(metalcomplex_part, 'location', force_string=True)
self.rms = self.getdata(metalcomplex_part, 'rms')
self.geometry = self.getdata(metalcomplex_part, 'geometry')
self.geometry = self.getdata(metalcomplex_part, 'geometry', force_string=True)
self.complexnum = self.getdata(metalcomplex_part, 'complexnum')
self.targetcoo = self.getcoordinates(metalcomplex_part, 'targetcoo')
self.metalcoo = self.getcoordinates(metalcomplex_part, 'metalcoo')
......@@ -190,13 +190,13 @@ class BSite(XMLStorage):
self.pdbid = pdbid
self.bsid = ":".join(bindingsite.xpath('identifiers/*/text()')[2:5])
self.uniqueid = ":".join([self.pdbid, self.bsid])
self.hetid = self.getdata(bindingsite, 'identifiers/hetid')
self.longname = self.getdata(bindingsite, 'identifiers/longname')
self.ligtype = self.getdata(bindingsite, 'identifiers/ligtype')
self.smiles = self.getdata(bindingsite, 'identifiers/smiles')
self.inchikey = self.getdata(bindingsite, 'identifiers/inchikey')
self.hetid = self.getdata(bindingsite, 'identifiers/hetid', force_string=True)
self.longname = self.getdata(bindingsite, 'identifiers/longname', force_string=True)
self.ligtype = self.getdata(bindingsite, 'identifiers/ligtype', force_string=True)
self.smiles = self.getdata(bindingsite, 'identifiers/smiles', force_string=True)
self.inchikey = self.getdata(bindingsite, 'identifiers/inchikey', force_string=True)
self.position = self.getdata(bindingsite, 'identifiers/position')
self.chain = self.getdata(bindingsite, 'identifiers/chain')
self.chain = self.getdata(bindingsite, 'identifiers/chain', force_string=True)
# Information on binding site members
self.members = []
......
......@@ -340,7 +340,10 @@ class LigandFinder:
write_message("Renumerated molecule generated\n", mtype='debug')
if not config.NOPDBCANMAP:
atomorder = canonicalize(lig)
else:
atomorder = None
can_to_pdb = {}
if atomorder is not None:
......
......@@ -19,17 +19,18 @@ from . import config
# External libraries
import lxml.etree as et
__version__ = '1.4.1'
__version__ = '1.4.2'
class StructureReport:
"""Creates reports (xml or txt) for one structure/"""
def __init__(self, mol):
def __init__(self, mol, outputprefix='report'):
self.mol = mol
self.excluded = self.mol.excluded
self.xmlreport = self.construct_xml_tree()
self.txtreport = self.construct_txt_file()
self.get_bindingsite_data()
self.outpath = mol.output_path
self.outputprefix = outputprefix
def construct_xml_tree(self):
"""Construct the basic XML tree"""
......@@ -95,7 +96,7 @@ class StructureReport:
def write_xml(self, as_string=False):
"""Write the XML report"""
if not as_string:
et.ElementTree(self.xmlreport).write('%s/report.xml' % self.outpath, pretty_print=True, xml_declaration=True)
et.ElementTree(self.xmlreport).write('{}/{}.xml'.format(self.outpath, self.outputprefix), pretty_print=True, xml_declaration=True)
else:
output = et.tostring(self.xmlreport, pretty_print=True)
if config.RAWSTRING:
......@@ -105,7 +106,7 @@ class StructureReport:
def write_txt(self, as_string=False):
"""Write the TXT report"""
if not as_string:
with open('%s/report.txt' % self.outpath, 'w') as f:
with open('{}/{}.txt'.format(self.outpath, self.outputprefix), 'w') as f:
[f.write(textline + '\n') for textline in self.txtreport]
else:
output = '\n'.join(self.txtreport)
......
......@@ -44,7 +44,7 @@ def threshold_limiter(aparser, arg):
def process_pdb(pdbfile, outpath, as_string=False):
def process_pdb(pdbfile, outpath, as_string=False, outputprefix='report'):
"""Analysis of a single PDB file. Can generate textual reports XML, PyMOL session files and images as output."""
if not as_string:
startmessage = '\nStarting analysis of %s\n' % pdbfile.split('/')[-1]
......@@ -62,7 +62,7 @@ def process_pdb(pdbfile, outpath, as_string=False):
create_folder_if_not_exists(outpath)
# Generate the report files
streport = StructureReport(mol)
streport = StructureReport(mol, outputprefix=outputprefix)
config.MAXTHREADS = min(config.MAXTHREADS, len(mol.interaction_sets))
......@@ -127,6 +127,7 @@ def main(inputstructs, inputpdbids):
write_message('\n' + '*' * len(title) + '\n')
write_message(title)
write_message('\n' + '*' * len(title) + '\n\n')
outputprefix = config.OUTPUTFILENAME
if inputstructs is not None: # Process PDB file(s)
num_structures = len(inputstructs)
......@@ -147,7 +148,8 @@ def main(inputstructs, inputpdbids):
if num_structures > 1:
basename = inputstruct.split('.')[-2].split('/')[-1]
config.OUTPATH = '/'.join([config.BASEPATH, basename])
process_pdb(inputstruct, config.OUTPATH, as_string=read_from_stdin)
outputprefix = 'report'
process_pdb(inputstruct, config.OUTPATH, as_string=read_from_stdin, outputprefix=outputprefix)
else: # Try to fetch the current PDB structure(s) directly from the RCBS server
num_pdbids = len(inputpdbids)
inputpdbids =remove_duplicates(inputpdbids)
......@@ -155,7 +157,8 @@ def main(inputstructs, inputpdbids):
pdbpath, pdbid = download_structure(inputpdbid)
if num_pdbids > 1:
config.OUTPATH = '/'.join([config.BASEPATH, pdbid[1:3].upper(), pdbid.upper()])
process_pdb(pdbpath, config.OUTPATH)
outputprefix = 'report'
process_pdb(pdbpath, config.OUTPATH, outputprefix=outputprefix)
if (pdbid is not None or inputstructs is not None) and config.BASEPATH is not None:
if config.BASEPATH in ['.', './']:
......@@ -204,9 +207,14 @@ if __name__ == '__main__':
parser.add_argument("--nofixfile", dest="nofixfile", default=False,
help="Turns off writing files for fixed PDB files.",
action="store_true")
parser.add_argument("--nopdbcanmap", dest="nopdbcanmap", default=False,
help="Turns off calculation of mapping between canonical and PDB atom order for ligands.",
action="store_true")
parser.add_argument("--dnareceptor", dest="dnareceptor", default=False,
help="Uses the DNA instead of the protein as a receptor for interactions.",
action="store_true")
parser.add_argument("--name", dest="outputfilename", default="report",
help="Set a filename for the report TXT and XML files. Will only work when processing single structures.")
ligandtype = parser.add_mutually_exclusive_group() # Either peptide/inter or intra mode
ligandtype.add_argument("--peptides", "--inter", dest="peptides", default=[],
help="Allows to define one or multiple chains as peptide ligands or to detect inter-chain contacts",
......@@ -251,8 +259,10 @@ if __name__ == '__main__':
config.INTRA = arguments.intra
config.NOFIX = arguments.nofix
config.NOFIXFILE = arguments.nofixfile
config.NOPDBCANMAP = arguments.nopdbcanmap
config.KEEPMOD = arguments.keepmod
config.DNARECEPTOR = arguments.dnareceptor
config.OUTPUTFILENAME = arguments.outputfilename
# Make sure we have pymol with --pics and --pymol
if config.PICS or config.PYMOL:
try:
......
......@@ -6,7 +6,7 @@ setup.py - Setup configuration file for pip, etc.
from setuptools import setup
setup(name='plip',
version='1.4.1',
version='1.4.2',
description='PLIP - Fully automated protein-ligand interaction profiler',
classifiers=[
'Development Status :: 5 - Production/Stable',
......