|
|
(63 intermediate revisions by 2 users not shown) |
Line 1: |
Line 1: |
| + | {{Infobox script-repo |
| + | |type = plugin |
| + | |filename = plugins/autodock_plugin.py |
| + | |author = [[User:Dseelig|Daniel Seeliger]] |
| + | |license = - |
| + | }} |
| + | |
| == Description == | | == Description == |
| This plugin should help to set up docking runs with Autodock and view docking results. It has two features: | | This plugin should help to set up docking runs with Autodock and view docking results. It has two features: |
| | | |
− | 1) Setup of a docking grid for Autodock with PyMOL.
| + | # Setup of a docking grid for Autodock with PyMOL. |
− | | + | # View the docking results. |
− | 2) View the docking results.
| |
| | | |
| == Installation == | | == Installation == |
| + | === Linux === |
| + | This plugin is ready "out-of-box" for Linux users through the project [[git_intro | Pymol-script-repo]] |
| | | |
− | 1)Download [http://www.mpibpc.mpg.de/groups/grubmueller/start/people/dseelig/autodock.py plugin]
| + | === Windows === |
| + | This plugin is ready "out-of-box" for win users through the project [[git_intro | Pymol-script-repo]] |
| | | |
− | 2) PyMOL -> Plugin -> Install Plugin
| + | You can download it manually |
| + | # Download [http://wwwuser.gwdg.de/~dseelig/adplugin.html plugin] |
| + | # '''PyMOL > Plugin > Install Plugin''' |
| + | # [http://autodock.scripps.edu/downloads/resources/adt/index_html MGLTools/AutoDockTools ] |
| + | # [http://autodock.scripps.edu/downloads/autodock-registration/autodock-4-2-download-page/ AutoDock4.2] |
| + | # [http://vina.scripps.edu/download.html AutoDock Vina] |
| | | |
− | == Author == | + | == Tutorial Video == |
| | | |
− | [[User:Dseelig|Daniel Seeliger]] | + | Watch Dan Seeliger's [http://wwwuser.gwdg.de/~dseelig/plugin_tutorial.html autodock plugin tutorial]. |
| | | |
− | [[Category:Plugins]]
| + | == Important == |
| + | # The Autodock tools, does not like funny atoms names like "C1, N13, O28" and so on. Rename them! See example 1. |
| + | # Ligands can not be in alternative configuration. Create by: '''create ROC_A, 1HXB and resn ROC and alt a''' . See example 2. |
| | | |
− | <source lang="python">#!/usr/bin/env python | + | == Example 1 - Rename of funny atom names == |
| + | Read about the protein here: http://www.proteopedia.org/wiki/index.php/3ig7 <br> |
| + | The example of video http://wwwuser.gwdg.de/~dseelig/plugin_tutorial.html <br> |
| + | Note, that the module "prepare_ligand4.py" does not like funny names of atoms, so we have to rename them |
| | | |
− | from __future__ import division
| + | {{Template:PymolScriptRepoDownload|examples/autodock_plugin_1.pml}} |
− | from __future__ import generators
| + | <include src="https://raw.github.com/Pymol-Scripts/Pymol-script-repo/master/examples/autodock_plugin_1.pml" highlight="python" /> |
| | | |
− | import os,math,re
| + | Open the Autodock/Vina plugin. Check/set the executable to folders (they should be automatically found): |
− | import Tkinter
| + | Autodock Tools: /home/you/another/pymol/Pymol-script-repo/modules/ADT/AutoDockTools/Utilities24 |
− | from Tkinter import *
| + | autogrid4 executable: /home/you/another/pymol/Pymol-script-repo/modules/autodock_423/ia64Linux2/autogrid4 # Platform dependent |
− | import tkMessageBox
| + | autogrid4 executable: /home/you/another/pymol/Pymol-script-repo/modules/autodock_423/ia64Linux2/autodock4 # Platform dependent |
− | import Pmw
| + | vina executable: /home/you/another/pymol/Pymol-script-repo/modules/autodock_vina/autodock_vina_1_1_2_linux_x86/vina # Platform dependent |
− | from pymol import cmd,selector
| + | Working Directory: /home/you/another/pymol/workingdir |
− | import sys
| + | Enlarge the window and click '''Save Plugin Configuration file'''. Plugin will not work, if you do not save. |
− | from pymol.cmd import _feedback,fb_module,fb_mask,is_list,_cmd
| |
− | from pymol.cgo import *
| |
− | from pymol import stored
| |
− | from Numeric import *
| |
− | import tkColorChooser
| |
− | from pymol.vfont import plain
| |
| | | |
− | # Python backward-compatibility...
| + | Click tab '''Grid settings'''. In '''Calculate Grid Center by Selection''', write '''EFP'''. <br> |
− | try:
| + | Try clicking '''Wired Box''' in top right, and then '''Show Box''', '''Hide Box''', '''Cylindric Box''', '''Show Box'''.<br> |
− | True
| + | Then push '''Select binding site'''. In PyMOL, write |
− | except:
| + | show sticks, binding_site |
− | True = 1
| + | cmd.disable("binding_site") |
− | try:
| + | hide sticks, binding_site |
− | False
| + | Click tab '''Receptor'''. Mark '''cdk''', and click '''Generate Receptor'''.<br> |
− | except:
| + | Click cdk2 to the "right", and see where the files are located.<br> |
− | False = 0
| + | Click tab '''Ligands'''. Mark '''EFP''', and click '''EFP''' in the Ligand list. Here is the files stored. Click '''Generate Ligand'''<br> |
− | #
| + | Click tab '''Docking''', and click '''Run Vina'''. Wait 3-5 minutes, until '''Writing output ... done.'''<br> |
− | # Cheap hack for testing purposes
| + | Click tab '''View poses''', Browse to '''EFP.docked.pdbqt'''. Click '''Load''', '''Show best 10'''. Experiment with "Display options, and click the candidates"<br> |
− | #
| + | Congratulations, you did it! |
− | try:
| |
− | import pymol
| |
− | REAL_PYMOL = True
| |
− | except ImportError:
| |
− | REAL_PYMOL = False
| |
− | class pymol:
| |
− | class cmd:
| |
− | def load(self,name,sel=''):
| |
− | pass
| |
− | def get_names(self):
| |
− | return ['mol1','mol2','map1','map2']
| |
− | def get_type(self,thing):
| |
− | if thing.startswith('mol'):
| |
− | return 'object:molecule'
| |
− | else:
| |
− | return 'object:map'
| |
− | f.close()
| |
− | cmd = cmd()
| |
− | pymol = pymol()
| |
| | | |
− | def __init__(self):
| + | == Example 2 - Alternative configurations of a Ligand == |
− | self.menuBar.addmenuitem('Plugin', 'command',
| + | Read about the protein here: http://www.proteopedia.org/wiki/index.php/1hxb <br> |
− | 'Launch Autodock',
| + | Ligands can not be in alternative configuration. Create by: create ROC_A, 1HXB and resn ROC and alt a . |
− | label='Autodock...',
| |
− | command = lambda s=self: Autodock(s))
| |
− |
| |
| | | |
− |
| + | {{Template:PymolScriptRepoDownload|examples/autodock_plugin_2.pml}} |
| + | <include src="https://raw.github.com/Pymol-Scripts/Pymol-script-repo/master/examples/autodock_plugin_2.pml" highlight="python" /> |
| | | |
− | # set the defaults
| + | == References and LICENSES == |
| + | === Vina === |
| + | If you used AutoDock Vina in your work, [http://vina.scripps.edu/ please cite:]<br> |
| + | O. Trott, A. J. Olson, ''AutoDock Vina: improving the speed and accuracy of docking with a new scoring function, efficient optimization and multithreading'', '''Journal of Computational Chemistry''' 31 (2010) 455-461 |
| | | |
− | defaults = {
| + | === MGLTOOLS === |
− | "spacing" : '0.375',
| + | LICENSE of MGLTOOLS: |
− | "xpst":'100',
| + | <syntaxhighlight lang="text"> |
− | "ypst":'100',
| + | This software is copyrighted by Michel F. Sanner (sanner@scripps.edu) and TSRI. |
− | "zpts":'100',
| + | The following terms apply to all files associated with the software |
− | "sel":'(all)',
| + | unless explicitly disclaimed in individual files. |
− | "X":'0',
| |
− | "Y":'0',
| |
− | "Z":'0',
| |
− | "dx":'1.0',
| |
− | "dy":'1.0',
| |
− | "dz":'1.0',
| |
− | "csize":'0.2',
| |
− | "lwidth":'1',
| |
− | "grid":'1',
| |
− | "output":'grid.gpf',
| |
− | "dlgfile":'dock.dlg'
| |
− | }
| |
− |
| |
| | | |
| + | MGLTOOLS SOFTWARE LICENSE AGREEMENT. |
| | | |
| + | 1. Grant Of Limited License; Software Use Restrictions. The programs |
| + | received by you will be used only for NON COMMERCIAL purposes. |
| + | This license is issued to you as an individual. |
| | | |
− | class FileDialogButtonClassFactory:
| + | For COMMERCIAL use done with the software please contact Michel F. |
− | def get(fn,filter='*'):
| + | Sanner for details about commercial usage license agreements. |
− | """This returns a FileDialogButton class that will
| + | |
− | call the specified function with the resulting file.
| + | For any question regarding license agreements, please contact |
− | """
| + | Michel Sanner: |
− | class FileDialogButton(Tkinter.Button):
| + | TSRI, Molecular Biology Department, TCP 26, |
− | # This is just an ordinary button with special colors.
| + | 10550 North Torrey Pines Road, La Jolla, CA 92037 |
| + | sanner@scripps.edu |
| + | tel (858) 784-7742 |
| + | fax (858) 784-2341 |
| | | |
− | def __init__(self, master=None, cnf={}, **kw):
| + | 2. COMMERCIAL USAGE is defined as revenues generating activities. These |
− | '''when we get a file, we call fn(filename)'''
| + | include using this software for consulting activities and selling |
− | self.fn = fn
| + | applications built on top of, or using this software. Scientific |
− | self.__toggle = 0
| + | research in an academic environment and teaching are considered |
− | apply(Tkinter.Button.__init__, (self, master, cnf), kw)
| + | NON COMMERCIAL. |
− | self.configure(command=self.set)
| |
− | def set(self):
| |
− | fd = PmwFileDialog(self.master,filter=filter)
| |
− | fd.title('Please choose a file')
| |
− | n=fd.askfilename()
| |
− | if n is not None:
| |
− | self.fn(n)
| |
− | return FileDialogButton
| |
− | get = staticmethod(get)
| |
| | | |
| + | 3. Copying Restrictions. You will not sell or otherwise distribute commercially |
| + | these programs or derivatives to any other party, whether with or without |
| + | consideration. |
| | | |
| + | 4. Ownership of Software. You will not obtain, and will not attempt to |
| + | obtain copyright coverage thereon without the express purpose written |
| + | consent of The Scripps Research Institute and Dr. Sanner. |
| | | |
| + | 5. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY |
| + | FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| + | ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY |
| + | DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE |
| + | POSSIBILITY OF SUCH DAMAGE. |
| | | |
| + | 6. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, |
| + | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, |
| + | FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE |
| + | IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE |
| + | NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR |
| + | MODIFICATIONS. |
| + | </syntaxhighlight> |
| | | |
− |
| + | [[Category:Plugins]] |
− | class Autodock:
| + | [[Category:Pymol-script-repo]] |
− | | |
− | def __init__(self,app):
| |
− | parent = app.root
| |
− | self.parent = parent
| |
− | self.on_screen = IntVar()
| |
− | self.on_screen.set(0) # 0 box | 1 wire
| |
− | self.center = []
| |
− | self.have_box = 0
| |
− | self.colorRGB = [1,1,1]
| |
− | self.dialog = Pmw.Dialog(parent,
| |
− | buttons = ('Exit',),
| |
− | title = 'PyMOL Autodock Tools',
| |
− | command = self.buttonPressed)
| |
− | self.dialog.withdraw()
| |
− | Pmw.setbusycursorattributes(self.dialog.component('hull'))
| |
− | | |
− | # the title
| |
− | | |
− | w = Tkinter.Label(self.dialog.interior(),
| |
− | text = 'PyMOL Autodock Tools\nDaniel Seeliger\n<http://www.mpibpc.mpg.de/groups/grubmueller/start/people/dseelig/index.html>',
| |
− | background = 'navy',
| |
− | foreground = 'white',
| |
− | #pady = 20,
| |
− | )
| |
− | w.pack(expand = 1, fill = 'both', padx = 4, pady = 4)
| |
− | | |
− | # the basic notebook
| |
− | | |
− | self.notebook = Pmw.NoteBook(self.dialog.interior())
| |
− | self.notebook.pack(fill='both',expand=0,padx=3,pady=3)
| |
− |
| |
− | # the grid page
| |
− |
| |
− | page = self.notebook.add('Grid')
| |
− | | |
− | # grid definiton page
| |
− | group = Pmw.Group(page,tag_text='Grid Definition')
| |
− | group.pack(fill = 'both', expand = 0, padx = 10, pady = 5)
| |
− | self.dialog.bind('<Return>',self.buttonPressed)
| |
− | | |
− | # we put the parametes on the left side
| |
− |
| |
− | lgroup = Pmw.Group(group.interior(),tag_text = "Parameters")
| |
− | lgroup.pack(side='left',fill = 'both', expand = 0, padx = 10, pady = 3)
| |
− | | |
− | # ... and the display stuff on the right side
| |
− |
| |
− | rgroup = Pmw.Group(group.interior(),tag_text = "Display Options")
| |
− | rgroup.pack(side='right',fill = 'both', expand = 0, padx = 10, pady = 3)
| |
− | | |
− | # the left side ...
| |
− | | |
− | self.space=DoubleVar()
| |
− | self.space.set(defaults['spacing'])
| |
− | self.spacefr = Tkinter.Frame(lgroup.interior())
| |
− | labSP = Label(self.spacefr,text="Grid:");
| |
− | self.splocation = Entry(self.spacefr,textvariable=self.space,bg='black',fg='green');
| |
− | self.scrSP=Scrollbar(self.spacefr,orient="horizontal",command=self.changeValueSpacing)
| |
− | labSP.pack(side=LEFT)
| |
− | self.splocation.pack(side=LEFT)
| |
− | self.scrSP.pack(side=LEFT)
| |
− | self.spacefr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | self.xpts=IntVar()
| |
− | self.xpts.set(100)
| |
− | self.xptsfr = Tkinter.Frame(lgroup.interior())
| |
− | labXP = Label(self.xptsfr,text="xpts:");
| |
− | self.xptslocation = Entry(self.xptsfr,textvariable=self.xpts,bg='black',fg='green');
| |
− | self.xptsSP=Scrollbar(self.xptsfr,orient="horizontal",command=self.changeValueXpts)
| |
− | labXP.pack(side=LEFT)
| |
− | self.xptslocation.pack(side=LEFT)
| |
− | self.xptsSP.pack(side=LEFT)
| |
− | self.xptsfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | self.ypts=IntVar()
| |
− | self.ypts.set(100)
| |
− | self.yptsfr = Tkinter.Frame(lgroup.interior())
| |
− | labYP = Label(self.yptsfr,text="ypts:");
| |
− | self.yptslocation = Entry(self.yptsfr,textvariable=self.ypts,bg='black',fg='green');
| |
− | self.yptsSP=Scrollbar(self.yptsfr,orient="horizontal",command=self.changeValueYpts)
| |
− | labYP.pack(side=LEFT)
| |
− | self.yptslocation.pack(side=LEFT)
| |
− | self.yptsSP.pack(side=LEFT)
| |
− | self.yptsfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | self.zpts=IntVar()
| |
− | self.zpts.set(100)
| |
− | self.zptsfr = Tkinter.Frame(lgroup.interior())
| |
− | labZP = Label(self.zptsfr,text="zpts:");
| |
− | self.zptslocation = Entry(self.zptsfr,textvariable=self.zpts,bg='black',fg='green');
| |
− | self.zptsSP=Scrollbar(self.zptsfr,orient="horizontal",command=self.changeValueZpts)
| |
− | labZP.pack(side=LEFT)
| |
− | self.zptslocation.pack(side=LEFT)
| |
− | self.zptsSP.pack(side=LEFT)
| |
− | self.zptsfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | | |
− | # put a dummy frame
| |
− | dumframe = Tkinter.Frame(page)
| |
− | dumframe.pack(fill='x',padx=4,pady=2)
| |
− |
| |
− | dum1 = Tkinter.Label(dumframe,
| |
− | justify=LEFT,
| |
− | text = "",
| |
− | )
| |
− | dum1.pack(side='left')
| |
− | | |
− | | |
− | # the center definition
| |
− |
| |
− | radiogroups = []
| |
− | self.selmode = Tkinter.IntVar()
| |
− | self.selmode.set(0)
| |
− | radioframe = Tkinter.Frame(page)
| |
− |
| |
− | w = Pmw.Group(radioframe,
| |
− | tag_pyclass = Tkinter.Radiobutton,
| |
− | tag_text='Use average coordinates \nof a given selection',
| |
− | tag_value = 0,
| |
− | tag_variable = self.selmode)
| |
− | w.pack(fill = 'x', expand = 1, side='top')
| |
− | cw = Tkinter.Frame(w.interior())
| |
− | cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
| |
− | radiogroups.append(w)
| |
− | self.selectionlist = Pmw.EntryField(w.interior(),
| |
− | labelpos='w',
| |
− | label_text='Selection: ',
| |
− | value=defaults['sel'],
| |
− | command = self.changed,
| |
− | )
| |
− | self.selectionlist.pack(fill='x',padx=4,pady=1,expand=0) # vertical
| |
− | | |
− |
| |
− | w = Pmw.Group(radioframe,
| |
− | tag_pyclass = Tkinter.Radiobutton,
| |
− | tag_text='Use coordinates',
| |
− | tag_value = 1,
| |
− | tag_variable = self.selmode)
| |
− | w.pack(fill = 'x', expand = 1, side='top')
| |
− | cw = Tkinter.Frame(w.interior())
| |
− | cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
| |
− | radiogroups.append(w)
| |
− | | |
− | radioframe.pack(padx = 6, pady = 6, expand='yes', fill='both')
| |
− | Pmw.aligngrouptags(radiogroups)
| |
− | | |
− |
| |
− | self.x=DoubleVar()
| |
− | self.x.set(float(defaults["X"]))
| |
− | self.y=DoubleVar()
| |
− | self.y.set(float(defaults["Y"]))
| |
− | self.z=DoubleVar()
| |
− | self.z.set(float(defaults["Z"]))
| |
− |
| |
− | self.xfr = Tkinter.Frame(w.interior())
| |
− | labX = Label(self.xfr,text="X:");
| |
− | self.xloc = Entry(self.xfr,textvariable=self.x,bg='black',fg='green');
| |
− | self.scrX=Scrollbar(self.xfr,orient="horizontal",command=self.changeValueX)
| |
− |
| |
− |
| |
− | self.yfr = Tkinter.Frame(w.interior())
| |
− | labY = Label(self.yfr,text="Y:");
| |
− | self.yloc = Entry(self.yfr,textvariable=self.y,bg='black',fg='green');
| |
− | self.scrY=Scrollbar(self.yfr,orient="horizontal",command=self.changeValueY)
| |
− |
| |
− | self.zfr = Tkinter.Frame(w.interior())
| |
− | labZ = Label(self.zfr,text="Z:");
| |
− | self.zloc = Entry(self.zfr,textvariable=self.z,bg='black',fg='green');
| |
− | self.scrZ=Scrollbar(self.zfr,orient="horizontal",command=self.changeValueZ)
| |
− |
| |
− | labX.pack(side=LEFT)
| |
− | self.xloc.pack(side=LEFT)
| |
− | self.scrX.pack(side=LEFT)
| |
− | self.xfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | labY.pack(side=LEFT)
| |
− | self.yloc.pack(side=LEFT)
| |
− | self.scrY.pack(side=LEFT)
| |
− | self.yfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | labZ.pack(side=LEFT)
| |
− | self.zloc.pack(side=LEFT)
| |
− | self.scrZ.pack(side=LEFT)
| |
− | self.zfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | self.butt1 = Pmw.ButtonBox(radioframe, padx=0)
| |
− | self.butt1.pack(side=TOP)
| |
− | self.butt1.add('Show Box',command = self.calc_box)
| |
− | self.butt1.add('Hide Box',command = self.hideBox)
| |
− | self.butt1.add('Write gpf',command = self.write_gpf)
| |
− | self.butt1.add('Write Box',command = self.write_box)
| |
− | self.butt1.add('Change Color',command=self.tk_color_dialog)
| |
− |
| |
− | | |
− | # the display options
| |
− |
| |
− | radiogroups = []
| |
− | radioframe = Tkinter.Frame(rgroup.interior())
| |
− | | |
− | w = Pmw.Group(radioframe,
| |
− | tag_pyclass = Tkinter.Radiobutton,
| |
− | tag_text='Cylindric Box',
| |
− | tag_value = 0,
| |
− | tag_variable = self.on_screen)
| |
− | w.pack(fill = 'x', expand = 1, side='top')
| |
− | cw = Tkinter.Frame(w.interior())
| |
− | cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
| |
− | radiogroups.append(w)
| |
− |
| |
− | self.csize=DoubleVar()
| |
− | self.csize.set(float(defaults["csize"]))
| |
− | | |
− | self.csizefr = Tkinter.Frame(w.interior())
| |
− | labcsize = Label(self.csizefr,text="size:");
| |
− | self.csizeloc = Entry(self.csizefr,textvariable=self.csize,bg='black',fg='green',width=15);
| |
− | self.scrcsize=Scrollbar(self.csizefr,orient="horizontal",command=self.changeValueCsize)
| |
− | | |
− | labcsize.pack(side=LEFT)
| |
− | self.csizeloc.pack(side=LEFT)
| |
− | self.scrcsize.pack(side=LEFT)
| |
− | self.csizefr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | w = Pmw.Group(radioframe,
| |
− | tag_pyclass = Tkinter.Radiobutton,
| |
− | tag_text='Wired Box',
| |
− | tag_value = 1,
| |
− | tag_variable = self.on_screen)
| |
− | w.pack(fill = 'x', expand = 1, side='top')
| |
− | cw = Tkinter.Frame(w.interior())
| |
− | cw.pack(padx = 2, pady = 2, expand='yes', fill='both')
| |
− | radiogroups.append(w)
| |
− |
| |
− | self.lwidth=DoubleVar()
| |
− | self.lwidth.set(float(defaults["lwidth"]))
| |
− | | |
− | self.lwidthfr = Tkinter.Frame(w.interior())
| |
− | lablwidth = Label(self.lwidthfr,text="line:");
| |
− | self.lwidthloc = Entry(self.lwidthfr,textvariable=self.lwidth,bg='black',fg='green',width=15);
| |
− | self.scrlwidth=Scrollbar(self.lwidthfr,orient="horizontal",command=self.changeValueLwidth)
| |
− | | |
− | lablwidth.pack(side=LEFT)
| |
− | self.lwidthloc.pack(side=LEFT)
| |
− | self.scrlwidth.pack(side=LEFT)
| |
− | self.lwidthfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | self.grid=DoubleVar()
| |
− | self.grid.set(float(defaults["grid"]))
| |
− | | |
− | self.gridfr = Tkinter.Frame(w.interior())
| |
− | labgrid = Label(self.gridfr,text="grid:");
| |
− | self.gridloc = Entry(self.gridfr,textvariable=self.grid,bg='black',fg='green',width=15);
| |
− | self.scrgrid=Scrollbar(self.gridfr,orient="horizontal",command=self.changeValueGrid)
| |
− | | |
− | labgrid.pack(side=LEFT)
| |
− | self.gridloc.pack(side=LEFT)
| |
− | self.scrgrid.pack(side=LEFT)
| |
− | self.gridfr.pack(fill='x',padx=4,pady=1) # vertical
| |
− | | |
− | radioframe.pack(padx = 6, pady = 6, expand='yes', fill='both')
| |
− | Pmw.aligngrouptags(radiogroups)
| |
− | | |
− | | |
− | # the output file stuff
| |
− | | |
− | self.outfile = StringVar()
| |
− | self.outfile.set(defaults['output'])
| |
− | self.outlocation = Pmw.EntryField(page,
| |
− | labelpos='w',
| |
− | label_pyclass = FileDialogButtonClassFactory.get(self.set_outfilename,filter=("*.gpf")),
| |
− | validate = {'validator':self.quickFileValidation,},
| |
− | value = defaults['output'],
| |
− | label_text = 'Browse:')
| |
− | | |
− | self.outlocation.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
− | | |
− |
| |
− | # Docking Results Card
| |
− |
| |
− | page = self.notebook.add('View Docked')
| |
− | | |
− | # the input file
| |
− |
| |
− | group = Pmw.Group(page,tag_text='File')
| |
− | group.pack(fill = 'both', expand = 0, padx = 10, pady = 5)
| |
− | | |
− | # the structure card
| |
− |
| |
− | rgroup = Pmw.Group(page,tag_text='Structures')
| |
− | rgroup.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
− | self.rgroup = Pmw.NoteBook(rgroup.interior())
| |
− | self.rgroup.pack(fill='both',expand=1,padx=3,pady=3)
| |
− | self.pages = {}
| |
− | self.struct_dic = {}
| |
− | self.dlgfile = StringVar()
| |
− | self.dlgfile.set(defaults['dlgfile'])
| |
− | self.dlglocation = Pmw.EntryField(group.interior(),
| |
− | labelpos='w',
| |
− | label_pyclass = FileDialogButtonClassFactory.get(self.set_dlgfilename,filter="*.dlg"),
| |
− | validate = {'validator':self.quickFileValidation,},
| |
− | value = defaults['dlgfile'],
| |
− | label_text = 'Browse:')
| |
− | | |
− | self.dlglocation.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
− | | |
− | self.load_buttonbox = Pmw.ButtonBox(group.interior(), padx=0)
| |
− | self.load_buttonbox.pack(side=LEFT,expand = 1, padx = 10, pady = 5)
| |
− | self.load_buttonbox.add('Load',command=self.load_dlg)
| |
− | | |
− | self.mlist = []
| |
− | self.namelist = []
| |
− | | |
− | self.radiobuttons = Pmw.RadioSelect(rgroup.interior(),
| |
− | buttontype = 'radiobutton',
| |
− | orient = 'horizontal',
| |
− | labelpos = 'w',
| |
− | )
| |
− | for text in ('Show Selected',
| |
− | 'Delete Selected'):
| |
− | self.radiobuttons.add(text)
| |
− | self.radiobuttons.setvalue('Show Selected')
| |
− | self.radiobuttons.pack(padx=4,pady=1,side='top')
| |
− | | |
− | self.status_line = Label(rgroup.interior(), #relief='groove',
| |
− | relief='sunken',
| |
− | font='helvetica 12', anchor='w',fg='yellow',bg='black')
| |
− | | |
− | self.status_line.pack(side='left', fill='x', expand=True)
| |
− |
| |
− | | |
− | # the about card
| |
− |
| |
− | page = self.notebook.add('About')
| |
− | group = Pmw.Group(page, tag_text='About PyMOL Autodock Tools')
| |
− | group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
− | text = """
| |
− | This plugin should help to set up docking runs and view docking results.
| |
− | | |
− | To set up a docking grid,
| |
− | | |
− | 1) Load a protein structure.
| |
− | 2) Select the center of the box either by giving a selection or
| |
− | the coordinates directly.
| |
− | 3) Adjust the box as needed and save the *.gpf file.
| |
− | | |
− | To view docking results,
| |
− |
| |
− | 1) Load the protein structure.
| |
− | 2) Load the *.dlg file (or multiple *dlg files).
| |
− |
| |
− | For any bug, please send a mail with description to the author.
| |
− | | |
− | Many thanks to
| |
− | - Warren DeLano for everything involving PyMOL
| |
− | - The PyMOL plugin writers for providing templates
| |
− |
| |
− | Created by Daniel Seeliger (dseelig@gwdg.de)
| |
− | <http://www.mpibpc.mpg.de/groups/grubmueller/start/people/dseelig/index.html>
| |
− | Computational Biomolecular Dynamics Group
| |
− | <http://www.mpibpc.gwdg.de/abteilungen/073/>
| |
− | """
| |
− | | |
− | lfre=Frame(group.interior())
| |
− | bar=Scrollbar(lfre,)
| |
− | ll=Text(lfre,yscrollcommand=bar.set,background="#ddddff",font="Times 14")
| |
− | bar.config(command=ll.yview)
| |
− | | |
− | ll.insert(END,text)
| |
− | ll.pack(side=LEFT,expand="yes",fill="both")
| |
− | bar.pack(side=LEFT,expand="yes",fill="y")
| |
− | lfre.pack(expand="yes",fill="both")
| |
− | | |
− | self.notebook.setnaturalsize()
| |
− | | |
− | self.showAppModal()
| |
− | | |
− | | |
− | # functions
| |
− | | |
− | def tk_color_dialog(self):
| |
− | color = tkColorChooser.Chooser(
| |
− | initialcolor='white',title='Choose box color').show()
| |
− | if color[0] is not None:
| |
− | self.colorRGB = [color[0][0]/100.,
| |
− | color[0][1]/100.,
| |
− | color[0][2]/100.]
| |
− |
| |
− | | |
− |
| |
− | def status_combobox(self, value):
| |
− | name = value.split('_')[0]
| |
− | if self.radiobuttons.getvalue()=='Show Selected':
| |
− | view = cmd.get_view()
| |
− | cmd.read_pdbstr(self.struct_dic[str(value)].as_string,str(value))
| |
− | cmd.set_view(view)
| |
− | text = 'Docked Energy: %8.2f kcal/mol' % self.struct_dic[str(value)].energy
| |
− | self.status_line.configure(text=text)
| |
− | usr = self.struct_dic[str(value)].info_as_string.split('\n')
| |
− | u = ''
| |
− | for l in usr:
| |
− | u+=l[8:]+'\n'
| |
− | atoms = self.struct_dic[str(value)].as_string.split('\n')
| |
− | at = ''
| |
− | for a in atoms:
| |
− | at+=a[8:]+'\n'
| |
− |
| |
− | self.pages[name]['text'].clear()
| |
− | self.pages[name]['text'].insert('end',u)
| |
− | self.pages[name]['text'].insert('end',at)
| |
− | else:
| |
− | cmd.delete(str(value))
| |
− | self.pages[name]['text'].clear()
| |
− | self.status_line.configure(text='')
| |
− |
| |
− | def set_outfilename(self,filename):
| |
− | self.outlocation.setvalue(filename)
| |
− | | |
− | def set_dlgfilename(self,filename):
| |
− | self.dlglocation.setvalue(filename)
| |
− | | |
− | def buttonPressed(self,result):
| |
− | if hasattr(result,'keycode'):
| |
− | if result.keycode == 36:
| |
− | if self.notebook.getcurselection()=='Grid':
| |
− | self.calc_box()
| |
− | elif self.notebook.getcurselection()=='View Docked':
| |
− | self.load_dlg()
| |
− | if result == 'Show Box':
| |
− | self.calc_box()
| |
− | elif result == 'Write gpf':
| |
− | self.write_gpf()
| |
− | elif result == 'Exit' or result == None:
| |
− | self.dialog.withdraw()
| |
− | | |
− | def write_gpf(self):
| |
− | fname = self.outlocation.getvalue()
| |
− | if os.path.isfile(fname):
| |
− | print "backing up %s to ~%s" % (fname,fname)
| |
− | os.rename(fname,'~'+fname)
| |
− | print 'writing file %s' % fname
| |
− | fp = self.fileopen(fname,'w')
| |
− | if fp:
| |
− | print >>fp,"receptor protein.pdbqs #macromolecule"
| |
− | print >>fp,"gridfld protein.maps.fld #grid_data_file"
| |
− | print >>fp,"npts %5d %5d %5d #num.grid points in xyz" % \
| |
− | (self.xpts.get(),self.ypts.get(),self.zpts.get())
| |
− | print >>fp,"spacing %7.3f #spacing (Angstroms)" % self.space.get()
| |
− | print >>fp,"gridcenter %6.3f %6.3f %6.3f #xyz-coordinates or \"auto\" "%\
| |
− | (self.center[0],self.center[1],self.center[2])
| |
− | self.print_stuff(fp)
| |
− | fp.close()
| |
− |
| |
− | def write_box(self):
| |
− | self.calc_box()
| |
− | fname = self.outlocation.getvalue()
| |
− | if os.path.isfile(fname):
| |
− | print "backing up %s to ~%s" % (fname,fname)
| |
− | os.rename(fname,'~'+fname)
| |
− | print 'writing file %s' % fname
| |
− | fp = self.fileopen(fname,'w')
| |
− | print >>fp, 'xmin = %8.3f' % self.dbox[0][0]
| |
− | print >>fp, 'xmax = %8.3f' % self.dbox[0][1]
| |
− | print >>fp, 'ymin = %8.3f' % self.dbox[1][0]
| |
− | print >>fp, 'ymax = %8.3f' % self.dbox[1][1]
| |
− | print >>fp, 'zmin = %8.3f' % self.dbox[2][0]
| |
− | print >>fp, 'zmax = %8.3f' % self.dbox[2][1]
| |
− | fp.close()
| |
− |
| |
− | def print_stuff(self,fp):
| |
− |
| |
− | print >>fp, """types CANOSH #atom type names
| |
− | smooth 0.500 #store minimum energy within radius (Ang)
| |
− | map protein.C.map #filename of grid map
| |
− | nbp_r_eps 4.00 0.0222750 12 6 #C-C lj
| |
− | nbp_r_eps 3.75 0.0230026 12 6 #C-N lj
| |
− | nbp_r_eps 3.60 0.0257202 12 6 #C-O lj
| |
− | nbp_r_eps 4.00 0.0257202 12 6 #C-S lj
| |
− | nbp_r_eps 3.00 0.0081378 12 6 #C-H lj
| |
− | nbp_r_eps 4.10 0.0257202 12 6 #C-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 3.70 0.0181874 12 6 #C-M lj (Met: Mg)
| |
− | sol_par 12.77 0.6844 #C atomic fragmental volume, solv. param.
| |
− | constant 0.000 #C grid map constant energy
| |
− | map protein.A.map #filename of grid map
| |
− | nbp_r_eps 4.00 0.0222750 12 6 #A-C lj
| |
− | nbp_r_eps 3.75 0.0230026 12 6 #A-N lj
| |
− | nbp_r_eps 3.60 0.0257202 12 6 #A-O lj
| |
− | nbp_r_eps 4.00 0.0257202 12 6 #A-S lj
| |
− | nbp_r_eps 3.00 0.0081378 12 6 #A-H lj
| |
− | nbp_r_eps 4.10 0.0257202 12 6 #A-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 3.70 0.0181874 12 6 #A-M lj (Met: Mg)
| |
− | sol_par 10.80 0.1027 #A atomic fragmental volume, solv. param.
| |
− | constant 0.000 #A grid map constant energy
| |
− | map protein.N.map #filename of grid map
| |
− | nbp_r_eps 3.75 0.0230026 12 6 #N-C lj
| |
− | nbp_r_eps 3.50 0.0237600 12 6 #N-N lj
| |
− | nbp_r_eps 3.35 0.0265667 12 6 #N-O lj
| |
− | nbp_r_eps 3.75 0.0265667 12 6 #N-S lj
| |
− | nbp_r_eps 2.75 0.0084051 12 6 #N-H lj
| |
− | nbp_r_eps 3.85 0.0265667 12 6 #N-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 3.45 0.0187839 12 6 #N-M lj (Met: Mg)
| |
− | sol_par 0.00 0.0000 #N atomic fragmental volume, solv. param.
| |
− | constant 0.000 #N grid map constant energy
| |
− | map protein.O.map #filename of grid map
| |
− | nbp_r_eps 3.60 0.0257202 12 6 #O-C lj
| |
− | nbp_r_eps 3.35 0.0265667 12 6 #O-N lj
| |
− | nbp_r_eps 3.20 0.0297000 12 6 #O-O lj
| |
− | nbp_r_eps 3.60 0.0297000 12 6 #O-S lj
| |
− | nbp_r_eps 1.90 0.3280000 12 10 #O-H hb
| |
− | nbp_r_eps 3.70 0.0297000 12 6 #O-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 3.30 0.0210010 12 6 #O-M lj (Met: Mg)
| |
− | sol_par 0.00 0.0000 #O atomic fragmental volume, solv. param.
| |
− | constant 0.236 #O grid map constant energy
| |
− | map protein.S.map #filename of grid map
| |
− | nbp_r_eps 4.00 0.0257202 12 6 #S-C lj
| |
− | nbp_r_eps 3.75 0.0265667 12 6 #S-N lj
| |
− | nbp_r_eps 3.60 0.0297000 12 6 #S-O lj
| |
− | nbp_r_eps 4.00 0.0297000 12 6 #S-S lj
| |
− | nbp_r_eps 2.50 0.0656000 12 10 #S-H hb
| |
− | nbp_r_eps 4.10 0.0297000 12 6 #S-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 3.70 0.0210010 12 6 #S-M lj (Met: Mg)
| |
− | sol_par 0.00 0.0000 #S atomic fragmental volume, solv. param.
| |
− | constant 0.000 #S grid map constant energy
| |
− | map protein.H.map #filename of grid map
| |
− | nbp_r_eps 3.00 0.0081378 12 6 #H-C lj
| |
− | nbp_r_eps 2.75 0.0084051 12 6 #H-N lj
| |
− | nbp_r_eps 1.90 0.3280000 12 10 #H-O hb
| |
− | nbp_r_eps 2.50 0.0656000 12 10 #H-S hb
| |
− | nbp_r_eps 2.00 0.0029700 12 6 #H-H lj
| |
− | nbp_r_eps 3.10 0.0093920 12 6 #H-X lj (X: Phosphorus in protein-cofactor)
| |
− | nbp_r_eps 2.70 0.0066411 12 6 #H-M lj (Met: Mg)
| |
− | sol_par 0.00 0.0000 #H atomic fragmental volume, solv. param.
| |
− | constant 0.118 #H grid map constant energy
| |
− | elecmap protein.e.map #electrostatic potential map
| |
− | dielectric -0.1146 #<0,distance-dep.diel; >0,constant
| |
− | #fmap ... .f.map #floating grid
| |
− | """
| |
− |
| |
− | def quickFileValidation(self,s):
| |
− | if s == '': return Pmw.PARTIAL
| |
− | elif os.path.isfile(s): return Pmw.OK
| |
− | elif os.path.exists(s): return Pmw.PARTIAL
| |
− | else: return Pmw.PARTIAL
| |
− | | |
− | def changed(self):
| |
− | self.selmode.set(0)
| |
− | self.calc_box()
| |
− | self.showCrisscross()
| |
− | self.selectionlist.clear()
| |
− |
| |
− | def calc_center(self):
| |
− | self.center = []
| |
− | if self.selmode.get() == 0:
| |
− | sel = self.selectionlist.getvalue()
| |
− | if sel:
| |
− | stored.xyz = []
| |
− | cmd.iterate_state(1,sel,"stored.xyz.append([x,y,z])")
| |
− | self.center = average(stored.xyz)
| |
− | else:
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | | |
− | elif self.selmode.get() == 1:
| |
− | self.center.append(float(self.x.get()))
| |
− | self.center.append(float(self.y.get()))
| |
− | self.center.append(float(self.z.get()))
| |
− | self.x.set(self.center[0])
| |
− | self.y.set(self.center[1])
| |
− | self.z.set(self.center[2])
| |
− |
| |
− | | |
− | def showCrisscross(self):
| |
− | startpoint = (self.center[0],self.center[1],self.center[2])
| |
− | cmd.delete("crisscross")
| |
− | self.crisscross(startpoint[0],startpoint[1],startpoint[2],0.5,"crisscross")
| |
− |
| |
− | def changeValueSpacing(self,a):
| |
− | val = float(self.space.get())+float(a)*0.005
| |
− | self.space.set(val)
| |
− | if self.have_box:
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− |
| |
− |
| |
− | def changeValueXpts(self,a):
| |
− | val = int(self.xpts.get())+int(a)
| |
− | self.xpts.set(val)
| |
− | if self.have_box:
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− | | |
− | def changeValueYpts(self,a):
| |
− | val = int(self.ypts.get())+int(a)
| |
− | self.ypts.set(val)
| |
− | if self.have_box:
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− | | |
− | def changeValueZpts(self,a):
| |
− | val = int(self.zpts.get())+int(a)
| |
− | self.zpts.set(val)
| |
− | if self.have_box:
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− | | |
− | | |
− | def changeValueX(self,a):
| |
− | self.selmode.set(1)
| |
− | val=float(self.x.get())+float(a)*1.0
| |
− | self.x.set(val)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− |
| |
− | def changeValueY(self,a):
| |
− | self.selmode.set(1)
| |
− | val=float(self.y.get())+float(a)*1.0
| |
− | self.y.set(val)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− |
| |
− | def changeValueZ(self,a):
| |
− | self.selmode.set(1)
| |
− | val=float(self.z.get())+float(a)*1.0
| |
− | self.z.set(val)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− |
| |
− | def changeValueCsize(self,a):
| |
− | val=float(self.csize.get())+float(a)*0.1
| |
− | self.csize.set(val)
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− | | |
− |
| |
− | def changeValueLwidth(self,a):
| |
− | val=float(self.lwidth.get())+float(a)*1.0
| |
− | self.lwidth.set(val)
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− |
| |
− | def changeValueGrid(self,a):
| |
− | val=float(self.grid.get())+float(a)*1.0
| |
− | self.grid.set(val)
| |
− | self.selmode.set(1)
| |
− | self.calc_center()
| |
− | self.showCrisscross()
| |
− | self.calc_box()
| |
− | | |
− | | |
− | def calc_box(self):
| |
− | self.calc_center()
| |
− | xpts = int(self.xpts.get())
| |
− | ypts = int(self.ypts.get())
| |
− | zpts = int(self.zpts.get())
| |
− | csize = float(self.csize.get())
| |
− | spacing = float(self.space.get())
| |
− | size = [xpts*spacing,ypts*spacing,zpts*spacing]
| |
− | xmax = xmin = ymax = ymin = zmax =zmin = 0
| |
− | xmax = self.center[0] + size[0]/2.
| |
− | xmin = self.center[0] - size[0]/2.
| |
− | ymax = self.center[1] + size[1]/2.
| |
− | ymin = self.center[1] - size[1]/2.
| |
− | zmax = self.center[2] + size[2]/2.
| |
− | zmin = self.center[2] - size[2]/2.
| |
− | x = [xmin,xmax]
| |
− | y = [ymin,ymax]
| |
− | z = [zmin,zmax]
| |
− | self.dbox = [x,y,z]
| |
− | if self.on_screen.get()==0:
| |
− | self.showBox(self.dbox,csize)
| |
− | elif self.on_screen.get()==1:
| |
− | self.showWireBox(self.dbox)
| |
− | self.have_box = 1
| |
− |
| |
− | def showBox(self,box,size):
| |
− | view = cmd.get_view()
| |
− | name =" box"
| |
− | obj = []
| |
− | # do the box
| |
− | for i in range(2):
| |
− | for k in range (2):
| |
− | for j in range(2):
| |
− | if i != 1:
| |
− | obj.append(CYLINDER)
| |
− | obj.extend([box[0][i],box[1][j],box[2][k]])
| |
− | obj.extend([box[0][i+1],box[1][j],box[2][k]])
| |
− | obj.append(size)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(SPHERE)
| |
− | obj.extend([box[0][i],box[1][j],box[2][k],size])
| |
− |
| |
− | if j != 1:
| |
− | obj.append(CYLINDER)
| |
− | obj.extend([box[0][i],box[1][j],box[2][k]])
| |
− | obj.extend([box[0][i],box[1][j+1],box[2][k]])
| |
− | obj.append(size)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(SPHERE)
| |
− | obj.extend([box[0][i],box[1][j+1],box[2][k],size])
| |
− | if k != 1:
| |
− | obj.append(CYLINDER)
| |
− | obj.extend([box[0][i],box[1][j],box[2][k]])
| |
− | obj.extend([box[0][i],box[1][j],box[2][k+1]])
| |
− | obj.append(size)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | obj.append(SPHERE)
| |
− | obj.extend([box[0][i],box[1][j],box[2][k+1],size])
| |
− | | |
− | axes = [[2.0,0.0,0.0],[0.0,2.0,0.0],[0.0,0.0,2.0]]
| |
− | xpos = [box[0][1]+(box[0][1]-box[0][0])/5.,box[1][0],box[2][0]]
| |
− | cyl_text(obj,plain,xpos,'X',0.10,axes=axes)
| |
− | ypos = [box[0][0],box[1][1]+(box[1][1]-box[1][0])/5,box[2][0]]
| |
− | cyl_text(obj,plain,ypos,'Y',0.10,axes=axes)
| |
− | zpos = [box[0][0],box[1][0],box[2][1]+(box[2][1]-box[2][0])/5]
| |
− | cyl_text(obj,plain,zpos,'Z',0.10,axes=axes)
| |
− | cmd.load_cgo(obj,name)
| |
− | cmd.set_view(view)
| |
− |
| |
− | def hideBox(self):
| |
− | cmd.delete("box")
| |
− | cmd.delete("wirebox")
| |
− |
| |
− | def showWireBox(self,box):
| |
− | cmd.delete("wirebox")
| |
− | view = cmd.get_view()
| |
− | spacing = float(self.grid.get())
| |
− | lwidth = float(self.lwidth.get())
| |
− | xpts = int(round((box[0][1]-box[0][0])/spacing))+1
| |
− | ypts = int(round((box[1][1]-box[1][0])/spacing))+1
| |
− | zpts = int(round((box[2][1]-box[2][0])/spacing))+1
| |
− | obj = []
| |
− | for i in range(xpts):
| |
− | for k in range (ypts):
| |
− | obj.append(BEGIN)
| |
− | obj.append(LINE_STRIP)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− |
| |
− | for j in range(zpts):
| |
− |
| |
− | obj.append(VERTEX)
| |
− | obj.extend([box[0][0]+spacing*i,box[1][0]+spacing*k,\
| |
− | box[2][0]+spacing*j])
| |
− | | |
− | obj.append(END)
| |
− | for i in range(xpts):
| |
− | for j in range (zpts):
| |
− | obj.append(BEGIN)
| |
− | obj.append(LINE_STRIP)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | for k in range(ypts):
| |
− | obj.append(VERTEX)
| |
− | obj.extend([box[0][0]+spacing*i,box[1][0]+spacing*k,\
| |
− | box[2][0]+spacing*j])
| |
− | obj.append(END)
| |
− | for j in range(zpts):
| |
− | for i in range (xpts):
| |
− | obj.append(BEGIN)
| |
− | obj.append(LINE_STRIP)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | for k in range(ypts):
| |
− | obj.append(VERTEX)
| |
− | obj.extend([box[0][0]+spacing*i,box[1][0]+spacing*k,\
| |
− | box[2][0]+spacing*j])
| |
− | obj.append(END)
| |
− | for j in range(zpts):
| |
− | for k in range (ypts):
| |
− | obj.append(BEGIN)
| |
− | obj.append(LINE_STRIP)
| |
− | obj.append(COLOR)
| |
− | obj.extend(self.colorRGB)
| |
− | for i in range(xpts):
| |
− | obj.append(VERTEX)
| |
− | obj.extend([box[0][0]+spacing*i,box[1][0]+spacing*k,\
| |
− | box[2][0]+spacing*j])
| |
− | obj.append(END)
| |
− | cmd.load_cgo(obj,"wirebox")
| |
− | cmd.set("cgo_line_width",lwidth)
| |
− | cmd.set_view(view)
| |
− |
| |
− | def crisscross(self,x,y,z,d,name="crisscross"):
| |
− |
| |
− | obj = [
| |
− | LINEWIDTH, 3,
| |
− |
| |
− | BEGIN, LINE_STRIP,
| |
− | VERTEX, float(x-d), float(y), float(z),
| |
− | VERTEX, float(x+d), float(y), float(z),
| |
− | END,
| |
− |
| |
− | BEGIN, LINE_STRIP,
| |
− | VERTEX, float(x), float(y-d), float(z),
| |
− | VERTEX, float(x), float(y+d), float(z),
| |
− | END,
| |
− |
| |
− | BEGIN, LINE_STRIP,
| |
− | VERTEX, float(x), float(y), float(z-d),
| |
− | VERTEX, float(x), float(y), float(z+d),
| |
− | END
| |
− |
| |
− | ]
| |
− | view = cmd.get_view()
| |
− | cmd.load_cgo(obj,name)
| |
− | cmd.set_view(view)
| |
− | | |
− | | |
− | | |
− | def load_dlg(self):
| |
− | filename = self.dlglocation.get()
| |
− | self.namelist = []
| |
− | name = filename.split('/')[-1].split('.')[0]
| |
− | fp=self.fileopen(filename,'r')
| |
− | if fp:
| |
− | string = fp.read()
| |
− | newl = []
| |
− | modlist = []
| |
− | ex = re.compile('DOCKED:.*')
| |
− | l = ex.findall(string)
| |
− | str = ''
| |
− | mod = []
| |
− | for i in range(len(l)):
| |
− | if 'MODEL' in l[i]:
| |
− | str+=l[i]+'\n'
| |
− | for k in range(i+1,len(l)):
| |
− | if 'TER' in l[k]:
| |
− | str+=l[k]+'\n'
| |
− | mod.append(str)
| |
− | str=''
| |
− | break
| |
− | else:
| |
− | str+=l[k]+'\n'
| |
− | mlist= []
| |
− | for x in mod:
| |
− | m = Model()
| |
− | m.str2mod(x)
| |
− | mlist.append(m)
| |
− | self.mlist = sortByEnergy(mlist)
| |
− | for i in range(len(self.mlist)):
| |
− | self.namelist.append(name+'_%d'%(i+1))
| |
− | self.struct_dic[name+'_%d'%(i+1)] = self.mlist[i]
| |
− | self.update_combo(name)
| |
− |
| |
− | def update_combo(self,name):
| |
− | try:
| |
− | self.rgroup.delete(name)
| |
− | except:
| |
− | pass
| |
− | self.pages[name] = {'name':self.rgroup.add(name)}
| |
− | self.pages[name].update({'structs':self.namelist})
| |
− | self.del_buttonbox = Pmw.ButtonBox(self.pages[name]['name'], padx=3)
| |
− | self.del_buttonbox.pack(fill='x',side=TOP)
| |
− | self.del_buttonbox.add('Show best 10 %s' % name,command=self.show_best_lig)
| |
− | self.del_buttonbox.add('Show all %s' % name,command=self.show_all_lig)
| |
− | self.del_buttonbox.add('Hide all %s' % name,command=self.hide_all_lig)
| |
− | self.del_buttonbox.add('Delete %s' % name,command=self.del_lig)
| |
− | | |
− | self.pages[name]['combo'] = Pmw.ComboBox(self.pages[name]['name'],
| |
− | label_text='Docked',
| |
− | labelpos='nw',
| |
− | scrolledlist_items= self.namelist,
| |
− | selectioncommand=self.status_combobox,
| |
− | listbox_height=10,
| |
− | listbox_width=1,
| |
− |
| |
− | dropdown=False)
| |
− | self.pages[name]['combo'].pack(side='left', padx=3, anchor='n')
| |
− | | |
− | self.pages[name]['text'] = Pmw.ScrolledText(self.pages[name]['name'],
| |
− | borderframe=5,
| |
− | vscrollmode='dynamic',
| |
− | hscrollmode='dynamic',
| |
− | labelpos='n',
| |
− | label_text=name,
| |
− | text_width=150, text_height=15,
| |
− | text_wrap='none',
| |
− | text_background='#000000',
| |
− | text_foreground='green'
| |
− | )
| |
− | self.pages[name]['text'].pack()
| |
− | self.rgroup.selectpage(name)
| |
− | self.status_line.configure(text ='Loading %s' % name)
| |
− |
| |
− | def show_all_lig(self):
| |
− | name = self.rgroup.getcurselection()
| |
− | for s in self.pages[name]['structs']:
| |
− | self.status_combobox(s)
| |
− | self.status_line.configure(text = 'Showing all %s' % name)
| |
− | | |
− | def show_best_lig(self):
| |
− | name = self.rgroup.getcurselection()
| |
− | for s in self.pages[name]['structs'][:10]:
| |
− | self.status_combobox(s)
| |
− | self.status_line.configure(text = 'Showing best 10 %s' % name)
| |
− | | |
− |
| |
− | def hide_all_lig(self):
| |
− | name = self.rgroup.getcurselection()
| |
− | cmd.delete(name+'*')
| |
− | self.status_line.configure(text = 'Deleted all %s' % name)
| |
− |
| |
− | def del_lig(self):
| |
− | name = self.rgroup.getcurselection()
| |
− | cmd.delete(name+'*')
| |
− | self.rgroup.delete(self.rgroup.getcurselection())
| |
− | self.status_line.configure(text = 'Deleted %s' % name)
| |
− | | |
− | def fileopen(self, filename, mode):
| |
− | try:
| |
− | fp = open(filename,mode)
| |
− | return fp
| |
− | except:
| |
− | tkMessageBox.showerror('Error','Could not open file %s' % filename)
| |
− | return None
| |
− |
| |
− | def showAppModal(self):
| |
− | #self.dialog.activate(geometry = 'centerscreenalways', globalMode = 'nograb')
| |
− | self.dialog.show()
| |
− | #self.dialog.activate(geometry = 'centerscreenalways')
| |
− |
| |
− | | |
− | #
| |
− | # The classes PmwFileDialog and PmwExistingFileDialog and the _errorpop function
| |
− | # are taken from the Pmw contrib directory. The attribution given in that file
| |
− | # is:
| |
− | ################################################################################
| |
− | # Filename dialogs using Pmw
| |
− | #
| |
− | # (C) Rob W.W. Hooft, Nonius BV, 1998
| |
− | #
| |
− | # Modifications:
| |
− | #
| |
− | # J. Willem M. Nissink, Cambridge Crystallographic Data Centre, 8/2002
| |
− | # Added optional information pane at top of dialog; if option
| |
− | # 'info' is specified, the text given will be shown (in blue).
| |
− | # Modified example to show both file and directory-type dialog
| |
− | #
| |
− | # No Guarantees. Distribute Freely.
| |
− | # Please send bug-fixes/patches/features to <r.hooft@euromail.com>
| |
− | #
| |
− | ################################################################################
| |
− | import os,fnmatch,time
| |
− | import Tkinter,Pmw
| |
− | #Pmw.setversion("0.8.5")
| |
− | | |
− | def _errorpop(master,text):
| |
− | d=Pmw.MessageDialog(master,
| |
− | title="Error",
| |
− | message_text=text,
| |
− | buttons=("OK",))
| |
− | d.component('message').pack(ipadx=15,ipady=15)
| |
− | d.activate()
| |
− | d.destroy()
| |
− |
| |
− | class PmwFileDialog(Pmw.Dialog):
| |
− | """File Dialog using Pmw"""
| |
− | def __init__(self, parent = None, **kw):
| |
− | # Define the megawidget options.
| |
− | optiondefs = (
| |
− | ('filter', '*', self.newfilter),
| |
− | ('directory', os.getcwd(), self.newdir),
| |
− | ('filename', '', self.newfilename),
| |
− | ('historylen',10, None),
| |
− | ('command', None, None),
| |
− | ('info', None, None),
| |
− | )
| |
− | self.defineoptions(kw, optiondefs)
| |
− | # Initialise base class (after defining options).
| |
− | Pmw.Dialog.__init__(self, parent)
| |
− | | |
− | self.withdraw()
| |
− | | |
− | # Create the components.
| |
− | interior = self.interior()
| |
− | | |
− | if self['info'] is not None:
| |
− | rowoffset=1
| |
− | dn = self.infotxt()
| |
− | dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
| |
− | else:
| |
− | rowoffset=0
| |
− | | |
− | dn = self.mkdn()
| |
− | dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
− | del dn
| |
− | | |
− | # Create the directory list component.
| |
− | dnb = self.mkdnb()
| |
− | dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3)
| |
− | del dnb
| |
− | | |
− | # Create the filename list component.
| |
− | fnb = self.mkfnb()
| |
− | fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3)
| |
− | del fnb
| |
− | | |
− | # Create the filter entry
| |
− | ft = self.mkft()
| |
− | ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
− | del ft
| |
− | | |
− | # Create the filename entry
| |
− | fn = self.mkfn()
| |
− | fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
− | fn.bind('<Return>',self.okbutton)
| |
− | del fn
| |
− | | |
− | # Buttonbox already exists
| |
− | bb=self.component('buttonbox')
| |
− | bb.add('OK',command=self.okbutton)
| |
− | bb.add('Cancel',command=self.cancelbutton)
| |
− | del bb
| |
− | | |
− | Pmw.alignlabels([self.component('filename'),
| |
− | self.component('filter'),
| |
− | self.component('dirname')])
| |
− | | |
− | def infotxt(self):
| |
− | """ Make information block component at the top """
| |
− | return self.createcomponent(
| |
− | 'infobox',
| |
− | (), None,
| |
− | Tkinter.Label, (self.interior(),),
| |
− | width=51,
| |
− | relief='groove',
| |
− | foreground='darkblue',
| |
− | justify='left',
| |
− | text=self['info']
| |
− | )
| |
− | | |
− | def mkdn(self):
| |
− | """Make directory name component"""
| |
− | return self.createcomponent(
| |
− | 'dirname',
| |
− | (), None,
| |
− | Pmw.ComboBox, (self.interior(),),
| |
− | entryfield_value=self['directory'],
| |
− | entryfield_entry_width=40,
| |
− | entryfield_validate=self.dirvalidate,
| |
− | selectioncommand=self.setdir,
| |
− | labelpos='w',
| |
− | label_text='Directory:')
| |
− | | |
− | def mkdnb(self):
| |
− | """Make directory name box"""
| |
− | return self.createcomponent(
| |
− | 'dirnamebox',
| |
− | (), None,
| |
− | Pmw.ScrolledListBox, (self.interior(),),
| |
− | label_text='directories',
| |
− | labelpos='n',
| |
− | hscrollmode='none',
| |
− | dblclickcommand=self.selectdir)
| |
− | | |
− | def mkft(self):
| |
− | """Make filter"""
| |
− | return self.createcomponent(
| |
− | 'filter',
| |
− | (), None,
| |
− | Pmw.ComboBox, (self.interior(),),
| |
− | entryfield_value=self['filter'],
| |
− | entryfield_entry_width=40,
| |
− | selectioncommand=self.setfilter,
| |
− | labelpos='w',
| |
− | label_text='Filter:')
| |
− | | |
− | def mkfnb(self):
| |
− | """Make filename list box"""
| |
− | return self.createcomponent(
| |
− | 'filenamebox',
| |
− | (), None,
| |
− | Pmw.ScrolledListBox, (self.interior(),),
| |
− | label_text='files',
| |
− | labelpos='n',
| |
− | hscrollmode='none',
| |
− | selectioncommand=self.singleselectfile,
| |
− | dblclickcommand=self.selectfile)
| |
− | | |
− | def mkfn(self):
| |
− | """Make file name entry"""
| |
− | return self.createcomponent(
| |
− | 'filename',
| |
− | (), None,
| |
− | Pmw.ComboBox, (self.interior(),),
| |
− | entryfield_value=self['filename'],
| |
− | entryfield_entry_width=40,
| |
− | entryfield_validate=self.filevalidate,
| |
− | selectioncommand=self.setfilename,
| |
− | labelpos='w',
| |
− | label_text='Filename:')
| |
− |
| |
− | def dirvalidate(self,string):
| |
− | if os.path.isdir(string):
| |
− | return Pmw.OK
| |
− | else:
| |
− | return Pmw.PARTIAL
| |
− |
| |
− | def filevalidate(self,string):
| |
− | if string=='':
| |
− | return Pmw.PARTIAL
| |
− | elif os.path.isfile(string):
| |
− | return Pmw.OK
| |
− | elif os.path.exists(string):
| |
− | return Pmw.PARTIAL
| |
− | else:
| |
− | return Pmw.OK
| |
− |
| |
− | def okbutton(self):
| |
− | """OK action: user thinks he has input valid data and wants to
| |
− | proceed. This is also called by <Return> in the filename entry"""
| |
− | fn=self.component('filename').get()
| |
− | self.setfilename(fn)
| |
− | if self.validate(fn):
| |
− | self.canceled=0
| |
− | self.deactivate()
| |
− | | |
− | def cancelbutton(self):
| |
− | """Cancel the operation"""
| |
− | self.canceled=1
| |
− | self.deactivate()
| |
− | | |
− | def tidy(self,w,v):
| |
− | """Insert text v into the entry and at the top of the list of
| |
− | the combobox w, remove duplicates"""
| |
− | if not v:
| |
− | return
| |
− | entry=w.component('entry')
| |
− | entry.delete(0,'end')
| |
− | entry.insert(0,v)
| |
− | list=w.component('scrolledlist')
| |
− | list.insert(0,v)
| |
− | index=1
| |
− | while index<list.index('end'):
| |
− | k=list.get(index)
| |
− | if k==v or index>self['historylen']:
| |
− | list.delete(index)
| |
− | else:
| |
− | index=index+1
| |
− | w.checkentry()
| |
− | | |
− | def setfilename(self,value):
| |
− | if not value:
| |
− | return
| |
− | value=os.path.join(self['directory'],value)
| |
− | dir,fil=os.path.split(value)
| |
− | self.configure(directory=dir,filename=value)
| |
− |
| |
− | c=self['command']
| |
− | if callable(c):
| |
− | c()
| |
− | | |
− | def newfilename(self):
| |
− | """Make sure a newly set filename makes it into the combobox list"""
| |
− | self.tidy(self.component('filename'),self['filename'])
| |
− |
| |
− | def setfilter(self,value):
| |
− | self.configure(filter=value)
| |
− | | |
− | def newfilter(self):
| |
− | """Make sure a newly set filter makes it into the combobox list"""
| |
− | self.tidy(self.component('filter'),self['filter'])
| |
− | self.fillit()
| |
− | | |
− | def setdir(self,value):
| |
− | self.configure(directory=value)
| |
− | | |
− | def newdir(self):
| |
− | """Make sure a newly set dirname makes it into the combobox list"""
| |
− | self.tidy(self.component('dirname'),self['directory'])
| |
− | self.fillit()
| |
− | | |
− | def singleselectfile(self):
| |
− | """Single click in file listbox. Move file to "filename" combobox"""
| |
− | cs=self.component('filenamebox').curselection()
| |
− | if cs!=():
| |
− | value=self.component('filenamebox').get(cs)
| |
− | self.setfilename(value)
| |
− | | |
− | def selectfile(self):
| |
− | """Take the selected file from the filename, normalize it, and OK"""
| |
− | self.singleselectfile()
| |
− | value=self.component('filename').get()
| |
− | self.setfilename(value)
| |
− | if value:
| |
− | self.okbutton()
| |
− | | |
− | def selectdir(self):
| |
− | """Take selected directory from the dirnamebox into the dirname"""
| |
− | cs=self.component('dirnamebox').curselection()
| |
− | if cs!=():
| |
− | value=self.component('dirnamebox').get(cs)
| |
− | dir=self['directory']
| |
− | if not dir:
| |
− | dir=os.getcwd()
| |
− | if value:
| |
− | if value=='..':
| |
− | dir=os.path.split(dir)[0]
| |
− | else:
| |
− | dir=os.path.join(dir,value)
| |
− | self.configure(directory=dir)
| |
− | self.fillit()
| |
− | | |
− | def askfilename(self,directory=None,filter=None):
| |
− | """The actual client function. Activates the dialog, and
| |
− | returns only after a valid filename has been entered
| |
− | (return value is that filename) or when canceled (return
| |
− | value is None)"""
| |
− | if directory!=None:
| |
− | self.configure(directory=directory)
| |
− | if filter!=None:
| |
− | self.configure(filter=filter)
| |
− | self.fillit()
| |
− | self.canceled=1 # Needed for when user kills dialog window
| |
− | self.activate()
| |
− | if self.canceled:
| |
− | return None
| |
− | else:
| |
− | return self.component('filename').get()
| |
− | | |
− | lastdir=""
| |
− | lastfilter=None
| |
− | lasttime=0
| |
− | def fillit(self):
| |
− | """Get the directory list and show it in the two listboxes"""
| |
− | # Do not run unnecesarily
| |
− | if self.lastdir==self['directory'] and self.lastfilter==self['filter'] and self.lasttime>os.stat(self.lastdir)[8]:
| |
− | return
| |
− | self.lastdir=self['directory']
| |
− | self.lastfilter=self['filter']
| |
− | self.lasttime=time.time()
| |
− | dir=self['directory']
| |
− | if not dir:
| |
− | dir=os.getcwd()
| |
− | dirs=['..']
| |
− | files=[]
| |
− | try:
| |
− | fl=os.listdir(dir)
| |
− | fl.sort()
| |
− | except os.error,arg:
| |
− | if arg[0] in (2,20):
| |
− | return
| |
− | raise
| |
− | for f in fl:
| |
− | if os.path.isdir(os.path.join(dir,f)):
| |
− | dirs.append(f)
| |
− | else:
| |
− | filter=self['filter']
| |
− | if not filter:
| |
− | filter='*'
| |
− | if fnmatch.fnmatch(f,filter):
| |
− | files.append(f)
| |
− | self.component('filenamebox').setlist(files)
| |
− | self.component('dirnamebox').setlist(dirs)
| |
− |
| |
− | def validate(self,filename):
| |
− | """Validation function. Should return 1 if the filename is valid,
| |
− | 0 if invalid. May pop up dialogs to tell user why. Especially
| |
− | suited to subclasses: i.e. only return 1 if the file does/doesn't
| |
− | exist"""
| |
− | return 1
| |
− | | |
− | class PmwExistingFileDialog(PmwFileDialog):
| |
− | def filevalidate(self,string):
| |
− | if os.path.isfile(string):
| |
− | return Pmw.OK
| |
− | else:
| |
− | return Pmw.PARTIAL
| |
− |
| |
− | def validate(self,filename):
| |
− | if os.path.isfile(filename):
| |
− | return 1
| |
− | elif os.path.exists(filename):
| |
− | _errorpop(self.interior(),"This is not a plain file")
| |
− | return 0
| |
− | else:
| |
− | _errorpop(self.interior(),"Please select an existing file")
| |
− | return 0
| |
− | | |
− | | |
− | #===============================================================
| |
− | #
| |
− | # stuff to deal with dlg files
| |
− | | |
− | class Model:
| |
− | def __init__(self):
| |
− | self.atoms = []
| |
− | self.energy = 0.
| |
− | self.info = []
| |
− | self.num = 0
| |
− | self.as_string = ''
| |
− | self.info_as_string = ''
| |
− | def str2mod(self,string):
| |
− | list = string.split('\n')
| |
− | for line in list:
| |
− | if 'ATOM' in line:
| |
− | self.atoms.append(line.split(':')[1].strip())
| |
− | self.as_string+=line.split(':')[1].strip()+'\n'
| |
− | elif 'USER' in line:
| |
− | self.info.append(line.split(':')[1].strip())
| |
− | self.info_as_string+=line.split(':')[1].strip()+'\n'
| |
− | elif 'MODEL' in line:
| |
− | self.num = int(line.split()[2])
| |
− | for line in self.info:
| |
− | if 'Docked Energy' in line:
| |
− | x = line.split('=')[1]
| |
− | self.energy = float(x.split()[0])
| |
− | | |
− | def writeMod(self,fp):
| |
− | print >>fp,'MODEL%8d' % self.num
| |
− | for at in self.atoms:
| |
− | print >>fp, at
| |
− | print >>fp,'ENDMDL'
| |
− | | |
− | | |
− | def sortByEnergy(mlist):
| |
− | en = []
| |
− | idx = []
| |
− | for m in mlist:
| |
− | en.append(m.energy)
| |
− | idx.append(mlist.index(m))
| |
− | changed = True
| |
− | while changed:
| |
− | changed = False
| |
− | for i in range(len(en)-1):
| |
− | if en[i] > en[i+1]:
| |
− | dum = en[i+1]
| |
− | en[i+1] = en[i]
| |
− | en[i] = dum
| |
− | dum = idx[i+1]
| |
− | idx[i+1] = idx[i]
| |
− | idx[i] = dum
| |
− | changed = True
| |
− | new = []
| |
− | for i in range(len(idx)):
| |
− | new.append(mlist[idx[i]])
| |
− | new[i].num=i+1
| |
− | return new
| |
− | | |
− | | |
− | # Create demo in root window for testing.
| |
− | if __name__ == '__main__':
| |
− | class App:
| |
− | def my_show(self,*args,**kwargs):
| |
− | pass
| |
− | app = App()
| |
− | app.root = Tkinter.Tk()
| |
− | Pmw.initialise(app.root)
| |
− | app.root.title('Some Title')
| |
− |
| |
− | widget = Autodock(app)
| |
− | exitButton = Tkinter.Button(app.root, text = 'Exit', command = app.root.destroy)
| |
− | exitButton.pack()
| |
− | app.root.mainloop()
| |
− | </source>
| |