class Interface(ModelessDialog): title = "Fill Gaps with Modeller" def __init__(self, *args, **kw): ModelessDialog.__init__(self, *args, **kw) # TODO: initialize instance variables def fillInUI(self, parent): from chimera.widgets import MoleculeOptionMenu from chimera.tkoptions import IntOption, BooleanOption, \ InputFileOption, StringOption import itertools info = Tk.Label(parent, justify=Tk.LEFT, wraplength=300, text="Select a molecule with gaps") info.pack(ipadx=2, ipady=2) options = Tk.Frame(parent) options.columnconfigure(0, pad=2) options.columnconfigure(1, pad=2) row = itertools.count() molRow = row.next() text = Tk.Label(options, text="Restrict selections to molecule:") text.grid(row=molRow, column=0) self.molecules = MoleculeOptionMenu(options, command=self.updateMolecule) self.molecules.grid(row=molRow, column=1, sticky=Tk.W) self.turnsOnly = BooleanOption(options, row.next(), "Skip gaps at ends of chains", False, None) self.hetatms = BooleanOption(options, row.next(), "Include HETATM residues", False, None) #self.waters = BooleanOption(options, row.next(), # "Include waters", False, None) self.nucleic = BooleanOption(options, row.next(), "Include nucleic acids", False, None) self.nucleic.disable() hr = Tk.Frame(options, relief=Tk.GROOVE, borderwidth=1, height=2) hr.grid(row=row.next(), columnspan=2, sticky='ew') # modeller location self.modeller = InputFileOption(options, row.next(), "Modeller location", "mod8v2", None) # temporary prefix -- TODO: add unique id #self.tempdir = StringOption(options, row.next(), # "Temporary file prefix", "modtmp", None) options.pack() def updateMolecule(self, *args, **kw): print 'updateMolecule', args, kw # TODO: look for gaps def Apply(self): from chimera import selection molecule = [self.molecules.getvalue()]
class Interface(ModelessDialog): title = "Model Loops with Modeller" buttons = ("OK", "Cancel") help = "ContributedSoftware/model/model.html" def __init__(self, *args, **kw): ModelessDialog.__init__(self, *args, **kw) # TODO: initialize instance variables def fillInUI(self, parent): from chimera.widgets import MoleculeOptionMenu from chimera.tkoptions import IntOption, BooleanOption, \ InputFileOption, StringOption, EnumOption import itertools info = Tk.Label(parent, justify=Tk.LEFT, wraplength=300, text= "Model alternate conformations of loops using " "Modeller from <http://salilab.org/>.\n" "First select the loops you wish to model." " Then choose the number of models " "you wish to generate.") info.pack(ipadx=2, ipady=2) options = Tk.Frame(parent) options.columnconfigure(0, pad=2) options.columnconfigure(1, pad=2) row = itertools.count() molRow = row.next() text = Tk.Label(options, text="Restrict selections to molecule:") text.grid(row=molRow, column=0) self.molecules = MoleculeOptionMenu(options) self.molecules.grid(row=molRow, column=1, sticky=Tk.W) self.turnsOnly = BooleanOption(options, row.next(), "Restrict selections to turns", True, None) self.hetatms = BooleanOption(options, row.next(), "Include HETATM residues", False, None) self.waters = BooleanOption(options, row.next(), "Include waters", False, None) self.waters.disable() self.nucleic = BooleanOption(options, row.next(), "Include nucleic acids", False, None) self.nucleic.disable() self.count = IntOption(options, row.next(), "Number of models", 10, None, min=1, sticky=Tk.W) #self.start = IntOption(options, row.next(), # "Starting model number", 1, None, min=0) class Refinement(EnumOption): values = ('very fast', 'fast', 'slow', 'very slow', 'slow large', 'none') self.refine = Refinement(options, row.next(), "Refinement", 'fast', None) button = Tk.Button(options, text="Prune selection", command=self.prune) button.grid(row=row.next(), column=0, columnspan=2, pady=2) self.start = 1 hr = Tk.Frame(options, relief=Tk.GROOVE, borderwidth=1, height=2) hr.grid(row=row.next(), columnspan=2, sticky='ew') # modeller location self.modeller = InputFileOption(options, row.next(), "Modeller location", "mod9v2", None) # temporary prefix -- TODO: add unique id #self.tempdir = StringOption(options, row.next(), # "Temporary file prefix", "modtmp", None) options.pack() def prune(self): from chimera import selection molecule = self.molecules.getvalue() import ModUtil pairs, residues = ModUtil.convertSelection( selection._currentSelection, minLen=4, molecule=molecule, keepHet=self.hetatms.get(), keepNA=self.nucleic.get(), turnsOnly=self.turnsOnly.get()) sel = selection.ItemizedSelection() sel.add(residues) sel.addImplied() selection.mergeCurrent(selection.INTERSECT, sel) return pairs, residues def Apply(self): pairs, residues = self.prune() if not pairs: from chimera import replyobj replyobj.status("no residues meet loop modelling criteria") return # create a temporary directory to work in import tempfile tempdir = tempfile.mkdtemp(prefix="modeller") print 'Modeller temporary directory:', tempdir # write PDB file with original coordinates import os fname = os.path.join(tempdir, 'original.pdb') molecule = self.molecules.getvalue() xform = molecule.openState.xform xform.invert() # want original coordinates chimera.viewer.pdbWrite([molecule], xform, fname) # write out Modeller input file count = self.count.get() refine = self.refine.get() fname = os.path.join(tempdir, "loopopt.py") f = file(fname, 'w') writeModeller(f, 'original.pdb', 'loop', pairs, count, refine) f.close() # run Modeller -- put up progress dialog import ModUtil def cb(process, dirname=tempdir, count=count): return loopFileCount(dirname, count) try: prog = self.modeller.get() p = ModUtil.run([prog, "loopopt.py"], cb, cwd=tempdir) except OSError, e: from chimera import replyobj replyobj.error("Unable to run modeller: %s\n" % e) return # Do concurrent work here # find atoms that are connected to the residues we will model atoms = set() for r in residues: for a in r.atoms: atoms.add(a) outsideAtoms = set() for a in atoms: for b in a.bonds: oa = b.otherAtom(a) if oa.residue not in residues: outsideAtoms.add(oa) outsideAtoms = [(a.residue.id, a.name) for a in outsideAtoms] residueIds = set([r.id for r in residues]) # TODO: use triggers to monitor process # and then startup dock interface # For now, we just wait returncode = p.wait() if returncode != 0: from chimera import replyobj replyobj.error("Modeller failed\n") return # create ViewDock input file from output files path = makedock(tempdir, residueIds, outsideAtoms) if not path: from chimera import replyobj replyobj.error("No models were generated\n") return # undisplay selected residues for r in residues: for a in r.atoms: a.display = False # startup dock import ViewDock v = ViewDock.ViewDock(path, 'Modeller') # remove long bonds since makedock can't put TERs # from both the model and the "longbond" PseudoBondGroup models = [c.chimeraModel for c in v.results.compoundList] length = 3 sqLen = length * length for m in models: for b in m.bonds: if b.sqlength() >= sqLen: # get rid of longbond PseudoBonds a0, a1 = b.atoms pbs = a0.associations( chimera.LONGBOND_PBG_NAME, a1) for pb in pbs: pb.pseudoBondGroup.deletePseudoBond(pb) # get rid of bond m.deleteBond(b)
class Interface(ModelessDialog): title = 'Nucleotides' help = "ContributedSoftware/nucleotides/nucleotides.html" buttons = ("NDB Colors",) + ModelessDialog.buttons provideStatus = True def __init__(self, *args, **kw): self.currentStyle = self.saveui_defaultItem() ModelessDialog.__init__(self, *args, **kw) self.__firstcanvas = True def fillInUI(self, parent): parent.columnconfigure(0, pad=2) parent.columnconfigure(1, pad=2) import itertools row = itertools.count() self.showBackbone = BackboneOption(parent, row.next(), 'Show backbone as', 'ribbon', None) self.showSide = SideOption(parent, row.next(), 'Show side (sugar/base) as', 'fill/slab', self._showSideCB) self.showOrientation = BooleanOption(parent, row.next(), 'Show base orientation', default.ORIENT, None) import Tix self.nb = Tix.NoteBook(parent) self.nb.grid(row=row.next(), column=0, columnspan=2, sticky=Tk.EW, padx=2) # ladder page self.nb.add("ladder", label="Ladder Options") f = self.nb.page("ladder") if Tk.TkVersion >= 8.5: parent.tk.call('grid', 'anchor', f._w, Tk.N) prow = itertools.count() self.skipNonBase = BooleanOption(f, prow.next(), 'Ignore non-base H-bonds', default.IGNORE, None) self.showStubs = BooleanOption(f, prow.next(), 'Show stubs', default.STUBS, None) self.rungRadius = FloatOption(f, prow.next(), 'Rung radius', default.RADIUS, None) self.rungRadius.min = 0.0 self.useExisting = BooleanOption(f, prow.next(), 'Using existing H-bonds', default.USE_EXISTING, self._useExistingCB) from FindHBond.gui import RelaxParams self.relaxParams = RelaxParams(f, None, colorOptions=False) #self.relaxParams.relaxConstraints = False self.relaxParams.grid(row=prow.next(), columnspan=2, sticky='nsew', padx=2) # slab page self.nb.add("slab", label="Slab Options") f = self.nb.page("slab") if Tk.TkVersion >= 8.5: parent.tk.call('grid', 'anchor', f._w, Tk.N) prow = itertools.count() self.thickness = FloatOption(f, prow.next(), 'Thickness', default.THICKNESS, None) self.thickness.min = 0.01 self.shape = ShapeOption(f, prow.next(), 'Slab object', default.SHAPE, None) self.hideBases = BooleanOption(f, prow.next(), 'Hide base atoms', default.HIDE, None) self.showGlycosidic = BooleanOption(f, prow.next(), 'Separate glycosidic bond', default.GLYCOSIDIC, None) self.nb.add("style", label="Slab Style", raisecmd=self.map) # style page f = self.nb.page("style") if Tk.TkVersion >= 8.5: f.tk.call('grid', 'anchor', f._w, Tk.N) info = NA.findStyle(self.currentStyle) from chimera.preferences import saveui f2 = Tk.Frame(f) self.saveui = saveui.SaveUI(f2, self) f2.grid(row=prow.next(), column=0, columnspan=2, sticky=Tk.EW, padx=2, pady=2) self.anchor = AnchorOption(f, prow.next(), 'Anchor', info[NA.ANCHOR], self._drawStyle) f2 = Pmw.Group(f, tag_text=NA.PURINE.title()) f2.grid(row=prow.next(), column=0, columnspan=2, sticky=Tk.EW, padx=2) f2 = f2.interior() f2.columnconfigure(0, weight=1, pad=2, uniform='a') f2.columnconfigure(1, weight=1, uniform='a') f2.columnconfigure(2, weight=1) self.purine_canvas = Tk.Canvas(f2, width=1, height=1) #, #borderwidth=2, relief=Tk.RIDGE) r = prow.next() self.purine_canvas.grid(row=r, column=0, rowspan=3, sticky=Tk.NSEW, padx=2, pady=2) corners = info[NA.PURINE] self.puLL = Float2Option(f2, prow.next(), 'Lower left', corners[0], self._drawStyle, startCol=1) self.puUR = Float2Option(f2, prow.next(), 'Upper right', corners[1], self._drawStyle, startCol=1) f3 = Pmw.Group(f, tag_text="%s, %s" % (NA.PYRIMIDINE.title(), NA.PSEUDO_PYRIMIDINE.title())) r = prow.next() f3.grid(row=r, column=0, columnspan=2, sticky=Tk.EW, padx=2) f3 = f3.interior() f3.columnconfigure(0, weight=1, pad=2, uniform='a') f3.columnconfigure(1, weight=1, uniform='a') f3.columnconfigure(2, weight=1) self.pyrimidine_canvas = Tk.Canvas(f3, width=1, height=1) #, #borderwidth=2, relief=Tk.RIDGE) r = prow.next() self.pyrimidine_canvas.grid(row=r, column=0, rowspan=3, sticky=Tk.NSEW, padx=2, pady=2) corners = info[NA.PYRIMIDINE] self.pyLL = Float2Option(f3, prow.next(), 'Lower left', corners[0], self._drawStyle, startCol=1) self.pyUR = Float2Option(f3, prow.next(), 'Upper right', corners[1], self._drawStyle, startCol=1) self.restrict = Tk.IntVar(parent) self.restrict.set(1) cb = Tk.Checkbutton(parent, variable=self.restrict, text="Restrict OK/Apply to current selection, if any") cb.grid(row=row.next(), columnspan=2) parent.pack(ipady=2) self._showSideCB() chimera.triggers.addHandler(NA.TRIGGER_SLAB_STYLES, self._updateStyles, None) def map(self, event=None): # need to update_idletasks so canvases in grid will have a size page = self.nb.raised() if page == 'style': if self.__firstcanvas: self.uiMaster().update_idletasks() self._drawStyle() self.__firstcanvas = False def _updateStyles(self, trigger, closure, arg): # pick up programmic changes in list of slab styles self.saveui.updateComboList() def saveui_label(self): return "Slab Style" def saveui_presetItems(self): return NA.SystemStyles.keys() def saveui_userItems(self): return NA.userStyles.keys() def saveui_defaultItem(self): return 'long' def saveui_select(self, name): self.currentStyle = name self._setSlabStyle(name) def saveui_save(self, name): info = self._getInfo() NA.addStyle(name, info) self.status("Slab style \"%s\" saved" % name) return True # successful def saveui_delete(self, name): NA.removeStyle(name) self.status("Slab style \"%s\" deleted" % name) return True # successful def _showSideCB(self, *args): side = self.showSide.get() hasSlab = 'slab' in side if side.startswith('fill') or hasSlab: self.showOrientation.enable() else: self.showOrientation.disable() if hasSlab: self.nb.raise_page('slab') elif side == 'ladder': self.nb.raise_page('ladder') if side == 'tube/slab': # tube connects to C1' if no slab # if slab, it goes to the middle of slab self.showGlycosidic.enable() return self.showGlycosidic.disable() def _useExistingCB(self, *args): useExisting = self.useExisting.get() if useExisting: self.relaxParams.disable() else: self.relaxParams.enable() def Apply(self): from chimera import selection if not self.restrict.get() or selection.currentEmpty(): molecules = chimera.openModels.list( modelTypes=[chimera.Molecule]) residues = [] for mol in molecules: residues.extend(mol.residues) else: residues = selection.currentResidues() molecules = tuple(set(r.molecule for r in residues)) residues = [r for r in residues if r.ribbonResidueClass.isNucleic()] backbone = self.showBackbone.get() display = backbone != 'atoms & bonds' for r in residues: r.ribbonDisplay = display side = self.showSide.get() if side == 'ladder': distSlop = 0.0 angleSlop = 0.0 relax = self.relaxParams.relaxConstraints if relax: distSlop = self.relaxParams.relaxDist angleSlop = self.relaxParams.relaxAngle NA.set_ladder(molecules, residues, rungRadius=self.rungRadius.get(), showStubs=self.showStubs.get(), skipNonBaseHBonds=self.skipNonBase.get(), useExisting=self.useExisting.get(), distSlop=distSlop, angleSlop=angleSlop) return if side.endswith('slab'): if self.currentStyle is None: info = self._getInfo() NA.addStyle(None, info) showGly = self.anchor.get() != NA.SUGAR if showGly and side.startswith('tube'): showGly = self.showGlycosidic.get() NA.set_slab(side, molecules, residues, style=self.currentStyle, thickness=self.thickness.get(), orient=self.showOrientation.get(), shape=self.shape.get(), showGly=showGly, hide=self.hideBases.get()) if side.startswith('fill'): for r in residues: r.fillDisplay = True else: for r in residues: r.fillDisplay = False if side.endswith('fill'): if self.showOrientation.get(): NA.set_orient(molecules, residues) else: NA.set_normal(molecules, residues) elif side.startswith('atoms'): NA.set_normal(molecules, residues) return def _showBase(self, type, info, canvas): # assume height is greater than width # keep in mind, canvases are "left-handed", so y is inverted # get unique bases of given type unique_bases = {} for b in NA.standard_bases.values(): if b['type'] == type: unique_bases[id(b)] = b # compute drawing parameters win_width = canvas.winfo_width() if win_width == 1: # no size assigned yet return win_height = canvas.winfo_height() # TODO: figure out how much room we really need for text if win_width < win_height: win_scale = .8 * win_width else: win_scale = .8 * win_height x_offset = .1 * win_width + 2 # 2==borderwidth if type == NA.PURINE: min = NA.purine_min max = NA.purine_max other = NA.pyrimidine_max[0] - NA.pyrimidine_min[0] elif type == NA.PYRIMIDINE: min = NA.pyrimidine_min max = NA.pyrimidine_max other = NA.purine_max[0] - NA.purine_min[0] width = max[0] - min[0] if other > width: width = other scale = win_scale / width # center vertically height = (max[1] - min[1]) * scale win_height -= (win_height - height) / 2 # clear canvas canvas.addtag_all('all') canvas.delete('all') def cvt_coords(c): for i in range(0, len(c), 2): c[i] = (c[i] - min[0]) * scale + x_offset c[i + 1] = win_height \ - (c[i + 1] - min[1]) * scale def draw_line(b, names): coords = [] for n in names: c = b[n] coords += [c[0], c[1]] if len(names) > 2: # close line coords += coords[0:2] cvt_coords(coords) kw = {'width':2} canvas.create_line(*coords, **kw) c1p_coords = None for b in unique_bases.values(): rn = b['ring atom names'] draw_line(b, rn) for o in b['other bonds']: draw_line(b, o) if c1p_coords is None: c1p_coords = list(b["C1'"][0:2]) else: coords = b["C1'"][0:2] if coords[0] < c1p_coords[0]: c1p_coords[0] = coords[0] if coords[1] > c1p_coords[1]: c1p_coords[1] = coords[1] corners = info[type] anchor = NA.anchor(info[NA.ANCHOR], type) offset = b[anchor] coords = [ offset[0] + corners[0][0], offset[1] + corners[0][1], offset[0] + corners[1][0], offset[1] + corners[1][1] ] cvt_coords(coords) kw = {'fill':'gray25', 'stipple':'gray25'} canvas.create_rectangle(*coords, **kw) coords = [min[0], max[1]] cvt_coords(c1p_coords) kw = {'text':" C1'", 'anchor':'s'} canvas.create_text(*c1p_coords, **kw) def _getInfo(self): info = { NA.ANCHOR: self.anchor.get(), NA.PURINE: (self.puLL.get(), self.puUR.get()), NA.PYRIMIDINE: (self.pyLL.get(), self.pyUR.get()), NA.PSEUDO_PYRIMIDINE: (self.pyLL.get(), self.pyUR.get()) } return info def _drawStyle(self, *args): if args: self.saveui.setItemChanged(True) self.currentStyle = None # fill in parameters info = self._getInfo() # show bases self._showBase(NA.PURINE, info, self.purine_canvas) self._showBase(NA.PYRIMIDINE, info, self.pyrimidine_canvas) def _setSlabStyle(self, name): # make options reflect current style info = NA.findStyle(name) if not info: return self.currentStyle = name self.anchor.set(info[NA.ANCHOR]) corners = info[NA.PURINE] self.puLL.set(corners[0]) self.puUR.set(corners[1]) corners = info[NA.PYRIMIDINE] self.pyLL.set(corners[0]) self.pyUR.set(corners[1]) self._drawStyle() def NDBColors(self): from chimera import selection if selection.currentEmpty(): import Midas residues = Midas._selectedResidues('#') else: residues = selection.currentResidues() NA.NDBColors(residues)