|
|
# -*- 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
|
|
|
"""
|
|
|
|
|
|
import cStringIO
|
|
|
import os
|
|
|
import string
|
|
|
import sys
|
|
|
import tempfile
|
|
|
import time
|
|
|
import types
|
|
|
|
|
|
import Gnuplot as Gnuplot_ori
|
|
|
import Numeric
|
|
|
|
|
|
from IPython.utils.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
|
|
|
|
|
|
elif Gnuplot_ori.__version__ =='1.7':
|
|
|
_FileClass = _BaseFileItem = PlotItems._FileItem
|
|
|
_BaseTempFileItem = PlotItems._TempFileItem
|
|
|
File = PlotItems.File
|
|
|
|
|
|
else: # changes in the newer version (svn as of March'06)
|
|
|
_FileClass = _BaseFileItem = PlotItems._FileItem
|
|
|
_BaseTempFileItem = PlotItems._NewFileItem
|
|
|
File = PlotItems.File
|
|
|
|
|
|
|
|
|
# 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> ************************
|
|
|
|