Gnuplot2.py
665 lines
| 25.9 KiB
| text/x-python
|
PythonLexer
/ IPython / Gnuplot2.py
fperez
|
r0 | # -*- coding: utf-8 -*- | ||
"""Improved replacement for the Gnuplot.Gnuplot class. | ||||
This module imports Gnuplot and replaces some of its functionality with | ||||
improved versions. They add better handling of arrays for plotting and more | ||||
convenient PostScript generation, plus some fixes for hardcopy(). | ||||
It also adds a convenient plot2 method for plotting dictionaries and | ||||
lists/tuples of arrays. | ||||
This module is meant to be used as a drop-in replacement to the original | ||||
Gnuplot, so it should be safe to do: | ||||
import IPython.Gnuplot2 as Gnuplot | ||||
Fernando Perez
|
r1853 | """ | ||
fperez
|
r0 | |||
import cStringIO | ||||
fperez
|
r52 | import os | ||
import string | ||||
fperez
|
r0 | import sys | ||
import tempfile | ||||
fperez
|
r52 | import time | ||
import types | ||||
fperez
|
r0 | import Gnuplot as Gnuplot_ori | ||
fperez
|
r52 | import Numeric | ||
fperez
|
r0 | from IPython.genutils import popkey,xsys | ||
# needed by hardcopy(): | ||||
gp = Gnuplot_ori.gp | ||||
# Patch for Gnuplot.py 1.6 compatibility. | ||||
# Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz> | ||||
try: | ||||
OptionException = Gnuplot_ori.PlotItems.OptionException | ||||
except AttributeError: | ||||
OptionException = Gnuplot_ori.Errors.OptionError | ||||
# exhibit a similar interface to Gnuplot so it can be somewhat drop-in | ||||
Data = Gnuplot_ori.Data | ||||
Func = Gnuplot_ori.Func | ||||
GridData = Gnuplot_ori.GridData | ||||
PlotItem = Gnuplot_ori.PlotItem | ||||
PlotItems = Gnuplot_ori.PlotItems | ||||
# Modify some of Gnuplot's functions with improved versions (or bugfixed, in | ||||
# hardcopy's case). In order to preserve the docstrings at runtime, I've | ||||
# copied them from the original code. | ||||
# After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit | ||||
# of version checking. | ||||
if Gnuplot_ori.__version__ <= '1.6': | ||||
_BaseFileItem = PlotItems.File | ||||
_BaseTempFileItem = PlotItems.TempFile | ||||
# Fix the File class to add the 'index' option for Gnuplot versions < 1.7 | ||||
class File(_BaseFileItem): | ||||
_option_list = _BaseFileItem._option_list.copy() | ||||
_option_list.update({ | ||||
'index' : lambda self, index: self.set_option_index(index), | ||||
}) | ||||
# A new initializer is needed b/c we want to add a modified | ||||
# _option_sequence list which includes 'index' in the right place. | ||||
def __init__(self,*args,**kw): | ||||
self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes', | ||||
'title', 'with'] | ||||
_BaseFileItem.__init__(self,*args,**kw) | ||||
# Let's fix the constructor docstring | ||||
__newdoc = \ | ||||
"""Additional Keyword arguments added by IPython: | ||||
'index=<int>' -- similar to the `index` keyword in Gnuplot. | ||||
This allows only some of the datasets in a file to be | ||||
plotted. Datasets within a file are assumed to be separated | ||||
by _pairs_ of blank lines, and the first one is numbered as | ||||
0 (similar to C/Python usage).""" | ||||
__init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc | ||||
def set_option_index(self, index): | ||||
if index is None: | ||||
self.clear_option('index') | ||||
elif type(index) in [type(''), type(1)]: | ||||
self._options['index'] = (index, 'index %s' % index) | ||||
elif type(index) is type(()): | ||||
self._options['index'] = (index,'index %s' % | ||||
string.join(map(repr, index), ':')) | ||||
else: | ||||
raise OptionException('index=%s' % (index,)) | ||||
# We need a FileClass with a different name from 'File', which is a | ||||
# factory function in 1.7, so that our String class can subclass FileClass | ||||
# in any version. | ||||
_FileClass = File | ||||
fperez
|
r223 | elif Gnuplot_ori.__version__ =='1.7': | ||
fperez
|
r0 | _FileClass = _BaseFileItem = PlotItems._FileItem | ||
_BaseTempFileItem = PlotItems._TempFileItem | ||||
File = PlotItems.File | ||||
fperez
|
r223 | else: # changes in the newer version (svn as of March'06) | ||
_FileClass = _BaseFileItem = PlotItems._FileItem | ||||
_BaseTempFileItem = PlotItems._NewFileItem | ||||
File = PlotItems.File | ||||
fperez
|
r0 | # Now, we can add our generic code which is version independent | ||
# First some useful utilities | ||||
def eps_fix_bbox(fname): | ||||
"""Fix the bounding box of an eps file by running ps2eps on it. | ||||
If its name ends in .eps, the original file is removed. | ||||
This is particularly useful for plots made by Gnuplot with square aspect | ||||
ratio: there is a bug in Gnuplot which makes it generate a bounding box | ||||
which is far wider than the actual plot. | ||||
This function assumes that ps2eps is installed in your system.""" | ||||
# note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The | ||||
# others make output with bitmapped fonts, which looks horrible. | ||||
print 'Fixing eps file: <%s>' % fname | ||||
xsys('ps2eps -f -q -l %s' % fname) | ||||
if fname.endswith('.eps'): | ||||
os.rename(fname+'.eps',fname) | ||||
def is_list1d(x,containers = [types.ListType,types.TupleType]): | ||||
"""Returns true if x appears to be a 1d list/tuple/array. | ||||
The heuristics are: identify Numeric arrays, or lists/tuples whose first | ||||
element is not itself a list/tuple. This way zipped lists should work like | ||||
the original Gnuplot. There's no inexpensive way to know if a list doesn't | ||||
have a composite object after its first element, so that kind of input | ||||
will produce an error. But it should work well in most cases. | ||||
""" | ||||
x_type = type(x) | ||||
return x_type == Numeric.ArrayType and len(x.shape)==1 or \ | ||||
(x_type in containers and | ||||
type(x[0]) not in containers + [Numeric.ArrayType]) | ||||
def zip_items(items,titles=None): | ||||
"""zip together neighboring 1-d arrays, and zip standalone ones | ||||
with their index. Leave other plot items alone.""" | ||||
class StandaloneItem(Exception): pass | ||||
def get_titles(titles): | ||||
"""Return the next title and the input titles array. | ||||
The input array may be changed to None when no titles are left to | ||||
prevent extra unnecessary calls to this function.""" | ||||
try: | ||||
title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope | ||||
except IndexError: | ||||
titles = None # so we don't enter again | ||||
title = None | ||||
else: | ||||
tit_ct[0] += 1 | ||||
return title,titles | ||||
new_items = [] | ||||
if titles: | ||||
# Initialize counter. It was put in a list as a hack to allow the | ||||
# nested get_titles to modify it without raising a NameError. | ||||
tit_ct = [0] | ||||
n = 0 # this loop needs to be done by hand | ||||
while n < len(items): | ||||
item = items[n] | ||||
try: | ||||
if is_list1d(item): | ||||
if n==len(items)-1: # last in list | ||||
raise StandaloneItem | ||||
else: # check the next item and zip together if needed | ||||
next_item = items[n+1] | ||||
if next_item is None: | ||||
n += 1 | ||||
raise StandaloneItem | ||||
elif is_list1d(next_item): | ||||
# this would be best done with an iterator | ||||
if titles: | ||||
title,titles = get_titles(titles) | ||||
else: | ||||
title = None | ||||
new_items.append(Data(zip(item,next_item), | ||||
title=title)) | ||||
n += 1 # avoid double-inclusion of next item | ||||
else: # can't zip with next, zip with own index list | ||||
raise StandaloneItem | ||||
else: # not 1-d array | ||||
new_items.append(item) | ||||
except StandaloneItem: | ||||
if titles: | ||||
title,titles = get_titles(titles) | ||||
else: | ||||
title = None | ||||
new_items.append(Data(zip(range(len(item)),item),title=title)) | ||||
except AttributeError: | ||||
new_items.append(item) | ||||
n+=1 | ||||
return new_items | ||||
# And some classes with enhanced functionality. | ||||
class String(_FileClass): | ||||
"""Make a PlotItem from data in a string with the same format as a File. | ||||
This allows writing data directly inside python scripts using the exact | ||||
same format and manipulation options which would be used for external | ||||
files.""" | ||||
def __init__(self, data_str, **keyw): | ||||
"""Construct a String object. | ||||
<data_str> is a string formatted exactly like a valid Gnuplot data | ||||
file would be. All options from the File constructor are valid here. | ||||
Warning: when used for interactive plotting in scripts which exit | ||||
immediately, you may get an error because the temporary file used to | ||||
hold the string data was deleted before Gnuplot had a chance to see | ||||
it. You can work around this problem by putting a raw_input() call at | ||||
the end of the script. | ||||
This problem does not appear when generating PostScript output, only | ||||
with Gnuplot windows.""" | ||||
self.tmpfile = _BaseTempFileItem() | ||||
tmpfile = file(self.tmpfile.filename,'w') | ||||
tmpfile.write(data_str) | ||||
_BaseFileItem.__init__(self,self.tmpfile,**keyw) | ||||
class Gnuplot(Gnuplot_ori.Gnuplot): | ||||
"""Improved Gnuplot class. | ||||
Enhancements: better plot,replot and hardcopy methods. New methods for | ||||
quick range setting. | ||||
""" | ||||
def xrange(self,min='*',max='*'): | ||||
"""Set xrange. If min/max is omitted, it is set to '*' (auto). | ||||
Note that this is different from the regular Gnuplot behavior, where | ||||
an unspecified limit means no change. Here any unspecified limit is | ||||
set to autoscaling, allowing these functions to be used for full | ||||
autoscaling when called with no arguments. | ||||
To preserve one limit's current value while changing the other, an | ||||
explicit '' argument must be given as the limit to be kept. | ||||
Similar functions exist for [y{2}z{2}rtuv]range.""" | ||||
self('set xrange [%s:%s]' % (min,max)) | ||||
def yrange(self,min='*',max='*'): | ||||
self('set yrange [%s:%s]' % (min,max)) | ||||
def zrange(self,min='*',max='*'): | ||||
self('set zrange [%s:%s]' % (min,max)) | ||||
def x2range(self,min='*',max='*'): | ||||
self('set xrange [%s:%s]' % (min,max)) | ||||
def y2range(self,min='*',max='*'): | ||||
self('set yrange [%s:%s]' % (min,max)) | ||||
def z2range(self,min='*',max='*'): | ||||
self('set zrange [%s:%s]' % (min,max)) | ||||
def rrange(self,min='*',max='*'): | ||||
self('set rrange [%s:%s]' % (min,max)) | ||||
def trange(self,min='*',max='*'): | ||||
self('set trange [%s:%s]' % (min,max)) | ||||
def urange(self,min='*',max='*'): | ||||
self('set urange [%s:%s]' % (min,max)) | ||||
def vrange(self,min='*',max='*'): | ||||
self('set vrange [%s:%s]' % (min,max)) | ||||
def set_ps(self,option): | ||||
"""Set an option for the PostScript terminal and reset default term.""" | ||||
self('set terminal postscript %s ' % option) | ||||
self('set terminal %s' % gp.GnuplotOpts.default_term) | ||||
def __plot_ps(self, plot_method,*items, **keyw): | ||||
"""Wrapper for plot/splot/replot, with processing of hardcopy options. | ||||
For internal use only.""" | ||||
# Filter out PostScript options which will crash the normal plot/replot | ||||
psargs = {'filename':None, | ||||
'mode':None, | ||||
'eps':None, | ||||
'enhanced':None, | ||||
'color':None, | ||||
'solid':None, | ||||
'duplexing':None, | ||||
'fontname':None, | ||||
'fontsize':None, | ||||
'debug':0 } | ||||
for k in psargs.keys(): | ||||
if keyw.has_key(k): | ||||
psargs[k] = keyw[k] | ||||
del keyw[k] | ||||
# Filter out other options the original plot doesn't know | ||||
hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None) | ||||
titles = popkey(keyw,'titles',0) | ||||
# the filename keyword should control hardcopy generation, this is an | ||||
# override switch only which needs to be explicitly set to zero | ||||
if hardcopy: | ||||
if psargs['filename'] is None: | ||||
raise ValueError, \ | ||||
'If you request hardcopy, you must give a filename.' | ||||
# set null output so nothing goes to screen. hardcopy() restores output | ||||
self('set term dumb') | ||||
# I don't know how to prevent screen output in Windows | ||||
if os.name == 'posix': | ||||
self('set output "/dev/null"') | ||||
new_items = zip_items(items,titles) | ||||
# plot_method is either plot or replot from the original Gnuplot class: | ||||
plot_method(self,*new_items,**keyw) | ||||
# Do hardcopy if requested | ||||
if hardcopy: | ||||
if psargs['filename'].endswith('.eps'): | ||||
psargs['eps'] = 1 | ||||
self.hardcopy(**psargs) | ||||
def plot(self, *items, **keyw): | ||||
"""Draw a new plot. | ||||
Clear the current plot and create a new 2-d plot containing | ||||
the specified items. Each arguments should be of the | ||||
following types: | ||||
'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most | ||||
flexible way to call plot because the PlotItems can | ||||
contain suboptions. Moreover, PlotItems can be saved to | ||||
variables so that their lifetime is longer than one plot | ||||
command; thus they can be replotted with minimal overhead. | ||||
'string' (e.g., 'sin(x)') -- The string is interpreted as | ||||
'Func(string)' (a function that is computed by gnuplot). | ||||
Anything else -- The object, which should be convertible to an | ||||
array, is passed to the 'Data' constructor, and thus | ||||
plotted as data. If the conversion fails, an exception is | ||||
raised. | ||||
This is a modified version of plot(). Compared to the original in | ||||
Gnuplot.py, this version has several enhancements, listed below. | ||||
Modifications to the input arguments | ||||
------------------------------------ | ||||
(1-d array means Numeric array, list or tuple): | ||||
(i) Any 1-d array which is NOT followed by another 1-d array, is | ||||
automatically zipped with range(len(array_1d)). Typing g.plot(y) will | ||||
plot y against its indices. | ||||
(ii) If two 1-d arrays are contiguous in the argument list, they are | ||||
automatically zipped together. So g.plot(x,y) plots y vs. x, and | ||||
g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2. | ||||
(iii) Any 1-d array which is followed by None is automatically zipped | ||||
with range(len(array_1d)). In this form, typing g.plot(y1,None,y2) | ||||
will plot both y1 and y2 against their respective indices (and NOT | ||||
versus one another). The None prevents zipping y1 and y2 together, and | ||||
since y2 is unpaired it is automatically zipped to its indices by (i) | ||||
(iv) Any other arguments which don't match these cases are left alone and | ||||
passed to the code below. | ||||
For lists or tuples, the heuristics used to determine whether they are | ||||
in fact 1-d is fairly simplistic: their first element is checked, and | ||||
if it is not a list or tuple itself, it is assumed that the whole | ||||
object is one-dimensional. | ||||
An additional optional keyword 'titles' has been added: it must be a | ||||
list of strings to be used as labels for the individual plots which | ||||
are NOT PlotItem objects (since those objects carry their own labels | ||||
within). | ||||
PostScript generation | ||||
--------------------- | ||||
This version of plot() also handles automatically the production of | ||||
PostScript output. The main options are (given as keyword arguments): | ||||
- filename: a string, typically ending in .eps. If given, the plot is | ||||
sent to this file in PostScript format. | ||||
- hardcopy: this can be set to 0 to override 'filename'. It does not | ||||
need to be given to produce PostScript, its purpose is to allow | ||||
switching PostScript output off globally in scripts without having to | ||||
manually change 'filename' values in multiple calls. | ||||
All other keywords accepted by Gnuplot.hardcopy() are transparently | ||||
passed, and safely ignored if output is sent to the screen instead of | ||||
PostScript. | ||||
For example: | ||||
In [1]: x=frange(0,2*pi,npts=100) | ||||
Generate a plot in file 'sin.eps': | ||||
In [2]: plot(x,sin(x),filename = 'sin.eps') | ||||
Plot to screen instead, without having to change the filename: | ||||
In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0) | ||||
Pass the 'color=0' option to hardcopy for monochrome output: | ||||
In [4]: plot(x,sin(x),filename = 'sin.eps',color=0) | ||||
PostScript generation through plot() is useful mainly for scripting | ||||
uses where you are not interested in interactive plotting. For | ||||
interactive use, the hardcopy() function is typically more convenient: | ||||
In [5]: plot(x,sin(x)) | ||||
In [6]: hardcopy('sin.eps') """ | ||||
self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw) | ||||
def plot2(self,arg,**kw): | ||||
"""Plot the entries of a dictionary or a list/tuple of arrays. | ||||
This simple utility calls plot() with a list of Gnuplot.Data objects | ||||
constructed either from the values of the input dictionary, or the entries | ||||
in it if it is a tuple or list. Each item gets labeled with the key/index | ||||
in the Gnuplot legend. | ||||
Each item is plotted by zipping it with a list of its indices. | ||||
Any keywords are passed directly to plot().""" | ||||
if hasattr(arg,'keys'): | ||||
keys = arg.keys() | ||||
keys.sort() | ||||
else: | ||||
keys = range(len(arg)) | ||||
pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys] | ||||
self.plot(*pitems,**kw) | ||||
def splot(self, *items, **keyw): | ||||
"""Draw a new three-dimensional plot. | ||||
Clear the current plot and create a new 3-d plot containing | ||||
the specified items. Arguments can be of the following types: | ||||
'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This | ||||
is the most flexible way to call plot because the | ||||
PlotItems can contain suboptions. Moreover, PlotItems can | ||||
be saved to variables so that their lifetime is longer | ||||
than one plot command--thus they can be replotted with | ||||
minimal overhead. | ||||
'string' (e.g., 'sin(x*y)') -- The string is interpreted as a | ||||
'Func()' (a function that is computed by gnuplot). | ||||
Anything else -- The object is converted to a Data() item, and | ||||
thus plotted as data. Note that each data point should | ||||
normally have at least three values associated with it | ||||
(i.e., x, y, and z). If the conversion fails, an | ||||
exception is raised. | ||||
This is a modified version of splot(). Compared to the original in | ||||
Gnuplot.py, this version has several enhancements, listed in the | ||||
plot() documentation. | ||||
""" | ||||
self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw) | ||||
def replot(self, *items, **keyw): | ||||
"""Replot the data, possibly adding new 'PlotItem's. | ||||
Replot the existing graph, using the items in the current | ||||
itemlist. If arguments are specified, they are interpreted as | ||||
additional items to be plotted alongside the existing items on | ||||
the same graph. See 'plot' for details. | ||||
If you want to replot to a postscript file, you MUST give the | ||||
'filename' keyword argument in each call to replot. The Gnuplot python | ||||
interface has no way of knowing that your previous call to | ||||
Gnuplot.plot() was meant for PostScript output.""" | ||||
self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw) | ||||
# The original hardcopy has a bug. See fix at the end. The rest of the code | ||||
# was lifted verbatim from the original, so that people using IPython get the | ||||
# benefits without having to manually patch Gnuplot.py | ||||
def hardcopy(self, filename=None, | ||||
mode=None, | ||||
eps=None, | ||||
enhanced=None, | ||||
color=None, | ||||
solid=None, | ||||
duplexing=None, | ||||
fontname=None, | ||||
fontsize=None, | ||||
debug = 0, | ||||
): | ||||
"""Create a hardcopy of the current plot. | ||||
Create a postscript hardcopy of the current plot to the | ||||
default printer (if configured) or to the specified filename. | ||||
Note that gnuplot remembers the postscript suboptions across | ||||
terminal changes. Therefore if you set, for example, color=1 | ||||
for one hardcopy then the next hardcopy will also be color | ||||
unless you explicitly choose color=0. Alternately you can | ||||
force all of the options to their defaults by setting | ||||
mode='default'. I consider this to be a bug in gnuplot. | ||||
Keyword arguments: | ||||
'filename=<string>' -- if a filename is specified, save the | ||||
output in that file; otherwise print it immediately | ||||
using the 'default_lpr' configuration option. If the | ||||
filename ends in '.eps', EPS mode is automatically | ||||
selected (like manually specifying eps=1 or mode='eps'). | ||||
'mode=<string>' -- set the postscript submode ('landscape', | ||||
'portrait', 'eps', or 'default'). The default is | ||||
to leave this option unspecified. | ||||
'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to | ||||
generate encapsulated postscript. | ||||
'enhanced=<bool>' -- if set (the default), then generate | ||||
enhanced postscript, which allows extra features like | ||||
font-switching, superscripts, and subscripts in axis | ||||
labels. (Some old gnuplot versions do not support | ||||
enhanced postscript; if this is the case set | ||||
gp.GnuplotOpts.prefer_enhanced_postscript=None.) | ||||
'color=<bool>' -- if set, create a plot with color. Default | ||||
is to leave this option unchanged. | ||||
'solid=<bool>' -- if set, force lines to be solid (i.e., not | ||||
dashed). | ||||
'duplexing=<string>' -- set duplexing option ('defaultplex', | ||||
'simplex', or 'duplex'). Only request double-sided | ||||
printing if your printer can handle it. Actually this | ||||
option is probably meaningless since hardcopy() can only | ||||
print a single plot at a time. | ||||
'fontname=<string>' -- set the default font to <string>, | ||||
which must be a valid postscript font. The default is | ||||
to leave this option unspecified. | ||||
'fontsize=<double>' -- set the default font size, in | ||||
postscript points. | ||||
'debug=<bool>' -- print extra debugging information (useful if | ||||
your PostScript files are misteriously not being created). | ||||
""" | ||||
if filename is None: | ||||
assert gp.GnuplotOpts.default_lpr is not None, \ | ||||
OptionException('default_lpr is not set, so you can only ' | ||||
'print to a file.') | ||||
filename = gp.GnuplotOpts.default_lpr | ||||
lpr_output = 1 | ||||
else: | ||||
if filename.endswith('.eps'): | ||||
eps = 1 | ||||
lpr_output = 0 | ||||
# Be careful processing the options. If the user didn't | ||||
# request an option explicitly, do not specify it on the 'set | ||||
# terminal' line (don't even specify the default value for the | ||||
# option). This is to avoid confusing older versions of | ||||
# gnuplot that do not support all of these options. The | ||||
# exception is 'enhanced', which is just too useful to have to | ||||
# specify each time! | ||||
setterm = ['set', 'terminal', 'postscript'] | ||||
if eps: | ||||
assert mode is None or mode=='eps', \ | ||||
OptionException('eps option and mode are incompatible') | ||||
setterm.append('eps') | ||||
else: | ||||
if mode is not None: | ||||
assert mode in ['landscape', 'portrait', 'eps', 'default'], \ | ||||
OptionException('illegal mode "%s"' % mode) | ||||
setterm.append(mode) | ||||
if enhanced is None: | ||||
enhanced = gp.GnuplotOpts.prefer_enhanced_postscript | ||||
if enhanced is not None: | ||||
if enhanced: setterm.append('enhanced') | ||||
else: setterm.append('noenhanced') | ||||
if color is not None: | ||||
if color: setterm.append('color') | ||||
else: setterm.append('monochrome') | ||||
if solid is not None: | ||||
if solid: setterm.append('solid') | ||||
else: setterm.append('dashed') | ||||
if duplexing is not None: | ||||
assert duplexing in ['defaultplex', 'simplex', 'duplex'], \ | ||||
OptionException('illegal duplexing mode "%s"' % duplexing) | ||||
setterm.append(duplexing) | ||||
if fontname is not None: | ||||
setterm.append('"%s"' % fontname) | ||||
if fontsize is not None: | ||||
setterm.append('%s' % fontsize) | ||||
self(string.join(setterm)) | ||||
self.set_string('output', filename) | ||||
# replot the current figure (to the printer): | ||||
self.refresh() | ||||
# fperez. Ugly kludge: often for some reason the file is NOT created | ||||
# and we must reissue the creation commands. I have no idea why! | ||||
if not lpr_output: | ||||
#print 'Hardcopy <%s>' % filename # dbg | ||||
maxtries = 20 | ||||
delay = 0.1 # delay (in seconds) between print attempts | ||||
for i in range(maxtries): | ||||
time.sleep(0.05) # safety, very small delay | ||||
if os.path.isfile(filename): | ||||
if debug: | ||||
print 'Hardcopy to file <%s> success at attempt #%s.' \ | ||||
% (filename,i+1) | ||||
break | ||||
time.sleep(delay) | ||||
# try again, issue all commands just in case | ||||
self(string.join(setterm)) | ||||
self.set_string('output', filename) | ||||
self.refresh() | ||||
if not os.path.isfile(filename): | ||||
print >> sys.stderr,'ERROR: Tried %s times and failed to '\ | ||||
'create hardcopy file `%s`' % (maxtries,filename) | ||||
# reset the terminal to its `default' setting: | ||||
self('set terminal %s' % gp.GnuplotOpts.default_term) | ||||
self.set_string('output') | ||||
#********************** End of file <Gnuplot2.py> ************************ | ||||