#!/usr/bin/python3
"""
A complete rewrite of grace_np.py, which was authored by Michael Haggerty
in 1999. This rewrite should provide the same features, while being
more pythonish, and able to run with both Python2 and Python3.
"""
from subprocess import Popen, PIPE
import sys, time
class GraceProcess:
"""Represents a running xmgrace program."""
def __init__(self, bufsize=-1, debug=0, fixedsize=None, ask=None, safe=True):
"""Start xmgrace, reading from a pipe that we control.
Parameters:
bufsize -- choose the size of the buffer used in the
communication. grace won't act on commands that
haven't been flushed from the buffer, but speed
should supposedly be better with some buffering.
The default is -1, which means the default buffering
inherited from the system; 0 means unbuffered,
1 means line-buffered, and bigger values mean
a buffer of apprimately that size.
debug -- when set, each command that is passed to xmgrace is
also echoed to stderr.
fixedsize -- if set to None, the grace window is
freely resizable (`-free'). Otherwise set to a
tuple, which will set the fixed size of the
grace canvas. (I don't know what units are
used.###)
ask -- if set, xmgrace will ask before doing `dangerous'
things, like overwriting a file or even clearing the
display. Default is not to ask.
safe -- True by default; if set, some operations are not
available and should trigger error messages, like
when saving a file
"""
self.debug = debug
self.fixedsize = fixedsize
self.ask = ask
self.safe = safe
cmd = ('xmgrace','-dpipe','-')
if self.fixedsize is None:
cmd = cmd + ('-free',)
else:
cmd = cmd + ('-fixed', repr(self.fixedsize[0]), repr(self.fixedsize[1]))
if self.ask is None:
cmd = cmd + ('-noask',)
if not self.safe:
cmd = cmd + ('-nosafe',)
self.p=Popen(cmd,
stdin=PIPE, stdout=PIPE, stderr=PIPE,
bufsize=bufsize,
universal_newlines=True)
def command(self, cmd):
"""
Issue a command to grace followed by a newline.
Unless Popen was called with bufsize=0 or 1, this
interface is buffered, and command execution may be delayed.
To flush the buffer, send the command via self(cmd), or call
self.flush()
@return stdout, stderr from the pipe
"""
if self.debug:
sys.stderr.write('Grace command: "%s"\n' % cmd)
self.p.stdin.write(cmd+"\n")
def flush(self):
"""
Flush the input buffer
"""
self.p.stdin.flush()
def __call__(self, cmd):
"""
Send the command to grace, then flush the write queue.
@return stdout, stderr from the pipe
"""
result = self.command(cmd)
self.p.stdin.flush()
return result
def __del__(self):
"""
kills the thread upon deletion
"""
self.p.kill()
def exit(self):
"""
self-deletion
"""
self.__del__()
if __name__=="__main__":
g=GraceProcess(debug=True, safe=False)
g('world xmax 100')
g('world ymax 10000')
g('xaxis tick major 20')
g('xaxis tick minor 10')
g('yaxis tick major 2000')
g('yaxis tick minor 1000')
g('s0 on')
g('s0 symbol 1')
g('s0 symbol size 0.3')
g('s0 symbol fill pattern 1')
g('s1 on')
g('s1 symbol 1')
g('s1 symbol size 0.3')
g('s1 symbol fill pattern 1')
# Display sample data
for i in range(1,101):
g('g0.s0 point %d, %d' % (i, i))
g('g0.s1 point %d, %d' % (i, i * i))
# Update the Grace display after every ten steps
if i % 10 == 0:
g('redraw')
# Wait a second, just to simulate some time needed for
# calculations. Your real application shouldn't wait.
time.sleep(0.2)
# Tell Grace to save the data:
g('saveall "sample.agr"')