Ruby, gnuplot, x11

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