PLplot  5.10.0
Plframe.py
Go to the documentation of this file.
00001 from Tkinter import *
00002 #from pl import *
00003 from plplot import *
00004 from TclSup import *
00005 
00006 from string import *
00007 
00008 from math import *
00009 
00010 CMD='cmd'
00011 
00012 # Physically imported this function from Tkinter.py, b/c it evidently
00013 # isn't made available via the above import statement.
00014 
00015 def _flatten(tuple):
00016     res = ()
00017     for item in tuple:
00018         if type(item) in (TupleType, ListType):
00019             res = res + _flatten(item)
00020         elif item is not None:
00021             res = res + (item,)
00022     return res
00023 
00024 #=============================================================================#
00025 # class Plframe
00026 #=============================================================================#
00027 
00028 class Plframe(Widget):
00029 
00030     def __init__( self, master=None, cnf={}, **kw ):
00031         """Constructor.
00032 
00033         Initialize the Tk base class, and squirel away the stream id,
00034         so that we will be able to ensure that future draw requests
00035         show up in the right place."""
00036 
00037         Widget.__init__( self, master, 'plframe', cnf, kw )
00038 
00039         self.strm = plgstrm()
00040 
00041     def cmd( s, *args ):
00042         "Invoke a subcommand on the plframe widget."
00043         apply( s.tk.call, (s._w, 'cmd',) + _flatten(args) )
00044 
00045     def info(s, what):
00046         return s.tk.call( s._w, 'info', what )
00047 
00048 ## Now implement the PLplot API.  For simple functions, can call
00049 ## straight to Tk, which is probably the most straightforward way, in
00050 ## the sense of making the Python/Tk widget look and act most like
00051 ## it's older brother the Tcl version.  However, functions which rely
00052 ## on the Numeric extensions cannot work this way, so for those we
00053 ## call straight to the Python compiled interface to the PLplot API.
00054 
00055     def plenv( s, xmin, xmax, ymin, ymax, i, j ):
00056         s.cmd( 'plenv', xmin, xmax, ymin, ymax, i, j )
00057 
00058     def pleop(s):
00059         s.cmd( 'pleop' )
00060 
00061     def pllab( s, xlab, ylab, tlab ):
00062         s.cmd( 'pllab', xlab, ylab, tlab )
00063 
00064     def plline( s, x, y ):
00065         plsstrm( s.strm )
00066         plline( x, y )
00067 
00068     def plpoin( s, xs, ys, mark ):
00069         plsstrm( s.strm )
00070         plpoin( xs, ys, mark )
00071 
00072 #=============================================================================#
00073 # class PlXframe
00074 #=============================================================================#
00075 
00076 class PlXframe(Frame):
00077 
00078     """This class provides the same facilities as the Plframe, plus
00079     several additional facilities for advanced plot interaction, which
00080     are provided through menus and bindings."""
00081 
00082     def __init__( s, master=None, cnf={}, **kw ):
00083         """Constructor.
00084 
00085         Configure the widget database, and then set up the internal
00086         members.  Namely, a menubar and a contained Plframe."""
00087 
00088         Frame.__init__( s, master )
00089 
00090         s.setup_defaults()
00091 
00092         # We will be using the grid geometry manager to pack a plframe
00093         # widget along with some additional addornments.  The top row
00094         # (row 0) will contain the menubar.  The next row (row 1) will
00095         # hold the actual plframe, as well as the vertical scrollbar
00096         # when present..  And the last row (row 2) will hold the
00097         # horizontal scrollbar when present.  We want the menubar and
00098         # the horizontal scrollbar to use only the required space, and
00099         # we want the plframe to expand to fill any remaining space.
00100         # To accomplish this we set the weights for the top and bottom
00101         # row to zero, thus preventing them from expanding.
00102 
00103         s.rowconfigure( 0, weight=0, minsize=0 )
00104         s.rowconfigure( 1, weight=1, minsize=0 )
00105         s.rowconfigure( 2, weight=0, minsize=0 )
00106 
00107         # Similarly for the columns, we will use the left column (col
00108         # 0) for the plframe and the horizontal scrollbar, and the
00109         # right column (col 1) for the vertical scrollbar.  Moreover, the
00110         # menubar in the top row will span columns 0 and 1.  Again, we
00111         # want the rightmost column (col 0) to stay at whatever is the
00112         # minimum width to display its contents, and want the plframe
00113         # in the leftmost column to grow to fill all space.
00114 
00115         s.columnconfigure( 0, weight=1, minsize=0 )
00116         s.columnconfigure( 1, weight=0, minsize=0 )
00117 
00118         # Okay, now get the actual plframe widget so we can display
00119         # it.  And we pack it into its grid cell with all four sides
00120         # of the plframe sticking to the expandable size of the
00121         # enclosing grid cell, as arranged by the row,col weighting
00122         # scheme described above.
00123 
00124         s.plf = Plframe( s, kw )
00125         s.plf.grid( row=1, column=0, sticky=NSEW )
00126 
00127         s.build_menu_bar()
00128 
00129         s.strm = plgstrm()
00130 
00131         s.setup_bindings()
00132 
00133         s.hscroll_exists = 0
00134         s.vscroll_exists = 0
00135 
00136 ## All this stuff is being based heavily on the Pltkwin.tcl thing by
00137 ## Vince, for itcl/itk (which in turn was based heavily on the
00138 ## plwidgets.tcl stuff by Maurice).
00139 
00140     def setup_defaults(s):
00141         #s.saveopt_dev = StringVar()
00142         s.saveopt_dev = "psc"
00143         #s.saveopt_dev.set( "psc" )
00144 
00145         #s.saveopt_file = IntVar()
00146         s.saveopt_file = 0
00147         #s.saveopt_file.set( 0 )
00148 
00149         # Now do the zoom support stuff.
00150 
00151         s.zidx = 0
00152         s.zxl = [ 0. ]; s.zyl = [ 0. ]
00153         s.zxr = [ 1. ]; s.zyr = [ 1. ]
00154 
00155     def setup_bindings(s):
00156         s.plf.bind( "<Any-KeyPress>", s.key_filter )
00157         s.plf.bind( "<Any-ButtonPress>", s.user_mouse )
00158         s.plf.bind( "<Any-Enter>", s.set_focus )
00159 
00160     def set_focus(s,e):
00161         # print "in set_focus"
00162         s.plf.focus()
00163 
00164     def build_menu_bar(s):
00165         "Create the menubar at the top of the PlXframe"
00166 
00167         s.ftop = Frame( s )
00168         s.ftop.grid( row=0, columnspan=2, sticky='ew' )
00169 
00170         s.ftop.plot = Menubutton( s.ftop, text="Plot", underline=0,
00171                                   relief=RAISED )
00172         s.ftop.plot.m = Menu( s.ftop.plot )
00173         s.ftop.plot["menu"] = s.ftop.plot.m
00174 
00175         s.ftop.plot.pack( side=LEFT )
00176 
00177         s.create_menu_print( s.ftop.plot.m )
00178         s.create_menu_save( s.ftop.plot.m )
00179         s.create_menu_orient( s.ftop.plot.m )
00180         s.create_menu_zoom( s.ftop.plot.m )
00181         s.create_menu_page( s.ftop.plot.m )
00182         s.create_menu_options( s.ftop.plot.m )
00183         s.create_menu_debug  ( s.ftop.plot.m )
00184 
00185         s.ftop.eop = Button( s.ftop, text="Clear",
00186                              command=s.clearpage )
00187         s.ftop.eop.pack( side=RIGHT )
00188 
00189         s.ftop.lstat = Label( s.ftop, anchor=W, relief=RAISED )
00190         s.ftop.lstat.pack( side=RIGHT, expand=1, fill=BOTH )
00191 
00192     def create_menu_print( s, m ):
00193         m.add( "command", label="Print", command=s.cmd_print )
00194 
00195     def create_menu_save( s, pmenu ):
00196         """Create the menu which lets us control the whole business of
00197         saving plots to disk."""
00198 
00199         m = Menu( pmenu )
00200         pmenu.add( "cascade", label='Save', menu=m )
00201 
00202         # Save - As
00203 
00204         m.add( "command", label="As", command=s.save_as )
00205 
00206         # Save - Again
00207 
00208         m.add( "command", label="Again", command=s.save_again,
00209                state=DISABLED )
00210 
00211         # Save - Close
00212 
00213         m.add( "command", label="Close", command=s.save_close,
00214                state=DISABLED )
00215 
00216         m.add( "separator" )
00217 
00218         # Save - Set device.. (another cascade)
00219 
00220         m.sdev = Menu( m )
00221         m.add( "cascade", label="Set device", menu=m.sdev )
00222 
00223         # Generate the device list in the "Save/Set device" widget
00224         # menu, by querying the plframe widget for the available
00225         # output devices (which are listed).
00226 
00227         devnames = s.plf.info( "devnames" )
00228         devkeys = s.plf.info( "devkeys" )
00229 
00230         # Oh no, these came back as Tcl lists.  Have to convert them
00231         # to Python lists.
00232 
00233         devnamlst = TclList2Py( devnames )
00234         devkeylst = TclList2Py( devkeys )
00235 
00236         print "devnamlst = ", devnamlst
00237         print "devkeylst = ", devkeylst
00238         print "len(devnamlst) = ", len(devnamlst)
00239 
00240 ##        for i in range( len(devnamlst) ):
00241 ##            devnam = devnamlst[i]
00242 ##            devkey = devkeylst[i]
00243 ##
00244 ##            m.sdev.add( "radio", label=devnam, variable=s.saveopt_dev,
00245 ##                        value=devkey )
00246 
00247         # Now get the ball rolling by preinvoking one of these.
00248         # Default to the first one, whatever it is, but use psc
00249         # (Postscript color), if we can find it in the list of
00250         # available devices.
00251 
00252 ##        ivk = 1
00253 ##        for i in range( len(devnamlst) ):
00254 ##            if devkeylst[i] == "psc":
00255 ##                ivk = i+1
00256 ##                break
00257 ##
00258 ##        m.sdev.invoke( ivk )
00259 
00260         # Save - Set file type.. (another cascade)
00261 
00262         m.sfile = Menu( m )
00263         m.add( "cascade", label="Set file type", menu=m.sfile )
00264 
00265         m.sfile.add( "radio", label="Single file (one plot/file)",
00266                      variable=s.saveopt_file, value=0 )
00267         m.sfile.add( "radio", label="Archive file( many plots/file)",
00268                      variable=s.saveopt_file, value=1 )
00269 
00270         m.sfile.invoke( 1 )
00271 
00272     def create_menu_orient( s, pmenu ):
00273         m = Menu( pmenu )
00274         pmenu.add( "cascade", label='Orient', menu=m )
00275 
00276         m.config( postcommand=lambda o=s, x=m: o.update_orient(x) )
00277 
00278         # Orient - 0 degrees
00279 
00280         m.add( 'radio', label="0 degrees", 
00281                command=lambda o=s: o.orient(0) )
00282 
00283         # Orient - 90 degrees
00284 
00285         m.add( 'radio', label="90 degrees", 
00286                command=lambda o=s: o.orient(1) )
00287 
00288         # Orient - 180 degrees
00289 
00290         m.add( 'radio', label="180 degrees", 
00291                command=lambda o=s: o.orient(2) )
00292 
00293         # Orient - 270 degrees
00294 
00295         m.add( 'radio', label="270 degrees", 
00296                command=lambda o=s: o.orient(3) )
00297 
00298     def create_menu_zoom( s, pmenu ):
00299         m = Menu( pmenu )
00300         pmenu.add( "cascade", label='Zoom', menu=m )
00301 
00302         m.config( postcommand=lambda o=s, x=m: o.update_zoom(x) )
00303 
00304         # Zoom - select        (by        mouse)
00305 
00306         m.add( 'command', label="Select",
00307                command=lambda o=s: o.zoom_select() )
00308 
00309         # Zoom - back (go back 1 zoom level)
00310 
00311         m.add( 'command', label="Back",
00312                command=lambda o=s: o.zoom_back(),
00313                state='disabled' )
00314 
00315         # Zoom - forward (go forward 1 zoom        level)
00316 
00317         m.add( 'command', label="Forward",
00318                command=lambda o=s: o.zoom_forward(),
00319                state='disabled' )
00320 
00321         # Zoom - enter bounds
00322 
00323         m.add( 'command', label="Enter bounds..",
00324                command=lambda o=s: o.zoom_enter() )
00325 
00326         # Zoom - reset
00327 
00328         m.add( 'command', label="Reset",
00329                command=lambda o=s: o.zoom_reset() )
00330 
00331         # Zoom - options (another cascade)
00332 
00333         zom = Menu( m )
00334         m.add( 'cascade', label="Options", menu=zom )
00335 
00336         s.zoomopts_asp = IntVar()
00337         s.zoomopts_sel = IntVar()
00338 
00339         zom.add( 'check', label="Preserve aspect ratio",
00340                  variable=s.zoomopts_asp )
00341 
00342         zom.add( 'separator' )
00343 
00344         zom.add( 'radio', label="Start from corner",
00345                  variable=s.zoomopts_sel, value=0 )
00346 
00347         zom.add( 'radio', label="Start from center",
00348                  variable=s.zoomopts_sel, value=1 )
00349 
00350         s.zoomopts_sel = 1
00351         s.zoomopts_asp = 1
00352 
00353         zom.invoke(1)
00354         zom.invoke(4)
00355 
00356     def create_menu_page( s, pmenu ):
00357         m = Menu( pmenu )
00358         pmenu.add( "cascade", label='Page', menu=m )
00359 
00360         # Page - enter bounds
00361 
00362         m.add( 'command', label="Setup..", command=s.page_enter )
00363 
00364         # Page - reset
00365 
00366         m.add( 'command', label="Reset", command=s.page_reset )
00367 
00368     def create_menu_options( s, pmenu ):
00369         m = Menu( pmenu )
00370         pmenu.add( 'cascade', label="Options", menu=m )
00371 
00372         m.add( 'command', label="Palette 0", command=s.plcmap0_edit )
00373         m.add( 'command', label="Palette 1", command=s.plcmap1_edit )
00374 
00375     def create_menu_debug( s, pmenu ):
00376         pmenu.add( "command", label="Debug PlXframe", command=s.debug )
00377 
00378 ## Now the commands needed to implement the menus.
00379 
00380     def key_filter( s, e ):
00381         """Process keystroke events, and parcell out to various control
00382         functions."""
00383 
00384         kn = e.keysym
00385 
00386         if kn == 'z':
00387             s.zoom_select()
00388         elif kn == 'b':
00389             s.zoom_back()
00390         elif kn == 'f':
00391             s.zoom_forward()
00392         elif kn == 'r':
00393             s.zoom_reset()
00394         else:
00395             pass
00396             #print "Unknown keyname ", kn
00397 
00398     def user_mouse( s, e ):
00399         print "in user_mouse"
00400 
00401 ## flash
00402 
00403     def cmd_print(s):
00404         s.label_set( "Printing plot..." )
00405         s.tk.call( s.plf._w, 'print' )
00406         # Should see about error trapping, like the itk widget does.
00407 
00408     def sucky_save(s):
00409         """A sucky save menu thing.  Needs to be enhanced to work like
00410         the one in Tcl/Itcl."""
00411 
00412         s.tk.call( s.plf._w, 'save', 'as', 'ps', 'xx.ps' )
00413         s.tk.call( s.plf._w, 'save', 'close' )
00414         print "Plot saved to xx.ps"
00415 
00416     def save_as(s): pass
00417     def save_again(s): pass
00418     def save_close(s): pass
00419 
00420     def update_zoom(s,m):
00421         """Configure zoom menu.
00422 
00423         Responsible for making sure zoom menu entries are normal or
00424         disabled as appropriate.  In particular, that 'Back' or 'Forward'
00425         are only displayed if it is possible to traverse the zoom windows
00426         list in that direction."""
00427 
00428         zframes = len( s.zxl )
00429 
00430         if s.zidx == 0:
00431             #print "disable back"
00432             m.entryconfig( 2, state=DISABLED )
00433         else:
00434             #print "enable back"
00435             m.entryconfig( 2, state=ACTIVE )
00436 
00437         if s.zidx == zframes-1:
00438             #print "disable forward"
00439             m.entryconfig( 3, state=DISABLED )
00440         else:
00441             #print "enable forward"
00442             m.entryconfig( 3, state=ACTIVE )
00443 
00444     def zoom_select(s):
00445         "Zooms plot in response to mouse selection."
00446 
00447         # In itk we save the existing binding so it can be restored.
00448 
00449         # Don't know how to save a binding for future use in Python/Tk.
00450 ##        s.def_button_cmd = s.plf.bind( "<ButtonPress>" )
00451 
00452 ##        global def_button_cmd zoomopts
00453 ##
00454 ##        set        def_button_cmd [bind [plwin] <ButtonPress>]
00455 
00456         if s.zoomopts_sel == 0:
00457             s.label_set( "Click on one corner of zoom region." )
00458         elif s.zoomopts_sel == 1:
00459             s.label_set( "Click on center of zoom region." )
00460 
00461         s.plf.bind( "<ButtonPress>", s.zoom_start )
00462 
00463     def zoom_enter(s):
00464         print "zoom_enter"
00465 
00466 ##----------------------------------------------------------------------------
00467 ## zoom_reset
00468 ##
00469 ## Resets after zoom.
00470 ## Note that an explicit redraw is not necessary since the packer
00471 ## issues a resize after the scrollbars are unmapped.
00472 ##----------------------------------------------------------------------------
00473 
00474     def zoom_reset(s):
00475 
00476 ##        global def_button_cmd
00477 
00478         s.label_reset()
00479 ##        bind [plwin] <ButtonPress>        $def_button_cmd
00480 
00481         s.tk.call( s.plf._w, 'view', 'reset' )
00482 
00483         if s.hscroll_exists and atoi( s.tk.call( 'winfo', 'ismapped',
00484                                                  s.hscroll._w ) ):
00485             s.hscroll.grid_forget()
00486 
00487         if s.vscroll_exists and atoi( s.tk.call( 'winfo', 'ismapped',
00488                                                  s.vscroll._w ) ):
00489             s.vscroll.grid_forget()
00490 
00491 ## Reset zoom windows list
00492 
00493         s.zidx = 0
00494         s.zxl = [ 0. ]; s.zyl = [ 0. ]
00495         s.zxr = [ 1. ]; s.zyr = [ 1. ]
00496 
00497     def update_orient(s,m):
00498 
00499         r = s.tk.call( s.plf._w, 'orient' )
00500 
00501         # Grr, this is a floating point string.  Must stand on our
00502         # heads to get an actual integer out of it.
00503 
00504         f = atof( r )
00505         fsi = "%.0f" % f
00506         i = atoi( fsi )
00507 
00508         n = i / 90
00509         n = i % 4
00510 
00511         m.invoke( n+1 )
00512 
00513     def orient(s, n):
00514         """Set the orientation of the plframe, but check to make sure
00515         we only do this if the new orientation is different from the
00516         old one."""
00517 
00518         oldori = s.tk.call( s.plf._w, 'orient' )
00519         oldf = atof( oldori )
00520         oldn = atoi( "%.0f" % oldf ) % 4
00521 
00522         if n != oldn:
00523             rots = "%d" % n
00524             s.tk.call( s.plf._w, 'orient', rots )
00525 
00526     def page_enter(s):
00527         print "in page_enter"
00528 
00529     def page_reset(s):
00530         print "in page_reset"
00531 
00532     def zoom_start( s, e ):
00533         "Starts plot zoom."
00534 
00535         s.wx = e.x
00536         s.wy = e.y
00537 
00538 ## Restore previous binding, but don't know how to do this in Python/Tk.
00539 ##        s.plf.bind( "<ButtonPress>", s.def_button_cmd )
00540 
00541 ##        global def_button_cmd
00542 ##
00543 ##        bind [plwin] <ButtonPress>        $def_button_cmd
00544 
00545 ## Maybe what I should do for now is just remove the one we instlaled,
00546 ## but punt on restoring the prexisting binding.
00547 
00548         s.plf.bind( "<ButtonPress>", None )
00549 
00550 ## Hmpffff.  That didn't work...  Grrrrrr.
00551 
00552         s.label_set( "Select zoom region by dragging mouse, then release." )
00553 
00554         s.tk.call( s.plf._w, 'draw', 'init' )
00555         s.plf.bind( "<B1-Motion>", s.zoom_mouse_draw )
00556         s.plf.bind( "<B1-ButtonRelease>", s.zoom_mouse_end )
00557 
00558 ##----------------------------------------------------------------------------
00559 ## zoom_coords
00560 ##
00561 ## Transforms the initial and final mouse coordinates to        either:
00562 ##
00563 ## opt =        0                device coordinates
00564 ## opt =        1                normalized device coordinates
00565 ##
00566 ## The global variable "zoomopts" is        used to        determine zoom behavior:
00567 ##
00568 ## zoomopts($this,0):
00569 ##        0        box        follows        mouse movements        exactly
00570 ##        1        box        follows        mouse movements        so that        aspect ratio is        preserved (default)
00571 ##
00572 ## zoomopts($this,1):
00573 ##        0        first and last points specified        determine opposite corners
00574 ##                of zoom        box.
00575 ##        1        box is centered about the first point clicked on, 
00576 ##                perimeter follows mouse        (default)
00577 ##
00578 ##----------------------------------------------------------------------------
00579 
00580     def zoom_coords( s, x0, y0, x1, y1, opt ):
00581 
00582         # Convert the integer input to float, prevents problems with
00583         # division. 
00584 
00585         x0 = float(x0)
00586         y0 = float(y0)
00587         x1 = float(x1)
00588         y1 = float(y1)
00589 
00590         Lx = s.plf.winfo_width()
00591         Ly = s.plf.winfo_height()
00592 
00593         # Enforce boundaries in device coordinate space
00594 
00595         bounds = split( s.tk.call( s.plf._w, 'view', 'bounds' ) )
00596         xmin = Lx * atof( bounds[0] )
00597         ymin = Ly * atof( bounds[1] )
00598         xmax = Lx * atof( bounds[2] )
00599         ymax = Ly * atof( bounds[3] )
00600 
00601         x1 = max( xmin, min( xmax, x1 ) )
00602         y1 = max( ymin, min( ymax, y1 ) )
00603 
00604         # Two-corners zoom.
00605 
00606         if s.zoomopts_sel == 0:
00607             pass
00608 
00609 ##        if { $zoomopts($this,1) ==        0 }        then {
00610 
00611             # Get box lengths
00612 
00613             dx = x1 - x0
00614             dy = y1 - y0
00615 ##                set        dx [expr $x1 - $x0]
00616 ##                set        dy [expr $y1 - $y0]
00617 
00618             sign_dx = sign(dx)
00619             sign_dy = sign(dy)
00620 ##                set        sign_dx        [expr ($dx > 0)        ? 1        : -1]
00621 ##                set        sign_dy        [expr ($dy > 0)        ? 1        : -1]
00622 
00623             xl = x0
00624             yl = y0
00625 ##                set        xl $x0
00626 ##                set        yl $y0
00627 
00628             # Constant aspect ratio
00629 
00630             if s.zoomopts_asp == 1:
00631                 pass
00632 ##                if { $zoomopts($this,0) ==        1 }        then {
00633 ##
00634 ##                # Scale        factors        used to        maintain plot aspect ratio
00635 ##
00636 ##                        set        xscale [expr $xmax - $xmin]
00637 ##                        set        yscale [expr $ymax - $ymin]
00638 ##
00639 ##                # Adjust box size for proper aspect        ratio
00640 ##
00641 ##                        set        rx [expr double(abs($dx)) /        $xscale]
00642 ##                        set        ry [expr double(abs($dy)) /        $yscale]
00643 ##
00644 ##                        if { $rx > $ry } then {
00645 ##                                set        dy [expr $yscale * $rx * $sign_dy]
00646 ##                        } else {
00647 ##                                set        dx [expr $xscale * $ry * $sign_dx]
00648 ##                        }
00649 ##
00650 ##                        set        xr [expr $xl + $dx]
00651 ##                        set        yr [expr $yl + $dy]
00652 ##
00653 ##                # Now check        again to see if        in bounds, and adjust if not
00654 ##
00655 ##                        if { $xr < $xmin ||        $xr        > $xmax        } then {
00656 ##                                if { $xr < $xmin } then        {
00657 ##                                        set        dx [expr $xmin - $x0]
00658 ##                                } else {
00659 ##                                        set        dx [expr $xmax - $x0]
00660 ##                                }
00661 ##                                set        rx [expr double(abs($dx)) /        $xscale]
00662 ##                                set        dy [expr $yscale * $rx * $sign_dy]
00663 ##                        }
00664 ##
00665 ##                        if { $yr < $ymin ||        $yr        > $ymax        } then {
00666 ##                                if { $yr < $ymin } then        {
00667 ##                                        set        dy [expr $ymin - $y0]
00668 ##                                } else {
00669 ##                                        set        dy [expr $ymax - $y0]
00670 ##                                }
00671 ##                                set        ry [expr double(abs($dy)) /        $yscale]
00672 ##                                set        dx [expr $xscale * $ry * $sign_dx]
00673 ##                        }
00674 ##                }
00675 
00676             # Final        box        coordinates
00677 
00678             xr = xl + dx
00679             yr = yl + dy
00680 ##                set        xr [expr $xl + $dx]
00681 ##                set        yr [expr $yl + $dy]
00682 
00683 ### zoom from        center out,        preserving aspect ratio
00684         else:
00685 
00686             # Get box lengths, adjusting downward if necessary to keep
00687             # in bounds
00688 
00689             dx = abs( x1 - x0 )
00690             dy = abs( y1 - y0 )
00691 
00692             xr = x0 + dx;
00693             xl = x0 - dx
00694             yr = y0 + dy
00695             yl = y0 - dy
00696 
00697             if xl < xmin: dx = x0 - xmin
00698             if xr > xmax: dx = xmax - x0
00699             if yl < ymin: dy = y0 - ymin
00700             if yr > ymax: dy = ymax - y0
00701 
00702             # Constant aspect ratio
00703 
00704             if s.zoomopts_asp == 1:
00705 
00706                 # Scale        factors        used to        maintain plot aspect ratio
00707 
00708                 xscale = xmax - xmin
00709                 yscale = ymax - ymin
00710 
00711                 # Adjust box size for proper aspect        ratio
00712 
00713                 rx = dx / xscale
00714                 ry = dy / yscale
00715 
00716                 if rx > ry:
00717                     dy = yscale * rx
00718                 else:
00719                     dx = xscale * ry
00720 
00721                 xr = x0 + dx
00722                 xl = x0 - dx
00723                 yr = y0 + dy
00724                 yl = y0 - dy
00725 
00726                 # Now check again to see if in bounds, and adjust
00727                 # downward if not
00728 
00729                 if xl < xmin:
00730                     dx = x0 - xmin
00731                     rx = dx / xscale
00732                     dy = yscale * rx
00733                 if yr > ymax:
00734                     dx = xmax - x0
00735                     rx = dx / xscale
00736                     dy = yscale * rx
00737                 if yl < ymin:
00738                     dy = y0 - ymin
00739                     ry = dy / yscale
00740                     dx = xscale * ry
00741                 if yr > ymax:
00742                     dy = ymax - y0
00743                     ry = dy / yscale
00744                     dx = xscale * ry
00745 
00746             # Final box        coordinates
00747 
00748             xr = x0 + dx
00749             xl = x0 - dx
00750             yr = y0 + dy
00751             yl = y0 - dy
00752 
00753 ## Optional translation to relative device coordinates.
00754 
00755         if opt == 1:
00756             wxl = xl / Lx
00757             wxr = xr / Lx
00758             wyl = 1.0 - float(yr) / Ly
00759             wyr = 1.0 - float(yl) / Ly
00760         else:
00761             wxr = xl
00762             wxl = xr
00763             wyr = yl
00764             wyl = yr
00765 
00766         return wxl, wyl, wxr, wyr
00767 
00768     def zoom_mouse_draw(s,e):
00769         "Draws zoom box in response to mouse motion (with button held down)."
00770 
00771         coords = s.zoom_coords( s.wx, s.wy, e.x, e.y, 0 )
00772 
00773         s.tk.call( s.plf._w, 'draw', 'rect',
00774                    coords[0], coords[1], coords[2], coords[3] )
00775 
00776     def zoom_mouse_end( s, e ):
00777         "Performs actual zoom, invoked when user releases mouse button."
00778 
00779         # Finish rubber        band draw
00780 
00781         s.plf.bind( "<B1-ButtonRelease>" )
00782         s.plf.bind( "<B1-Motion>" )
00783 ##        bind [plwin] <B1-ButtonRelease> {}
00784 ##        bind [plwin] <B1-Motion> {}
00785         s.label_reset()
00786         s.tk.call( s.plf._w, 'draw', 'end' )
00787 
00788         # Select new plot region
00789 
00790         coords = s.zoom_coords( s.wx, s.wy, e.x, e.y, 1 )
00791 
00792         s.view_zoom( coords[0], coords[1], coords[2], coords[3] )
00793 
00794 ### Hmm, view_select is only called by update_view, which isn't called
00795 ### by anything...
00796 ##    def view_select( s, x0, y0, x1, y1 ):
00797 ##        """Handles change of view into plot.
00798 ##        Given in relative plot window coordinates."""
00799 ##
00800 ##        print "in view_select"
00801 ####body Pltkwin::view_select {x0 y0 x1 y1} {
00802 ##
00803 #### Adjust arguments to be in bounds and properly ordered (xl < xr, etc)
00804 ##
00805 ####        set        xl [min        $x0        $x1]
00806 ####        set        yl [min        $y0        $y1]
00807 ####        set        xr [max        $x0        $x1]
00808 ####        set        yr [max        $y0        $y1]
00809 ##
00810 ##        xl = min( x0, x1 ); yl = min( y0, y1 )
00811 ##        xr = max( x0, x1 ); yr = max( y0, y1 )
00812 ##
00813 ####        set        xmin 0.
00814 ####        set        ymin 0.
00815 ####        set        xmax 1.
00816 ####        set        ymax 1.
00817 ##
00818 ##        xmin = 0.; ymin = 0.
00819 ##        xmax = 1.; ymax = 1.
00820 ##
00821 ####        set        xl [max        $xmin [min $xmax $xl]]
00822 ####        set        yl [max        $ymin [min $ymax $yl]]
00823 ####        set        xr [max        $xmin [min $xmax $xr]]
00824 ####        set        yr [max        $ymin [min $ymax $yr]]
00825 ##
00826 ##        xl = max( xmin, min( xmax, xl ) )
00827 ##        yl = max( ymin, min( ymax, yl ) )
00828 ##        xr = max( xmin, min( xmax, xr ) )
00829 ##        yr = max( ymin, min( ymax, yr ) )
00830 ##
00831 #### Only create scrollbars if        really needed.
00832 ##
00833 ####        if {($xl ==        $xmin) && ($xr == $xmax)} \
00834 ####        then {set hscroll 0} else {set hscroll 1}
00835 ####
00836 ####        if {($yl ==        $xmin) && ($yr == $xmax)} \
00837 ####        then {set vscroll 0} else {set vscroll 1}
00838 ####
00839 ####        if { ! ($hscroll ||        $vscroll)} {return}
00840 ##
00841 ##        if xl == xmin and xr == xmax:
00842 ##            hscroll = 0
00843 ##        else:
00844 ##            hscroll = 1
00845 ##
00846 ##        if yl == ymin and yr == ymax:
00847 ##            vscroll = 0
00848 ##        else:
00849 ##            vscroll = 1
00850 ##
00851 ##        if not (hscroll or vscroll):
00852 ##            return
00853 ##
00854 #### Select plot region
00855 ##
00856 ####        [plwin] view select $xl $yl $xr $yr
00857 ##
00858 ##        s.tk.call( s.plf._w, 'view', 'select', xl, yl, xr, yr )
00859 ##
00860 #### Fix up view
00861 ##
00862 ####        fixview        $hscroll $vscroll
00863 ##        s.fixview( hscroll, vscroll )
00864 
00865     def view_zoom( s, x0, y0, x1, y1 ):
00866         "Handles zoom. Given in relative device coordinates."
00867 
00868 ## Adjust arguments to be properly ordered (xl <        xr,        etc)
00869 
00870         xl = min( x0, x1 )
00871         yl = min( y0, y1 )
00872         xr = max( x0, x1 )
00873         yr = max( y0, y1 )
00874 
00875 ## Check for double-click (specified zoom region less than a few
00876 ## pixels wide).  In this case, magnification is 2X in each direction,
00877 ## centered at the mouse location.  At the boundary, the magnification
00878 ## is determined by the distance to the boundary.
00879 
00880         stdzoom = .5
00881         if (xr - xl) < .02 and (yr - yl) < .02:
00882             nxl = xl - .5 * stdzoom
00883             nxr = xl + .5 * stdzoom
00884             if nxl < 0.:
00885                 nxl = 0.
00886                 nxr = 2. * xl
00887             if nxr > 1.:
00888                 nxr = 1.
00889                 nxl = 2. * xl - 1.
00890             xl = nxl
00891             xr = nxr
00892 
00893             nyl = yl - .5 * stdzoom
00894             nyr = yl + .5 * stdzoom
00895             if nyl < 0.:
00896                 nyl = 0.
00897                 nyr = 2. * yl
00898             if nyr > 1.:
00899                 nyr = 1.
00900                 nyl = 2. * yl - 1.
00901             yl = nyl
00902             yr = nyr
00903 
00904 ## Adjust arguments to be in bounds (in case margins are in effect).
00905 
00906         bounds = split( s.tk.call( s.plf._w, 'view', 'bounds' ) )
00907         xmin = atof( bounds[0] )
00908         ymin = atof( bounds[1] )
00909         xmax = atof( bounds[2] )
00910         ymax = atof( bounds[3] )
00911 
00912         xl = max( xmin, min( xmax, xl ) )
00913         yl = max( ymin, min( ymax, yl ) )
00914         xr = max( xmin, min( xmax, xr ) )
00915         yr = max( ymin, min( ymax, yr ) )
00916 
00917 ## Only create scrollbars if        really needed.
00918 
00919         hscroll, vscroll = 0, 0
00920         if xl != xmin or xr != xmax: hscroll = 1
00921         if yl != ymin or yr != ymax: vscroll = 1
00922 
00923         if not (hscroll or yscroll):
00924             s.tk.call( s.plf._w, 'redraw' )
00925             return
00926 
00927 ## Select plot region
00928  
00929         s.tk.call( s.plf._w, 'view', 'zoom', xl, yl, xr, yr )
00930 
00931 ## Fix up view
00932 
00933         s.fixview( hscroll, vscroll )
00934 
00935 ## Add window to zoom windows list
00936 
00937         coords = split( s.tk.call( s.plf._w, 'view' ) )
00938 
00939         s.zidx = s.zidx + 1
00940 
00941         if s.zidx == len( s.zxl ):
00942             # Adding onto the end, no big deal
00943             s.zxl.append( atof( coords[0] ) )
00944             s.zyl.append( atof( coords[1] ) )
00945             s.zxr.append( atof( coords[2] ) )
00946             s.zyr.append( atof( coords[3] ) )
00947         else:
00948             # Adding into the middle...
00949             s.zxl[ s.zidx ] = atof( coords[0] )
00950             s.zyl[ s.zidx ] = atof( coords[1] )
00951             s.zxr[ s.zidx ] = atof( coords[2] )
00952             s.zyr[ s.zidx ] = atof( coords[3] )
00953 
00954             if s.zidx < len( s.zxl ) - 1:
00955                 # Now chop off the end.
00956                 s.zxl = s.zxl[0:s.zidx+1]
00957                 s.zyl = s.zyl[0:s.zidx+1]
00958                 s.zxr = s.zxr[0:s.zidx+1]
00959                 s.zyr = s.zyr[0:s.zidx+1]
00960 
00961     def zoom_back(s):
00962         "Traverse the zoom windows list backward."
00963 
00964         if s.zidx > 0:
00965             s.zidx = s.zidx - 1
00966 
00967             xl = s.zxl[ s.zidx ]; yl = s.zyl[ s.zidx ]
00968             xr = s.zxr[ s.zidx ]; yr = s.zyr[ s.zidx ]
00969 
00970             # Select plot region
00971 
00972             s.tk.call( s.plf._w, 'view', 'select', xl, yl, xr, yr )
00973 
00974     def zoom_forward(s):
00975         "Traverse the zoom windows list forward."
00976 
00977         zframes = len( s.zxl )
00978 
00979         if zframes == 1 or s.zidx == zframes-1:
00980             return
00981 
00982         s.zidx = s.zidx + 1
00983 
00984         xl = s.zxl[ s.zidx ]; yl = s.zyl[ s.zidx ]
00985         xr = s.zxr[ s.zidx ]; yr = s.zyr[ s.zidx ]
00986 
00987         # Select plot region
00988 
00989         s.tk.call( s.plf._w, 'view', 'select', xl, yl, xr, yr )
00990 
00991     def view_scroll(s):
00992         print "in view_scroll"
00993 
00994     def fixview( s, hscroll, vscroll ):
00995         "Handles updates of scrollbars        & plot after view change."
00996 
00997 ## Create scrollbars if they don't already exist.
00998 
00999         created_sb = 0
01000         if hscroll and not s.hscroll_exists:
01001             s.hscroll = Scrollbar( s, relief=SUNKEN, orient=HORIZONTAL )
01002             s.hscroll['command'] = ( s.plf._w, 'xscroll' )
01003             s.plf.config( xscroll=( s.hscroll, 'set' ) )
01004             s.hscroll_exists = 1
01005             created_sb = 1
01006 
01007         if vscroll and not s.vscroll_exists:
01008             s.vscroll = Scrollbar( s, relief=SUNKEN, orient=VERTICAL )
01009             s.vscroll['command'] = ( s.plf._w, 'yscroll' )
01010             s.plf.config( yscroll=( s.vscroll, 'set' ) )
01011             s.vscroll_exists = 1
01012             created_sb = 1
01013 
01014 ## When scrollbars are first created, it may be necessary to unmap
01015 ## then map the plframe widget so that it has a chance to initialize
01016 ## the scrollbars before they are mapped.
01017 
01018         if created_sb:
01019             s.plf.grid_forget()
01020             s.plf.grid( row=1, column=0, sticky='nsew' )
01021 
01022 ## Map scrollbars if not already mapped.  To get packing right, need
01023 ## to unmap then remap plot widget.  Otherwise need to do explicit
01024 ## redraw.
01025 
01026         if hscroll and not atoi( s.tk.call( 'winfo', 'ismapped',
01027                                             s.hscroll._w ) ) \
01028         or vscroll and not atoi( s.tk.call( 'winfo', 'ismapped',
01029                                             s.vscroll._w ) ) :
01030             s.update()
01031             s.plf.grid_forget()
01032             if hscroll:
01033                 s.hscroll.grid( row=2, column=0, sticky='ew' )
01034             if vscroll:
01035                 s.vscroll.grid( row=1, column=1, sticky='ns' )
01036             s.plf.grid( row=1, column=0, sticky='nsew' )
01037         else:
01038             s.tk.call( s.plf._w, 'redraw' )
01039 
01040 ## Hmmm.  Actually, "update_view" doesn't seem to be used by anything...
01041 ##    def update_view(s):
01042 ##        """Updates view.  
01043 ##        Results in scrollbars being added if they are appropriate.
01044 ##        Does nothing if the plot window is unchanged from the default."""
01045 ##
01046 ##        print "in update_view"
01047 ####        set        coords [[plwin] view]
01048 ####
01049 ####        set        xl [lindex "$coords" 0]
01050 ####        set        yl [lindex "$coords" 1]
01051 ####        set        xr [lindex "$coords" 2]
01052 ####        set        yr [lindex "$coords" 3]
01053 ####
01054 ####        view_select        $xl $yl $xr $yr
01055 
01056     def status_msg(s,msg):
01057         s.label_set(msg)
01058         # schedule removal of the message with Tk "after"
01059         s.after( 2500, s.label_reset )
01060 
01061     def label_reset(s):
01062         s.ftop.lstat.config( text='' )
01063 
01064     def label_set(s,msg):
01065         s.ftop.lstat.config( text=msg )
01066 
01067     def plcmap0_edit(s):
01068         print "in plcmap0_edit"
01069 
01070     def plcmap1_edit(s):
01071         print "in plcmap1_edit"
01072 
01073 ## Now do the PLplot API.  Just vector these off to the contained
01074 ## Plframe widget.
01075 
01076     def cmd( s, *args ):
01077         "Invoke a subcommand on the plframe widget."
01078         apply( s.tk.call, (s.plf._w, 'cmd',) + _flatten(args) )
01079 
01080     def pladv( s, page ):
01081         s.cmd( 'pladv', page )
01082 
01083     def plaxes( s, x0, y0, xopt, xtick, nxsub, yopt, ytick, nysub ):
01084         s.cmd( 'plaxes', x0, y0, xopt, xtick, nxsub, yopt, ytick, nysub )
01085 
01086     def plbin(s): pass
01087     def plbop(s):
01088         s.cmd( 'plbop' )
01089 
01090     def plbox( s, xopt, xtick, nxsub, yopt, ytick, nysub ):
01091         s.cmd( 'plbox', xopt, xtick, nxsub, yopt, ytick, nysub )
01092 
01093     def plbox3( s, xopt, xlabel, xtick, nsubx,
01094                 yopt, ylabel, ytick, nsuby,
01095                 zopt, zlabel, ztick, nsubz ):
01096         s.cmd( 'plbox3',
01097                xopt, xlabel, xtick, nsubx,
01098                yopt, ylabel, ytick, nsuby,
01099                zopt, zlabel, ztick, nsubz )
01100 
01101     def plcol0( s, col0 ):
01102         s.cmd( 'plcol0', col0 )
01103 
01104     def plcol1( s, col1 ):
01105         s.cmd( 'plcol1', col1 )
01106 
01107 #    def plcont( s ): pass
01108 
01109 ##    def plcontxxx( s, z, kx, lx, ky, ly, clev, pltr, xg, yg, wrap ):
01110 ##        plsstrm( s.strm )
01111 ##        plcont( z, kx, lx, ky, ly, clev, pltr, xg, yg, wrap )
01112 
01113     def plcont( s, *args ):
01114         plsstrm( s.strm )
01115         apply( plcont, args )
01116 
01117     def plfcont( s ): pass
01118     def plcpstream( s ): pass
01119     
01120     def plenv( s, xmin, xmax, ymin, ymax, i, j ):
01121         s.cmd( 'plenv', xmin, xmax, ymin, ymax, i, j )
01122 
01123     def pleop(s):
01124         s.cmd( 'pleop' )
01125         #print "should've waited here, but it didn't."
01126         s.plf.setvar( 'wv', '0' )
01127         s.label_set( "Plotting paused ... (Hit Clear to continue)" )
01128         #print "preparing to wait for wv to change"
01129         s.plf.waitvar( 'wv' )
01130         #print "it changed."
01131         s.label_reset()
01132         s.update()
01133 
01134     def clearpage(s):
01135         s.plf.setvar( 'wv', 1 )
01136 
01137     def plfill( s, x, y ):
01138         plsstrm( s.strm )
01139         plfill( x, y )
01140 
01141     def plfont( s, ifnt ):
01142         s.cmd( 'plfont', ifnt )
01143 
01144     def plfontld( s, fnt ):
01145         s.cmd( 'plfontld', fnt )
01146 
01147     def plhist( s, data, datmin, datmax, nbin, oldwin ):
01148         plsstrm( s.strm )
01149         plhist( data, datmin, datmax, nbin, oldwin )
01150 
01151     def plhls( s, h, l, sat ):
01152         s.cmd( 'plhls', h, l, sat )
01153 
01154     def pljoin( s, x1, y1, x2, y2 ):
01155         s.cmd( 'pljoin', x1, y1, x2, y2 )
01156 
01157     def pllab( s, xlab, ylab, tlab ):
01158         s.cmd( 'pllab', xlab, ylab, tlab )
01159 
01160     def plline( s, x, y ):
01161         plsstrm( s.strm )
01162         plline( x, y )
01163 
01164     def plline3( s, x, y, z ):
01165         plsstrm( s.strm )
01166         plline3( x, y, z )
01167 
01168     def pllsty( s, lin ):
01169         s.cmd( 'pllsty', lin )
01170 
01171     # map and merridians ommitted.
01172 
01173     def plmesh( s, x, y, z, opt ):
01174         plsstrm( s.strm )
01175         plmesh( x, y, z, opt )
01176 
01177     def plmtex( s, side, disp, pos, just, text ):
01178         s.cmd( 'plmtex', side, disp, pos, just, text )
01179 
01180     def plot3d( s, x, y, z, opt, side ):
01181         plsstrm( s.strm )
01182         plplot3d( x, y, z, opt, side )
01183 
01184     def plplot3d( s, x, y, z, opt, side ):
01185         plsstrm( s.strm )
01186         plplot3d( x, y, z, opt, side )
01187 
01188     def plpoin( s, xs, ys, mark ):
01189         plsstrm( s.strm )
01190         plpoin( xs, ys, mark )
01191 
01192     def plpoin3( s, x, y, z, code ):
01193         plsstrm( s.strm )
01194         plpoin3( x, y, z, code )
01195 
01196     def plpoly3( s, x, y, z, draw ):
01197         plsstrm( s.strm )
01198         plpoly3( x, y, z, draw )
01199 
01200     def plprec( s, setp, prec ):
01201         s.cmd( 'plprec', setp, prec )
01202 
01203     def plpsty( s, patt ):
01204         s.cmd( 'plpsty', patt )
01205 
01206     def plptex( s, x, y, dx, dy, just, text ):
01207         s.cmd( 'plptex', x, y, dx, dy, just, text )
01208 
01209     def plreplot( s ):
01210         s.cmd( 'plreplot' )
01211 
01212     def plrgb( s, r, g, b ):
01213         s.cmd( 'plrgb', r, g, b )
01214 
01215     def plrgb1( s, r, g, b ):
01216         s.cmd( 'plrgb1', r, g, b )
01217 
01218     def plschr( s, dflt, scale ):
01219         s.cmd( 'plschr', dflt, scale )
01220 
01221     def plshade( s, z, xmin, xmax, ymin, ymax,
01222                  sh_min, sh_max, sh_cmap, sh_color, sh_width,
01223                  min_col, min_wid, max_col, max_wid, rect,
01224                  pltr='pltr0', xg=None, yg=None, wrap=0 ):
01225         "Color filled shad plot."
01226 
01227         plsstrm( s.strm );
01228         plshade( z, xmin, xmax, ymin, ymax,
01229                  sh_min, sh_max, sh_cmap, sh_color, sh_width,
01230                  min_col, min_wid, max_col, max_wid, rect,
01231                  pltr, xg, yg, wrap )
01232 
01233 ##    def plshade2( s, z, xmin, xmax, ymin, ymax,
01234 ##                  sh_min, sh_max, sh_cmap, sh_color, sh_width,
01235 ##                  min_col, min_wid, max_col, max_wid, rect,
01236 ##                  pltr, xg, yg, wrap ):
01237 ##        "Was unable to fix plshade, must make new plshade2, grrr."
01238 ##
01239 ##        print "in plshade2"
01240 ##        plsstrm( s.strm );
01241 ##        plshade( z, xmin, xmax, ymin, ymax,
01242 ##                 sh_min, sh_max, sh_cmap, sh_color, sh_width,
01243 ##                 min_col, min_wid, max_col, max_wid, rect,
01244 ##                 pltr, xg, yg, wrap )
01245 
01246 # Only works for special conditions so comment it out for now.
01247 #    def plsmem( ny, ny, plotmem ):
01248 #        s.cmd('plsmem', nx, ny plotmem )
01249 
01250     def plssub( s, nx, ny ):
01251         s.cmd( 'plssub', nx, ny )
01252 
01253     def plssym( s, dflt, scale ):
01254         s.cmd( 'plssym', dflt, scale )
01255 
01256     # plstar and plstart not relevant
01257 
01258     #def plstyl( s, ...
01259     
01260     def plsvpa( s, xmin, xmax, ymin, ymax ):
01261         s.cmd( 'plsvpa', xmin, xmax, ymin, ymax )
01262 
01263     def plsxax( s, digmax, digits ):
01264         s.cmd( 'plsxax', digmax, digits )
01265 
01266     def plsyax( s, digmax, digits ):
01267         s.cmd( 'plsyax', digmax, digits )
01268 
01269     def plsym( s, x, y, code ):
01270         plsstrm( s.strm )
01271         plsym( x, y, code )
01272 
01273     def plszax( s, digmax, digits ):
01274         s.cmd( 'plszax', digmax, digits )
01275 
01276     def plvasp( s, aspect ):
01277         s.cmd( 'plvasp', aspect )
01278 
01279     def plvpas( s, xmin, xmax, ymin, ymax, aspect ):
01280         s.cmd( 'plvpas', xmin, xmax, ymin, ymax, aspect )
01281 
01282     def plvpor( s, xmin, xmax, ymin, ymax ):
01283         s.cmd( 'plvpor', xmin, xmax, ymin, ymax )
01284 
01285     def plvsta(s):
01286         s.cmd( 'plvsta' )
01287 
01288     def plw3d( s, basex, basey, height, xmin0,
01289                xmax0, ymin0, ymax0, zmin0, zmax0, alt, az):
01290         s.cmd( 'plw3d',
01291                basex, basey, height, xmin0,
01292                xmax0, ymin0, ymax0, zmin0, zmax0, alt, az)
01293 
01294     def plwid( s, width ):
01295         s.cmd( 'plwid', width )
01296 
01297     def plwind( s, xmin, xmax, ymin, ymax ):
01298         s.cmd( 'plwind', xmin, xmax, ymin, ymax )
01299 
01300     def debug(s):
01301         print "Debugging dump for PlXframe:"
01302         print "s.saveopt_dev = ", s.saveopt_dev
01303 
01304 ## End of Plframe.py
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines