def align_molecule(): # TODO: Not ported. from chimera import selection atoms = selection.currentAtoms(ordered=True) mols = set([a.molecule for a in atoms]) if len(mols) != 1: return mol = mols.pop() molxf = mol.openState.xform from Molecule import atom_positions axyz = atom_positions(atoms, molxf) from numpy import roll, float32, float64 from Matrix import xform_matrix, xform_points from chimera.match import matchPositions xflist = [] for mset in cage_marker_sets(): for p in polygons(mset): if p.n == len(atoms): c = p.center() vxyz = [p.vertex_xyz(m) for m in p.vertices] exyz = (0.5 * (vxyz + roll(vxyz, 1, axis=0))).astype(float32) xform_points(exyz, mset.transform(), molxf) xf, rms = matchPositions(exyz.astype(float64), axyz.astype(float64)) xflist.append(xf) molxf.multiply(xflist[0]) mol.openState.xform = molxf import MultiScale mm = MultiScale.multiscale_manager() tflist = [xform_matrix(xf) for xf in xflist] mm.molecule_multimer(mol, tflist)
def update(self, trigName, myData, changes): # print >> __stdout__, "update", trigName, myData, dir(changes), changes.modified # coordSet = list(changes.modified)[0] # print >> __stdout__, len(coordSet.coords()) # print >> __stdout__, dir(coordSet) # print >> __stdout__, "update" # atoms = [] # for selection in xla.get_gui().Subunits.getMovableAtomSpecs(): # atoms.extend(evalSpec(selection).atoms()) for serie in self.series: serie['new'] = [] for chainId in serie['chainIds']: atoms = evalSpec(':.{0}'.format(chainId)).atoms() serie['new'].append(numpyArrayFromAtoms(atoms)) # if self.was_changed(): i = 0 changed_c = None for old_c, new_c in zip(serie['old'], serie['new']): if not (old_c == new_c).all(): changed_c = i i = i + 1 if changed_c is not None: other = set(range(len(serie['chainIds']))) other.remove(changed_c) t3d, rmsd = matchPositions(serie['new'][changed_c], serie['old'][changed_c]) for o in other: newT = Xform.identity() newT.premultiply(serie['t3ds'][o][changed_c]) newT.premultiply(t3d) newT.premultiply(serie['t3ds'][changed_c][o]) atoms = evalSpec(':.{0}'.format( serie['chainIds'][o])).atoms() for a in atoms: a.setCoord(newT.apply(a.coord())) serie['old'] = [] for chainId in serie['chainIds']: atoms = evalSpec(':.{0}'.format(chainId)).atoms() serie['old'].append(numpyArrayFromAtoms(atoms))
def update(self, trigName, myData, changes): # print >> __stdout__, "update", trigName, myData, dir(changes), changes.modified # coordSet = list(changes.modified)[0] # print >> __stdout__, len(coordSet.coords()) # print >> __stdout__, dir(coordSet) # print >> __stdout__, "update" # atoms = [] # for selection in xla.get_gui().Subunits.getMovableAtomSpecs(): # atoms.extend(evalSpec(selection).atoms()) for serie in self.series: serie['new'] = [] for chainId in serie['chainIds']: atoms = evalSpec(':.{0}'.format(chainId)).atoms() serie['new'].append(numpyArrayFromAtoms(atoms)) # if self.was_changed(): i = 0 changed_c = None for old_c, new_c in zip(serie['old'], serie['new']): if not (old_c == new_c).all(): changed_c = i i = i + 1 if changed_c is not None: other = set(range(len(serie['chainIds']))) other.remove(changed_c) t3d, rmsd = matchPositions(serie['new'][changed_c], serie['old'][changed_c]) for o in other: newT = Xform.identity() newT.premultiply(serie['t3ds'][o][changed_c]) newT.premultiply(t3d) newT.premultiply(serie['t3ds'][changed_c][o]) atoms = evalSpec(':.{0}'.format(serie['chainIds'][o])).atoms() for a in atoms: a.setCoord(newT.apply(a.coord())) serie['old'] = [] for chainId in serie['chainIds']: atoms = evalSpec(':.{0}'.format(chainId)).atoms() serie['old'].append(numpyArrayFromAtoms(atoms))
def interpolate(mol, molXform, segments, equivAtoms, method, rMethod, frames, cartesian, cb): # mol molecule where new coordinate sets are added # should already have first frame in place # molXform transform to convert atoms from their own # local coordinate system into "mol" local coordinates # (usually [inverse transform of trajectory model] x # [transform of target model]) # segments list of 2-tuples of matching residue lists # equivAtoms dictionary of equivalent atoms # key is atom from first frame # value is 2-tuple of atoms from last frame and "mol" # method interpolation method name # rMethod rate profile, e.g., "linear" # frames number of frames to generate in trajectory # cartesian use cartesian coordinate interpolation? # cb function called for every frame generated import InterpResidue from util import getAtomList, findBestMatch import chimera from chimera import match method = findBestMatch(method, InterpolationMap.iterkeys()) interpolateFunction = InterpolationMap[method] rMethod = findBestMatch(rMethod, RateMap.iterkeys()) rateFunction = RateMap[rMethod] if cartesian: planFunction = InterpResidue.planCartesian else: planFunction = InterpResidue.planInternal rate = rateFunction(frames) numFrames = len(rate) + 1 activeCS = mol.activeCoordSet csSize = len(mol.activeCoordSet.coords()) baseCS = max(mol.coordSets.keys()) + 1 segMap = {} plan = {} for seg in segments: rList0, rList1 = seg aList0 = getAtomList(rList0) aList1 = [ equivAtoms[a0] for a0 in aList0 ] c1 = chimera.Point([ a.coord() for a in aList1 ]) segMap[seg] = (aList0, aList1, molXform.apply(c1)) for r in rList0: plan[r] = planFunction(r) import numpy def coordsToPosition(atoms): return numpy.array([a.coord().data() for a in atoms]) def xformCoordsToPosition(atoms): return numpy.array([molXform.apply(a.coord()).data() for a in atoms]) lo = 0.0 interval = 1.0 for i in range(len(rate)): f = (rate[i] - lo) / interval lo = rate[i] interval = 1.0 - lo cs = mol.newCoordSet(baseCS + i, csSize) for seg in segments: aList0, aList1, c1 = segMap[seg] c = chimera.Point([ a.coord() for a in aList0 ]) cList0 = coordsToPosition(aList0) cList1 = xformCoordsToPosition(aList1) xform, rmsd = match.matchPositions(cList1, cList0) xf, xf1 = interpolateFunction(xform, c, c1, f) xf1.multiply(molXform) rList0, rList1 = seg for r in rList0: InterpResidue.applyPlan(plan[r], r, cs, f, equivAtoms, xf, xf1) mol.activeCoordSet = cs if cb: cb(mol) cs = mol.newCoordSet(baseCS + len(rate), csSize) for a0, a1 in equivAtoms.iteritems(): a0.setCoord(molXform.apply(a1.coord()), cs) mol.activeCoordSet = cs
def fillInUI(self, parent): from chimera.match import matchPositions from chimera import numpyArrayFromAtoms from chimera import selection, UserError self._computing = False # load needed coord sets... frameNums = range(self.startFrame, self.endFrame+1, self.stride) for frameNum in frameNums: if not self.movie.findCoordSet(frameNum): self.status("loading frame %d" % frameNum) self.movie._LoadFrame(frameNum, makeCurrent=False) # compute RMSDs from analysis import analysisAtoms try: atoms = analysisAtoms(self.movie, self.useSel, self.ignoreBulk, self.ignoreHyds) except UserError: self.Close() raise self.buttonWidgets['Close'].configure(text="Abort") numFrames = len(frameNums) self.status("Fetching %d coordinate arrays" % numFrames) numpyArrays = {} from time import time t0 = time() for i, fn in enumerate(frameNums): numpyArrays[fn] = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(fn)) self._computing = True self._abort = False parent.update() # allow Abort button to function self._computing = False if self._abort: parent.after_idle(self.Close) return if i == numFrames - 1: self.status("Fetched %d coordinate arrays" % (i+1)) else: elapsed = time() - t0 perSec = elapsed / (i+1) remaining = perSec * (numFrames - (i+1)) self.status("Fetched %d of %d coordinate arrays" "\nAbout %.1f minutes remaining" % (i+1, numFrames, remaining / 60.0)) t0 = time() totalRMSDs = numFrames * (numFrames - 1) / 2 self.status("Computing %d RMSDs" % totalRMSDs) from EnsembleMatch.distmat import DistanceMatrix fullDM = DistanceMatrix(numFrames) sameAs = {} for i, frame1 in enumerate(frameNums): na1 = numpyArrays[frame1] for j, frame2 in enumerate(frameNums[i+1:]): na2 = numpyArrays[frame2] rmsd = matchPositions(na1, na2)[1] fullDM.set(i, i+j+1, rmsd) if rmsd == 0.0: sameAs[frame2] = frame1 self._computing = True self._abort = False parent.update() # allow Abort button to function self._computing = False if self._abort: parent.after_idle(self.Close) return numComputed = totalRMSDs - ((numFrames - (i+1)) * (numFrames - (i+2))) / 2 if numComputed == totalRMSDs: self.status("Computed %d RMSDs" % totalRMSDs) else: elapsed = time() - t0 perSec = elapsed / numComputed remaining = perSec * (totalRMSDs - numComputed) if remaining < 50: timeEst = "%d seconds" % int( remaining + 0.5) else: timeEst = "%.1f minutes" % ( remaining / 60.0) self.status("Computed %d of %d RMSDs\n" "About %s remaining" % (numComputed, totalRMSDs, timeEst)) self.status("Generating clusters") self.buttonWidgets['Close'].configure(text="Close") if not sameAs: dm = fullDM reducedFrameNums = frameNums indexMap = range(len(frameNums)) elif len(sameAs) == numFrames - 1: raise UserError("All frames to cluster are identical!") self.Close() else: dm = DistanceMatrix(numFrames - len(sameAs)) reducedFrameNums = [] indexMap = [] for i, fn in enumerate(frameNums): if fn in sameAs: continue reducedFrameNums.append(fn) indexMap.append(i) for i in range(len(reducedFrameNums)): mapi = indexMap[i] for j in range(i+1, len(reducedFrameNums)): mapj = indexMap[j] dm.set(i, j, fulldm.get(mapi, mapj)) from EnsembleMatch.nmrclust import NMRClust clustering = NMRClust(dm) self.clusterMap = {} self.representatives = [] self.clusters = [] unsortedClusters = [(c, clustering.representative(c)) for c in clustering.clusters] # sort the clusters so that the coloring is reproducible # while trying to avoid using adjacent colors for # adjacent clusters clusters = [unsortedClusters.pop()] while unsortedClusters: bestCluster = bestVal = None for uc in unsortedClusters: val = abs(uc[-1] - clusters[-1][-1]) if len(clusters) > 1: val += 0.5 * abs(uc[-1] - clusters[-2][-1]) if len(clusters) > 2: val += 0.25 * abs(uc[-1] - clusters[-3][-1]) if bestVal == None or val > bestVal: bestCluster = uc bestVal = val unsortedClusters.remove(bestCluster) clusters.append(bestCluster) colors = colorRange(len(clusters)) for c, rep in clusters: cluster = Cluster() cluster.color = colors.pop() self.clusters.append(cluster) cluster.representative = reducedFrameNums[rep] cluster.members = [] for m in c.members(): f = reducedFrameNums[m] self.clusterMap[f] = cluster cluster.members.append(f) for dup, base in sameAs.items(): c = self.clusterMap[base] self.clusterMap[dup] = c c.members.append(dup) self.status("%d clusters" % len(self.clusters)) from CGLtk.Table import SortableTable self.table = SortableTable(parent) self.table.addColumn("Color", "color", format=(False, False), titleDisplay=False) membersCol = self.table.addColumn("Members", "lambda c: len(c.members)", format="%d") self.table.addColumn("Representative Frame", "representative", format="%d") self.table.setData(self.clusters) self.table.launch(browseCmd=self.showRep) self.table.sortBy(membersCol) self.table.sortBy(membersCol) # to get descending order self.table.grid(sticky="nsew") self.timeLine = Pmw.ScrolledCanvas(parent, canvas_height="0.5i") self.timeLine.grid(row=1, column=0, sticky="nsew") parent.rowconfigure(0, weight=1) parent.columnconfigure(0, weight=1) self.zoom = 2.0 self.drawTimeLine()
def fillInUI(self, parent): from chimera.match import matchPositions from chimera import numpyArrayFromAtoms from chimera import selection, UserError self._computing = False top = parent.winfo_toplevel() menuBar = Tkinter.Menu(top) top.config(menu=menuBar) self.dependentDialogs = [] rmsdMenu = Tkinter.Menu(menuBar) menuBar.add_cascade(label="RMSD", menu=rmsdMenu) rmsdMenu.add_command(label="Change thresholds...", command=self.launchRmsdBoundsDialog) numFrames = self.endFrame - self.startFrame + 1 scale1size = numFrames / self.stride if scale1size < 200: scale = int(1 + 200 / scale1size) else: scale = 1 # load needed coord sets... for frameNum in range(self.startFrame, self.endFrame + 1, self.stride): if not self.movie.findCoordSet(frameNum): self.status("loading frame %d" % frameNum) self.movie._LoadFrame(frameNum, makeCurrent=False) self.widgets = [] width = max(len(str(self.endFrame)), 6) for i in range(2): entryFrame = Tkinter.Frame(parent) entryFrame.grid(row=1, column=i) entry = Pmw.EntryField(entryFrame, labelpos='w', entry_width=width, label_text="Frame", validate='numeric') entry.configure(command=lambda ent=entry: self.entryCB(ent)) entry.grid(row=0, column=0) self.widgets.append(entry) goBut = Tkinter.Button(entryFrame, text="Go", padx=0, pady=0, command=lambda ent=entry: self.entryCB(ent)) goBut.grid(row=0, column=1) self.widgets.append(goBut) self.widgets[0].insert(0, "Click") self.widgets[2].insert(0, "on map") for widget in self.widgets: if isinstance(widget, Pmw.EntryField): widget = widget.component('entry') widget.config(state='disabled') size = scale1size * scale self.scrCanvas = Pmw.ScrolledCanvas(parent, canvas_bg="blue", canvas_width=size, canvas_height=size, borderframe=True) self.scrCanvas.grid(row=0, column=0, columnspan=2, sticky="nsew") parent.rowconfigure(0, weight=1) parent.columnconfigure(0, weight=1) parent.columnconfigure(1, weight=1) # compute RMSD/image canvas from analysis import analysisAtoms try: atoms = analysisAtoms(self.movie, self.useSel, self.ignoreBulk, self.ignoreHyds) except UserError: self.Close() raise self.buttonWidgets['Close'].configure(text="Abort") self.rects = {} numpyArrays = {} if self.recolor: rmsds = [] minRmsd = maxRmsd = None for step1, frame1 in enumerate( range(self.startFrame, self.endFrame + 1, self.stride)): self.status("compute/show RMSDs for frame %d" % frame1) try: na1 = numpyArrays[frame1] except KeyError: na1 = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(frame1)) numpyArrays[frame1] = na1 canvas = self.scrCanvas.component('canvas') for step2, frame2 in enumerate( range(frame1, self.endFrame + 1, self.stride)): try: na2 = numpyArrays[frame2] except KeyError: na2 = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(frame2)) numpyArrays[frame2] = na2 rmsd = matchPositions(na1, na2)[1] if self.recolor: rmsds.append(rmsd) color = self.tkRmsdColor(rmsd) rect1 = canvas.create_rectangle(step1 * scale, (step1 + step2) * scale, (step1 + 1) * scale, (step1 + step2 + 1) * scale, fill=color, outline="") self.rects[rect1] = (frame1, frame2, rmsd) rect2 = canvas.create_rectangle((step1 + step2) * scale, step1 * scale, (step1 + step2 + 1) * scale, (step1 + 1) * scale, fill=color, outline="") self.rects[rect2] = (frame2, frame1, rmsd) if frame1 != frame2: if minRmsd is None: minRmsd = maxRmsd = rmsd elif rmsd < minRmsd: minRmsd = rmsd elif rmsd > maxRmsd: maxRmsd = rmsd if step1 == 0: self.scrCanvas.resizescrollregion() self._computing = True self._abort = False canvas.update() # show each line and allow quit self._computing = False if self._abort: canvas.after_idle(self.Close) return self.buttonWidgets['Close'].configure(text="Close") if self.recolor: self.status("Calculating recoloring thresholds\n") rmsds.sort() newMin = float("%.1f" % rmsds[int(len(rmsds) / 3)]) newMax = float("%.1f" % rmsds[int(2 * len(rmsds) / 3)]) if newMin == newMax: if newMin > 0: newMin -= 0.1 else: newMax += 0.1 self.newMinMax(newMin, newMax) canvas.bind("<Motion>", self.mouseOverCB) canvas.bind("<Button-1>", self.mouseClickCB) self.status("Calculated RMSD varies from %.3f to %.3f\n" % (minRmsd, maxRmsd), log=True)
def getRotamers(res, phi=None, psi=None, cisTrans="trans", resType=None, lib="Dunbrack", log=False): """Takes a Residue instance and optionally phi/psi angles (if different from the Residue), residue type (e.g. "TYR"), and/or rotamer library name. Returns a boolean and a list of Molecule instances. The boolean indicates whether the rotamers are backbone dependent. The Molecules are each a single residue (a rotamer) and are in descending probability order. Each has an attribute "rotamerProb" for the probability and "chis" for the chi angles. """ # find n/c/ca early to identify swapping non-amino acid before # the NoResidueRotamersError gets raised, which will attempt # a swap for ALA/GLY (and result in a traceback) resAtomsMap = res.atomsMap try: n = resAtomsMap["N"][0] ca = resAtomsMap["CA"][0] c = resAtomsMap["C"][0] except KeyError: raise LimitationError("N, CA, or C missing from %s:" " needed to position CB" % res) resType = resType or res.type if not phi and not psi: ignore, phi, psi, cisTrans = extractResInfo(res) if log: def _info(ang): if ang is None: return "none" return "%.1f" % ang replyobj.info("%s: phi %s, psi %s" % (res, _info(phi), _info(psi))) if cisTrans: replyobj.info(" " + cisTrans) replyobj.info("\n") replyobj.status("Retrieving rotamers from %s library\n" % getattr(lib, "displayName", lib)) bbdep, params = getRotamerParams(resType, phi=phi, psi=psi, cisTrans=cisTrans, lib=lib) replyobj.status("Rotamers retrieved from %s library\n" % getattr(lib, "displayName", lib)) template = chimera.restmplFindResidue(resType, False, False) tmplMap = template.atomsMap tmplN = tmplMap["N"] tmplCA = tmplMap["CA"] tmplC = tmplMap["C"] tmplCB = tmplMap["CB"] from chimera.molEdit import addAtom, addDihedralAtom, addBond from chimera.match import matchPositions, _coordArray xform, rmsd = matchPositions(_coordArray([n, ca, c]), _coordArray([tmplN, tmplCA, tmplC])) ncoord = xform.apply(tmplN.coord()) cacoord = xform.apply(tmplCA.coord()) cbcoord = xform.apply(tmplCB.coord()) from data import chiInfo info = chiInfo[resType] bondCache = {} angleCache = {} torsionCache = {} from chimera.bondGeom import bondPositions mols = [] middles = {} ends = {} for i, rp in enumerate(params): m = chimera.Molecule() mols.append(m) m.name = "rotamer %d of %s" % (i + 1, res) r = m.newResidue(resType, ' ', 1, ' ') # can't use a local variable for r.atomsMap since we receive # only an unchanging copy of the map m.rotamerProb = rp.p m.chis = rp.chis rotN = addAtom("N", tmplN.element, r, ncoord) rotCA = addAtom("CA", tmplCA.element, r, cacoord, bondedTo=rotN) rotCB = addAtom("CB", tmplCB.element, r, cbcoord, bondedTo=rotCA) todo = [] for i, chi in enumerate(rp.chis): n3, n2, n1, new = info[i] blen, angle = _lenAngle(new, n1, n2, tmplMap, bondCache, angleCache) n3 = r.atomsMap[n3][0] n2 = r.atomsMap[n2][0] n1 = r.atomsMap[n1][0] new = tmplMap[new] a = addDihedralAtom(new.name, new.element, n1, n2, n3, blen, angle, chi, bonded=True) todo.append(a) middles[n1] = [a, n1, n2] ends[a] = [a, n1, n2] # if there are any heavy non-backbone atoms bonded to template # N and they haven't been added by the above (which is the # case for Richardson proline parameters) place them now for tnnb in tmplN.bondsMap.keys(): if tnnb.name in r.atomsMap or tnnb.element.number == 1: continue tnnbcoord = xform.apply(tnnb.coord()) addAtom(tnnb.name, tnnb.element, r, tnnbcoord, bondedTo=rotN) # fill out bonds and remaining heavy atoms from chimera.idatm import typeInfo from chimera import distance done = set([rotN, rotCA]) while todo: a = todo.pop(0) if a in done: continue tmplA = tmplMap[a.name] for bonded, bond in tmplA.bondsMap.items(): if bonded.element.number == 1: continue try: rbonded = r.atomsMap[bonded.name][0] except KeyError: # use middles if possible... try: p1, p2, p3 = middles[a] conn = p3 except KeyError: p1, p2, p3 = ends[a] conn = p2 t1 = tmplMap[p1.name] t2 = tmplMap[p2.name] t3 = tmplMap[p3.name] xform, rmsd = matchPositions(_coordArray([p1, p2, p3]), _coordArray([t1, t2, t3])) pos = xform.apply(tmplMap[bonded.name].coord()) rbonded = addAtom(bonded.name, bonded.element, r, pos, bondedTo=a) middles[a] = [rbonded, a, conn] ends[rbonded] = [rbonded, a, conn] if a not in rbonded.bondsMap: addBond(a, rbonded) if rbonded not in done: todo.append(rbonded) done.add(a) return bbdep, mols
def fillInUI(self, parent): from chimera.match import matchPositions from chimera import numpyArrayFromAtoms from chimera import selection, UserError self._computing = False top = parent.winfo_toplevel() menuBar = Tkinter.Menu(top) top.config(menu=menuBar) self.dependentDialogs = [] rmsdMenu = Tkinter.Menu(menuBar) menuBar.add_cascade(label="RMSD", menu=rmsdMenu) rmsdMenu.add_command(label="Change thresholds...", command=self.launchRmsdBoundsDialog) numFrames = self.endFrame - self.startFrame + 1 scale1size = numFrames / self.stride if scale1size < 200: scale = int(1 + 200 / scale1size) else: scale = 1 # load needed coord sets... for frameNum in range(self.startFrame, self.endFrame+1, self.stride): if not self.movie.findCoordSet(frameNum): self.status("loading frame %d" % frameNum) self.movie._LoadFrame(frameNum, makeCurrent=False) self.widgets = [] width = max(len(str(self.endFrame)), 6) for i in range(2): entryFrame = Tkinter.Frame(parent) entryFrame.grid(row=1, column=i) entry = Pmw.EntryField(entryFrame, labelpos='w', entry_width=width, label_text="Frame", validate='numeric') entry.configure(command=lambda ent=entry: self.entryCB(ent)) entry.grid(row=0, column=0) self.widgets.append(entry) goBut = Tkinter.Button(entryFrame, text="Go", padx=0, pady=0, command=lambda ent=entry: self.entryCB(ent)) goBut.grid(row=0, column=1) self.widgets.append(goBut) self.widgets[0].insert(0, "Click") self.widgets[2].insert(0, "on map") for widget in self.widgets: if isinstance(widget, Pmw.EntryField): widget = widget.component('entry') widget.config(state='disabled') size = scale1size * scale self.scrCanvas = Pmw.ScrolledCanvas(parent, canvas_bg="blue", canvas_width=size, canvas_height=size, borderframe=True) self.scrCanvas.grid(row=0, column=0, columnspan=2, sticky="nsew") parent.rowconfigure(0, weight=1) parent.columnconfigure(0, weight=1) parent.columnconfigure(1, weight=1) # compute RMSD/image canvas from analysis import analysisAtoms try: atoms = analysisAtoms(self.movie, self.useSel, self.ignoreBulk, self.ignoreHyds) except UserError: self.Close() raise self.buttonWidgets['Close'].configure(text="Abort") self.rects = {} numpyArrays = {} if self.recolor: rmsds = [] minRmsd = maxRmsd = None for step1, frame1 in enumerate(range(self.startFrame, self.endFrame+1, self.stride)): self.status("compute/show RMSDs for frame %d" % frame1) try: na1 = numpyArrays[frame1] except KeyError: na1 = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(frame1)) numpyArrays[frame1] = na1 canvas = self.scrCanvas.component('canvas') for step2, frame2 in enumerate(range(frame1, self.endFrame+1, self.stride)): try: na2 = numpyArrays[frame2] except KeyError: na2 = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(frame2)) numpyArrays[frame2] = na2 rmsd = matchPositions(na1, na2)[1] if self.recolor: rmsds.append(rmsd) color = self.tkRmsdColor(rmsd) rect1 = canvas.create_rectangle(step1*scale, (step1+step2)*scale, (step1+1)*scale, (step1+step2+1)*scale, fill=color, outline="") self.rects[rect1] = (frame1, frame2, rmsd) rect2 = canvas.create_rectangle( (step1+step2)*scale, step1*scale, (step1+step2+1)*scale, (step1+1)*scale, fill=color, outline="") self.rects[rect2] = (frame2, frame1, rmsd) if frame1 != frame2: if minRmsd is None: minRmsd = maxRmsd = rmsd elif rmsd < minRmsd: minRmsd = rmsd elif rmsd > maxRmsd: maxRmsd = rmsd if step1 == 0: self.scrCanvas.resizescrollregion() self._computing = True self._abort = False canvas.update() # show each line and allow quit self._computing = False if self._abort: canvas.after_idle(self.Close) return self.buttonWidgets['Close'].configure(text="Close") if self.recolor: self.status("Calculating recoloring thresholds\n") rmsds.sort() newMin = float("%.1f" % rmsds[int(len(rmsds)/3)]) newMax = float("%.1f" % rmsds[int(2*len(rmsds)/3)]) if newMin == newMax: if newMin > 0: newMin -= 0.1 else: newMax += 0.1 self.newMinMax(newMin, newMax) canvas.bind("<Motion>", self.mouseOverCB) canvas.bind("<Button-1>", self.mouseClickCB) self.status("Calculated RMSD varies from %.3f to %.3f\n" % (minRmsd, maxRmsd), log=True)
def fillInUI(self, parent): from chimera.match import matchPositions from chimera import numpyArrayFromAtoms from chimera import selection, UserError self._computing = False # load needed coord sets... frameNums = range(self.startFrame, self.endFrame + 1, self.stride) for frameNum in frameNums: if not self.movie.findCoordSet(frameNum): self.status("loading frame %d" % frameNum) self.movie._LoadFrame(frameNum, makeCurrent=False) # compute RMSDs from analysis import analysisAtoms try: atoms = analysisAtoms(self.movie, self.useSel, self.ignoreBulk, self.ignoreHyds) except UserError: self.Close() raise self.buttonWidgets['Close'].configure(text="Abort") numFrames = len(frameNums) self.status("Fetching %d coordinate arrays" % numFrames) numpyArrays = {} from time import time t0 = time() for i, fn in enumerate(frameNums): numpyArrays[fn] = numpyArrayFromAtoms(atoms, self.movie.findCoordSet(fn)) self._computing = True self._abort = False parent.update() # allow Abort button to function self._computing = False if self._abort: parent.after_idle(self.Close) return if i == numFrames - 1: self.status("Fetched %d coordinate arrays" % (i + 1)) else: elapsed = time() - t0 perSec = elapsed / (i + 1) remaining = perSec * (numFrames - (i + 1)) self.status("Fetched %d of %d coordinate arrays" "\nAbout %.1f minutes remaining" % (i + 1, numFrames, remaining / 60.0)) t0 = time() totalRMSDs = numFrames * (numFrames - 1) / 2 self.status("Computing %d RMSDs" % totalRMSDs) from EnsembleMatch.distmat import DistanceMatrix fullDM = DistanceMatrix(numFrames) sameAs = {} for i, frame1 in enumerate(frameNums): na1 = numpyArrays[frame1] for j, frame2 in enumerate(frameNums[i + 1:]): na2 = numpyArrays[frame2] rmsd = matchPositions(na1, na2)[1] fullDM.set(i, i + j + 1, rmsd) if rmsd == 0.0: sameAs[frame2] = frame1 self._computing = True self._abort = False parent.update() # allow Abort button to function self._computing = False if self._abort: parent.after_idle(self.Close) return numComputed = totalRMSDs - ((numFrames - (i + 1)) * (numFrames - (i + 2))) / 2 if numComputed == totalRMSDs: self.status("Computed %d RMSDs" % totalRMSDs) else: elapsed = time() - t0 perSec = elapsed / numComputed remaining = perSec * (totalRMSDs - numComputed) if remaining < 50: timeEst = "%d seconds" % int(remaining + 0.5) else: timeEst = "%.1f minutes" % (remaining / 60.0) self.status("Computed %d of %d RMSDs\n" "About %s remaining" % (numComputed, totalRMSDs, timeEst)) self.status("Generating clusters") self.buttonWidgets['Close'].configure(text="Close") if not sameAs: dm = fullDM reducedFrameNums = frameNums indexMap = range(len(frameNums)) elif len(sameAs) == numFrames - 1: raise UserError("All frames to cluster are identical!") self.Close() else: dm = DistanceMatrix(numFrames - len(sameAs)) reducedFrameNums = [] indexMap = [] for i, fn in enumerate(frameNums): if fn in sameAs: continue reducedFrameNums.append(fn) indexMap.append(i) for i in range(len(reducedFrameNums)): mapi = indexMap[i] for j in range(i + 1, len(reducedFrameNums)): mapj = indexMap[j] dm.set(i, j, fulldm.get(mapi, mapj)) from EnsembleMatch.nmrclust import NMRClust clustering = NMRClust(dm) self.clusterMap = {} self.representatives = [] self.clusters = [] unsortedClusters = [(c, clustering.representative(c)) for c in clustering.clusters] # sort the clusters so that the coloring is reproducible # while trying to avoid using adjacent colors for # adjacent clusters clusters = [unsortedClusters.pop()] while unsortedClusters: bestCluster = bestVal = None for uc in unsortedClusters: val = abs(uc[-1] - clusters[-1][-1]) if len(clusters) > 1: val += 0.5 * abs(uc[-1] - clusters[-2][-1]) if len(clusters) > 2: val += 0.25 * abs(uc[-1] - clusters[-3][-1]) if bestVal == None or val > bestVal: bestCluster = uc bestVal = val unsortedClusters.remove(bestCluster) clusters.append(bestCluster) colors = colorRange(len(clusters)) for c, rep in clusters: cluster = Cluster() cluster.color = colors.pop() self.clusters.append(cluster) cluster.representative = reducedFrameNums[rep] cluster.members = [] for m in c.members(): f = reducedFrameNums[m] self.clusterMap[f] = cluster cluster.members.append(f) for dup, base in sameAs.items(): c = self.clusterMap[base] self.clusterMap[dup] = c c.members.append(dup) self.status("%d clusters" % len(self.clusters)) from CGLtk.Table import SortableTable self.table = SortableTable(parent) self.table.addColumn("Color", "color", format=(False, False), titleDisplay=False) membersCol = self.table.addColumn("Members", "lambda c: len(c.members)", format="%d") self.table.addColumn("Representative Frame", "representative", format="%d") self.table.setData(self.clusters) self.table.launch(browseCmd=self.showRep) self.table.sortBy(membersCol) self.table.sortBy(membersCol) # to get descending order self.table.grid(sticky="nsew") self.timeLine = Pmw.ScrolledCanvas(parent, canvas_height="0.5i") self.timeLine.grid(row=1, column=0, sticky="nsew") parent.rowconfigure(0, weight=1) parent.columnconfigure(0, weight=1) self.zoom = 2.0 self.drawTimeLine()