Non-X11 fallback on import

I have a script that uses matplotlib to plot graphs both displayed as
a GUI and as PDF documents. The script may need to be run from remote
terminals without X11-passthrough so they way I would like it to work
is to use the default backend if X is available and, otherwise, fall
back to using the Agg backend. How can I do this?

I've been trying to catch a RuntimeError and then retry with a
different backend but part of matplotlib remains loaded and won't let
me change backend:

try:
   import matplotlib.pyplot as plt
except RuntimeError:
   # retry import but without GUI capability
   import matplotlib
   plt.use('Agg')
   import matplotlib.pyplot as plt

Has anyone managed this?

Many thanks.

Alex

Alexander Lamaison wrote:

I would like it to work
is to use the default backend if X is available and, otherwise, fall
back to using the Agg backend. How can I do this?

I had a similar need a good while back with wxPython. I found some C code on the net that tries to connect to an X server and fails gracefully if it can't. I also wrote a Python wrapper around it. I haven't used it for years, and can't even find it on my machine, but thanks to the glory of archives and google, here it is:

http://osdir.com/ml/python.wxpython/2004-03/msg00294.html

You'd use it like:

import matplotlib
import isX

if isX.isX:
     matplotlib.use("wxGTK") or whatever..
else:
     matplotlib.use("AGG")

note that you can also just check and see if the "DISPLAY" environment variable is set, but that won't be as reliable.

However, as the whole user interaction has to be totally different, I wonder if you can't just have a different start-up script depending on whether they want to run the GUI version or not.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...

FYI I just went through this w/ an application of ours. There is no easy way to handle this. You can do this:

Display* disp = XOpenDisplay( 0 );
if ( ! disp )
{
   // no DISPLAY variable is set - no x connection
}

However, if the DISPLAY variable is set but doesn't point to a usable x-server (or it can't connect to the x-server), this will actually call halt/exit inside the X library. The X library has this coded as the standard error behavior. You can set a custom X11 IO error handler but it's kind of worthless because if the error handler ever returns, the X11 library will exit. The work around is to do a setjmp/longjump call in the error handler.

Here's the resulting code we use to check for a valid x-server connection. We actually trap 3 different conditions (success, no display, display but can't connect). You modify this a little bit if you just wanted to check for a valid display.

···

====================================
#include <X11/Xlib.h>
#include <setjmp.h>

static jmp_buf s_displayJumpBuf;

static int s_xIOhandler( Display* disp )
{
   // Jump back to the status function.
   longjmp( s_displayJumpBuf, 1 );
   return 0;
}

int serverStatus()
{
   typedef int (*ErrorHandler)( Display* display );
   
   // Initial execution path. setjmp() returns 0 to begin with. If
   // XOpenDisplay fails and calls the error handler, then execution
   // will resume here but with a non-zero return value.
   if ( setjmp( s_displayJumpBuf ) == 0 )
   {
      // Set our handler and try to open the display.
      ErrorHandler prevHandler = XSetIOErrorHandler( s_xIOhandler );
   
      Display* disp = XOpenDisplay( 0 );

      // Restore the previous handler.
      XSetIOErrorHandler( prevHandler );

      // Success - valid X11 display.
      if ( disp )
      {
         return 0;
      }
      // DISPLAY env variable not set.
      return -1;
   }
   else
   {
      // X11 IO error indicates that a DISPLAY variable was set but
      // that it's invalid.
      return -2;
   }
}

-----Original Message-----
From: Christopher Barker [mailto:Chris.Barker@…259…]
Sent: Monday, June 01, 2009 11:45 AM
To: matplotlib-users@lists.sourceforge.net
Subject: Re: [Matplotlib-users] Non-X11 fallback on import

Alexander Lamaison wrote:
> I would like it to work
> is to use the default backend if X is available and, otherwise, fall
> back to using the Agg backend. How can I do this?

I had a similar need a good while back with wxPython. I found some C
code on the net that tries to connect to an X server and fails
gracefully if it can't. I also wrote a Python wrapper around it. I
haven't used it for years, and can't even find it on my machine, but
thanks to the glory of archives and google, here it is:

http://osdir.com/ml/python.wxpython/2004-03/msg00294.html

You'd use it like:

import matplotlib
import isX

if isX.isX:
     matplotlib.use("wxGTK") or whatever..
else:
     matplotlib.use("AGG")

note that you can also just check and see if the "DISPLAY" environment
variable is set, but that won't be as reliable.

However, as the whole user interaction has to be totally different, I
wonder if you can't just have a different start-up script depending on
whether they want to run the GUI version or not.

-Chris

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...

-----------------------------------------------------------------------
-------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity
professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, &
iPhoneDevCamp as they present alongside digital heavyweights like
Barbarian
Group, R/GA, & Big Spaceship. http://p.sf.net/sfu/creativitycat-com
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users