1 # $Id: termdefs.py 302 2008-01-14 22:15:19Z bmcage $
3 # Copyright (C) 2001-2003 Michael Haggerty <mhagger@alum.mit.edu>
5 # This file is licensed under the GNU Lesser General Public License
6 # (LGPL). See LICENSE.txt for details.
8 """Terminal definition file.
10 This module describes the options available to gnuplot's various
11 terminals. For the moment, it only supports a few terminals, but the
12 infrastructure is here to add others as they are needed.
14 Part of the trick is that the 'set terminal' command takes myriad
15 suboptions with various argument types, and order is sometimes
16 significant. The other part of the trick is that there are over 50
17 terminal types, and each terminal has its own set of options.
19 The strategy here is to define a general mechanism for turning Python
20 keyword parameters into fragments of gnuplot command strings. There
21 are a number of classes derived from Arg that do this. Some take
22 string args, some boolean, etc. Then the list of options that each
23 terminal accepts is stored in the terminal_opts dictionary.
24 Gnuplot.hardcopy(), in turn, uses this dictionary to interpret its
25 keyword arguments and build the 'set terminal' command.
36 """Process terminal subargs and return a command fragment.
38 Pull one or more arguments from keyw and output a list of strings
39 that will be appended to the 'set terminal' (separated by spaces).
40 Delete any used args from keyw. If no relevant options are found,
43 This is a base class for the actual argument-processing classes.
44 Derived classes must define a __call__(self, keyw) method
45 returning a list of strings or None.
52 class ArgOneParam(Arg
):
53 """Arg abstract base class specialized for exactly one parameter.
57 'argname' -- The name of the keyword argument used to pass
58 this argument to Python.
60 'default' -- The default value of the argument, used if no
61 keyword parameter is found. If this is None, then no
66 def __init__(self
, argname
, default
):
67 self
.argname
= argname
68 self
.default
= default
70 def get_option(self
, keyw
):
71 """Get the keyword argument corresponding to this Arg.
73 Look in keyw for the keyword argument needed by this Arg. If
74 it is found, delete it from keyw and return it. If it is not
75 found, return self.default.
80 k
= keyw
[self
.argname
]
84 del keyw
[self
.argname
]
88 class KeywordArg(ArgOneParam
):
89 """Represent an argument that must be passed as a keyword to gnuplot.
91 Some gnuplot options take the form of single unquoted keywords
92 (possibly preceded by a fixed keyword). We allow those to be
93 passed as strings 'option="keyword"'. Check that the option
94 supplied is in the list of allowed options.
98 'fixedword' -- the fixed keyword that must precede the
99 variable keyword in the gnuplot command, or None if none
102 'options' -- a list of strings containing the legal
103 alternatives for this argument.
107 def __init__(self
, argname
, options
, fixedword
=None, default
=None):
108 ArgOneParam
.__init
__(self
, argname
, default
)
109 self
.fixedword
= fixedword
110 self
.options
= options
112 def __call__(self
, keyw
):
113 k
= self
.get_option(keyw
)
117 elif k
in self
.options
:
118 if self
.fixedword
is None:
121 return [self
.fixedword
, k
]
123 raise Errors
.OptionError(
124 'Illegal option %s="%s"' % (self
.argname
, k
,))
127 class StringArg(ArgOneParam
):
128 """An option taking a quoted string argument."""
130 def __init__(self
, argname
, fixedword
=None, default
=None):
131 ArgOneParam
.__init
__(self
, argname
, default
)
132 self
.fixedword
= fixedword
134 def __call__(self
, keyw
):
135 k
= self
.get_option(keyw
)
139 elif type(k
) is not types
.StringType
:
140 raise Errors
.OptionError(
141 'Option %s must be a string' % (self
.argname
,))
144 if self
.fixedword
is not None:
145 retval
.append(self
.fixedword
)
146 retval
.append('"%s"' % k
)
150 class BareStringArg(ArgOneParam
):
151 """An arbitrary argument output without quotes.
153 The argument can be a string or anything with a str()
154 representation, or a tuple of such things. Thus this can be used
155 for strings (which will be output without quotation marks),
156 integers, floating point arguments, or multiple arguments of the
157 above types (which will be output separated by spaces). No
158 checking is done that the argument is sensible.
162 def __init__(self
, argname
, fixedword
=None, default
=None):
163 ArgOneParam
.__init
__(self
, argname
, default
)
164 self
.fixedword
= fixedword
166 def __call__(self
, keyw
):
167 k
= self
.get_option(keyw
)
173 if self
.fixedword
is not None:
174 retval
.append(self
.fixedword
)
175 if type(k
) in (types
.TupleType
, types
.ListType
):
177 retval
.append(str(i
))
179 retval
.append(str(k
))
183 class BooleanArg(ArgOneParam
):
184 """An argument that takes a true/false value.
186 The argument should be 0 or 1. The option is output to gnuplot as
187 'trueval' if the argument is true or 'falseval' if the argument is
188 false. Either one can be 'None', in which case nothing is output.
189 'default' should also be 0 or 1.
193 def __init__(self
, argname
, trueval
, falseval
,
194 fixedword
=None, default
=None):
195 ArgOneParam
.__init
__(self
, argname
, default
)
196 self
.trueval
= trueval
197 self
.falseval
= falseval
198 self
.fixedword
= fixedword
200 def __call__(self
, keyw
):
201 k
= self
.get_option(keyw
)
206 if self
.fixedword
is not None:
207 retval
.append(self
.fixedword
)
217 class MutuallyExclusiveArgs(Arg
):
218 """A group of args, of which either zero or one may be set, but not more.
222 subargs -- a list [('argname', arg), ...] of Arg instances.
223 'argname' is used to identify the corresponding arg in
224 error messages. (The name of the corresponding keyword
225 args is determined internally by each arg.)
229 def __init__(self
, *subargs
):
230 self
.subargs
= list(subargs
)
232 def __call__(self
, keyw
):
235 for (argname
, arg
,) in self
.subargs
:
238 if foundargname
is not None:
239 raise Errors
.OptionError(
240 'Arguments %s and %s cannot both be specified'
241 % (foundargname
, argname
,)
244 foundargname
= argname
246 return retval
# might be None
249 class KeywordOrBooleanArg(Arg
):
250 """Allow a keyword arg to be specified either as a keyword or a boolean.
252 This arg type is the most flexible way to allow keyword parameters
253 to be specified. Say there is an option like 'fontsize' that can
254 take the values 'small' or 'large'. This could be represented as
256 'KeywordOrBooleanArg(options=["small", "large"], argname="fontsize")'
258 In that case, the fontsize could be specified in any of the
261 'g.hardcopy(..., fontsize="small", ...)'
262 'g.hardcopy(..., fontsize="large", ...)'
263 'g.hardcopy(..., small=1, ...)'
264 'g.hardcopy(..., large=1, ...)'
266 If 'argname' is set to be 'None', then the first two possibilities
269 In the special case that there are exactly two alternatives, one
272 'g.hardcopy(..., small=0, ...) # implies fontsize="large"'
273 'g.hardcopy(..., large=0, ...) # implies fontsize="small"'
275 Obviously care must be taken to ensure that none of the implied
276 keyword parameter names conflict with one another or with any of
277 the other Args allowed by a function.
281 'options' -- a list of strings representing allowed keyword
282 values. These options can be used as boolean values in
283 the style 'option=1'.
285 'argname' -- the name of the argname for the 'arg=value' style
286 of setting the argument. If 'None', then this style is
289 'fixedword' -- a fixed keyword that must precede the option,
292 'default' -- the default option to set if nothing is set
293 explicitly, or None to leave nothing set in that case.
297 def __init__(self
, options
, argname
=None, fixedword
=None, default
=None):
298 self
.options
= options
299 self
.argname
= argname
300 self
.fixedword
= fixedword
301 self
.default
= default
302 assert self
.default
is None or self
.default
in self
.options
, \
303 'default must be a valid option'
305 def __call__(self
, keyw
):
306 if self
.argname
is not None and self
.argname
in keyw
:
307 k
= keyw
[self
.argname
]
308 del keyw
[self
.argname
]
311 elif k
in self
.options
:
312 # Make sure it isn't contradicted by the corresponding boolean:
313 if k
in keyw
and not keyw
[k
]:
314 raise Errors
.OptionError(
315 'Arguments %s and %s are contradictory'
319 # Store the option into the boolean to be processed below:
322 raise Errors
.OptionError(
323 'Illegal option %s=%s' % (self
.argname
, k
,))
325 # Now scan the booleans and make sure that at most one is set:
327 for i
in range(len(self
.options
)):
333 if option
is not None:
334 raise Errors
.OptionError(
335 'Arguments %s and %s cannot both be specified'
341 # newval was false. This is only legal if this
342 # option only has two possible values:
343 if len(self
.options
) == 2:
344 option
= self
.options
[1 - i
]
349 if self
.default
is None:
352 option
= self
.default
354 if self
.fixedword
is not None:
355 retval
.append(self
.fixedword
)
356 retval
.append(option
)
360 # Now we define the allowed options for a few terminal types. This
361 # table is used by Gnuplot.hardcopy() to construct the necessary 'set
366 terminal_opts
['postscript'] = [
368 options
=['landscape', 'portrait', 'eps', 'default'],
372 options
=['enhanced', 'noenhanced'],
373 # This default should probably be computed from the *current*
374 # value of GnuplotOpts, not at import time. ###
375 default
=(gp
.GnuplotOpts
.prefer_enhanced_postscript
379 KeywordOrBooleanArg(options
=['color', 'monochrome']),
380 KeywordOrBooleanArg(options
=['solid', 'dashed']),
382 options
=['defaultplex', 'simplex', 'duplex'],
385 StringArg(argname
='fontname'),
386 BareStringArg(argname
='fontsize'),
389 terminal_opts
['pdf'] = [
391 options
=['landscape', 'portrait', 'eps', 'default'],
394 KeywordOrBooleanArg(options
=['color', 'monochrome']),
395 KeywordOrBooleanArg(options
=['solid', 'dashed']),
397 options
=['defaultplex', 'simplex', 'duplex'],
400 StringArg(argname
='fontname'),
401 BareStringArg(argname
='fontsize'),
404 terminal_opts
['png'] = [
406 options
=['small', 'medium', 'large'],
409 KeywordOrBooleanArg(options
=['monochrome', 'gray', 'color']),
412 terminal_opts
['fig'] = [
413 KeywordOrBooleanArg(options
=['monochrome', 'color']),
414 KeywordOrBooleanArg(options
=['small', 'big']),
415 BareStringArg(argname
='pointsmax', fixedword
='pointsmax'),
416 KeywordOrBooleanArg(options
=['landscape', 'portrait']),
417 KeywordOrBooleanArg(options
=['metric', 'inches']),
418 BareStringArg(argname
='fontsize'),
419 BareStringArg(argname
='size'), # needs a tuple of two doubles
420 BareStringArg(argname
='thickness'),
421 BareStringArg(argname
='depth'),
424 terminal_opts
['cgm'] = [
426 options
=['landscape', 'portrait', 'default'],
429 KeywordOrBooleanArg(options
=['color', 'monochrome']),
430 KeywordOrBooleanArg(options
=['rotate', 'norotate']),
431 BareStringArg(argname
='width', fixedword
='width'),
432 BareStringArg(argname
='linewidth', fixedword
='linewidth'),
433 StringArg(argname
='font'),
434 BareStringArg(argname
='fontsize'),
437 terminal_opts
['pict'] = [
439 options
=['landscape', 'portrait', 'default'],
442 KeywordOrBooleanArg(options
=['color', 'monochrome']),
443 KeywordOrBooleanArg(options
=['dashes', 'nodashes']),
445 # default font, which must be a valid pict font:
446 StringArg(argname
='fontname'),
448 # default font size, in points:
449 BareStringArg(argname
='fontsize'),
451 # width of plot in pixels:
452 BareStringArg(argname
='width'),
454 # height of plot in pixels:
455 BareStringArg(argname
='height'),
459 terminal_opts
['mp'] = [
460 KeywordOrBooleanArg(options
=['color', 'colour', 'monochrome']),
461 KeywordOrBooleanArg(options
=['solid', 'dashed']),
462 KeywordOrBooleanArg(options
=['notex', 'tex', 'latex']),
463 BareStringArg(argname
='magnification'),
464 KeywordOrBooleanArg(options
=['psnfss', 'psnfss-version7', 'nopsnfss']),
465 BareStringArg(argname
='prologues'),
466 KeywordOrBooleanArg(options
=['a4paper']),
467 KeywordOrBooleanArg(options
=['amstex']),
468 StringArg(argname
='fontname'),
469 BareStringArg(argname
='fontsize'),
472 terminal_opts
['svg'] = [
473 BareStringArg(argname
='size', fixedword
='size'), # tuple of two doubles
474 KeywordOrBooleanArg(options
=['fixed', 'dynamic']),
475 StringArg(argname
='fname', fixedword
='fname'),
476 BareStringArg(argname
='fsize', fixedword
='fsize'),
477 KeywordOrBooleanArg(options
=['enhanced', 'noenhanced']),
478 StringArg(argname
='fontfile', fixedword
='fontfile'),