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 import sys, string, types
16
17 import gp, PlotItems, termdefs, Errors
18
19
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
46 """Open the file for writing."""
47
48 self.gnuplot = open(filename, 'w')
49
50 self.write = self.gnuplot.write
51 self.flush = self.gnuplot.flush
52
54 """Write a command string to the file, followed by newline."""
55
56 self.write(s + '\n')
57 self.flush()
58
59
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
136
137
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
190
191
192
193 if self.gnuplot is not None:
194 self.gnuplot.close()
195 self.gnuplot = None
196
200
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
213 sys.stderr.write('gnuplot> %s\n' % (s,))
214
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
229 item.pipein(self.gnuplot)
230 self.gnuplot.flush()
231
233 """Clear the 'PlotItems' from the queue."""
234
235 self.itemlist = []
236
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
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
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
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)
356 sys.stderr.write('\n')
357
359 """Clear the plot window (without affecting the current itemlist)."""
360
361 self('clear')
362
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
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
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
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
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
551
552
553
554
555
556
557
558
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
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
580 self.refresh()
581
582 self('set terminal %s' % gp.GnuplotOpts.default_term)
583 self.set_string('output')
584