def _saveCB(okay, dialog, pathInfo=None): mav = dialog.mav if not okay: return if dialog.saveRegion.get(): try: saveSeqs, saveFileMarkups = _verifySaveRegion(mav) except: dialog.enter() raise else: saveSeqs = mav.seqs saveFileMarkups = mav.fileMarkups if dialog.omitGaps.get(): saveSeqs, saveFileMarkups = _omitGapColumns(saveSeqs, saveFileMarkups) if dialog.appendNumberings.get(): saveSeqs = _appendNumberings(saveSeqs, doCopy=(saveSeqs == mav.seqs)) if pathInfo is None: pathInfo = dialog.getPathsAndTypes() if not pathInfo: dialog.enter() raise ValueError, "No filename specified" from OpenSave import osOpen for path, fileType in pathInfo: f = osOpen(path, "w") saverFunc[fileType](f, mav, saveSeqs, saveFileMarkups) f.close() mav.status("Saved %s\n" % path) mav._edited = False
def _saveCB(okay, dialog, pathInfo=None): mav = dialog.mav if not okay: return if dialog.saveRegion.get(): try: saveSeqs, saveFileMarkups = _verifySaveRegion(mav) except: dialog.enter() raise else: saveSeqs = mav.seqs saveFileMarkups = mav.fileMarkups if dialog.omitGaps.get(): saveSeqs, saveFileMarkups = _omitGapColumns(saveSeqs, saveFileMarkups) if dialog.appendNumberings.get(): saveSeqs = _appendNumberings(saveSeqs, doCopy=(saveSeqs == mav.seqs)) if pathInfo is None: pathInfo = dialog.getPathsAndTypes() if not pathInfo: dialog.enter() raise ValueError, "No filename specified" from OpenSave import osOpen for path, fileType in pathInfo: f = osOpen(path, "w") saverFunc[fileType](f, mav, saveSeqs, saveFileMarkups) f.close() mav.status("Saved %s\n" % path) mav._edited = False
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") inSequence = 0 sequences = [] for line in f.readlines(): if inSequence: if not line or line.isspace(): inSequence = 0 continue if line[0] == '>': inSequence = 0 # fall through else: sequences[-1].extend(line.strip()) if not inSequence: if line[0] == '>': if sequences and len(sequences[-1]) == 0: raise FormatSyntaxError("No sequence" " found for %s" % sequences[-1].name) inSequence = 1 sequences.append(Sequence(makeReadable( line[1:]))) f.close() if not sequences: raise WrongFileTypeError() return sequences, {}, {}
def writeSel(saveFile, namingStyle=None, selected=True, itemType="Residue"): from chimera.selection import currentAtoms, currentBonds, \ currentEdges, currentResidues, currentMolecules, currentGraphs classNames = [c.__name__.lower() for c in classes] try: classIndex = classNames.index(itemType.lower()) except ValueError: # might be a trailing 's'... classIndex = classNames.index(itemType.lower()[:-1]) if selected: func = [currentAtoms, currentBonds, lambda : filter( lambda b: isinstance(b, chimera.PseudoBond), currentEdges()), currentResidues, currentMolecules, currentGraphs][classIndex] else: func = [unselAtoms, unselBonds, unselPseudobonds, unselResidues, unselMolecules, unselModels][classIndex] from chimera.misc import chimeraLabel, oslCmp items = map(lambda i: (i.oslIdent(), i), func()) if items and not isinstance(items[0][1], chimera.Bond) \ and not isinstance(items[0][1], chimera.PseudoBond): items.sort(oslCmp) if saveFile == "-": import sys f = sys.stdout else: from OpenSave import osOpen, tildeExpand saveFile = tildeExpand(saveFile) f = osOpen(saveFile, "w") for ident, item in items: print>>f, chimeraLabel(item, style=namingStyle, bondSep=" <-> ") if saveFile != "-": f.close()
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") # skip header crap inHeader = True lineNum = 0 sequences = [] for line in f: line = line.strip() lineNum += 1 if not line: continue fields = line.split() if inHeader: if len(fields[0]) == 2: continue inHeader = False if len(fields) != 2: # since this format lacks mandatory headers, # cannot be sure it _is_ a Pfam file and therefore # cannot raise FormatSyntaxError raise WrongFileTypeError() seq = Sequence(makeReadable(fields[0])) seq.extend(fields[1]) sequences.append(seq) f.close() if not sequences: raise WrongFileTypeError() return sequences, {}, {}
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") # skip header crap inHeader = True lineNum = 0 sequences = [] for line in f: line = line.strip() lineNum += 1 if not line: continue fields = line.split() if inHeader: if len(fields[0]) == 2: continue inHeader = False if len(fields) != 2: # since this format lacks mandatory headers, # cannot be sure it _is_ a Pfam file and therefore # cannot raise FormatSyntaxError raise WrongFileTypeError() seq = Sequence(makeReadable(fields[0])) seq.extend(fields[1]) sequences.append(seq) f.close() if not sequences: raise WrongFileTypeError() return sequences, {}, {}
def writeFile(fileName): from OpenSave import osOpen f = osOpen(fileName, 'w') if _ilabelModel: labelIDs = _ilabelModel.labelMap.keys() labelIDs.sort() for labelID in labelIDs: if labelID.startswith(AUTO_ID_PREFIX): print>>f, "Label" else: print>>f, "Label %s" % labelID label = _ilabelModel.labelMap[labelID] print>>f, "\t(x,y): %s" % repr(label.pos) print>>f, "\ttext: %s" % repr(unicode(label)) print>>f, "\tshown: %s" % label.shown print>>f, "\tfont size(s): %s" % _valuesString([str(c.size) for l in label.lines for c in l]) print>>f, "\tfont style(s): %s" % _valuesString([ FONT_STYLE_LABELS[FONT_STYLE_VALUES.index(c.style)] for l in label.lines for c in l]) print>>f, "\tfont typeface(s): %s" % _valuesString([ FONT_TYPEFACE_LABELS[FONT_TYPEFACE_VALUES.index(c.fontName)] for l in label.lines for c in l]) print>>f, "\tcolor(s): %s" % _valuesString([repr(c.rgba) for l in label.lines for c in l]) f.close()
def writeFile(fileName): from OpenSave import osOpen f = osOpen(fileName, 'w') if _ilabelModel: labelIDs = _ilabelModel.labelMap.keys() labelIDs.sort() for labelID in labelIDs: if labelID.startswith(AUTO_ID_PREFIX): print >> f, "Label" else: print >> f, "Label %s" % labelID label = _ilabelModel.labelMap[labelID] print >> f, "\t(x,y): %s" % repr(label.pos) print >> f, "\ttext: %s" % repr(unicode(label)) print >> f, "\tshown: %s" % label.shown print >> f, "\tfont size(s): %s" % _valuesString( [str(c.size) for l in label.lines for c in l]) print >> f, "\tfont style(s): %s" % _valuesString([ FONT_STYLE_LABELS[FONT_STYLE_VALUES.index(c.style)] for l in label.lines for c in l ]) print >> f, "\tfont typeface(s): %s" % _valuesString([ FONT_TYPEFACE_LABELS[FONT_TYPEFACE_VALUES.index(c.fontName)] for l in label.lines for c in l ]) print >> f, "\tcolor(s): %s" % _valuesString( [repr(c.rgba) for l in label.lines for c in l]) f.close()
def processCastpFiles(pdb, mouthAtoms, mouthInfo, pocketAtoms, pocketInfo, identifyAs=None): from OpenSave import osOpen if not identifyAs: identifyAs = pdb[:-4] pdb = osOpen(pdb) mouthAtoms = osOpen(mouthAtoms) mouthInfo = osOpen(mouthInfo) pocketAtoms = osOpen(pocketAtoms) pocketInfo = osOpen(pocketInfo) from chimera import PDBio pdbio = PDBio() molList = pdbio.readPDBstream(pdb, "CASTp PDB", 0)[0] pdb.close() if not pdbio.ok(): raise IOError(pdbio.error()) if not molList: raise ValueError("No structures in CASTp PDB file?!?") elif len(molList) > 1: raise ValueError("Multiple structures in CASTp PDB file?!?") structure = molList[0] structure.name = identifyAs mouthInfoDicts = processMouthInfoFile(mouthInfo) pocketInfoDicts = processPocketInfoFile(pocketInfo) mouthInfo.close() pocketInfo.close() if len(mouthInfoDicts) != len(pocketInfoDicts): raise ValueError("Number of mouths (%d) does not match number" " of pockets (%d)." % (len(mouthInfoDicts), len(pocketInfoDicts))) bySerial = {} for a in structure.atoms: bySerial[a.serialNumber] = a gatherAtoms(bySerial, "mouth", mouthAtoms, mouthInfoDicts) gatherAtoms(bySerial, "pocket", pocketAtoms, pocketInfoDicts) mouthAtoms.close() pocketAtoms.close() cavities = [] for mid, pid in zip(mouthInfoDicts, pocketInfoDicts): cavities.append(CastpCavity(mid, pid)) #chimera.openModels.add([structure]) return structure, cavities
def __init__(self, f): if isinstance(f, basestring): from OpenSave import osOpen file = osOpen(f) self._readMSF(file) file.close() else: self._readMSF(f)
def __init__(self, f): if isinstance(f, basestring): from OpenSave import osOpen file = osOpen(f) self._readMSF(file) file.close() else: self._readMSF(f)
def _fileOutput(fileName, outputInfo, namingStyle): intermodel, intramodel, relaxConstraints, \ distSlop, angleSlop, modelList, hbonds = outputInfo from OpenSave import osOpen outFile = osOpen(fileName, 'w') if intermodel: outFile.write("Finding intermodel H-bonds\n") if intramodel: outFile.write("Finding intramodel H-bonds\n") if relaxConstraints: outFile.write("Constraints relaxed by %g angstroms" " and %d degrees\n" % (distSlop, angleSlop)) else: outFile.write("Using precise constraint criteria\n") outFile.write("Models used:\n") for model in modelList: outFile.write("\t%s %s\n" % (model.oslIdent(), model.name)) outFile.write("\nH-bonds (donor, acceptor, hydrogen, D..A dist, D-H..A dist):\n") # want the bonds listed in some kind of consistent # order... hbonds.sort(_oslSort) # figure out field widths to make things line up dwidth = awidth = hwidth = 0 labels = {} from chimera.misc import chimeraLabel for don, acc in hbonds: labels[don] = chimeraLabel(don, style=namingStyle) labels[acc] = chimeraLabel(acc, style=namingStyle) dwidth = max(dwidth, len(labels[don])) awidth = max(awidth, len(labels[acc])) da = don.xformCoord().distance(acc.xformCoord()) dha = None for h in don.primaryNeighbors(): if h.element.number != 1: continue d = h.xformCoord().distance(acc.xformCoord()) if dha is None or d < dha: dha = d hyd = h if dha is None: dhaOut = "N/A" hydOut = "no hydrogen" else: dhaOut = "%5.3f" % dha hydOut = chimeraLabel(hyd, style=namingStyle) hwidth = max(hwidth, len(hydOut)) labels[(don, acc)] = (hydOut, da, dhaOut) for don, acc in hbonds: hydOut, da, dhaOut = labels[(don, acc)] outFile.write("%*s %*s %*s %5.3f %s\n" % ( 0-dwidth, labels[don], 0-awidth, labels[acc], 0-hwidth, hydOut, da, dhaOut)) if outFile != fileName: # we opened it, so close it... outFile.close()
def _fileChosen(okayed, dialog): if okayed: paths = dialog.getPaths() if paths: filename = paths[0] from OpenSave import osOpen outFile = osOpen(filename, "w") outFile.write(dialog._text) outFile.close() delattr(dialog, "_text")
def __init__(self, topology): from OpenSave import osOpen topFile = osOpen(topology, 'rb') import os self.topFileSize = os.stat(topology).st_size from xdrlib import Unpacker self.fileString = FileString(topFile, 0, self.topFileSize) self.xdr = Unpacker(self.fileString) version = self._readHeader() self._readTopology(version)
def __init__(self, topology): from OpenSave import osOpen topFile = osOpen(topology, 'rb') import os self.topFileSize = os.stat(topology).st_size from xdrlib import Unpacker self.fileString = FileString(topFile, 0, self.topFileSize) self.xdr = Unpacker(self.fileString) version = self._readHeader() self._readTopology(version)
def __init__(self, topology): from OpenSave import osOpen self.atomNames = [] self.resNames = [] self.resIndices = [] self.bonds = [] self.elements = [] self.molInfo = {} topFile = osOpen(topology) while self._readLine(topFile): pass topFile.close()
def __init__(self, topology): from OpenSave import osOpen self.atomNames = [] self.resNames = [] self.resIndices = [] self.bonds = [] self.elements = [] self.molInfo = {} topFile = osOpen(topology) while self._readLine(topFile): pass topFile.close()
def _fileChosen(okayed, dialog): if okayed: paths = dialog.getPaths() if paths: filename = paths[0] from OpenSave import osOpen outFile = osOpen(filename, "w") outFile.write(dialog._output) outFile.close() if dialog._show: import urllib from chimera import help help.display(urllib.pathname2url(filename)) delattr(dialog, "_output") delattr(dialog, "_show")
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") inHeader = 1 sequences = [] lineNum = 0 for line in f.readlines(): lineNum += 1 if inHeader: if line.startswith("CLUSTAL"): inHeader = 0 firstBlock = 1 else: if line.strip() !="": raise WrongFileTypeError() continue if not line or line[0].isspace(): if sequences: firstBlock = 0 expect = 0 continue try: seqName, seqBlock, numResidues = line.split() except ValueError: try: seqName, seqBlock = line.split() except ValueError: raise FormatSyntaxError("Line %d is not " "sequence name followed by sequence " " contents and optional ungapped length" % lineNum) if firstBlock: sequences.append(Sequence(makeReadable(seqName))) sequences[-1].append(seqBlock) continue try: seq = sequences[expect] except IndexError: raise FormatSyntaxError("Sequence on line %d not in" " initial sequence block" % lineNum) expect += 1 seq.append(seqBlock) f.close() if not sequences: raise WrongFileTypeError() return sequences, {}, {}
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") inHeader = 1 sequences = [] lineNum = 0 for line in f.readlines(): lineNum += 1 if inHeader: if line.startswith("CLUSTAL"): inHeader = 0 firstBlock = 1 else: if line.strip() != "": raise WrongFileTypeError() continue if not line or line[0].isspace(): if sequences: firstBlock = 0 expect = 0 continue try: seqName, seqBlock, numResidues = line.split() except ValueError: try: seqName, seqBlock = line.split() except ValueError: raise FormatSyntaxError( "Line %d is not " "sequence name followed by sequence " " contents and optional ungapped length" % lineNum) if firstBlock: sequences.append(Sequence(makeReadable(seqName))) sequences[-1].append(seqBlock) continue try: seq = sequences[expect] except IndexError: raise FormatSyntaxError("Sequence on line %d not in" " initial sequence block" % lineNum) expect += 1 seq.append(seqBlock) f.close() if not sequences: raise WrongFileTypeError() return sequences, {}, {}
def _fileOutput(fileName, info, namingStyle): overlapCutoff, hbondAllowance, bondSeparation, ignoreIntraRes, \ clashes, outputGrouping = info from OpenSave import osOpen outFile = osOpen(fileName, 'w') print>>outFile, "Allowed overlap: %g" % overlapCutoff print>>outFile, "H-bond overlap reduction: %g" % hbondAllowance print>>outFile, "Ignore contacts between atoms separated by %d bonds" \ " or less" % bondSeparation if ignoreIntraRes: print>>outFile, "Ignore intra-residue contacts" else: print>>outFile, "Detect intra-residue contacts also" seen = set() data = [] from chimera.misc import chimeraLabel for a, aclashes in clashes.items(): for c, val in aclashes.items(): if (c, a) in seen: continue seen.add((a, c)) if a in outputGrouping: out1, out2 = a, c else: out1, out2 = c, a l1, l2 = chimeraLabel(out1, style=namingStyle), \ chimeraLabel(out2, style=namingStyle) data.append((val, l1, l2, out1.xformCoord().distance( out2.xformCoord()))) data.sort() data.reverse() print>>outFile, "\n%d contacts" % len(data) print>>outFile, "atom1 atom2 overlap distance" if data: fieldWidth1 = max([len(l1) for v, l1, l2, d in data]) fieldWidth2 = max([len(l2) for v, l1, l2, d in data]) for v, l1, l2, d in data: print>>outFile, "%*s %*s %5.3f %5.3f" % ( 0-fieldWidth1, l1, 0-fieldWidth2, l2, v, d) if fileName != outFile: # only close file if we opened it... outFile.close()
def _fileOutput(fileName, info, namingStyle): overlapCutoff, hbondAllowance, bondSeparation, ignoreIntraRes, \ clashes, outputGrouping = info from OpenSave import osOpen outFile = osOpen(fileName, 'w') print >> outFile, "Allowed overlap: %g" % overlapCutoff print >> outFile, "H-bond overlap reduction: %g" % hbondAllowance print>>outFile, "Ignore contacts between atoms separated by %d bonds" \ " or less" % bondSeparation if ignoreIntraRes: print >> outFile, "Ignore intra-residue contacts" else: print >> outFile, "Detect intra-residue contacts also" seen = set() data = [] from chimera.misc import chimeraLabel for a, aclashes in clashes.items(): for c, val in aclashes.items(): if (c, a) in seen: continue seen.add((a, c)) if a in outputGrouping: out1, out2 = a, c else: out1, out2 = c, a l1, l2 = chimeraLabel(out1, style=namingStyle), \ chimeraLabel(out2, style=namingStyle) data.append( (val, l1, l2, out1.xformCoord().distance(out2.xformCoord()))) data.sort() data.reverse() print >> outFile, "\n%d contacts" % len(data) print >> outFile, "atom1 atom2 overlap distance" if data: fieldWidth1 = max([len(l1) for v, l1, l2, d in data]) fieldWidth2 = max([len(l2) for v, l1, l2, d in data]) for v, l1, l2, d in data: print >> outFile, "%*s %*s %5.3f %5.3f" % ( 0 - fieldWidth1, l1, 0 - fieldWidth2, l2, v, d) if fileName != outFile: # only close file if we opened it... outFile.close()
def open_mmcif(path): from OpenSave import osOpen p = osOpen(path) # # No bonds are created for standard mmCIF files from the PDB unless the # library_bonds or distance_bonds options are given. # # It appears that mmlib 0.9.7 can only link residues of a polymer using # distance rules. Residue templates are used for intra-residue bonds. # from mmLib.FileIO import LoadStructure from mmLib.mmCIF import mmCIFSyntaxError try: struct = LoadStructure(fil=p, format="CIF", library_bonds=True, auto_sort=False) except mmCIFSyntaxError, e: from chimera import NotABug raise NotABug("%s: %s" % (path, str(e)))
def writeDMS(surf, fileName, writeNormals=True, displayedOnly=True): from OpenSave import osOpen from chimera import UserError, replyobj m = surf.molecule if not m: raise UserError("No molecule for surface") out = osOpen(fileName, "wb") vMap = {} for i, a in enumerate(surf.atomMap): vMap.setdefault(a, []).append(i) for i, a in enumerate(m.atoms): atomPart = atomFormat(a) crd = a.coord() print>>out, "%s%8.3f %8.3f %8.3f A" % (atomPart, crd.x, crd.y, crd.z) if displayedOnly and not a.surfaceDisplay: continue vertices = surf.surface_piece.geometry[0] normals = surf.surface_piece.normals vtypes = surf.triData[1][:,2] # vtypes (according to MSMS man page): # 1 == toric reentrant # 2 == inside reentrant # 3 == inside contact vses = surf.triData[0][:,6] for vi in vMap.get(a, []): v = vertices[vi] vtype = vtypes[vi] try: dmsType = ('S', 'R', 'C')[vtype-1] except IndexError: raise ValueError("Vertex type (%d) not in" " range 1-3" % vtype) ses = vses[vi] line = "%s%8.3f %8.3f %8.3f S%s0 %6.3f" % (atomPart, v[0], v[1], v[2], dmsType, ses) if writeNormals: line += " %6.3f %6.3f %6.3f" \ % tuple(normals[vi]) print>>out, line out.close()
def writeDMS(surf, fileName, writeNormals=True, displayedOnly=True): from OpenSave import osOpen from chimera import UserError, replyobj m = surf.molecule if not m: raise UserError("No molecule for surface") out = osOpen(fileName, "wb") vMap = {} for i, a in enumerate(surf.atomMap): vMap.setdefault(a, []).append(i) for i, a in enumerate(m.atoms): atomPart = atomFormat(a) crd = a.coord() print >> out, "%s%8.3f %8.3f %8.3f A" % (atomPart, crd.x, crd.y, crd.z) if displayedOnly and not a.surfaceDisplay: continue vertices = surf.surface_piece.geometry[0] normals = surf.surface_piece.normals vtypes = surf.triData[1][:, 2] # vtypes (according to MSMS man page): # 1 == toric reentrant # 2 == inside reentrant # 3 == inside contact vses = surf.triData[0][:, 6] for vi in vMap.get(a, []): v = vertices[vi] vtype = vtypes[vi] try: dmsType = ('S', 'R', 'C')[vtype - 1] except IndexError: raise ValueError("Vertex type (%d) not in" " range 1-3" % vtype) ses = vses[vi] line = "%s%8.3f %8.3f %8.3f S%s0 %6.3f" % (atomPart, v[0], v[1], v[2], dmsType, ses) if writeNormals: line += " %6.3f %6.3f %6.3f" \ % tuple(normals[vi]) print >> out, line out.close()
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") want = 'init' sequences = [] for line in f.readlines(): line = line.strip() if want == 'init': if len(line) < 4: continue if line[0] != '>' or line[3] != ';': continue sequences.append(Sequence(makeReadable(line[4:]))) pirType = line[1:3] if pirType in ("P1", "F1"): sequences[-1].nucleic = 0 else: sequences[-1].nucleic = 1 sequences[-1].PIRtype = pirType want = 'descript' elif want == 'descript': sequences[-1].descript = line sequences[-1].PIRdescript = line want = 'sequence' elif want == 'sequence': if not line: continue if line[-1] == '*': want = 'init' line = line[:-1] sequences[-1].extend(filter(lambda c, whsp=string.whitespace: not c in whsp, line)) f.close() if not sequences: raise WrongFileTypeError() if want != 'init': raise FormatSyntaxError("Could not find end of sequence '%s'" % sequences[-1].name) return sequences, {}, {}
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") want = 'init' sequences = [] for line in f.readlines(): line = line.strip() if want == 'init': if len(line) < 4: continue if line[0] != '>' or line[3] != ';': continue sequences.append(Sequence(makeReadable(line[4:]))) pirType = line[1:3] if pirType in ("P1", "F1"): sequences[-1].nucleic = 0 else: sequences[-1].nucleic = 1 sequences[-1].PIRtype = pirType want = 'descript' elif want == 'descript': sequences[-1].descript = line sequences[-1].PIRdescript = line want = 'sequence' elif want == 'sequence': if not line: continue if line[-1] == '*': want = 'init' line = line[:-1] sequences[-1].extend( filter(lambda c, whsp=string.whitespace: not c in whsp, line)) f.close() if not sequences: raise WrongFileTypeError() if want != 'init': raise FormatSyntaxError("Could not find end of sequence '%s'" % sequences[-1].name) return sequences, {}, {}
def open_mmcif(path): from OpenSave import osOpen p = osOpen(path) # # No bonds are created for standard mmCIF files from the PDB unless the # library_bonds or distance_bonds options are given. # # It appears that mmlib 0.9.7 can only link residues of a polymer using # distance rules. Residue templates are used for intra-residue bonds. # from mmLib.FileIO import LoadStructure from mmLib.mmCIF import mmCIFSyntaxError try: struct = LoadStructure(fil=p, format="CIF", library_bonds=True, auto_sort=False) except mmCIFSyntaxError, e: from chimera import NotABug raise NotABug("%s: %s" % (path, str(e)))
def writeSel(saveFile, namingStyle=None, selected=True, itemType="Residue"): from chimera.selection import currentAtoms, currentBonds, \ currentEdges, currentResidues, currentMolecules, currentGraphs classNames = [c.__name__.lower() for c in classes] try: classIndex = classNames.index(itemType.lower()) except ValueError: # might be a trailing 's'... classIndex = classNames.index(itemType.lower()[:-1]) if selected: func = [ currentAtoms, currentBonds, lambda: filter( lambda b: isinstance(b, chimera.PseudoBond), currentEdges()), currentResidues, currentMolecules, currentGraphs ][classIndex] else: func = [ unselAtoms, unselBonds, unselPseudobonds, unselResidues, unselMolecules, unselModels ][classIndex] from chimera.misc import chimeraLabel, oslCmp items = map(lambda i: (i.oslIdent(), i), func()) if items and not isinstance(items[0][1], chimera.Bond) \ and not isinstance(items[0][1], chimera.PseudoBond): items.sort(oslCmp) if saveFile == "-": import sys f = sys.stdout else: from OpenSave import osOpen, tildeExpand saveFile = tildeExpand(saveFile) f = osOpen(saveFile, "w") for ident, item in items: print >> f, chimeraLabel(item, style=namingStyle, bondSep=" <-> ") if saveFile != "-": f.close()
def Apply(self, event=None): paths = self.getPaths() if not paths: raise ValueError, "No filename given for recording" fname = paths[0] if self.appending.get(): mode = "a" else: mode = "w" from OpenSave import osOpen file = osOpen(fname, mode) writePython = self.commandStyle.getvalue()[:6] == "Python" if writePython: file.write("from chimera import runCommand\n") if self.amount.getvalue()[:3] == "all": cmds = self.histDialog.listbox.get() else: cmds = self.histDialog.listbox.getvalue() for cmd in cmds: if writePython: file.write("runCommand(" + repr(cmd) + ")\n") else: file.write(cmd + "\n") file.close()
def readSDF(fileName, identifyAs=None): from OpenSave import osOpen from chimera import UserError, Molecule, Element, openModels, replyobj from chimera import Coord state = "init" f = osOpen(fileName) mols = [] nonblank = False for l in f: line = l.strip() nonblank = nonblank or line if state == "init": state = "post header 1" molName = line elif state == "post header 1": state = "post header 2" elif state == "post header 2": state = "counts" elif state == "counts": if not line: break state = "atoms" serial = 1 anums = {} atoms = [] try: numAtoms = int(l[:3].strip()) numBonds = int(l[3:6].strip()) except ValueError: raise UserError("Atom/bond counts line of" " MOL/SDF file '%s' is botched: '%s'" % (fileName, l)) m = Molecule() mols.append(m) if identifyAs: m.name = identifyAs else: from chimera.misc import isInformativeName mn = molName.strip() if isInformativeName(mn): m.name = mn else: import os.path m.name = os.path.split(fileName)[-1] r = m.newResidue("UNK", " ", 1, " ") elif state == "atoms": numAtoms -= 1 if numAtoms == 0: if numBonds: state = "bonds" else: state = "properties" try: x = float(l[:10].strip()) y = float(l[10:20].strip()) z = float(l[21:30].strip()) elem = l[31:34].strip() except ValueError: raise UserError("Atom line of MOL/SDF file" " '%s' is not x y z element...: '%s'" % (fileName, l)) element = Element(elem) if element.number == 0: # lone pair or somesuch atoms.append(None) continue anum = anums.get(element.name, 0) + 1 anums[element.name] = anum a = m.newAtom("%s%d" % (element.name, anum), element) atoms.append(a) r.addAtom(a) a.setCoord(Coord(x, y, z)) a.serialNumber = serial serial += 1 elif state == "bonds": numBonds -= 1 if numBonds == 0: state = "properties" try: a1index = int(l[:3].strip()) a2index = int(l[3:6].strip()) order = int(l[6:9].strip()) except ValueError: raise UserError("Bond line of MOL/SDF file" " '%s' is not a1 a2 order...: '%s'" % (fileName, l)) a1 = atoms[a1index-1] a2 = atoms[a2index-1] if not a1 or not a2: continue m.newBond(a1, a2).order = order elif state == "properties": if not m.atoms: raise UserError("No atoms found for compound" " '%s' in MOL/SDF file '%s'" % (m.name, fileName)) if line.split() == ["M", "END"]: state = "data" elif state == "data": if line == "$$$$": nonblank = False state = "init" f.close() if nonblank and state not in ["data", "init"]: if mols: replyobj.warning("Extraneous text after final $$$$" " in MOL/SDF file '%s'" % fileName) else: raise UserError("Unexpected end of file (parser state:" " %s) in MOL/SDF file '%s'" % (state, fileName)) return mols
def parse(fileName): from OpenSave import osOpen from chimera import replyobj f = osOpen(fileName, "r") lineNum = 0 fileAttrs = {} fileMarkups = {} seqAttrs = {} seqMarkups = {} sequences = {} seqSequence = [] for line in f: line = line[:-1] # drop newline lineNum += 1 if lineNum == 1: if line.startswith("# STOCKHOLM"): continue raise WrongFileTypeError() if not line: continue if line.startswith('#='): markupType = line[2:4] markup = line[5:].strip() def trySplit(numSplit): fields = markup.split(None, numSplit) if len(fields) == numSplit: # value is empty fields.append("") if len(fields) != numSplit + 1: raise FormatSyntaxError("Not enough" " arguments after #=%s markup" " on line %d" % (markupType, lineNum)) return fields if markupType == "GF": tag, val = trySplit(1) tag = tag.replace("_", " ") tag = genericFileAttrs.get(tag, "Stockholm " + tag) if tag in fileAttrs: fileAttrs[tag] += '\n' + val else: fileAttrs[tag] = val elif markupType == "GS": seqName, tag, val = trySplit(2) tag = tag.replace("_", " ") attrs = seqAttrs.setdefault(seqName, {}) tag = genericSeqAttrs.get(tag, "Stockholm " + tag) if tag in attrs: attrs[tag] += '\n' + val else: attrs[tag] = val elif markupType == "GC": tag, val = trySplit(1) tag = tag.replace("_", " ") fileMarkups[tag] = fileMarkups.get(tag, "") + val elif markupType == "GR": seqName, tag, val = trySplit(2) tag = tag.replace("_", " ") seqMarkups.setdefault(seqName, {}).setdefault(tag, "") seqMarkups[seqName][tag] += val # ignore other types continue elif line.startswith('#'): # unstructured comment if 'comments' in fileAttrs: fileAttrs['comments'] += "\n" + line[1:] else: fileAttrs['comments'] = line[1:] continue elif line.strip() == "//": # end of sequence alignment blocks, but comments # may follow this, so keep going... continue # sequence info... try: seqName, block = line.split(None, 1) except ValueError: raise FormatSyntaxError("Sequence info not in name/" "contents format on line %d" % lineNum) if seqName not in sequences: sequences[seqName] = Sequence(makeReadable(seqName)) seqSequence.append(seqName) sequences[seqName].extend(block) f.close() if not sequences: raise FormatSyntaxError("No sequences found") for seqName, seq in sequences.items(): if seqName in seqAttrs: seq.attrs = seqAttrs[seqName] if seqName in seqMarkups: seq.markups = seqMarkups[seqName] for tag, markup in seq.markups.items(): if len(markup) != len(seq): replyobj.warning("Markup %s for" " sequence %s is wrong length;" " ignoring\n" % (tag, seqName)) del seq.markups[tag] for seqInfo, label in [(seqAttrs, "sequence"), (seqMarkups, "residue")]: for seqName in seqInfo.keys(): if seqName in sequences: continue # might be sequence name without trailing '/start-end' for fullName in sequences.keys(): if fullName.startswith(seqName) \ and fullName[len(seqName)] == '/' \ and '/' not in fullName[len(seqName)+1:]: break else: raise FormatSyntaxError( "%s annotations " "provided for non-existent sequence %s" % (label.capitalize(), seqName)) replyobj.info("Updating %s %s annotions with %s " "annotations\n" % (fullName, label, seqName)) seqInfo[fullName].update(seqInfo[seqName]) del seqInfo[seqName] for tag, markup in fileMarkups.items(): if len(markup) != len(sequences[seqSequence[0]]): raise FormatSyntaxError("Column annotation %s is" " wrong length" % tag) return map(lambda name: sequences[name], seqSequence), \ fileAttrs, fileMarkups
def Apply(self): savePaths = self.getPaths() if not savePaths: replyobj.error("No save file specified\n") return from OpenSave import osOpen saveFile = osOpen(savePaths[0], "w") mols = chimera.openModels.list(modelTypes=[chimera.Molecule]) for mol in mols: print>>saveFile, "Model %s is %s" % (mol.oslIdent(), mol.name) sm = self.structMeasure selected = self.saveTypes.getcurselection() if DISTANCES in selected: print>>saveFile, "\nDistance information" output = {} for d in sm.distances: a1, a2 = d.atoms distID = d.id if d.distance[-1].isdigit(): dval = d.distance else: # omit angstrom character dval = d.distance[:-1] output[distID] = "%2d %s <-> %s: %s" % ( distID, sm.atomLabel(a1), sm.atomLabel(a2), dval) ids = output.keys() ids.sort() for distID in ids: print>>saveFile, output[distID] if ANGLES in selected: print>>saveFile, "\nAngles/Torsions" printables = [] maxLabel = 0 for atoms in sm.angleInfo: labelArgs = tuple([sm.atomLabel(a) for a in atoms]) if len(atoms) == 3: label = "%s -> %s -> %s" % labelArgs func = chimera.angle else: label = "%s -> %s -> %s -> %s" \ % labelArgs func = chimera.dihedral maxLabel = max(maxLabel, len(label)) printables.append((label, "%8.3f" % func(*tuple([a.xformCoord() for a in atoms])))) format = "%%%ds: %%s" % maxLabel for printArgs in printables: print>>saveFile, format % printArgs if BONDROTS in selected: print>>saveFile, "\nBond rotations" printables = [] maxLabel = 0 for br in sm.rotations: na, fa = sm.dihedEndAtoms(br) label = "%s -> %s -> %s -> %s" % ( sm.atomLabel(na), sm.atomLabel(br.atoms[0]), sm.atomLabel(br.atoms[1]), sm.atomLabel(fa)) maxLabel = max(maxLabel, len(label)) printables.append((label, "%8.3f" % sm.dihedral(br), "%8.3f" % br.get())) format = "%%%ds: %%s (delta: %%s)" % maxLabel for printArgs in printables: print>>saveFile, format % printArgs if GEOMETRIES in selected: print>>saveFile, "\nAxes" print>>saveFile, "axis name, length, center, direction" from Axes import axisManager axes = axisManager.axes axes.sort(lambda a1, a2: cmp(a1.name, a2.name)) nameSize = max([0] + [len(a.name) for a in axes]) from chimera import Point for axis in axes: ends = [axis.direction * ext + axis.center for ext in axis.extents] cx, cy, cz = Point(ends) dx, dy, dz = axis.direction print>>saveFile, "%*s: %6.3f (%7.3f, %7.3f," \ " %7.3f) (%6.3f, %6.3f, %6.3f)" % ( nameSize, axis.name, abs(axis.extents[0] - axis.extents[1]), cx, cy, cz, dx, dy, dz) print>>saveFile, "\nPlanes" print>>saveFile, "plane name, center, normal, radius" from Planes import planeManager planes = planeManager.planes planes.sort(lambda p1, p2: cmp(p1.name, p2.name)) nameSize = max([0] + [len(pl.name) for pl in planes]) for plane in planes: ox, oy, oz = plane.plane.origin nx, ny, nz = plane.plane.normal print>>saveFile, "%*s: (%7.3f, %7.3f, %7.3f)" \ " (%6.3f, %6.3f, %6.3f) %.3f" % (nameSize, plane.name, ox, oy, oz, nx, ny, nz, plane.radius) saveFile.close()
def writeMol2(models, fileName, status=None, anchor=None, relModel=None, hydNamingStyle="sybyl", multimodelHandling="individual", skip=None, resNum=True, gaffType=False, gaffFailError=None): """Write a Mol2 file. 'models' are the models to write out into a file named 'fileName'. 'status', if not None, is a function that takes a string -- used to report the progress of the write. 'anchor' is a selection (i.e. instance of a subclass of chimera.selection.Selection) containing atoms/bonds that should be written out to the @SETS section of the file as the rigid framework for flexible ligand docking. 'hydNamingStyle' controls whether hydrogen names should be "Sybyl-like" (value: sybyl) or "PDB-like" (value: pdb) -- e.g. HG21 vs. 1HG2. 'multimodelHandling' controls whether multiple models will be combined into a single @MOLECULE section (value: combined) or each given its own section (value: individual). 'skip' is a list of atoms to not output 'resNum' controls whether residue sequence numbers are included in the substructure name. Since Sybyl Mol2 files include them, this defaults to True. If 'gaffType' is True, outout GAFF atom types instead of Sybyl atom types. 'gaffFailError', if specified, is the type of error to throw (e.g. UserError) if there is no gaffType attribute for an atom, otherwise throw the standard AttributeError. """ # open the given file name for writing from OpenSave import osOpen f = osOpen(fileName, "w") sortFunc = serialSort = lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex) if isinstance(models, chimera.Molecule): models = [models] elif isinstance(models, Selection): # create a fictitious jumbo model if isinstance(models, ItemizedSelection): sel = models else: sel = ItemizedSelection() sel.merge(models) sel.addImplied() class Jumbo: def __init__(self, sel): self.atoms = sel.atoms() self.residues = sel.residues() self.bonds = sel.bonds() self.name = "(selection)" models = [Jumbo(sel)] sortFunc = lambda a1, a2: cmp(a1.molecule.id, a2.molecule.id) \ or cmp(a1.molecule.subid, a2.molecule.subid) \ or serialSort(a1, a2) multimodelHandling = "individual" # transform... if relModel is None: xform = chimera.Xform.identity() else: xform = relModel.openState.xform xform.invert() # need to find amide moieties since Sybyl has an explicit amide type if status: status("Finding amides\n") from ChemGroup import findGroup amides = findGroup("amide", models) amideNs = dict.fromkeys([amide[2] for amide in amides]) amideCNs = dict.fromkeys([amide[0] for amide in amides]) amideCNs.update(amideNs) amideOs = dict.fromkeys([amide[1] for amide in amides]) substructureNames = None if multimodelHandling == "combined": # create a fictitious jumbo model class Jumbo: def __init__(self, models): self.atoms = [] self.residues = [] self.bonds = [] self.name = models[0].name + " (combined)" for m in models: self.atoms.extend(m.atoms) self.residues.extend(m.residues) self.bonds.extend(m.bonds) # if combining single-residue models, # can be more informative to use model name # instead of residue type for substructure if len(models) == len(self.residues): rtypes = [r.type for r in self.residues] if len(set(rtypes)) < len(rtypes): mnames = [m.name for m in models] if len(set(mnames)) == len(mnames): self.substructureNames = dict( zip(self.residues, mnames)) models = [Jumbo(models)] if hasattr(models[-1], 'substructureNames'): substructureNames = models[-1].substructureNames delattr(models[-1], 'substructureNames') sortFunc = lambda a1, a2: cmp(a1.molecule.id, a2.molecule.id) \ or cmp(a1.molecule.subid, a2.molecule.subid) \ or serialSort(a1, a2) # write out models for mol in models: if hasattr(mol, 'mol2comments'): for m2c in mol.mol2comments: print>>f, m2c if hasattr(mol, 'solventInfo' ): print>>f, mol.solventInfo # molecule section header print>>f, "%s" % MOLECULE_HEADER # molecule name print>>f, "%s" % mol.name ATOM_LIST = mol.atoms BOND_LIST = mol.bonds if skip: skip = set(skip) ATOM_LIST = [a for a in ATOM_LIST if a not in skip] BOND_LIST = [b for b in BOND_LIST if b.atoms[0] not in skip and b.atoms[1] not in skip] RES_LIST = mol.residues # Chimera has an unusual internal order for its atoms, so # sort them by input order if status: status("Putting atoms in input order") ATOM_LIST.sort(sortFunc) # if anchor is not None, then there will be two entries in # the @SETS section of the file... if anchor: sets = 2 else: sets = 0 # number of entries for various sections... print>>f, "%d %d %d 0 %d" % (len(ATOM_LIST), len(BOND_LIST), len(RES_LIST), sets) # type of molecule if hasattr(mol, "mol2type"): mtype = mol.mol2type else: mtype = "SMALL" from chimera.resCode import nucleic3to1, protein3to1 for r in mol.residues: if r.type in protein3to1: mtype = "PROTEIN" break if r.type in nucleic3to1: mtype = "NUCLEIC_ACID" break print>>f, mtype # indicate type of charge information if hasattr(mol, 'chargeModel'): print>>f, mol.chargeModel else: print>>f, "NO_CHARGES" if hasattr(mol, 'mol2comment'): print>>f, "\n%s" % mol.mol2comment else: print>>f, "\n" if status: status("writing atoms\n") # atom section header print>>f, "%s" % ATOM_HEADER # make a dictionary of residue indices so that we can do # quick look ups resIndices = {} for i, r in enumerate(RES_LIST): resIndices[r] = i+1 for i, atom in enumerate(ATOM_LIST): # atom ID, starting from 1 print>>f, "%7d" % (i+1), # atom name, possibly rearranged if it's a hydrogen if hydNamingStyle == "sybyl" \ and not atom.name[0].isalpha(): atomName = atom.name[1:] + atom.name[0] else: atomName = atom.name print>>f, "%-8s" % atomName, # untransformed coordinate position coord = xform.apply(atom.xformCoord()) print>>f, "%9.4f %9.4f %9.4f" % ( coord.x, coord.y, coord.z), # atom type if gaffType: try: atomType = atom.gaffType except AttributeError: if not gaffFailError: raise raise gaffFailError("%s has no Amber/GAFF type assigned.\n" "Use the AddCharge tool to assign Amber/GAFF types." % atom) elif hasattr(atom, 'mol2type'): atomType = atom.mol2type elif atom in amideNs: atomType = "N.am" elif atom.residue.id.chainId == "water": if atom.element.name == "O": atomType = "O.t3p" else: atomType = "H.t3p" elif atom.element.name == "N" and len( [r for r in atom.minimumRings() if r.aromatic()]) > 0: atomType = "N.ar" elif atom.idatmType == "C2" and len([nb for nb in atom.neighbors if nb.idatmType == "Ng+"]) > 2: atomType = "C.cat" else: try: atomType = chimera2sybyl[atom.idatmType] except KeyError: chimera.replyobj.warning("Atom whose" " IDATM type has no equivalent" " Sybyl type: %s (type: %s)\n" % (atom.oslIdent(), atom.idatmType)) atomType = str(atom.element) print>>f, "%-5s" % atomType, # residue-related info res = atom.residue # residue index print>>f, "%5d" % resIndices[res], # substructure identifier and charge if hasattr(atom, 'charge'): charge = atom.charge else: charge = 0.0 if substructureNames: rname = substructureNames[res] elif resNum: rname = "%3s%-5d" % (res.type, res.id.position) else: rname = "%3s" % res.type print>>f, "%s %9.4f" % (rname, charge) if status: status("writing bonds\n") # bond section header print>>f, "%s" % BOND_HEADER # make an atom-index dictionary to speed lookups atomIndices = {} for i, a in enumerate(ATOM_LIST): atomIndices[a] = i+1 for i, bond in enumerate(BOND_LIST): a1, a2 = bond.atoms # ID print>>f, "%6d" % (i+1), # atom IDs print>>f, "%4d %4d" % ( atomIndices[a1], atomIndices[a2]), # bond order; give it our best shot... amideA1 = a1 in amideCNs amideA2 = a2 in amideCNs if amideA1 and amideA2: print>>f, "am" continue if amideA1 or amideA2: if a1 in amideOs or a2 in amideOs: print>>f, "2" else: print>>f, "1" continue aromatic = False for ring in bond.minimumRings(): if ring.aromatic(): aromatic = True break if aromatic: print>>f, "ar" continue try: geom1 = typeInfo[a1.idatmType].geometry except KeyError: print>>f, "1" continue try: geom2 = typeInfo[a2.idatmType].geometry except KeyError: print>>f, "1" continue if geom1 not in [2,3] or geom2 not in [2,3]: print>>f, "1" continue # if either endpoint atom is in an aromatic ring and # the bond isn't, it's a single bond... for endp in [a1, a2]: aromatic = False for ring in endp.minimumRings(): if ring.aromatic(): aromatic = True break if aromatic: break else: # neither endpoint in aromatic ring print>>f, "2" continue print>>f, "1" if status: status("writing residues") # residue section header print>>f, "%s" % SUBSTR_HEADER for i, res in enumerate(RES_LIST): # residue id field print>>f, "%6d" % (i+1), # residue name field if substructureNames: rname = substructureNames[res] elif resNum: rname = "%3s%-4d" % (res.type, res.id.position) else: rname = "%3s" % res.type print>>f, rname, # ID of the root atom of the residue from chimera.misc import principalAtom chainAtom = principalAtom(res) if chainAtom is None: if hasattr(res, 'atomsMap'): chainAtom = res.atoms[0] else: chainAtom = res.atoms.values()[0][0] print>>f, "%5d" % atomIndices[chainAtom], print>>f, "RESIDUE 4", # Sybyl seems to use chain 'A' when chain ID is blank, # so run with that chainID = res.id.chainId if len(chainID.strip()) != 1: chainID = 'A' print>>f, "%s %3s" % (chainID, res.type), # number of out-of-substructure bonds crossResBonds = 0 if hasattr(res, "atomsMap"): atoms = res.atoms for a in atoms: for oa in a.bondsMap.keys(): if oa.residue != res: crossResBonds += 1 else: atoms = [a for aList in res.atoms.values() for a in aList] for a in atoms: for oa in a.bonds.keys(): if oa.residue != res: crossResBonds += 1 print>>f, "%5d" % crossResBonds, # print "ROOT" if first or only residue of a chain if a.molecule.rootForAtom(a, True).atom.residue == res: print>>f, "ROOT" else: print>>f # write flexible ligand docking info if anchor: if status: status("writing anchor info") print>>f, "%s" % SET_HEADER atomIndices = {} for i, a in enumerate(ATOM_LIST): atomIndices[a] = i+1 bondIndices = {} for i, b in enumerate(BOND_LIST): bondIndices[b] = i+1 print>>f, "ANCHOR STATIC ATOMS <user> **** Anchor Atom Set" atoms = anchor.atoms() print>>f, len(atoms), for a in atoms: if a in atomIndices: print>>f, atomIndices[a], print>>f print>>f, "RIGID STATIC BONDS <user> **** Rigid Bond Set" bonds = anchor.bonds() print>>f, len(bonds), for b in bonds: if b in bondIndices: print>>f, bondIndices[b], print>>f f.close()
def saveSession(filename): replyobj.status("Initializing session save...", blankAfter=0) from OpenSave import osOpen, tildeExpand fullName = tildeExpand(filename) try: outf = osOpen(fullName, "w") except: replyobj.reportException("Error opening %s for writing" % filename) return try: from cStringIO import StringIO except ImportError: from StringIO import StringIO class SessionIO: def __init__(self, stringIO, fileName): self.fileName = fileName self.stringIO = stringIO() def __getattr__(self, attrName): return getattr(self.stringIO, attrName) buf = SessionIO(StringIO, fullName) print >> outf, "import cPickle, base64" print >> outf, "try:" print >> outf, "\tfrom SimpleSession.versions.v45 import beginRestore,\\" print >> outf, "\t registerAfterModelsCB, reportRestoreError, checkVersion" print >> outf, "except ImportError:" print >> outf, "\tfrom chimera import UserError" print >> outf, "\traise UserError('Cannot open session that was saved in a'" print >> outf, "\t ' newer version of Chimera; update your version')" print >> outf, "checkVersion(%s)" % repr(version.releaseNum) print >> outf, "import chimera" print >> outf, "from chimera import replyobj" print >> outf, "replyobj.status('Beginning session restore...', \\" print >> outf, " blankAfter=0)" print >> outf, "beginRestore()" print >> outf, """ def restoreCoreModels(): \tfrom SimpleSession.versions.v45 import init, restoreViewer, \\ \t restoreMolecules, restoreColors, restoreSurfaces, \\ \t restoreVRML, restorePseudoBondGroups, restoreModelAssociations""" global _id2color, _color2id _id2color = {} _color2id = {} molecules = [ m for m in chimera.openModels.list(modelTypes=[chimera.Molecule], all=True) if autoRestorable(m) ] allSurfaces = chimera.openModels.list(modelTypes=[chimera.MSMSModel]) allVrmls = [ m for m in chimera.openModels.list(modelTypes=[chimera.VRMLModel]) if autoRestorable(m) ] surfaces = [s for s in allSurfaces if s.molecule] if surfaces != allSurfaces: replyobj.warning( "Cannot save surfaces without associated structure.\nSurface will not be saved.\n" ) vrmls = [] for v in allVrmls: source = v.openedAs[0] if not source.startswith('#VRML')\ and not os.path.exists(source): replyobj.warning("Source file for VRML model '%s' no" " longer exists.\nThe model will not be" " saved.\n" % v.name) else: vrmls.append(v) atoms = [] bonds = [] residues = [] for m in molecules: atoms.extend(m.atoms) bonds.extend(m.bonds) residues.extend(m.residues) mgr = chimera.PseudoBondMgr.mgr() pbGroups = [] for g in mgr.pseudoBondGroups: if g.category.startswith("internal-chain-"): noAutoRestore(g) else: pbGroups.append(g) pseudobonds = [] pbMap = {} for pbg in pbGroups: pbs = [ pb for pb in pbg.pseudoBonds if autoRestorable(pb.atoms[0].molecule) and autoRestorable(pb.atoms[1].molecule) ] pseudobonds.extend(pbs) pbMap[pbg] = pbs setSessionIDparams(molecules, residues, atoms, bonds, surfaces, vrmls, pseudobonds, pbGroups) replyobj.status("Gathering molecule information...", blankAfter=0) molInfo = {} molInfo['ids'] = summarizeVals([(m.id, m.subid) for m in molecules]) molInfo['name'] = summarizeVals([m.name for m in molecules]) molInfo['color'] = summarizeVals([colorID(m.color) for m in molecules]) molInfo['display'] = summarizeVals([m.display for m in molecules]) molInfo['lineWidth'] = summarizeVals([m.lineWidth for m in molecules]) molInfo['pointSize'] = summarizeVals([m.pointSize for m in molecules]) molInfo['stickScale'] = summarizeVals([m.stickScale for m in molecules]) molInfo['pdbHeaders'] = [m.pdbHeaders for m in molecules] molInfo['surfaceOpacity'] = summarizeVals( [m.surfaceOpacity for m in molecules]) molInfo['ballScale'] = summarizeVals([m.ballScale for m in molecules]) molInfo['vdwDensity'] = summarizeVals([m.vdwDensity for m in molecules]) molInfo['autochain'] = summarizeVals([m.autochain for m in molecules]) molInfo['ribbonHidesMainchain'] = summarizeVals( [m.ribbonHidesMainchain for m in molecules]) molInfo['ribbonInsideColor'] = summarizeVals( [colorID(m.ribbonInsideColor) for m in molecules]) molInfo['aromaticColor'] = summarizeVals( [colorID(m.aromaticColor) for m in molecules]) molInfo['aromaticDisplay'] = summarizeVals( [m.aromaticDisplay for m in molecules]) molInfo['aromaticLineType'] = summarizeVals( [m.aromaticLineType for m in molecules]) molInfo['aromaticMode'] = summarizeVals( [m.aromaticMode for m in molecules]) molInfo['hidden'] = summarizeVals( [m in m.openState.hidden for m in molecules]) molInfo['optional'] = saveOptionalAttrs(chimera.Molecule, molecules) print >> outf, "\tmolInfo =", pickled(molInfo) replyobj.status("Gathering residue information...", blankAfter=0) resInfo = {} resInfo['molecule'] = summarizeVals( [sessionID(r.molecule) for r in residues], consecutiveExceptions=True) resInfo['name'] = summarizeVals([r.type for r in residues]) resInfo['chain'] = summarizeVals([r.id.chainId for r in residues], consecutiveExceptions=True) resInfo['insert'] = summarizeVals([r.id.insertionCode for r in residues]) resInfo['position'] = summarizeSequentialVals( [r.id.position for r in residues]) resInfo['ribbonColor'] = summarizeVals( [colorID(r.ribbonColor) for r in residues], consecutiveExceptions=True) resInfo['labelColor'] = summarizeVals( [colorID(r.labelColor) for r in residues], consecutiveExceptions=True) resInfo['ss'] = summarizeVals([(r.isHelix, r.isStrand, r.isTurn) for r in residues], consecutiveExceptions=True) resInfo['ssId'] = summarizeVals([r.ssId for r in residues], consecutiveExceptions=True) resInfo['ribbonDrawMode'] = summarizeVals( [r.ribbonDrawMode for r in residues], consecutiveExceptions=True) resInfo['ribbonDisplay'] = summarizeVals( [r.ribbonDisplay for r in residues], consecutiveExceptions=True) resInfo['label'] = summarizeVals([r.label for r in residues]) resInfo['labelOffset'] = summarizeVals([r.labelOffset for r in residues]) resInfo['isHet'] = summarizeVals([r.isHet for r in residues], consecutiveExceptions=True) resInfo['fillDisplay'] = summarizeVals([r.fillDisplay for r in residues], consecutiveExceptions=True) resInfo['fillMode'] = summarizeVals([r.fillMode for r in residues], consecutiveExceptions=True) resInfo['optional'] = saveOptionalAttrs(chimera.Residue, residues) print >> outf, "\tresInfo =", pickled(resInfo) replyobj.status("Gathering atom information...", blankAfter=0) atomInfo = {} atomInfo['altLoc'] = summarizeVals([a.altLoc for a in atoms]) atomInfo['residue'] = summarizeVals([sessionID(a.residue) for a in atoms], consecutiveExceptions=True) atomInfo['element'] = summarizeVals([a.element.number for a in atoms]) atomInfo['name'] = summarizeVals([a.name for a in atoms]) atomInfo['color'] = summarizeVals([colorID(a.color) for a in atoms]) atomInfo['vdwColor'] = summarizeVals([colorID(a.vdwColor) for a in atoms]) atomInfo['labelColor'] = summarizeVals( [colorID(a.labelColor) for a in atoms]) atomInfo['surfaceColor'] = summarizeVals( [colorID(a.surfaceColor) for a in atoms]) atomInfo['drawMode'] = summarizeVals([a.drawMode for a in atoms], consecutiveExceptions=True) atomInfo['display'] = summarizeVals([a.display for a in atoms], consecutiveExceptions=True) atomInfo['label'] = summarizeVals([a.label for a in atoms]) atomInfo['labelOffset'] = summarizeVals([a.labelOffset for a in atoms]) atomInfo['radius'] = summarizeVals([a.radius for a in atoms]) atomInfo['surfaceDisplay'] = summarizeVals( [a.surfaceDisplay for a in atoms], consecutiveExceptions=True) atomInfo['surfaceCategory'] = summarizeVals( [a.surfaceCategory for a in atoms], consecutiveExceptions=True) atomInfo['surfaceOpacity'] = summarizeVals( [a.surfaceOpacity for a in atoms], consecutiveExceptions=True) atomInfo['vdw'] = summarizeVals([a.vdw for a in atoms], consecutiveExceptions=True) atomInfo['optional'] = saveOptionalAttrs(chimera.Atom, atoms) # only restore explicitly-set IDATM types... atomInfo['idatmType'] = summarizeVals([(a.idatmIsExplicit and a.idatmType) for a in atoms]) print >> outf, "\tatomInfo =", pickled(atomInfo) replyobj.status("Gathering bond information...", blankAfter=0) bondInfo = {} bondInfo['atoms'] = [[sessionID(a) for a in b.atoms] for b in bonds] bondInfo['drawMode'] = summarizeVals([b.drawMode for b in bonds], consecutiveExceptions=True) bondInfo['display'] = summarizeVals([b.display for b in bonds]) bondInfo['label'] = summarizeVals([b.label for b in bonds]) bondInfo['labelOffset'] = summarizeVals([b.labelOffset for b in bonds]) bondInfo['radius'] = summarizeVals([b.radius for b in bonds]) bondInfo['optional'] = saveOptionalAttrs(chimera.Bond, bonds) print >> outf, "\tbondInfo =", pickled(bondInfo) replyobj.status("Gathering coordinates...", blankAfter=0) crdInfo = {} for m in molecules: crdSets = {} crdInfo[sessionID(m)] = crdSets for key, coordSet in m.coordSets.items(): crdSets[key] = [(sessionID(a), str(a.coord(coordSet))) for a in m.atoms] if coordSet == m.activeCoordSet: crdSets['active'] = key print >> outf, "\tcrdInfo =", pickled(crdInfo) replyobj.status("Gathering surface information...", blankAfter=0) surfInfo = {} surfInfo['molecule'] = [sessionID(s.molecule) for s in surfaces] surfInfo['name'] = [s.name for s in surfaces] surfInfo['customColors'] = surfColors = [] for attrname in ('category', 'colorMode', 'density', 'drawMode', 'display', 'probeRadius', 'allComponents', 'lineWidth', 'pointSize', 'useLighting', 'twoSidedLighting', 'smoothLines', 'transparencyBlendMode', 'oneTransparentLayer'): values = [getattr(s, attrname) for s in surfaces] surfInfo[attrname] = summarizeVals(values) for s in surfaces: if s.colorMode == chimera.MSMSModel.Custom: surfColors.append( summarizeVals([colorID(c) for c in s.customColors])) else: surfColors.append(summarizeVals([])) print >> outf, "\tsurfInfo =", sesRepr(surfInfo) replyobj.status("Gathering VRML information...", blankAfter=0) vrmlInfo = {} vrmlInfo['id'] = summarizeVals([v.id for v in vrmls]) vrmlInfo['subid'] = summarizeVals([v.subid for v in vrmls]) vrmlInfo['name'] = summarizeVals([v.name for v in vrmls]) vrmlInfo['display'] = summarizeVals([v.display for v in vrmls]) vrmlInfo['vrmlString'] = vrmlStrings = [] for v in vrmls: source = v.openedAs[0] if source.startswith('#VRML'): vrmlStrings.append(source) else: # source is file name vrmlFile = open(source, 'r') vrmlStrings.append(vrmlFile.read()) vrmlFile.close() print >> outf, "\tvrmlInfo =", sesRepr(vrmlInfo) replyobj.status("Gathering color information...", blankAfter=0) # remember all saved colors/materials... knownColors = {} knownMaterials = {} from chimera import _savedColors, _savedMaterials for name, material in _savedMaterials.items(): knownMaterials[name] = (material.specular, material.shininess) for name, color in _savedColors.items(): if not isinstance(color, chimera.MaterialColor): continue matName = color.material.name() if matName is None: # unnamed material matName = "mat" + str(id(color.material)) knownColors[name] = (color.ambientDiffuse, color.opacity, matName) if matName not in knownMaterials: mat = color.material knownMaterials[matName] = (mat.specular, mat.shininess) print >> outf, "\tcolors =", sesRepr(knownColors) print >> outf, "\tmaterials =", sesRepr(knownMaterials) replyobj.status("Gathering pseudobond information...", blankAfter=0) pbInfo = {} pbInfo['category'] = [g.category for g in pbGroups] pbInfo['id'] = [g.id for g in pbGroups] pbInfo['color'] = summarizeVals([colorID(g.color) for g in pbGroups]) pbInfo['showStubBonds'] = summarizeVals( [g.showStubBonds for g in pbGroups]) pbInfo['lineWidth'] = summarizeVals([g.lineWidth for g in pbGroups]) pbInfo['stickScale'] = summarizeVals([g.stickScale for g in pbGroups]) pbInfo['lineType'] = summarizeVals([g.lineType for g in pbGroups]) pbInfo['bondInfo'] = pbBondInfos = [] for g in pbGroups: pbs = pbMap[g] info = {} pbBondInfos.append(info) info['atoms'] = [[sessionID(a) for a in pb.atoms] for pb in pbs] info['drawMode'] = summarizeVals([pb.drawMode for pb in pbs]) info['display'] = summarizeVals([pb.display for pb in pbs]) info['halfbond'] = summarizeVals([pb.halfbond for pb in pbs]) info['label'] = summarizeVals([pb.label for pb in pbs]) info['color'] = summarizeVals([colorID(pb.color) for pb in pbs]) info['labelColor'] = summarizeVals( [colorID(pb.labelColor) for pb in pbs]) print >> outf, "\tpbInfo =", sesRepr(pbInfo) associations = {} for m in molecules + surfaces + vrmls + pbGroups: ams = [] for am in m.associatedModels(): if autoRestorable(am): ams.append(sessionID(am)) if ams: associations[sessionID(m)] = ams print >> outf, "\tmodelAssociations =", sesRepr(associations) replyobj.status("Gathering font information...", blankAfter=0) from chimera.bgprefs import BACKGROUND, LABEL_FONT from chimera import preferences fontInfo = {'face': preferences.getOption(BACKGROUND, LABEL_FONT).get()} replyobj.status("Gathering clip plane information...", blankAfter=0) clipPlaneInfo = {} for m in molecules + surfaces: if m.useClipPlane: pl = m.clipPlane clipPlaneInfo[sessionID(m)] = (pl.origin.data(), pl.normal.data(), m.useClipThickness, m.clipThickness) replyobj.status("Gathering selection information...", blankAfter=0) curSelIds = [] curSel = selection.copyCurrent() selMols = curSel.molecules() badMols = filter(lambda m: not autoRestorable(m), selMols) if badMols: curSel.remove(badMols) for a in curSel.atoms(): curSelIds.append(sessionID(a)) for b in curSel.bonds(): curSelIds.append(sessionID(b)) savedSels = [] from copy import copy for selName, sel in selection.savedSels.items(): badMols = [m for m in sel.molecules() if not autoRestorable(m)] filtSel = copy(sel) if badMols: filtSel.remove(badMols) ids = [] for a in filtSel.atoms(): ids.append(sessionID(a)) for b in filtSel.bonds(): ids.append(sessionID(b)) savedSels.append((selName, ids)) replyobj.status("Gathering transformation information...", blankAfter=0) xfDict = {} for m in (molecules + vrmls): xf = m.openState.xform rotV, angle = xf.getRotation() rot = tuple([float(v) for v in str(rotV).split()]) trans = tuple([float(v) for v in str(xf.getTranslation()).split()]) xfDict[sessionID(m)] = ((rot, angle), trans, m.openState.active) replyobj.status("Gathering view information...", blankAfter=0) viewer = chimera.viewer camera = viewer.camera viewerAttrs = {} for va in ("viewSize", "scaleFactor", "clipping", "highlight", "depthCue", "depthCueRange", "showSilhouette", "silhouetteColor", "silhouetteWidth"): if va.endswith("Color"): viewerAttrs[va] = colorID(getattr(viewer, va)) else: viewerAttrs[va] = getattr(viewer, va) cameraAttrs = {} for ca in ("ortho", "nearFar", "focal", "center", "fieldOfView", "eyeSeparation"): cameraAttrs[ca] = getattr(camera, ca) viewerInfo = { "detail": chimera.LODControl.get().quality, "viewerFog": colorID(viewer.depthCueColor), "viewerBG": colorID(viewer.background), "viewerHL": colorID(viewer.highlightColor), "viewerAttrs": viewerAttrs, "cameraAttrs": cameraAttrs, "cameraMode": camera.mode(), } # start printing into buffer so that color map can be inserted here replyobj.status("Writing preliminary session info...", blankAfter=0) print >> buf, "\tviewerInfo =", sesRepr(viewerInfo) print >> buf, """ \treplyobj.status("Initializing session restore...", blankAfter=0) \tinit(colorInfo) \treplyobj.status("Restoring colors...", blankAfter=0) \trestoreColors(colors, materials) \treplyobj.status("Restoring molecules...", blankAfter=0) \trestoreMolecules(molInfo, resInfo, atomInfo, bondInfo, crdInfo) \treplyobj.status("Restoring surfaces...", blankAfter=0) \trestoreSurfaces(surfInfo) \treplyobj.status("Restoring VRML models...", blankAfter=0) \trestoreVRML(vrmlInfo) \treplyobj.status("Restoring pseudobond groups...", blankAfter=0) \trestorePseudoBondGroups(pbInfo) \treplyobj.status("Restoring model associations...", blankAfter=0) \trestoreModelAssociations(modelAssociations) \treplyobj.status("Restoring camera...", blankAfter=0) \trestoreViewer(viewerInfo) try: restoreCoreModels() except: reportRestoreError("Error restoring core models") \treplyobj.status("Restoring extension info...", blankAfter=0) """ replyobj.status("Writing extension session info...", blankAfter=0) chimera.triggers.activateTrigger(SAVE_SESSION, buf) replyobj.status("Writing remaining session info...", blankAfter=0) print >> buf, """ def restoreRemainder(): \tfrom SimpleSession.versions.v45 import restoreWindowSize, \\ \t restoreOpenStates, restoreSelections, restoreFontInfo, \\ \t restoreOpenModelsAttrs, restoreModelClip """ # any use of colors below have to have those colors also run through # colorID() before init() gets printed, so that the color map contains # those colors print >> buf, "\tcurSelIds = ", sesRepr(curSelIds) print >> buf, "\tsavedSels =", sesRepr(savedSels) print >> buf, "\topenModelsAttrs = { 'cofrMethod': %d }" % ( chimera.openModels.cofrMethod) if chimera.openModels.cofrMethod == chimera.openModels.Fixed: cofr = chimera.openModels.cofr print >> buf, "\tfrom chimera import Point" print>> buf, "\topenModelsAttrs['cofr'] = Point(%g, %g, %g)" \ % (cofr.x, cofr.y, cofr.z) print >> buf, "\twindowSize =", sesRepr(chimera.viewer.windowSize) print >> buf, "\txformMap =", sesRepr(xfDict) print >> buf, "\tfontInfo =", sesRepr(fontInfo) print >> buf, "\tclipPlaneInfo =", sesRepr(clipPlaneInfo) print >> buf, """ \treplyobj.status("Restoring window...", blankAfter=0) \trestoreWindowSize(windowSize) \treplyobj.status("Restoring open states...", blankAfter=0) \trestoreOpenStates(xformMap) \treplyobj.status("Restoring font info...", blankAfter=0) \trestoreFontInfo(fontInfo) \treplyobj.status("Restoring selections...", blankAfter=0) \trestoreSelections(curSelIds, savedSels) \treplyobj.status("Restoring openModel attributes...", blankAfter=0) \trestoreOpenModelsAttrs(openModelsAttrs) \treplyobj.status("Restoring model clipping...", blankAfter=0) \trestoreModelClip(clipPlaneInfo) \treplyobj.status("Restoring remaining extension info...", blankAfter=0) try: restoreRemainder() except: reportRestoreError("Error restoring post-model state") from SimpleSession.versions.v45 import makeAfterModelsCBs makeAfterModelsCBs() """ print >> buf, "from SimpleSession.versions.v45 import endRestore" print >> buf, "replyobj.status('Finishing restore...', blankAfter=0)" print >> buf, "endRestore()" print >> buf, "replyobj.status('Restore finished.')" # insert color map print >> outf, "\tcolorInfo =", sesRepr(_id2color) # print buffered output print >> outf, buf.getvalue() buf.close() outf.close() from versions import globals del globals.sessionMap _id2color = _color2id = None replyobj.status("Session written")
def readPBinfo(fileName, category=None, clearCategory=1, lineWidth=None, drawMode=None, leftModel=None, rightModel=None, defColor=None): """read a file containing pseudobond info and display those bonds 'category' defaults to 'fileName'. 'clearCategory' controls whether the pseudobond group should be cleared of pre-existing pseudobonds before reading the file. 'lineWidth' is a floating- point number and controls the width of lines used to draw the pseudobonds. This only is relevant if 'drawMode' is Wire. 'drawMode' controls the depiction style of the pseudobonds. Possible modes are: Wire (aka chimera.Bond_Wire) -- wireframe Stick (aka chimera.Bond_Stick) -- sticks 'leftModel' and 'rightModel' control what models the endpoints of the pseudobond lie in, if none are specified in the input file. 'defColor' is the color assigned to the pseudobond group as a whole, which can be overridden by specific pseudobonds. """ foundErrors = False colorCache = {} if not category: category = fileName group = chimera.misc.getPseudoBondGroup(category) if lineWidth: group.lineWidth = lineWidth if drawMode: group.drawMode = drawMode if clearCategory: group.deleteAll() if defColor: if isinstance(defColor, basestring): c = chimera.Color.lookup(defColor) if not c: replyobj.message( "Cannot find color '%s'\n" % defColor) foundErrors = True else: c = defColor group.color = c from OpenSave import osOpen bondFile = osOpen(fileName) lineNum = 0 for line in bondFile.readlines(): line = line.strip() lineNum = lineNum + 1 if not line: # blank line continue try: spec1, spec2, color = line.split(None, 2) except: label = color = None try: spec1, spec2 = line.split() except ValueError: replyobj.message("Line %d does not have at" " least two atom specifiers.") foundErrors = True continue if color: # try to distinguish between color name and label try: color, label = color.split(None, 1) except: label = None if color[0] != "#": while (label and not colors.has_key(color)): try: c, label = label.split(None, 1) except: color = " ".join([color, label]) label = None else: color = " ".join([color, c]) atom1 = _processSpec(spec1, leftModel) if not atom1: replyobj.message( "Left atom spec of line %d of file doesn't" " select exactly one atom." " Skipping.\n" % lineNum) foundErrors = True continue atom2 = _processSpec(spec2, leftModel) if not atom2: replyobj.message( "Right atom spec of line %d of file doesn't" " select exactly one atom." " Skipping.\n" % lineNum) foundErrors = True continue if color: if color[0] == '#': fieldLen = int((len(color) - 1) / 3) if 3 * fieldLen + 1 != len(color): replyobj.message("Bad Tk color '%s'" " on line %d of file.\n" % (color, lineNum)) foundErrors = True elif colorCache.has_key(color): color = colorCache[color] else: r = color[1:1+fieldLen] g = color[1+fieldLen:1+2*fieldLen] b = color[1+2*fieldLen:] r = int(r, 16) g = int(g, 16) b = int(b, 16) maxVal = int('f' * fieldLen, 16) maxVal = float(maxVal) c = chimera.MaterialColor(r/maxVal, g/maxVal, b/maxVal) colorCache[color] = c color = c else: try: color = getColorByName(color) except KeyError: replyobj.message( "Unknown color '%s' on line %d" " of file.\n" % (color,lineNum)) foundErrors = True color = None pb = group.newPseudoBond(atom1, atom2) if color: pb.color = color if label: pb.label = label bondFile.close() if foundErrors: chimera.replyobj.error( "Errors encountered while reading file.\n" "Check reply log for details.\n")
def readFiles(fileNames, clear=True): if not _ilabelModel: IlabelModel() if clear: for label in _ilabelModel.labels[:]: _ilabelModel.removeLabel(label) _ilabelModel.setMajorChange() from chimera import UserError for fileName in fileNames: from OpenSave import osOpen f = osOpen(fileName) label = labelID = text = None for ln, line in enumerate(f): lineNum = ln + 1 if not line.strip() or line.strip().startswith('#'): # skip blank lines / comments continue if line.lower().startswith("label"): labelID = line[5:].strip() continue if line[0] != '\t': f.close() raise UserError("%s, line %d: line must start with 'Label'" " or tab" % (fileName, lineNum)) try: semi = line.index(':') except ValueError: f.close() raise UserError("%s, line %d: line must have semi-colon" % (fileName, lineNum)) name = line[1:semi].lower() if not label and name != "(x,y)": f.close() raise UserError("%s, line %d: xy position must immediately" " follow 'Label' line" % (fileName, lineNum)) if label and text is None and name != "text": f.close() raise UserError("%s, line %d: text must immediately" " follow xy position" % (fileName, lineNum)) value = line[semi + 1:].strip() if name == "(x,y)": text = None try: pos = eval(value) except: f.close() raise UserError("%s, line %d: could not parse xy value" % (fileName, lineNum)) if labelID: label = _ilabelModel.newLabel(pos) else: label = _ilabelModel.newLabel(pos, labelID=labelID) elif name == "text": try: text = eval(value) except: f.close() _ilabelModel.removeLabel(label) raise UserError( "%s, line %d: could not parse 'text' value" % (fileName, lineNum)) label.set(text) elif name == "shown": if name == "shown": try: label.shown = eval(value.capitalize()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse 'shown'" " value" % (fileName, lineNum)) else: chars = [] for l in label.lines: chars.extend(l) if '),' in value: values = value.split('),') for i, v in enumerate(values[:-1]): values[i] = v + ')' elif ',' in value and not value.strip().startswith('('): values = value.split(',') else: values = [value] * len(chars) if len(values) != len(chars): f.close() raise UserError( "%s, line %d: number of values not equal" " to numbers of characters in text (and not a single" " value)" % (fileName, lineNum)) if name.startswith("font size"): try: values = [eval(v) for v in values] except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font size' value(s)" % (fileName, lineNum)) for c, v in zip(chars, values): c.size = v elif name.startswith("font style"): for c, v in zip(chars, values): try: c.style = styleLookup(v.strip().lower()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font style' value(s)" % (fileName, lineNum)) elif name.startswith("font typeface"): for c, v in zip(chars, values): try: c.fontName = typefaceLookup(v.strip().lower()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font typeface' value(s)" % (fileName, lineNum)) elif name.startswith("color"): try: values = [eval(v) for v in values] except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'color' value(s)" % (fileName, lineNum)) for c, v in zip(chars, values): c.rgba = v else: _ilabelModel.removeLabel(label) raise UserError( "%s, line %d: unknown label attribute '%s'" % (fileName, lineNum, name)) f.close() if chimera.nogui: dlg = None else: from gui import IlabelDialog from chimera import dialogs dlg = dialogs.find(IlabelDialog.name) if dlg: dlg.updateGUI("file")
def readFiles(fileNames, clear=True): if not _ilabelModel: IlabelModel() if clear: for label in _ilabelModel.labels[:]: _ilabelModel.removeLabel(label) _ilabelModel.setMajorChange() from chimera import UserError for fileName in fileNames: from OpenSave import osOpen f = osOpen(fileName) label = labelID = text = None for ln, line in enumerate(f): lineNum = ln + 1 if not line.strip() or line.strip().startswith('#'): # skip blank lines / comments continue if line.lower().startswith("label"): labelID = line[5:].strip() continue if line[0] != '\t': f.close() raise UserError("%s, line %d: line must start with 'Label'" " or tab" % (fileName, lineNum)) try: semi = line.index(':') except ValueError: f.close() raise UserError("%s, line %d: line must have semi-colon" % (fileName, lineNum)) name = line[1:semi].lower() if not label and name != "(x,y)": f.close() raise UserError("%s, line %d: xy position must immediately" " follow 'Label' line" % (fileName, lineNum)) if label and text is None and name != "text": f.close() raise UserError("%s, line %d: text must immediately" " follow xy position" % (fileName, lineNum)) value = line[semi+1:].strip() if name == "(x,y)": text = None try: pos = eval(value) except: f.close() raise UserError("%s, line %d: could not parse xy value" % (fileName, lineNum)) if labelID: label = _ilabelModel.newLabel(pos) else: label = _ilabelModel.newLabel(pos, labelID=labelID) elif name == "text": try: text = eval(value) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse 'text' value" % (fileName, lineNum)) label.set(text) elif name == "shown": if name == "shown": try: label.shown = eval(value.capitalize()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse 'shown'" " value" % (fileName, lineNum)) else: chars = [] for l in label.lines: chars.extend(l) if '),' in value: values = value.split('),') for i, v in enumerate(values[:-1]): values[i] = v + ')' elif ',' in value and not value.strip().startswith('('): values = value.split(',') else: values = [value] * len(chars) if len(values) != len(chars): f.close() raise UserError("%s, line %d: number of values not equal" " to numbers of characters in text (and not a single" " value)" % (fileName, lineNum)) if name.startswith("font size"): try: values = [eval(v) for v in values] except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font size' value(s)" % (fileName, lineNum)) for c, v in zip(chars, values): c.size = v elif name.startswith("font style"): for c, v in zip(chars, values): try: c.style = styleLookup(v.strip().lower()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font style' value(s)" % (fileName, lineNum)) elif name.startswith("font typeface"): for c, v in zip(chars, values): try: c.fontName = typefaceLookup(v.strip().lower()) except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'font typeface' value(s)" % (fileName, lineNum)) elif name.startswith("color"): try: values = [eval(v) for v in values] except: f.close() _ilabelModel.removeLabel(label) raise UserError("%s, line %d: could not parse" " 'color' value(s)" % (fileName, lineNum)) for c, v in zip(chars, values): c.rgba = v else: _ilabelModel.removeLabel(label) raise UserError("%s, line %d: unknown label attribute '%s'" % (fileName, lineNum, name)) f.close() if chimera.nogui: dlg = None else: from gui import IlabelDialog from chimera import dialogs dlg = dialogs.find(IlabelDialog.name) if dlg: dlg.updateGUI("file")
def readPBinfo(fileName, category=None, clearCategory=1, lineWidth=None, drawMode=None, leftModel=None, rightModel=None, defColor=None): """read a file containing pseudobond info and display those bonds 'category' defaults to 'fileName'. 'clearCategory' controls whether the pseudobond group should be cleared of pre-existing pseudobonds before reading the file. 'lineWidth' is a floating- point number and controls the width of lines used to draw the pseudobonds. This only is relevant if 'drawMode' is Wire. 'drawMode' controls the depiction style of the pseudobonds. Possible modes are: Wire (aka chimera.Bond_Wire) -- wireframe Stick (aka chimera.Bond_Stick) -- sticks 'leftModel' and 'rightModel' control what models the endpoints of the pseudobond lie in, if none are specified in the input file. 'defColor' is the color assigned to the pseudobond group as a whole, which can be overridden by specific pseudobonds. """ foundErrors = False colorCache = {} if not category: category = fileName group = chimera.misc.getPseudoBondGroup(category) if lineWidth: group.lineWidth = lineWidth if drawMode: group.drawMode = drawMode if clearCategory: group.deleteAll() if defColor: if isinstance(defColor, basestring): c = chimera.Color.lookup(defColor) if not c: replyobj.message("Cannot find color '%s'\n" % defColor) foundErrors = True else: c = defColor group.color = c from OpenSave import osOpen bondFile = osOpen(fileName) lineNum = 0 for line in bondFile.readlines(): line = line.strip() lineNum = lineNum + 1 if not line: # blank line continue try: spec1, spec2, color = line.split(None, 2) except: label = color = None try: spec1, spec2 = line.split() except ValueError: replyobj.message("Line %d does not have at" " least two atom specifiers.") foundErrors = True continue if color: # try to distinguish between color name and label try: color, label = color.split(None, 1) except: label = None if color[0] != "#": while (label and not colors.has_key(color)): try: c, label = label.split(None, 1) except: color = " ".join([color, label]) label = None else: color = " ".join([color, c]) atom1 = _processSpec(spec1, leftModel) if not atom1: replyobj.message("Left atom spec of line %d of file doesn't" " select exactly one atom." " Skipping.\n" % lineNum) foundErrors = True continue atom2 = _processSpec(spec2, leftModel) if not atom2: replyobj.message("Right atom spec of line %d of file doesn't" " select exactly one atom." " Skipping.\n" % lineNum) foundErrors = True continue if color: if color[0] == '#': fieldLen = int((len(color) - 1) / 3) if 3 * fieldLen + 1 != len(color): replyobj.message("Bad Tk color '%s'" " on line %d of file.\n" % (color, lineNum)) foundErrors = True elif colorCache.has_key(color): color = colorCache[color] else: r = color[1:1 + fieldLen] g = color[1 + fieldLen:1 + 2 * fieldLen] b = color[1 + 2 * fieldLen:] r = int(r, 16) g = int(g, 16) b = int(b, 16) maxVal = int('f' * fieldLen, 16) maxVal = float(maxVal) c = chimera.MaterialColor(r / maxVal, g / maxVal, b / maxVal) colorCache[color] = c color = c else: try: color = getColorByName(color) except KeyError: replyobj.message("Unknown color '%s' on line %d" " of file.\n" % (color, lineNum)) foundErrors = True color = None pb = group.newPseudoBond(atom1, atom2) if color: pb.color = color if label: pb.label = label bondFile.close() if foundErrors: chimera.replyobj.error("Errors encountered while reading file.\n" "Check reply log for details.\n")
def loadEnsemble(inputs, startFrame, endFrame, callback, relativeTo=None): from chimera import replyobj style = inputs[0] files = inputs[1:] if relativeTo: for i, f in enumerate(files): if not isinstance(f, basestring) or os.path.isabs(f): continue files[i] = os.path.join(relativeTo, f) if style.lower().startswith("multiple"): startFile, endFile = files errMsg = "Can't determine numeric sequence from starting file name (%s) to ending file name (%s)" % (startFile, endFile) for i, c in enumerate(startFile): if i >= len(endFile): raise ValueError(errMsg) if endFile[i] != c: break else: raise ValueError(errMsg) # push trailing digits on the prefix back into the number part, # otherwise ranges like 1-100 are bug problems while i > 0 and startFile[i-1].isdigit(): i -= 1 prefixIndex = i prefix = startFile[:i] while i < len(startFile) and startFile[i].isdigit(): i += 1 startSuffixIndex = i endSuffixIndex = i + len(endFile) - len(startFile) suffix = startFile[startSuffixIndex:] replyobj.status("Collating PDB files\n", blankAfter=0) first = int(startFile[prefixIndex:startSuffixIndex]) if first < 1: offset = 1 - first first += offset replyobj.info("Adjusting frame numbers to start at 1\n") else: offset = 0 try: last = int(endFile[prefixIndex:endSuffixIndex]) + offset except ValueError: raise ValueError("Last file name not similar to first" " file name\nCan't determine numeric sequence") if startFrame is None: startFrame = first elif startFrame < first: replyobj.error("Starting frame (%d) less than first" " file's frame (%d); using the latter\n" % (startFrame, first)) startFrame = first if endFrame is None: endFrame = last elif endFrame > last: replyobj.error("Ending frame (%d) greater than last" " file's frame (%d); using the latter\n" % (endFrame, last)) endFrame = last if startFrame > endFrame: raise ValueError("Start frame > end frame") addMODEL = True sf = file(startFile, "r") for line in sf: if line.startswith("MODEL"): addMODEL = False break if line.strip() == "END": raise ValueError("PDB files must not contain" " END records") sf.close() from tempfile import mkstemp (handle, trajFile) = mkstemp(suffix=".pdb") os.close(handle) collation = open(trajFile, "w") zeroPad = len(startFile) == len(endFile) for f in range(startFrame, endFrame+1): if addMODEL: print>>collation, "MODEL %8d" % f if zeroPad: fname = prefix + "%0*d" % (startSuffixIndex - prefixIndex, f-offset) + suffix else: fname = prefix + "%d" % (f-offset) + suffix replyobj.status("Collating file %s\n" % fname, blankAfter=0) try: frameFile = open(fname, "r") except IOError: collation.close() os.unlink(trajFile) raise collation.write(frameFile.read()) frameFile.close() if addMODEL: print>>collation, "ENDMDL" collation.close() replyobj.status("Done collating PDB files\n") else: trajFile = files[0] class PdbTraj: def __len__(self): return len(self.molecule.coordSets) ensemble = PdbTraj() ensemble.name = "PDB trajectory from %s" % os.path.basename(files[0]) ensemble.startFrame = startFrame ensemble.endFrame = endFrame from chimera import PDBio pdbio = PDBio() pdbio.explodeNMR = False replyobj.status("Reading PDB trajectory\n", blankAfter=0) # allow for compression... from OpenSave import osOpen pdbStream = osOpen(trajFile) traj, lineNum = pdbio.readPDBstream(pdbStream, trajFile, 0) pdbStream.close() replyobj.status("Done reading PDB trajectory\n") if style == "multiple files": os.unlink(trajFile) ensemble.name += "..." if not pdbio.ok(): raise ValueError(pdbio.error()) elif not traj: raise ValueError("No structures in the PDB file!") else: traj = traj[0] if len(traj.coordSets) < 2: raise ValueError("The PDB file contains only one structure") ensemble.molecule = traj traj.name = os.path.basename(files[0]) replyobj.status("Creating interface\n", blankAfter=0) try: callback(ensemble) finally: replyobj.status("Interface created\n")
def writeMol2(models, fileName, status=None, anchor=None, relModel=None, hydNamingStyle="sybyl", multimodelHandling="individual", skip=None, resNum=True, gaffType=False, gaffFailError=None): """Write a Mol2 file. 'models' are the models to write out into a file named 'fileName'. 'status', if not None, is a function that takes a string -- used to report the progress of the write. 'anchor' is a selection (i.e. instance of a subclass of chimera.selection.Selection) containing atoms/bonds that should be written out to the @SETS section of the file as the rigid framework for flexible ligand docking. 'hydNamingStyle' controls whether hydrogen names should be "Sybyl-like" (value: sybyl) or "PDB-like" (value: pdb) -- e.g. HG21 vs. 1HG2. 'multimodelHandling' controls whether multiple models will be combined into a single @MOLECULE section (value: combined) or each given its own section (value: individual). 'skip' is a list of atoms to not output 'resNum' controls whether residue sequence numbers are included in the substructure name. Since Sybyl Mol2 files include them, this defaults to True. If 'gaffType' is True, outout GAFF atom types instead of Sybyl atom types. 'gaffFailError', if specified, is the type of error to throw (e.g. UserError) if there is no gaffType attribute for an atom, otherwise throw the standard AttributeError. """ # open the given file name for writing from OpenSave import osOpen f = osOpen(fileName, "w") sortFunc = serialSort = lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex) if isinstance(models, chimera.Molecule): models = [models] elif isinstance(models, Selection): # create a fictitious jumbo model if isinstance(models, ItemizedSelection): sel = models else: sel = ItemizedSelection() sel.merge(models) sel.addImplied() class Jumbo: def __init__(self, sel): self.atoms = sel.atoms() self.residues = sel.residues() self.bonds = sel.bonds() self.name = "(selection)" models = [Jumbo(sel)] sortFunc = lambda a1, a2: cmp(a1.molecule.id, a2.molecule.id) \ or cmp(a1.molecule.subid, a2.molecule.subid) \ or serialSort(a1, a2) multimodelHandling = "individual" # transform... if relModel is None: xform = chimera.Xform.identity() else: xform = relModel.openState.xform xform.invert() # need to find amide moieties since Sybyl has an explicit amide type if status: status("Finding amides\n") from ChemGroup import findGroup amides = findGroup("amide", models) amideNs = dict.fromkeys([amide[2] for amide in amides]) amideCNs = dict.fromkeys([amide[0] for amide in amides]) amideCNs.update(amideNs) amideOs = dict.fromkeys([amide[1] for amide in amides]) substructureNames = None if multimodelHandling == "combined": # create a fictitious jumbo model class Jumbo: def __init__(self, models): self.atoms = [] self.residues = [] self.bonds = [] self.name = models[0].name + " (combined)" for m in models: self.atoms.extend(m.atoms) self.residues.extend(m.residues) self.bonds.extend(m.bonds) # if combining single-residue models, # can be more informative to use model name # instead of residue type for substructure if len(models) == len(self.residues): rtypes = [r.type for r in self.residues] if len(set(rtypes)) < len(rtypes): mnames = [m.name for m in models] if len(set(mnames)) == len(mnames): self.substructureNames = dict( zip(self.residues, mnames)) models = [Jumbo(models)] if hasattr(models[-1], 'substructureNames'): substructureNames = models[-1].substructureNames delattr(models[-1], 'substructureNames') sortFunc = lambda a1, a2: cmp(a1.molecule.id, a2.molecule.id) \ or cmp(a1.molecule.subid, a2.molecule.subid) \ or serialSort(a1, a2) # write out models for mol in models: if hasattr(mol, 'mol2comments'): for m2c in mol.mol2comments: print >> f, m2c if hasattr(mol, 'solventInfo'): print >> f, mol.solventInfo # molecule section header print >> f, "%s" % MOLECULE_HEADER # molecule name print >> f, "%s" % mol.name ATOM_LIST = mol.atoms BOND_LIST = mol.bonds if skip: skip = set(skip) ATOM_LIST = [a for a in ATOM_LIST if a not in skip] BOND_LIST = [ b for b in BOND_LIST if b.atoms[0] not in skip and b.atoms[1] not in skip ] RES_LIST = mol.residues # Chimera has an unusual internal order for its atoms, so # sort them by input order if status: status("Putting atoms in input order") ATOM_LIST.sort(sortFunc) # if anchor is not None, then there will be two entries in # the @SETS section of the file... if anchor: sets = 2 else: sets = 0 # number of entries for various sections... print >> f, "%d %d %d 0 %d" % (len(ATOM_LIST), len(BOND_LIST), len(RES_LIST), sets) # type of molecule if hasattr(mol, "mol2type"): mtype = mol.mol2type else: mtype = "SMALL" from chimera.resCode import nucleic3to1, protein3to1 for r in mol.residues: if r.type in protein3to1: mtype = "PROTEIN" break if r.type in nucleic3to1: mtype = "NUCLEIC_ACID" break print >> f, mtype # indicate type of charge information if hasattr(mol, 'chargeModel'): print >> f, mol.chargeModel else: print >> f, "NO_CHARGES" if hasattr(mol, 'mol2comment'): print >> f, "\n%s" % mol.mol2comment else: print >> f, "\n" if status: status("writing atoms\n") # atom section header print >> f, "%s" % ATOM_HEADER # make a dictionary of residue indices so that we can do # quick look ups resIndices = {} for i, r in enumerate(RES_LIST): resIndices[r] = i + 1 for i, atom in enumerate(ATOM_LIST): # atom ID, starting from 1 print >> f, "%7d" % (i + 1), # atom name, possibly rearranged if it's a hydrogen if hydNamingStyle == "sybyl" \ and not atom.name[0].isalpha(): atomName = atom.name[1:] + atom.name[0] else: atomName = atom.name print >> f, "%-8s" % atomName, # untransformed coordinate position coord = xform.apply(atom.xformCoord()) print >> f, "%9.4f %9.4f %9.4f" % (coord.x, coord.y, coord.z), # atom type if gaffType: try: atomType = atom.gaffType except AttributeError: if not gaffFailError: raise raise gaffFailError( "%s has no Amber/GAFF type assigned.\n" "Use the AddCharge tool to assign Amber/GAFF types." % atom) elif hasattr(atom, 'mol2type'): atomType = atom.mol2type elif atom in amideNs: atomType = "N.am" elif atom.residue.id.chainId == "water": if atom.element.name == "O": atomType = "O.t3p" else: atomType = "H.t3p" elif atom.element.name == "N" and len( [r for r in atom.minimumRings() if r.aromatic()]) > 0: atomType = "N.ar" elif atom.idatmType == "C2" and len( [nb for nb in atom.neighbors if nb.idatmType == "Ng+"]) > 2: atomType = "C.cat" else: try: atomType = chimera2sybyl[atom.idatmType] except KeyError: chimera.replyobj.warning("Atom whose" " IDATM type has no equivalent" " Sybyl type: %s (type: %s)\n" % (atom.oslIdent(), atom.idatmType)) atomType = str(atom.element) print >> f, "%-5s" % atomType, # residue-related info res = atom.residue # residue index print >> f, "%5d" % resIndices[res], # substructure identifier and charge if hasattr(atom, 'charge'): charge = atom.charge else: charge = 0.0 if substructureNames: rname = substructureNames[res] elif resNum: rname = "%3s%-5d" % (res.type, res.id.position) else: rname = "%3s" % res.type print >> f, "%s %9.4f" % (rname, charge) if status: status("writing bonds\n") # bond section header print >> f, "%s" % BOND_HEADER # make an atom-index dictionary to speed lookups atomIndices = {} for i, a in enumerate(ATOM_LIST): atomIndices[a] = i + 1 for i, bond in enumerate(BOND_LIST): a1, a2 = bond.atoms # ID print >> f, "%6d" % (i + 1), # atom IDs print >> f, "%4d %4d" % (atomIndices[a1], atomIndices[a2]), # bond order; give it our best shot... amideA1 = a1 in amideCNs amideA2 = a2 in amideCNs if amideA1 and amideA2: print >> f, "am" continue if amideA1 or amideA2: if a1 in amideOs or a2 in amideOs: print >> f, "2" else: print >> f, "1" continue aromatic = False for ring in bond.minimumRings(): if ring.aromatic(): aromatic = True break if aromatic: print >> f, "ar" continue try: geom1 = typeInfo[a1.idatmType].geometry except KeyError: print >> f, "1" continue try: geom2 = typeInfo[a2.idatmType].geometry except KeyError: print >> f, "1" continue if geom1 not in [2, 3] or geom2 not in [2, 3]: print >> f, "1" continue # if either endpoint atom is in an aromatic ring and # the bond isn't, it's a single bond... for endp in [a1, a2]: aromatic = False for ring in endp.minimumRings(): if ring.aromatic(): aromatic = True break if aromatic: break else: # neither endpoint in aromatic ring print >> f, "2" continue print >> f, "1" if status: status("writing residues") # residue section header print >> f, "%s" % SUBSTR_HEADER for i, res in enumerate(RES_LIST): # residue id field print >> f, "%6d" % (i + 1), # residue name field if substructureNames: rname = substructureNames[res] elif resNum: rname = "%3s%-4d" % (res.type, res.id.position) else: rname = "%3s" % res.type print >> f, rname, # ID of the root atom of the residue from chimera.misc import principalAtom chainAtom = principalAtom(res) if chainAtom is None: if hasattr(res, 'atomsMap'): chainAtom = res.atoms[0] else: chainAtom = res.atoms.values()[0][0] print >> f, "%5d" % atomIndices[chainAtom], print >> f, "RESIDUE 4", # Sybyl seems to use chain 'A' when chain ID is blank, # so run with that chainID = res.id.chainId if len(chainID.strip()) != 1: chainID = 'A' print >> f, "%s %3s" % (chainID, res.type), # number of out-of-substructure bonds crossResBonds = 0 if hasattr(res, "atomsMap"): atoms = res.atoms for a in atoms: for oa in a.bondsMap.keys(): if oa.residue != res: crossResBonds += 1 else: atoms = [a for aList in res.atoms.values() for a in aList] for a in atoms: for oa in a.bonds.keys(): if oa.residue != res: crossResBonds += 1 print >> f, "%5d" % crossResBonds, # print "ROOT" if first or only residue of a chain if a.molecule.rootForAtom(a, True).atom.residue == res: print >> f, "ROOT" else: print >> f # write flexible ligand docking info if anchor: if status: status("writing anchor info") print >> f, "%s" % SET_HEADER atomIndices = {} for i, a in enumerate(ATOM_LIST): atomIndices[a] = i + 1 bondIndices = {} for i, b in enumerate(BOND_LIST): bondIndices[b] = i + 1 print >> f, "ANCHOR STATIC ATOMS <user> **** Anchor Atom Set" atoms = anchor.atoms() print >> f, len(atoms), for a in atoms: if a in atomIndices: print >> f, atomIndices[a], print >> f print >> f, "RIGID STATIC BONDS <user> **** Rigid Bond Set" bonds = anchor.bonds() print >> f, len(bonds), for b in bonds: if b in bondIndices: print >> f, bondIndices[b], print >> f f.close()
def readSDF(fileName, identifyAs=None): from OpenSave import osOpen from chimera import UserError, Molecule, Element, openModels, replyobj from chimera import Coord state = "init" f = osOpen(fileName) mols = [] nonblank = False for l in f: line = l.strip() nonblank = nonblank or line if state == "init": state = "post header 1" molName = line elif state == "post header 1": state = "post header 2" elif state == "post header 2": state = "counts" elif state == "counts": if not line: break state = "atoms" serial = 1 anums = {} atoms = [] try: numAtoms = int(l[:3].strip()) numBonds = int(l[3:6].strip()) except ValueError: raise UserError("Atom/bond counts line of" " MOL/SDF file '%s' is botched: '%s'" % (fileName, l)) m = Molecule() mols.append(m) if identifyAs: m.name = identifyAs else: from chimera.misc import isInformativeName mn = molName.strip() if isInformativeName(mn): m.name = mn else: import os.path m.name = os.path.split(fileName)[-1] r = m.newResidue("UNK", " ", 1, " ") elif state == "atoms": numAtoms -= 1 if numAtoms == 0: if numBonds: state = "bonds" else: state = "properties" try: x = float(l[:10].strip()) y = float(l[10:20].strip()) z = float(l[21:30].strip()) elem = l[31:34].strip() except ValueError: raise UserError("Atom line of MOL/SDF file" " '%s' is not x y z element...: '%s'" % (fileName, l)) element = Element(elem) if element.number == 0: # lone pair or somesuch atoms.append(None) continue anum = anums.get(element.name, 0) + 1 anums[element.name] = anum a = m.newAtom("%s%d" % (element.name, anum), element) atoms.append(a) r.addAtom(a) a.setCoord(Coord(x, y, z)) a.serialNumber = serial serial += 1 elif state == "bonds": numBonds -= 1 if numBonds == 0: state = "properties" try: a1index = int(l[:3].strip()) a2index = int(l[3:6].strip()) order = int(l[6:9].strip()) except ValueError: raise UserError("Bond line of MOL/SDF file" " '%s' is not a1 a2 order...: '%s'" % (fileName, l)) a1 = atoms[a1index - 1] a2 = atoms[a2index - 1] if not a1 or not a2: continue m.newBond(a1, a2).order = order elif state == "properties": if not m.atoms: raise UserError("No atoms found for compound" " '%s' in MOL/SDF file '%s'" % (m.name, fileName)) if line.split() == ["M", "END"]: state = "data" elif state == "data": if line == "$$$$": nonblank = False state = "init" f.close() if nonblank and state not in ["data", "init"]: if mols: replyobj.warning("Extraneous text after final $$$$" " in MOL/SDF file '%s'" % fileName) else: raise UserError("Unexpected end of file (parser state:" " %s) in MOL/SDF file '%s'" % (state, fileName)) return mols
def parse(fileName): IN_HEADER = 0 START_ATTRS = 1 IN_ATTRS = 2 IN_FEATURES = 3 IN_SEQ = 4 state = IN_HEADER from OpenSave import osOpen f = osOpen(fileName, "r") sequences = [] lineNum = 0 hasOffset = 0 longest = None fileAttrs = {} for line in f: line = line.rstrip() # remove trailing whitespace/newline lineNum += 1 if lineNum == 1: if line.startswith("!!RICH_SEQUENCE"): continue raise WrongFileTypeError() if state == IN_HEADER: if line.strip() == "..": state = START_ATTRS continue if "comments" in fileAttrs: fileAttrs["comments"] += "\n" + line else: fileAttrs["comments"] = line continue if not line.strip(): continue if state == START_ATTRS: if line.strip() == "{": state = IN_ATTRS curAttr = None attrs = {} elif line: raise FormatSyntaxError("Unexpected text before" " start of sequence on line %d" % lineNum) continue if state == IN_ATTRS or state == IN_FEATURES: if line.strip() == "sequence" and line[0] == "s": if "RSF name" not in attrs: raise FormatSyntaxError("sequence on " "line %d has no name" % lineNum) state = IN_SEQ seq = Sequence(makeReadable(attrs["RSF name"])) del attrs["RSF name"] seq.attrs = attrs if "RSF descrip" in attrs: attrs["description"] = attrs[ "RSF descrip"] del attrs["RSF descrip"] sequences.append(seq) if "RSF offset" in attrs: seq.extend("." * int( attrs["RSF offset"])) hasOffset = 1 del attrs["RSF offset"] continue if line.startswith("feature"): if state == IN_ATTRS: attrs["RSF features"] = [[line[8:]]] else: attrs["RSF features"].append([line[8:]]) state = IN_FEATURES continue if state == IN_ATTRS: if line[0].isspace(): # continuation if not curAttr: raise FormatSyntaxError("Bogus " "indentation at line %d" % lineNum) if attrs[curAttr]: attrs[curAttr] += "\n" + line else: attrs[curAttr] = line continue if " " in line.strip(): curAttr, val = line.split(None, 1) curAttr.replace("_", " ") curAttr = "RSF " + curAttr attrs[curAttr] = val.strip() else: curAttr = "RSF " + line.strip().replace("_", " ") attrs[curAttr] = "" continue if state == IN_FEATURES: attrs["RSF features"][-1].append(line) continue if line.strip() == "}": state = START_ATTRS if not longest: longest = len(seq) else: if len(seq) < longest: seq.extend("." * (longest - len(seq))) elif len(seq) > longest: longest = len(seq) for s in sequences[:-1]: s.extend("." * (longest - len(s))) continue seq.extend(line.strip()) if not seq[0].isalpha(): hasOffset = 1 f.close() if state == IN_HEADER: raise FormatSyntaxError( "No end to header (i.e. '..' line) found") if state == IN_ATTRS or state == IN_FEATURES: if "RSF name" in attrs: raise FormatSyntaxError( "No sequence data found for sequence %s" % attrs["RSF name"]) raise FormatSyntaxError("Sequence without sequence data") if state == IN_SEQ: raise FormatSyntaxError("No terminating brace for sequence %s" % attrs["RSF name"]) if not sequences: raise FormatSyntaxError("No sequences found") if not hasOffset: from chimera import replyobj replyobj.warning("No offset fields in RSF file;" " assuming zero offset\n") return sequences, fileAttrs, {}
def readAIM(fileName): import re from OpenSave import osOpen from chimera import UserError, Molecule, Element, openModels, replyobj from chimera import Coord, connectMolecule, MaterialColor anums = {} ## Open the file getatoms = osOpen(fileName) ## Search for the string: ## 'Number of NACPs' ## which gives us the number of atoms ## and store it in numAtoms for data in getatoms: data = data.strip() if data.startswith("Number of NACPs"): a,b,c,d,e = data.split() numAtoms = int(e) getatoms.close() ################################################################### f = osOpen(fileName) readAtoms = 0 state = "init" ## Skip the 26 header lines from the mpgviz file #f = f.readlines()[4:] for lines in f: lines = lines.strip() if lines.startswith("Atom Charge X Y Z"): f.next() for line in f: if readAtoms == numAtoms: break line = line.strip() if state == "init": state = "post" m = Molecule() r = m.newResidue("UNK", " ", 1, " ") state = "atoms" serial = 1 if not line: continue elem, charge, x, y, z = line.split() x, y, z = [float(c) for c in [x,y,z]] ## Remove the number from the atomic symbol elem = filter(lambda x: x.isalpha(), elem) element = Element(elem) anum = anums.get(element.name, 0) + 1 anums[element.name] = anum a = m.newAtom("%s%d" % (element.name, anum), element) r.addAtom(a) a.setCoord(Coord((x*0.52918), (y*0.52918), (z*0.52918))) a.serialNumber = serial serial += 1 readAtoms += 1 connectMolecule(m) ################################################################### ## Critical points idNACP = 1 mNACP = Molecule() rNACP = mNACP.newResidue("Nuclear atractors critical points", " ", 1, " ") idBCP = 1 mBCP = Molecule() rBCP = mBCP.newResidue("Bond critical points", " ", 1, " ") idBPP = 1 mBPP = Molecule() rBPP = mBPP.newResidue("Bond path points", " ", 1, " ") cpnumber = 1 cpread = 0 getcriticalpoints = osOpen(fileName) for text in getcriticalpoints: text = text.strip() if cpread == 0: if text.startswith("CP#"): readtext = text cpread = 1 elif cpread == 1: if text.startswith("Type = (3,-3)"): a,b,signature,type,atom1 = text.split() cpnum,id,a,b,x,y,z = readtext.split() x, y, z = [float(c) for c in [x,y,z]] ## Remove the number from the atomic symbol elem = filter(lambda x: x.isalpha(), atom1) element = Element(elem) anum = anums.get(element.name, 0) + 1 anums[element.name] = anum #atomNACP = m.newAtom("%s%d" % (element.name, anum), element) atomNACP = mNACP.newAtom("%s%s" % ("NACP# ", atom1), element) atomNACP.serialNumber = serial #atomNACP = mNACP.newAtom(atom1, Element("NACP")) atomNACP.drawMode = 1 atomNACP.radius = 0.2 rNACP.addAtom(atomNACP) atomNACP.setCoord(Coord((x*0.52918), (y*0.52918), (z*0.52918))) cpread = 0 serial += 1 elif text.startswith("Type = (3,+3)"): print 'CCP' cpread = 0 elif text.startswith("Type = (3,+1)"): print 'RCP' cpread = 0 elif text.startswith("Type = (3,-1)"): a,b,signature,type,atom1,atom2 = text.split() cpnum,id,a,b,x,y,z = readtext.split() x, y, z = [float(c) for c in [x,y,z]] ## Remove the number from the atomic symbol elem = filter(lambda x: x.isalpha(), atom1) element = Element(elem) anum = anums.get(element.name, 0) + 1 anums[element.name] = anum atomBCP = mBCP.newAtom("%s%s" % ("BCP# ", id), element) atomBCP.serialNumber = serial #atomBCP = mBCP.newAtom(atom1, Element("He")) atomBCP.color = MaterialColor(1,0,0,1) atomBCP.drawMode = 1 atomBCP.radius = 0.07 rBCP.addAtom(atomBCP) atomBCP.setCoord(Coord((x*0.52918), (y*0.52918), (z*0.52918))) cpread = 0 serial += 1 ################################################################### ## Bond Paths getbondpaths = osOpen(fileName) statusSamples = 0 countSamples = 0 totalSamples = 0 skip = 0 for samples in getbondpaths: samples = samples.strip() if re.match("(.*)sample points along path from BCP to atom(.*)", samples): numSamples,a,b,c,d,e,tipo,g,h,atom = samples.split() numSamples = int(numSamples) statusSamples = 1 totalSamples = int(totalSamples) if statusSamples == 1: totalSamples = totalSamples + statusSamples if countSamples == numSamples: countSamples = 0 statusSamples = 0 else: try: x,y,z,rho = samples.split() x, y, z = [float(c) for c in [x,y,z]] ## Remove the number from the atomic symbol elem = filter(lambda x: x.isalpha(), atom1) element = Element(elem) anum = anums.get(element.name, 0) + 1 anums[element.name] = anum atomBPP = mBPP.newAtom("%s%s" % ("BPP", serial), element) atomBPP.serialNumber = serial #atomBPP = mBPP.newAtom(atom1, Element("kr")) #atomBPP = mBPP.newAtom("%s%s" % ("BPP", serial), element) atomBPP.color = MaterialColor(0,206,209,1) atomBPP.drawMode = 1 atomBPP.radius = 0.01 rBPP.addAtom(atomBPP) atomBPP.setCoord(Coord((x*0.52918), (y*0.52918), (z*0.52918))) #cpread = 0 serial += 1 #cpnumber += 1 countSamples += 1 except ValueError: countSamples += 1 continue mNACP.isRealMolecule = False # mNACP.noprefs = True mBCP.isRealMolecule = False mBCP.noprefs = True mBPP.isRealMolecule = False mBPP.noprefs = True ## Return molecules return [m, mNACP, mBCP, mBPP]
def parse(fileName): from OpenSave import osOpen f = osOpen(fileName, "r") doing = None sequences = [] headerOK = False lineNum = 0 alignStartIndex = None for line in f: if doing == 'alignments': # don't strip() alignment section since it has significant # leading spaces line = line.rstrip() else: line = line.strip() lineNum += 1 if not headerOK: if line.lower().startswith('hssp'): headerOK = True continue raise WrongFileTypeError("No initial HSSP header line") if line.startswith('##'): if doing == 'proteins' and not sequences: raise FormatSyntaxError("No entries in PROTEINS section") try: doing = line.split()[1].lower() except IndexError: doing = None if doing == 'alignments': try: hashes, alignments, begin, dash, end = line.strip().split() begin = int(begin) end = int(end) except ValueError: raise FormatSyntaxError( "ALIGNMENTS line (line #%d) not of " "the form: ## ALIGNMENTS (number) - (number)" % lineNum) continue if doing == 'proteins': if not line[0].isdigit(): continue try: seqName = line.split()[2] except IndexError: raise WrongFormatError( "Line %d in PROTEINS section does not " "start with [integer] : [sequence name]" % lineNum) sequences.append(Sequence(makeReadable(seqName))) elif doing == 'alignments': if line.lstrip().lower().startswith('seqno'): try: alignStartIndex = line.index('.') except: raise FormatSyntaxError( "No indication of alignment " " starting column ('.' character) in SeqNo line " " in ALIGNMENTS section") continue if alignStartIndex == None: raise FormatSyntaxError("No initial SeqNo line in " "ALIGNMENTS section") block = line[alignStartIndex:] if not block: raise FormatSyntaxError("No alignment block given on line %d" % lineNum) blockLen = end - begin + 1 if len(block) > blockLen: raise FormatSyntaxError( "Too many characters (%d, only %d " " sequences) in alignment block given on line %d" % (len(block), blockLen, lineNum)) block = block + ' ' * (blockLen - len(block)) for seq, c in zip(sequences[begin - 1:end], block): seq.append(c) f.close() return sequences, {}, {}
def clustalInfo(fileName=None): if fileName is None: return _clustalCategories, _clustalColorings from prefs import RC_HYDROPHOBICITY if fileName == RC_HYDROPHOBICITY: import os.path fileName = os.path.join(os.path.dirname(__file__), "kdHydrophob.par") colorInfo = {} for colorName in [ "RED", "BLUE", "GREEN", "CYAN", "PINK", "MAGENTA", "YELLOW", "ORANGE"]: colorInfo[colorName] = eval("_clustal%s" % colorName.capitalize()) from OpenSave import osOpen from chimera import UserError f = osOpen(fileName) section = None colorSeen = False categories = [] colorings = {} for line in f: line = line.strip() if line.startswith("@"): section = line[1:].lower() continue if not line: continue if section == "rgbindex": try: name, sr, sg, sb = line.split() except ValueError: raise UserError("Line in @rgbindex section of" " %s is not color name followed by" " red, green and blue values: '%s'" % (fileName, line)) try: r, g, b = [float(x) for x in [sr, sg, sb]] except ValueError: raise UserError("Line in @rgbindex section of" " %s has non-floating-point" " red, green or blue value: '%s'" % (fileName, line)) if r>1 or g>1 or b>1 or r<0 or g<0 or b<0: raise UserError("Line in @rgbindex section of" " %s has red, green or blue value" " not in the range 0-1: '%s'" % (fileName, line)) colorInfo[name] = rgba2tk((r, g, b)) elif section == "consensus": try: symbol, eq, percent, composition = line.split() except ValueError: raise UserError("Line in @consensus section of" " %s is not of the form 'symbol = " " percentage%% res-list: '%s'" % (fileName, line)) if eq != '=': raise UserError("Line in @consensus section of" " %s doesn't have '=' as second" " component: '%s'" % (fileName, line)) if percent[-1] != '%': raise UserError("Line in @consensus section of" " %s doesn't have '%' as last character" " of third component: '%s'" % (fileName, line)) try: percentage = float(percent[:-1]) except ValueError: raise UserError("Line in @consensus section of" " %s doesn't have a number before the" " '%' of third component: '%s'" % (fileName, line)) if percentage < 0 or percentage > 100: raise UserError("Line in @consensus section of" " %s has a percentage not in the range" " 0-100: '%s'" % (fileName, line)) composition = composition.replace(":", "") categories.append((composition, percentage/100.0, symbol)) elif section == "color": colorSeen = True fields = line.split() if len(fields) not in [3,5]: raise UserError("Line in @color section of" " %s not of the form AA = color" " [if consensus-list]: '%s'" % (fileName, line)) aa, eq, color = fields[:3] if len(aa) > 1 or not aa.islower(): raise UserError("Line in @color section of" " %s uses amino-acid code that is not" " a single lowercase character: '%s'" % (fileName, line)) if eq != '=': raise UserError("Line in @color section of" " %s doesn't have '=' as second" " component: '%s'" % (fileName, line)) if color not in colorInfo: raise UserError("Line in @color section of" " %s uses an unknown color:" " '%s'" % (fileName, line)) if len(fields) == 3: colorings.setdefault(aa.upper(), []).append( (colorInfo[color], None)) continue if fields[3] != 'if': raise UserError("Line in @color section of" " %s doesn't have 'if' as fourth" " component: '%s'" % (fileName, line)) colorings.setdefault(aa.upper(), []).append( (colorInfo[color], fields[-1].replace(":", ""))) f.close() if not colorSeen: raise UserError("'%s' has missing or empty @color section" % fileName) return categories, colorings
def loadScfFile(self, path, colorStructures=True): if path is None: if not self._scfDialog: self._scfDialog = ScfDialog( self.seqCanvas.mav.prefs[ SCF_COLOR_STRUCTURES], command=self.loadScfCB) self._scfDialog.enter() return seqs = self.seqCanvas.seqs from OpenSave import osOpen scfFile = osOpen(path) lineNum = 0 regionInfo = {} for line in scfFile.readlines(): lineNum += 1 line.strip() if not line or line[0] == '#' \ or line.startswith('//'): continue for commentIntro in ['//', '#']: commentPos = line.find(commentIntro) if commentPos >= 0: break if commentPos >= 0: comment = line[commentPos + len(commentIntro):].strip() line = line[:commentPos].strip() else: comment = None try: pos1, pos2, seq1, seq2, r, g, b = map( int, line.split()) if seq1 == -1: # internal to jevtrace/webmol continue if seq1 == 0: seq2 = -1 else: seq1 -= 1 seq2 -= 1 except: try: pos, seq, r, g, b = map(int, line.split()) pos1 = pos2 = pos except: replyobj.error("Bad format for line %d of %s [not 5 or 7 integers]\n" % (lineNum, path)) scfFile.close() return if seq == 0: seq1 = 0 seq2 = -1 else: seq1 = seq2 = seq - 1 key = ((r, g, b), comment) if key in regionInfo: regionInfo[key].append((seqs[seq1], seqs[seq2], pos1, pos2)) else: regionInfo[key] = [(seqs[seq1], seqs[seq2], pos1, pos2)] scfFile.close() if not regionInfo: replyobj.error("No annotations found in %s\n" % path) return for rgbComment, blocks in regionInfo.items(): rgb, comment = rgbComment rgb = map(lambda v: v/255.0, rgb) region = self.newRegion(namePrefix="Seqsel: ", blocks=blocks, name=comment, fill=rgb, coverGaps=True) if not colorStructures: continue c = chimera.MaterialColor(*rgb) for res in self.regionResidues(region): res.ribbonColor = c for a in res.atoms: a.color = c self.seqCanvas.mav.status("%d scf regions created\n" % len(regionInfo))
def addAttributes(attrFile, models=None, log=False, raiseAttrDialog=True): """add/set attributes from a file 'attrFile' indicates a file path or an opened file object. The file contains control lines and data lines. Control and data lines may be freely interspersed. The data lines are of the form: <tab>selector<tab>attribute value The selector is an atom specification (as per the Atom Specification section of the User's Guide). The attribute value is a boolean, integer, float, or string. If it is necessary to specify a string attribute that could be interpreted as one of the other types, embed the value in double quotes (it will then be evaluated as a Python string, including backslash interpretation). The control lines are of the form: name: value The possible name/value pairs are: Name Value ---- ----- attribute name of the attribute to assign to match mode expected matches per selector: "1 to 1": exactly one match per selector "non-zero": at least one match per selector "any": no constraint selectors not conforming to the match mode will generate an error recipient where to put attribute (atoms/residues/molecules) The only mandatory control line is 'attribute', which must precede any data lines. The default match mode is 1 to 1, and the default recipient is atoms. Empty lines are ignored and lines beginning with the '#' character are considered comments and ignored. 'log' controls whether information about what each selector matched is sent to the reply log. 'models' restricts any selector matching to the given models. If 'models' is None, then no restriction occurs. This function return a list of recipient/attribute tuples that actually were set in at least one object. If an error occurred, None is returned instead. """ from OpenSave import osOpen try: if isinstance(attrFile, basestring): attrFile = osOpen(attrFile) try: return _addAttr(attrFile, models, log, raiseAttrDialog) finally: attrFile.close() else: return _addAttr(attrFile, models, log, raiseAttrDialog) except SyntaxError, v: replyobj.error(str(v) + "\n") return None