# Copyright 2002 by Katharine Lindner. All rights reserved. # This code is part of the Biopython distribution and governed by its # license. Please see the LICENSE file that should have been included # as part of this package. """Represent the NDB Atlas structure (a minimal subset of PDB format) (DEPRECATED). Hetero, Crystal and Chain exist to represent the NDB Atlas structure. Atlas is a minimal subset of the PDB format. Hetero supports a 3 alphanumeric code. The NDB web interface is located at http://ndbserver.rutgers.edu Bio.Crystal.Hetero substitute is Bio.PDB.Atom Bio.Crystal.Chain substitute is Bio.PDB.Chain Bio.Crystal.Crystal substitute is Bio.PDB.Structure Using Bio.PDB you can navigate the data as below:: from Bio.PDB.PDBParser import PDBParser parser = PDBParser(PERMISSIVE=1) # PDB NDB Only file structure = parser.get_structure("001", "001_msd.pbd") for model in structure: print('Model ',model) for chain in model: print('Chain ', chain) for residue in chain: print('Res ', residue) for atom in residue: print('Atom ', atom) Bio.Crystal is self-contained, with the main functionality covered by Bio.PDB. """ import copy import warnings from functools import reduce from Bio._py3k import map from Bio._py3k import basestring from Bio import BiopythonDeprecationWarning warnings.warn("Bio.Crystal has been deprecated, and we intend to remove it" " in a future release of Biopython. Please use Bio.PDB instead" " to parse NDB files.", BiopythonDeprecationWarning) class CrystalError(Exception): """Class to manage errors.""" pass def wrap_line(line): """Add end of line at character eighty, to match PDB record standard.""" output = "" for i in range(0, len(line), 80): output += "%s\n" % line[i : i + 80] return output def validate_key(key): """Check if key is a string and has at least one character.""" if not isinstance(key, str): raise CrystalError("chain requires a string label") if len(key) != 1: raise CrystalError("chain label should contain one letter") class Hetero(object): """Class to support the PDB hetero codes. Supports only the 3 alphanumeric code. The annotation is available from http://xray.bmc.uu.se/hicup/xname.html """ def __init__(self, data): """Initialize the class.""" # Enforce string storage if not isinstance(data, str): raise CrystalError("Hetero data must be an alphanumeric string") if data.isalnum() == 0: raise CrystalError("Hetero data must be an alphanumeric string") if len(data) > 3: raise CrystalError("Hetero data may contain up to 3 characters") if len(data) < 1: raise CrystalError("Hetero data must not be empty") self.data = data[:].lower() def __eq__(self, other): return self.data == other.data def __ne__(self, other): """Return true iff self is not equal to other.""" return not self.__eq__(other) def __repr__(self): return "%s" % self.data def __str__(self): return "%s" % self.data def __len__(self): return len(self.data) class Chain(object): """Class representing a sequence of Hetero elements.""" def __init__(self, residues=""): """Initialize the class.""" self.data = [] if isinstance(residues, str): residues = residues.replace("*", " ") residues = residues.strip() elements = residues.split() self.data = [Hetero(x) for x in elements] elif isinstance(residues, list): for element in residues: if not isinstance(element, Hetero): raise CrystalError("Text must be a string") for residue in residues: self.data.append(residue) elif isinstance(residues, Chain): for residue in residues: self.data.append(residue) self.validate() def validate(self): """Check all data elements are of type Hetero.""" data = self.data for element in data: self.validate_element(element) def validate_element(self, element): """Check the element is of type Hetero.""" if not isinstance(element, Hetero): raise TypeError def __str__(self): output = "" for element in self.data: output = output + "%s " % element output = output.strip() output = wrap_line(output) return output def __eq__(self, other): if len(self.data) != len(other.data): return 0 ok = reduce( lambda x, y: x and y, map(lambda x, y: x == y, self.data, other.data) ) return ok def __ne__(self, other): """Return true iff self is not equal to other.""" return not self.__eq__(other) def __len__(self): return len(self.data) def __getitem__(self, index): if isinstance(index, int): return self.data[index] elif isinstance(index, slice): return self.__class__(self.data[index]) else: raise TypeError def __setitem__(self, index, value): if isinstance(index, int): try: self.validate_element(value) except TypeError: value = Hetero(value.lower()) self.data[index] = value elif isinstance(index, slice): if isinstance(value, Chain): self.data[index] = value.data elif isinstance(value, type(self.data)): self.data[index] = value elif isinstance(value, basestring): self.data[index] = Chain(value).data else: raise TypeError else: raise TypeError def __delitem__(self, index): del self.data[index] def __contains__(self, item): try: self.validate_element(item) except TypeError: item = Hetero(item.lower()) return item in self.data def append(self, item): """Add Hetero element.""" try: self.validate_element(item) except TypeError: item = Hetero(item.lower()) self.data.append(item) def insert(self, i, item): """Insert Hetero element in position i of the Chain.""" try: self.validate_element(item) except TypeError: item = Hetero(item.lower()) self.data.insert(i, item) def remove(self, item): """Delete Hetero element.""" item = Hetero(item.lower()) self.data.remove(item) def count(self, item): """Return number of elements in the Chain.""" try: self.validate_element(item) except TypeError: item = Hetero(item.lower()) return self.data.count(item) def index(self, item): """Find the index of the item.""" try: self.validate_element(item) except TypeError: item = Hetero(item.lower()) return self.data.index(item) def __add__(self, other): if isinstance(other, Chain): return self.__class__(self.data + other.data) elif isinstance(other, str): return self.__class__(self.data + Chain(other).data) else: raise TypeError def __radd__(self, other): if isinstance(other, Chain): return self.__class__(other.data + self.data) elif isinstance(other, str): return self.__class__(Chain(other).data + self.data) else: raise TypeError def __iadd__(self, other): if isinstance(other, Chain): self.data += other.data elif isinstance(other, str): self.data += Chain(other).data else: raise TypeError return self class Crystal(object): """Represents a dictionary of labeled chains from the same structure.""" def __init__(self, data=None): """Initialize the class.""" # Enforce storage if not isinstance(data, dict): raise CrystalError("Crystal must be a dictionary") if data is None: self.data = {} else: self.data = data self.fix() def fix(self): """Change element of type string to type Chain. All elements of Crystal shall be Chain. """ data = self.data for key in data: element = data[key] if isinstance(element, Chain): pass elif isinstance(element, str): data[key] = Chain(element) else: raise TypeError def __repr__(self): output = "" for key in sorted(self.data): output += "%s : %s\n" % (key, self.data[key]) return output def __str__(self): output = "" for key in sorted(self.data): output += "%s : %s\n" % (key, self.data[key]) return output def tostring(self): """Return Chains and correspondent Heteros.""" return self.data def __len__(self): return len(self.data) def __getitem__(self, key): return self.data[key] def __setitem__(self, key, item): if isinstance(item, Chain): self.data[key] = item elif isinstance(item, str): self.data[key] = Chain(item) else: raise TypeError def __delitem__(self, key): del self.data[key] def clear(self): """Empty the data.""" self.data.clear() def copy(self): """Copy the Crystal object.""" return copy.copy(self) def keys(self): """Return all Chain labels.""" return self.data.keys() def items(self): """Return all tuples (Chain label, Hetero).""" return self.data.items() def values(self): """Return all Hetero in the Chains.""" return self.data.values() def __contains__(self, value): return value in self.data def has_key(self, key): """Return true if the Chain Label is in the dictionary.""" return key in self.data def get(self, key, failobj=None): """Return Hetero for the given Chain Label.""" return self.data.get(key, failobj) def setdefault(self, key, failobj=None): """Return Hetero for the given Chain Label, if Chain Label is not there add it.""" if key not in self.data: self.data[key] = failobj return self.data[key] def popitem(self): """Return and delete a Chain.""" return self.data.popitem()