ruby, gnuplot, x11

  • Thread starter Joel VanderWerf
  • Start date
J

Joel VanderWerf

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top