Plugins Tutorial: Difference between revisions

From PyMOLWiki
Jump to navigation Jump to search
Line 18: Line 18:


===Adding Functionality===
===Adding Functionality===
For this example we are going to dynamically download, from the Protein Data Bank, a pdb structure and then load it into the PyMOL interface.  Here is a simple method which does that, given a pdb Code.
For this example we are going to dynamically download, from the [http://www.rcsb.org/pdb/home/home.do Protein Data Bank], a molecular structure and then load it into the PyMOL interface.  Here is a simple method which does that, given a PDB-ID (''pdbCode'').


<source lang="python">
<source lang="python">

Revision as of 10:31, 30 June 2015

Installing Plugins

To install a plugin, simply save the plugin file and load it into PyMol with the Plugin -> Install Plugin... menu item. Alternatively, plugins can be installed by copying the file into the PYMOLPATH/module/pmg_tk/startup/ folder.


Writing Plugins: Learn By Example

This tutorial is a more sophisticated version of the PDB Loader Service plugin that is bundled with PyMol. It is a relatively simple plugin, but should prove to be a good starting point for developing new plugins.

Registering your Plugin

First you must add your plugin to the Plugins menu. This is most easily done in the __init__ method of your plugin. A callback, fetchPDBDialog, is added. It is passed a reference to the main Tk app. It will need this in order to create new content in the main Tkinter loop. It is not strictly required in this example, but is needed in more complex interfaces.

 def __init__(self):
    self.menuBar.addmenuitem('Plugin', 'command',
                             'PDB Loader Service',
                             label = 'PDB Loader Service',
                             command = lambda s=self : fetchPDBDialog(s))

Adding Functionality

For this example we are going to dynamically download, from the Protein Data Bank, a molecular structure and then load it into the PyMOL interface. Here is a simple method which does that, given a PDB-ID (pdbCode).

 def remote(pdbCode):
    pdbCode = pdbCode.upper()
    try:
       pdbFile = urllib2.urlopen('http://www.rcsb.org/pdb/cgi/export.cgi/' +
                                 pdbCode + '.pdb.gz?format=PDB&pdbId=' +
                                 pdbCode + '&compression=gz')
       cmd.read_pdbstr(zlib.decompress(pdbFile.read()[22:], -zlib.MAX_WBITS), pdbCode)
    except:
       print "Unexpected error:", sys.exc_info()[0]
       tkMessageBox.showerror('Invalid Code',
                              'You entered an invalid pdb code:' + pdbCode)

Creating the Interface

Now we need to write the callback method, fetchPDBDialog, which creates the interface.

 def fetchPDBDialog(app):
    pdbCode = tkSimpleDialog.askstring('PDB Loader Service',
                                       'Please enter a 4-digit pdb code:',
                                       parent=app.root)
    remote(pdbCode)

Pretty simple! As of now you have a fully functional plugin that will prompt the user for a pdb code, download it from RCSB, and load it into the PyMol interface.

Extending Plugins to the Command Line

Opening the dialog can be tedious, so let's add a command line callback to make use of this new functionality.

 cmd.extend('remote', remote)

Now you can type remote 1di9, for example, to load the the corresponding pdb.

Full Source

Here is the complete example. You can save this file and load it into PyMol with the Plugin -> Install Plugin... menu item. I also include the sample license that Warren provides for plugin developers. It is optional, of course.

# Copyright Notice
# ================
# 
# The PyMOL Plugin source code in this file is copyrighted, but you can
# freely use and copy it as long as you don't change or remove any of
# the copyright notices.
# 
# ----------------------------------------------------------------------
# This PyMOL Plugin is Copyright (C) 2004 by Charles Moad <cmoad@indiana.edu>
# 
#                        All Rights Reserved
# 
# Permission to use, copy, modify, distribute, and distribute modified
# versions of this software and its documentation for any purpose and
# without fee is hereby granted, provided that the above copyright
# notice appear in all copies and that both the copyright notice and
# this permission notice appear in supporting documentation, and that
# the name(s) of the author(s) not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# prior permission.
# 
# THE AUTHOR(S) DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN
# NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# ----------------------------------------------------------------------

import tkSimpleDialog
import tkMessageBox
from pymol import cmd
import sys, urllib2, zlib

def __init__(self):
   self.menuBar.addmenuitem('Plugin', 'command',
                            'PDB Loader Service',
                            label = 'PDB Loader Service',
                            command = lambda s=self : fetchPDBDialog(s))

def remote(pdbCode):
   pdbCode = pdbCode.upper()
   try:
      pdbFile = urllib2.urlopen('http://www.rcsb.org/pdb/cgi/export.cgi/' +
                                pdbCode + '.pdb.gz?format=PDB&pdbId=' +
                                pdbCode + '&compression=gz')
      cmd.read_pdbstr(zlib.decompress(pdbFile.read()[22:], -zlib.MAX_WBITS), pdbCode)
   except:
      print "Unexpected error:", sys.exc_info()[0]
      tkMessageBox.showerror('Invalid Code',
                             'You entered an invalid pdb code:' + pdbCode)

def fetchPDBDialog(app):
   pdbCode = tkSimpleDialog.askstring('PDB Loader Service',
                                      'Please enter a 4-digit pdb code:',
                                      parent=app.root)
   
   remote(pdbCode)

cmd.extend('remote', remote)