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