1
2
3
4
5
6
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
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
48 """Open the file for writing."""
49
50 self.gnuplot = open(filename, 'w')
51
52 self.write = self.gnuplot.write
53 self.flush = self.gnuplot.flush
54
56 """Write a command string to the file, followed by newline."""
57
58 self.write(s + '\n')
59 self.flush()
60
61
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
138
139
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
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
202 sys.stderr.write('gnuplot> %s\n' % (s,))
203
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
218 item.pipein(self.gnuplot)
219 self.gnuplot.flush()
220
222 """Clear the 'PlotItems' from the queue."""
223
224 self.itemlist = []
225
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
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
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
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)
345 sys.stderr.write('\n')
346
348 """Clear the plot window (without affecting the current itemlist)."""
349
350 self('clear')
351
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
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
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
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
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
533
534
535
536
537
538
539
540
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
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
562 self.refresh()
563
564 self('set terminal %s' % gp.GnuplotOpts.default_term)
565 self.set_string('output')
566