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