On Mon, 3 Oct 2005, Terry Jones wrote: > Is it possible to embed a pymol window into a bigger independent > application?
"Embed"? No. At least, not if you want the pymol window to act as a widget that can be embedded in a frame of some sort. The last time I used pymol was version 0.87, so the information below may very well be useless. Reader beware. > I am writing some code using PyQt and various other things (like PyOpenGL, > Open Inventor, pivy), and it would be nice to be able to be able to pop a > window with pymol in it (if that's the right way to put it). So the tk GUI > would not be there, just the PyMol graphics window. You *can* do that, if I'm understanding you correctly. The pymol window can be popped up from your application, you just can't embed it into another window. (And, at least in 0.87, you couldn't dismiss the pymol window, because pymol insisted on terminating the whole application). > When I do what seems most obvious, putting > > from pymol import cmd > > in a file and running python on it, it tells me there's no such module as > pymol. Maybe this is simply my python path not including the right thing. It's a little tricker, see below. > If it matters, I'm on Mac OS X (10.3.9) but I'm running python 2.4, not the > stock distributed 2.3. Would that stop me being able to import pymol as > above (I mean is it incompatible, not is the path to pymol unknown, which I > assume is probably the case)? I've always used pymol with my own Python interpreter, you shouldn't have to use what came with pymol. And Warren wrote: > We are very interested in this, but it is outside the scope of PyMOL > 1.x. It will definitely be possible in PyMOL 2.x, but we'll need to > break the API a bit for that in order to achieve an object-oriented > usage paradigm. 2 years ago I was involved with a project where we only wanted to use pymol as a rendering widget, but it was impossible. Our prototype used pymol's separate window, but I recommended that the project look for another solution because my impression was that the pymol project was more interested in being an application, and introducing new features. Glad to hear a "library" or "toolkit" usage will be a deliverable for 2.X. > To accomplish this with current versions, it is necessary to launch and > message PyMOL as an independent process or at least as a singleton > component within a Python interpreter that includes a PyQT user > interface in a separate window. > > You can get a graphics-only PyMOL window by launching with command line > options -qxiF. You can control window placement with -X -Y # -H # -W # And so here is what we did on our project. We had a python/tk application that had a UI to do something other than molecule viewing. There was a button to launch a "structure viewer". Ideally it would launch a top level window that had a navbar on top, a residue/atom tree on the left, and the pymol rendering window as the main part of the top level window. Instead we launched the toplevel which did layout the navbar and tree widget, but then launched pymol separately. The navbar and tree controlled pymol via cmd.* calls, plus it interacted with the "twpick" Wizard to detect when a user clicked on something. So in a file, say sw.py: import os, threading, sys import __main__ import Tkinter from Tkinter import * from tkFileDialog import * import Pmw . . . app specific stuff. . . # # First, add the pymol modules path to the python module path # so we can we can import pymol # modules_path = os.environ['PYMOL_PATH']+'/modules' if modules_path not in sys.path: sys.path.append(modules_path) # # Now we can import pymol # # This stuff is for pymol v0.86 and above __main__.pymol_launch = 0 __main__.pymol_argv = [ "pymol", "-q -i -x" ] # no UI import pymol from pymol import cmd, util from pymol.cgo import * # Don't really need a separate class for this, but much more # was envisioned. . . class PymolWindow(threading.Thread): def __init__(self): # print "PymolWindow: New Instance" threading.Thread.__init__(self) def run(self): pymol_argv = [ "pymol", "-q -i -x" ] # no UI #pymol_argv = [ "pymol", "-q -x " ] # with internal UI # Now start the pymol threads pymol.invocation.parse_args(pymol_argv) pymol.start_pymol() class StructureWidget(Pmw.MegaWidget): . . . app specific stuff. . . def __init__(self, mainGUI, parent, **kwDict): . . . app specific stuff. . . self.defineoptions(kwDict, optiondefs) Pmw.MegaWidget.__init__(self, parent, **kwDict) self._createComponents() # Pymol should be ready for commands now # print "Loading picking event wizard..." cmd.wizard("twpick") # Quiet down pymol a bit cmd.feedback('disable', 'executive', 'everything') def _createComponents(self): # Create the Pymol Window self.pymol = PymolWindow() self.pymol.start() # While pymol starts, construct our GUI self._createMenuBar(self.parent) . . . app specific stuff. . . # Wait for pymol before making any pymol calls e = threading.Event() while not pymol._cmd.ready(): e.wait(0.1) Can you follow that? Pymol is running in a separate thread and you can now control it via cmd.* calls. For example, there was a pulldown to select a rendering style, one of which was cartoon mode, and it ultimately called: # # Set the cartoon mode. # def setCartoonDisplayStyle(self, objName, type): # print "SetCartoonStyle to %s on %s" % (type, objName) if (type == 'off'): cmd.hide('cartoon', objName); else: cmd.cartoon(type, objName) cmd.show('cartoon', objName) Or, there was a pulldown to rebind the mouse buttons in a few preset configurations, which ultimately called this method: def rebindMouse(self, which): if which == 'mouseModeSelect': # print "Rebinding the mouse for selection" pymol.controlling.ring_dict['OurApp'] = [ 'OurApp_three_button' ] pymol.controlling.mode_dict['OurApp_three_button'] = [ ('l','none','rota'), ('m','none','movz'), ('r','none','pkat'), ('l','shft','movz'), ('m','shft','move'), ('r','shft','pkat'), # +lb ('l','ctrl','movz'), ('m','ctrl','move'), ('r','ctrl','pkat'), # +lb ('l','ctsh','orig'), ('m','ctsh','orig'), ('r','ctsh','orig') ] . . . rest elided. . . Or, the app had a PDB class, and to load a PDB into pymol: # Load a PDB from a string. def loadPDBString(self, pdbString, seqID): # Turn the sequence ID into a pymol-capable name pmName = self.seqIDToPymolName(seqID) # print "Loading from String:" cmd.read_pdbstr(pdbString, pmName, 1, 1) # Check the PDB for HELIX or SHEET records, which define the # secondary structure in the PDB. If they're not there, then # we'll call pymol and attempt to create a secondary structure. if (None == re.search('\nHELIX', pdbString) and None == re.search('\nSHEET', pdbString)): # print "####" # print "#### WARNING: NO Secondary Structure defined in PDB." # print "#### Calling pymol's util.ss() to generate one." # print "####" util.ss(pmName) self._finishLoadingPDB(pmName, seqID); # # This version of load takes a PDB object # def loadPDB(self, pdb, seqID): # Add it to our list of PDBs self.loadedPDBs[seqID] = pdb # And load it... self.loadPDBString(pdb.pdbStr, seqID) . . . rest elided. . . # Called after a PDB has been loaded. It creates the objects # we use internally to maninipulate the structure def _finishLoadingPDB(self, pmName, seqID): visProps = self.getVisualProps(pmName) #cmd.rebuild() self.sm.addStructure(seqID) #self.addNameToWSMenu(objName) # Don't need this anymore, since we have Tree # Now make a named selection that corresponds to the working set object. # We need this because certain props (eg. cartoon_style) only seem to # work on selections. Go figure. cmd.select(pmName + "Sel", "byObj all") cmd.deselect() . . . rest elided. . . Does this help at all? Again, this was pymol 0.87 so I am not sure if you can start pymol this way in the current release. And although we used Tk to build our GUI, you should be able to use anything you like. Our app worked on Windows and Linux, we never did any work on the Mac. Good luck, -Bob