This is a workaround for a minor annoyance in driving gnuplot from ruby
(or from anything else for that matter), and I’m posting it here for
posterity. Hope it helps someone. Sorry if it’s a bit OT…
The scenario is this: you’re developing a tool that sometimes pops up a
graph window (or three) for the user to look at and close when desired.
You’d like that window to stay alive until the user closes it
(preferably, even if the main tool itself has exited). When the user
closes it, you’d like to clean up the processes that manage it.
The problem is this: there’s no way in gnuplot to detect that the user
has closed the window (using ‘q’ or the close box), so cleanup becomes
problematic. You either time out the child process arbitrarily (yuck) or
use the “-persist” option (which disables mouse interaction), or just
leave those processes running (which may keep tempfiles around, too).
(See 7.9 of the Gnuplot FAQ.) Not good alternatives. The last of the
three is used in the first part of my example below.
(I don’t think the ruby-gnuplot gem solves this problem.)
Anyway, here’s my X11 solution. It works by managing the window title
and the periodically querying the X server to see if that title is still
around. Windows or OSX will have to be handled differently, probably.
------- gp-x11-prob.rb -------
This solves the problem on xwindows in which closing a gnuplot
window doesn’t exit the controlling process, and so you end up
with lots of idle gnuplot processes, which have to be killed
manually. The problem can be seen in the following simplistic
attempt to spawn a process to manage a gnuplot session. It works
as far as setting up a process that keeps gnuplot alive.
However, gnuplot has no way of notifying the controlling process
that the window has been closed by the user either using the “q”
key or clicking in the close box. As long as the pipe remains
open, gnuplot awaits more commands (as it should), but we cannot
close the pipe because we don’t know the user is done with the
session. This is more of an issue for tools that wrap gnuplot
rather than for direct command line use. A long-living gui can
easily spawn hundreds of these processes.
The ‘gnuplot -persist’ option also solves this process problem
but is not very useful because it disables mouse interaction.
Run like this to see the problem:
ruby gp-x11-prob.rb bad
Then close the window. To stop the gnuplot processes you will
have to kill the gnuplot process.
Run like this to use the workaround
ruby gp-x11-prob.rb
Within 5 sec after closing the window, the gnuplot process
is gone!
ps -f | grep gnuplot
if ARGV[0] == “bad”
fork do
trap “CLD” do exit end
# doesn’t normally happen, even on “q” keypress or window
# close event so this isn’t a way to tell that user has
# finished and we can close pipe
gp = IO.popen("gnuplot", "w")
gp.sync = true
gp.puts "plot '-' w l\n1 2\n3 4\ne\n"
# inline data, but could just as well be file
sleep
end
exit
end
The workaround uses xwindows tools to check whether the plot
window has been closed. This assumes that assume fork works (so,
not win32), and that we’re on X windows and we have xprop (or
xwininfo) program (so, not OSX native GUI)
fork do
gnuplot_counter = 0
gp = IO.popen(“gnuplot”, “w”)
gp.sync = true
uniqname = “Gnuplot_#{Process.pid}_#{gnuplot_counter+=1}”
gp.puts “set term x11 title #{uniqname}”
gp.puts “plot ‘-’ w l\n1 2\n3 4\ne\n”
loop do
sleep 5
rslt = system(
“xprop -name #{uniqname} WM_STATE 1>/dev/null 2>/dev/null”)
break unless rslt
end
end