Package PyFoam :: Package ThirdParty :: Package Gnuplot :: Module _Gnuplot
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.ThirdParty.Gnuplot._Gnuplot

  1  # $Id: _Gnuplot.py,v 2.9 2003/08/18 21:34:46 mhagger Exp $ 
  2   
  3  # Copyright (C) 1998-2003 Michael Haggerty <mhagger@alum.mit.edu> 
  4  # 
  5  # This file is licensed under the GNU Lesser General Public License 
  6  # (LGPL).  See LICENSE.txt for details. 
  7   
  8  """_Gnuplot.py -- An object that represents a running gnuplot process. 
  9   
 10  This file implements the Gnuplot plotter object, which is an abstract 
 11  interface to a running gnuplot process. 
 12   
 13  """ 
 14   
 15  __cvs_version__ = '$Revision: 2.9 $' 
 16   
 17  import sys, string, types 
 18   
 19  import gp, PlotItems, termdefs 
 20   
 21   
22 -class _GnuplotFile:
23 """A file to which gnuplot commands can be written. 24 25 Sometimes it is convenient to write gnuplot commands to a command 26 file for later evaluation. In that case, one of these objects is 27 used as a mock gnuplot process. Note that temporary files may be 28 deleted before you have time to execute the file! 29 30 Members: 31 32 'gnuplot' -- the file object gathering the commands. 33 34 Methods: 35 36 '__init__' -- open the file. 37 38 '__call__' -- write a gnuplot command to the file, followed by a 39 newline. 40 41 'write' -- write an arbitrary string to the file. 42 43 'flush' -- cause pending output to be written immediately. 44 45 """ 46
47 - def __init__(self, filename):
48 """Open the file for writing.""" 49 50 self.gnuplot = open(filename, 'w') 51 # forward write and flush methods: 52 self.write = self.gnuplot.write 53 self.flush = self.gnuplot.flush
54
55 - def __call__(self, s):
56 """Write a command string to the file, followed by newline.""" 57 58 self.write(s + '\n') 59 self.flush()
60 61
62 -class Gnuplot:
63 """Interface to a gnuplot program. 64 65 A Gnuplot represents a higher-level interface to a gnuplot 66 program. It can plot 'PlotItem's, which represent each thing to 67 be plotted on the current graph. It keeps a reference to each of 68 the 'PlotItems' used in the current plot, so that they (and their 69 associated temporary files) are not deleted prematurely. 70 71 Members: 72 73 'itemlist' -- a list of the PlotItems that are associated with 74 the current plot. These are deleted whenever a new plot 75 command is issued via the 'plot' method. 76 77 'plotcmd' -- 'plot' or 'splot', depending on what was the last 78 plot command. 79 80 Methods: 81 82 '__init__' -- if a filename argument is specified, the 83 commands will be written to that file instead of being 84 piped to gnuplot. 85 86 'plot' -- clear the old plot and old 'PlotItems', then plot 87 the arguments in a fresh plot command. Arguments can be: 88 a 'PlotItem', which is plotted along with its internal 89 options; a string, which is plotted as a 'Func'; or 90 anything else, which is plotted as a 'Data'. 91 92 'splot' -- like 'plot', except for 3-d plots. 93 94 'hardcopy' -- replot the plot to a postscript file (if 95 filename argument is specified) or pipe it to the printer 96 as postscript othewise. If the option 'color' is set to 97 true, then output color postscript. 98 99 'replot' -- replot the old items, adding any arguments as 100 additional items as in the plot method. 101 102 'refresh' -- issue (or reissue) the plot command using the 103 current 'PlotItems'. 104 105 '__call__' -- pass an arbitrary string to the gnuplot process, 106 followed by a newline. 107 108 'xlabel', 'ylabel', 'title' -- set corresponding plot 109 attribute. 110 111 'interact' -- read lines from stdin and send them, one by one, 112 to the gnuplot interpreter. Basically you can type 113 commands directly to the gnuplot command processor. 114 115 'load' -- load a file (using the gnuplot 'load' command). 116 117 'save' -- save gnuplot commands to a file (using gnuplot 118 'save' command) If any of the 'PlotItem's is a temporary 119 file, it will be deleted at the usual time and the save 120 file will be pretty useless :-). 121 122 'clear' -- clear the plot window (but not the itemlist). 123 124 'reset' -- reset all gnuplot settings to their defaults and 125 clear the current itemlist. 126 127 'set_string' -- set or unset a gnuplot option whose value is a 128 string. 129 130 '_clear_queue' -- clear the current 'PlotItem' list. 131 132 '_add_to_queue' -- add the specified items to the current 133 'PlotItem' list. 134 135 """ 136 137 # optiontypes tells how to set parameters. Specifically, the 138 # parameter will be set using self.set_<type>(option, value), 139 # where <type> is a string looked up in the following table. 140 optiontypes = { 141 'title' : 'string', 142 'xlabel' : 'string', 143 'ylabel' : 'string', 144 'xrange' : 'range', 145 'yrange' : 'range', 146 'zrange' : 'range', 147 'trange' : 'range', 148 'urange' : 'range', 149 'vrange' : 'range', 150 'parametric' : 'boolean', 151 'polar' : 'boolean', 152 'output' : 'string', 153 } 154
155 - def __init__(self, filename=None, persist=None, debug=0):
156 """Create a Gnuplot object. 157 158 Create a 'Gnuplot' object. By default, this starts a gnuplot 159 process and prepares to write commands to it. 160 161 Keyword arguments: 162 163 'filename=<string>' -- if a filename is specified, the 164 commands are instead written to that file (e.g., for 165 later use using 'load'). 166 167 'persist=1' -- start gnuplot with the '-persist' option 168 (which creates a new plot window for each plot command). 169 (This option is not available on older versions of 170 gnuplot.) 171 172 'debug=1' -- echo the gnuplot commands to stderr as well as 173 sending them to gnuplot. 174 175 """ 176 177 if filename is None: 178 self.gnuplot = gp.GnuplotProcess(persist=persist) 179 else: 180 if persist is not None: 181 raise Errors.OptionError( 182 'Gnuplot with output to file does not allow ' 183 'persist option.') 184 self.gnuplot = _GnuplotFile(filename) 185 self._clear_queue() 186 self.debug = debug 187 self.plotcmd = 'plot' 188 self('set terminal %s' % (gp.GnuplotOpts.default_term,))
189
190 - def __call__(self, s):
191 """Send a command string to gnuplot. 192 193 Send the string s as a command to gnuplot, followed by a 194 newline. All communication with the gnuplot process (except 195 for inline data) is through this method. 196 197 """ 198 199 self.gnuplot(s) 200 if self.debug: 201 # also echo to stderr for user to see: 202 sys.stderr.write('gnuplot> %s\n' % (s,))
203
204 - def refresh(self):
205 """Refresh the plot, using the current 'PlotItem's. 206 207 Refresh the current plot by reissuing the gnuplot plot command 208 corresponding to the current itemlist. 209 210 """ 211 212 plotcmds = [] 213 for item in self.itemlist: 214 plotcmds.append(item.command()) 215 self(self.plotcmd + ' ' + string.join(plotcmds, ', ')) 216 for item in self.itemlist: 217 # Uses self.gnuplot.write(): 218 item.pipein(self.gnuplot) 219 self.gnuplot.flush()
220
221 - def _clear_queue(self):
222 """Clear the 'PlotItems' from the queue.""" 223 224 self.itemlist = []
225
226 - def _add_to_queue(self, items):
227 """Add a list of items to the itemlist (but don't plot them). 228 229 'items' is a sequence of items, each of which should be a 230 'PlotItem' of some kind, a string (interpreted as a function 231 string for gnuplot to evaluate), or a Numeric array (or 232 something that can be converted to a Numeric array). 233 234 """ 235 236 for item in items: 237 if isinstance(item, PlotItems.PlotItem): 238 self.itemlist.append(item) 239 elif type(item) is types.StringType: 240 self.itemlist.append(PlotItems.Func(item)) 241 else: 242 # assume data is an array: 243 self.itemlist.append(PlotItems.Data(item))
244
245 - def plot(self, *items, **keyw):
246 """Draw a new plot. 247 248 Clear the current plot and create a new 2-d plot containing 249 the specified items. Each arguments should be of the 250 following types: 251 252 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most 253 flexible way to call plot because the PlotItems can 254 contain suboptions. Moreover, PlotItems can be saved to 255 variables so that their lifetime is longer than one plot 256 command; thus they can be replotted with minimal overhead. 257 258 'string' (e.g., 'sin(x)') -- The string is interpreted as 259 'Func(string)' (a function that is computed by gnuplot). 260 261 Anything else -- The object, which should be convertible to an 262 array, is passed to the 'Data' constructor, and thus 263 plotted as data. If the conversion fails, an exception is 264 raised. 265 266 """ 267 268 if keyw: 269 apply(self.set, (), keyw) 270 271 self.plotcmd = 'plot' 272 self._clear_queue() 273 self._add_to_queue(items) 274 self.refresh()
275
276 - def splot(self, *items, **keyw):
277 """Draw a new three-dimensional plot. 278 279 Clear the current plot and create a new 3-d plot containing 280 the specified items. Arguments can be of the following types: 281 282 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This 283 is the most flexible way to call plot because the 284 PlotItems can contain suboptions. Moreover, PlotItems can 285 be saved to variables so that their lifetime is longer 286 than one plot command--thus they can be replotted with 287 minimal overhead. 288 289 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a 290 'Func()' (a function that is computed by gnuplot). 291 292 Anything else -- The object is converted to a Data() item, and 293 thus plotted as data. Note that each data point should 294 normally have at least three values associated with it 295 (i.e., x, y, and z). If the conversion fails, an 296 exception is raised. 297 298 """ 299 300 if keyw: 301 apply(self.set, (), keyw) 302 303 self.plotcmd = 'splot' 304 self._clear_queue() 305 self._add_to_queue(items) 306 self.refresh()
307
308 - def replot(self, *items, **keyw):
309 """Replot the data, possibly adding new 'PlotItem's. 310 311 Replot the existing graph, using the items in the current 312 itemlist. If arguments are specified, they are interpreted as 313 additional items to be plotted alongside the existing items on 314 the same graph. See 'plot' for details. 315 316 """ 317 318 if keyw: 319 apply(self.set, (), keyw) 320 321 self._add_to_queue(items) 322 self.refresh()
323
324 - def interact(self):
325 """Allow user to type arbitrary commands to gnuplot. 326 327 Read stdin, line by line, and send each line as a command to 328 gnuplot. End by typing C-d. 329 330 """ 331 332 import time 333 if sys.platform == 'win32': 334 sys.stderr.write('Press Ctrl-z twice to end interactive input\n') 335 else: 336 # What should this be for the Macintosh? 337 sys.stderr.write('Press C-d to end interactive input\n') 338 while 1: 339 try: 340 line = raw_input('gnuplot>>> ') 341 except EOFError: 342 break 343 self(line) 344 time.sleep(0.2) # give a little time for errors to be written 345 sys.stderr.write('\n')
346
347 - def clear(self):
348 """Clear the plot window (without affecting the current itemlist).""" 349 350 self('clear')
351
352 - def reset(self):
353 """Reset all gnuplot settings to their defaults and clear itemlist.""" 354 355 self('reset') 356 self.itemlist = []
357
358 - def load(self, filename):
359 """Load a file using gnuplot's 'load' command.""" 360 361 self("load '%s'" % (filename,))
362
363 - def save(self, filename):
364 """Save the current plot commands using gnuplot's 'save' command.""" 365 366 self("save '%s'" % (filename,))
367
368 - def set_string(self, option, s=None):
369 """Set a string option, or if s is omitted, unset the option.""" 370 371 if s is None: 372 self('set %s' % (option,)) 373 else: 374 self('set %s "%s"' % (option, s))
375
376 - def set_label(self, option, s=None, offset=None, font=None):
377 """Set or clear a label option, which can include an offset or font. 378 379 If offset is specified, it should be a tuple of two integers 380 or floats. 381 382 If font is specified, it is appended to the command as a 383 string in double quotes. Its interpretation is 384 terminal-dependent; for example, for postscript it might be 385 'Helvetica,14' for 14 point Helvetica. 386 387 """ 388 389 cmd = ['set', option] 390 if s is not None: 391 cmd.append('"%s"' % (s,)) 392 393 if offset is not None: 394 cmd.append('%s,%s' % offset) 395 396 if font is not None: 397 cmd.append('"%s"' % (font,)) 398 399 self(string.join(cmd))
400
401 - def set_boolean(self, option, value):
402 """Set an on/off option. It is assumed that the way to turn 403 the option on is to type `set <option>' and to turn it off, 404 `set no<option>'.""" 405 406 if value: 407 self('set %s' % option) 408 else: 409 self('set no%s' % option)
410
411 - def set_range(self, option, value):
412 """Set a range option (xrange, yrange, trange, urange, etc.). 413 The value can be a string (which is passed as-is, without 414 quotes) or a tuple (minrange,maxrange) of numbers or string 415 expressions recognized by gnuplot. If either range is None 416 then that range is passed as `*' (which means to 417 autoscale).""" 418 419 if value is None: 420 self('set %s [*:*]' % (option,)) 421 elif type(value) is types.StringType: 422 self('set %s %s' % (option, value,)) 423 else: 424 # Must be a tuple: 425 (minrange,maxrange) = value 426 if minrange is None: 427 minrange = '*' 428 if maxrange is None: 429 maxrange = '*' 430 self('set %s [%s:%s]' % (option, minrange, maxrange,))
431
432 - def set(self, **keyw):
433 """Set one or more settings at once from keyword arguments. 434 The allowed settings and their treatments are determined from 435 the optiontypes mapping.""" 436 437 for (k,v) in keyw.items(): 438 try: 439 type = self.optiontypes[k] 440 except KeyError: 441 raise 'option %s is not supported' % (k,) 442 getattr(self, 'set_%s' % type)(k, v)
443
444 - def xlabel(self, s=None, offset=None, font=None):
445 """Set the plot's xlabel.""" 446 447 self.set_label('xlabel', s, offset=offset, font=font)
448
449 - def ylabel(self, s=None, offset=None, font=None):
450 """Set the plot's ylabel.""" 451 452 self.set_label('ylabel', s, offset=offset, font=font)
453
454 - def title(self, s=None, offset=None, font=None):
455 """Set the plot's title.""" 456 457 self.set_label('title', s, offset=offset, font=font)
458
459 - def hardcopy(self, filename=None, terminal='postscript', **keyw):
460 """Create a hardcopy of the current plot. 461 462 Create a postscript hardcopy of the current plot to the 463 default printer (if configured) or to the specified filename. 464 465 Note that gnuplot remembers the postscript suboptions across 466 terminal changes. Therefore if you set, for example, color=1 467 for one hardcopy then the next hardcopy will also be color 468 unless you explicitly choose color=0. Alternately you can 469 force all of the options to their defaults by setting 470 mode='default'. I consider this to be a bug in gnuplot. 471 472 Keyword arguments: 473 474 'filename=<string>' -- if a filename is specified, save the 475 output in that file; otherwise print it immediately 476 using the 'default_lpr' configuration option. 477 478 'terminal=<string>' -- the type of gnuplot 'terminal' to use 479 for the output (e.g., 'postscript', 'png', 'latex', 480 etc). At the moment only 'postscript' is implemented. 481 482 The rest of the keyword arguments depend on the terminal type. 483 484 Keyword arguments for 'postscript' terminal: 485 486 'mode=<string>' -- set the postscript submode ('landscape', 487 'portrait', 'eps', or 'default'). The default is 488 to leave this option unspecified. 489 490 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to 491 generate encapsulated postscript. 492 493 'enhanced=<bool>' -- if set (the default), then generate 494 enhanced postscript, which allows extra features like 495 font-switching, superscripts, and subscripts in axis 496 labels. (Some old gnuplot versions do not support 497 enhanced postscript; if this is the case set 498 gp.GnuplotOpts.prefer_enhanced_postscript=None.) 499 500 'color=<bool>' -- if set, create a plot with color. Default 501 is to leave this option unchanged. 502 503 'solid=<bool>' -- if set, force lines to be solid (i.e., not 504 dashed). 505 506 'duplexing=<string>' -- set duplexing option ('defaultplex', 507 'simplex', or 'duplex'). Only request double-sided 508 printing if your printer can handle it. Actually this 509 option is probably meaningless since hardcopy() can only 510 print a single plot at a time. 511 512 'fontname=<string>' -- set the default font to <string>, 513 which must be a valid postscript font. The default is 514 to leave this option unspecified. 515 516 'fontsize=<double>' -- set the default font size, in 517 postscript points. 518 519 Note that this command will return immediately even though it 520 might take gnuplot a while to actually finish working. Be 521 sure to pause briefly before issuing another command that 522 might cause the temporary files to be deleted. 523 524 """ 525 526 if filename is None: 527 if gp.GnuplotOpts.default_lpr is None: 528 raise Errors.OptionError( 529 'default_lpr is not set, so you can only print to a file.') 530 filename = gp.GnuplotOpts.default_lpr 531 532 # Be careful processing the options. If the user didn't 533 # request an option explicitly, do not specify it on the 'set 534 # terminal' line (don't even specify the default value for the 535 # option). This is to avoid confusing older versions of 536 # gnuplot that do not support all of these options. The 537 # exception is 'enhanced', which is just too useful to have to 538 # specify each time! 539 540 # Build up the 'set terminal' command here: 541 setterm = ['set', 'terminal', terminal] 542 try: 543 opts = termdefs.terminal_opts[terminal] 544 except KeyError: 545 raise Errors.OptionError( 546 'Terminal "%s" is not configured in Gnuplot.py.' % (terminal,)) 547 548 for opt in opts: 549 cmd = opt(keyw) 550 if cmd is not None: 551 setterm.extend(cmd) 552 if keyw: 553 # Not all options were consumed. 554 raise Errors.OptionError( 555 'The following options are unrecognized: %s' 556 % (string.join(keyw.keys(), ', '),) 557 ) 558 559 self(string.join(setterm)) 560 self.set_string('output', filename) 561 # replot the current figure (to the printer): 562 self.refresh() 563 # reset the terminal to its `default' setting: 564 self('set terminal %s' % gp.GnuplotOpts.default_term) 565 self.set_string('output')
566