views:

383

answers:

4

Hi there, I have to VPN and then ssh from home to my work server and want to run a python script in the background, then log out of the ssh session. My script makes several histogram plots using matplotlib, and as long as I keep the connection open everything is fine, but if I log out I keep getting an error message in the log file I created for the script.

 File "/Home/eud/jmcohen/.local/lib/python2.5/site-packages/matplotlib/pyplot.py", line 2058, in loglog
    ax = gca()
  File "/Home/eud/jmcohen/.local/lib/python2.5/site-packages/matplotlib/pyplot.py", line 582, in gca
    ax =  gcf().gca(**kwargs)
  File "/Home/eud/jmcohen/.local/lib/python2.5/site-packages/matplotlib/pyplot.py", line 276, in gcf
    return figure()
  File "/Home/eud/jmcohen/.local/lib/python2.5/site-packages/matplotlib/pyplot.py", line 254, in figure
    **kwargs)
  File "/Home/eud/jmcohen/.local/lib/python2.5/site-packages/matplotlib/backends/backend_tkagg.py", line 90, in new_figure_manager
    window = Tk.Tk()
  File "/Home/eud/jmcohen/.local/lib/python2.5/lib-tk/Tkinter.py", line 1647, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: couldn't connect to display "localhost:10.0"

I'm assuming that it doesn't know where to create the figures I want since I close my X11 ssh session. If I'm logged in while the script is running I don't see any figures popping up (although that's because I don't have the show() command in my script), and I thought that python uses tkinter to display figures. The way that I'm creating the figures is,

loglog()
hist(list,x)
ylabel('y')
xlabel('x')
savefig('%s_hist.ps' %source.name)
close()

The script requires some initial input, so the way I'm running it in the background is

python scriptToRun.py << start>& logfile.log&

Is there a way around this, or do I just have to stay ssh'd into my machine?

Thanks.

A: 

If you are running on a *nix OS the problem is your session is terminated and all processes requiring a session are also terminated when you disconnect. More specifically all your processes are sent a SIGHUP (signal hang-up). The default handling of SITHUP is to terminate the process. If you want you script to continue it needs to ignore the signal. The easiest way to do that assuming you start your script via the command line it to run it using the nohup command:

nohup python scriptToRun.py << start>& logfile.log&

nohup normally sends standard out and standard error to the file nohup.out in the current directory. Since you're redirecting already output nohup.out will not be created.

Robert Menteer
his problem is due to X11 connection failing.
aaa
Adding nohup to the beginning didn't seem to do anything, got the same error message.
Jamie
A: 

I believe your matplotlib backend requires X11. Look in your matplotlibrc file to determine what your default is (from the error, I'm betting TkAgg). To run without X11, use the Agg backend. Either set it globally in the matplotlibrc file or on a script by script by adding this to the python program:

import matplotlib
matplotlib.use('Agg')
Mark
I added that line to the beginning of my program but still get the same error message.
Jamie
+2  A: 

Sorry if this is a stupid answer, but if you're just running a console session, would 'screen' not suffice? Detachable sessions, etc.

Andrew Bolster
This might be a stupid reply to your possibly stupid question :)What do you mean by console session, 'screen', and detachable session?The way I'm running this is I'm home on my OS X machine VPN then SSH via terminal into my linux box at work.
Jamie
@Jamie, the unix screen command allows you to detach from your terminal and then re-attach later. Once you are at the terminal prompt, type screen, launch your program. Now just close out of your SSH client. Next time your reconnect on that box, type "screen -R" and you are back to where you left off. Of course, see the screen manpage for lots more details.
Mark
@Mark- Oh cool, that sound like it can be really useful.
Jamie
+1  A: 

It looks like you're running in interactive mode by default, so matplotlib wants to plot everything to the screen first, which of course it can't do.

Try putting

ioff()

at the top of your script, along with making the backend change.

Vicki Laidler
Awesome, that did the job. Thanks so much!
Jamie