1

I'm running R (3.2.2) on a Debian Jessie VPS thanks to rpy2 (2.6.1) through Python (2.7.10).

I have a Flask (0.10.1) application launching R via rpy2 and then loading R package devEMF (2.0.0) to plot various graphics. The aim is to save vector images created thanks to devEMF.

My sample code is:

robjects.r(u'''
    suppressPackageStartupMessages(library(qgraph))
    suppressPackageStartupMessages(library(devEMF))

    emf(file =  "''' + pathToSaveGraphEmf + '''", bg = "white", width = 6.25, height = 5.21)
    attach(mtcars)
    plot(wt,mpg)
    dev.off()
''')

And I get the following error message:

/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py:106:   UserWarning: Error in axis(side = side, at = at, labels = labels, ...) :
  Can't open connection to X server to read font metric information.

  res = super(Function, self).__call__(*new_args, **new_kwargs)
/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py:106: UserWarning: In addition:
  res = super(Function, self).__call__(*new_args, **new_kwargs)
/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py:106: UserWarning: Warning message:

  res = super(Function, self).__call__(*new_args, **new_kwargs)
/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py:106: UserWarning: no DISPLAY variable so Tk is not available

  res = super(Function, self).__call__(*new_args, **new_kwargs)
[2016-01-21 20:03:18 +0000] [21430] [ERROR] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py", line 130, in handle
    self.handle_request(listener, req, client, addr)
  File "/usr/local/lib/python2.7/dist-packages/gunicorn/workers/sync.py", line 171, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask_cors/extension.py", line 110, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask_cors/extension.py", line 110, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python2.7/dist-packages/flask_classy.py", line 200, in proxy
    response = view(**request.view_args)
  File "/routines/routine2.py", line 124, in keyDriverAnalysis
    myCorrelationMatrix, rowName, colName = r2.getCorrelationGraph(myCorrelationMethod, myPreparedData, myGroupUserInput, myDependentVariable, myIndependentVariable, myPathToSaveGraph)
  File "../graph.py", line 194, in getCorrelationGraph
    ''')
  File "/usr/local/lib/python2.7/dist-packages/rpy2/robjects/__init__.py", line 317, in __call__
    res = self.eval(p)
  File "/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py", line 178, in __call__
    return super(SignatureTranslatedFunction, self).__call__(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/rpy2/robjects/functions.py", line 106, in __call__
    res = super(Function, self).__call__(*new_args, **new_kwargs)
RRuntimeError: Error in axis(side = side, at = at, labels = labels, ...) :
  Can't open connection to X server to read font metric information.

devEMF needs X11 and Xft (line 35), when not running on OSX or Windows, so I installed it. But now it is unable to connect to the X server. Certainly because the VPS has no GUI feature.

Hopefully I found this very helping SO question, and I understood that I should use virtual framebuffer X11 server.

I tried the advice from the SO question in a command line R session, and it worked ! (Now it outputs an empty file, but it was fully working two minutes ago. (I had downloaded the file, inserted is in an .xls file and my graph was openable and ungroupable.))

But now I have to make it work within rpy2.

I tried the second answer in the previously cited SO question, but it doesn't work because it gives a trick when X11 is problematic when loading but not needed then.

I think where I am now is: how do I launch an R session thanks to rpy2 that will use virtual framebuffer X11 server ?

EDIT0:

I think I found something useful here. It explains how to configure a Virtual Frame Buffer on headless unix servers.

EDIT1:

Eventually, what I have done:

  • Launch xvfb thanks to the command from the main environment, and bind it to the desired screen (1) (I don't reminder where I found this precise line, but well it can be analyzed thanks to the xvfb documentation):

    Xvfb :1 -screen 0 1024x768x16 &
    
  • Attach the tmux session, and export the DISPLAY environment variable linked to the correct screen (1):

    export DISPLAY=:1
    

And it works !

Important note: the environment variable should be set inside the session.

Also: I don't have the "launch at boot time" problem mentioned in the link from EDIT0, probably because I am on a VPS (the xvfb-run folder is still in tmp and it seems to run because I can plot and save in .emf ;-) )

Community
  • 1
  • 1
Pierre Cordier
  • 494
  • 3
  • 17
  • It's indeed going to be either start `Xvfb` as you point it out in your edit, or `xvfb-run python`. At least that's what I'd guess. – lgautier Jan 23 '16 at 01:03
  • I didn't think about `xvfb-run python` ! I use `gunicorn`, I guess I could do `xvfb-run gunicorn`, but I wonder if it would have a wrong impact on some other features of the app. Otherwise, I run the `Flask` application in a `tmux` session which is never killed, so i think I can start `Xvfb` only once in this session, and this might be the best solution. I'll try and give feedback about this. – Pierre Cordier Jan 25 '16 at 09:55

0 Answers0