Как запустить сеанс R с rpy2, который будет использовать сервер виртуального фреймбуфера X11

Я использую R (3.2.2) на Debian Jessie VPS благодаря версиям с rpy2 (2.6.1) по Python (2.7.10).

У меня есть приложение Flask (0.10.1), запускающее R через rpy2, а затем загружающее R пакет devEMF (2.0.0) для построения различных графиков. Цель состоит в том, чтобы сохранить векторные изображения, созданные благодаря devEMF.

Мой пример кода:

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()
''')

И я получаю следующее сообщение об ошибке:

/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 требуется X11 и Xft (строка 35), если нет работает на OSX или Windows, поэтому я установил его. Но теперь он не может подключиться к X-серверу. Конечно, потому что VPS не имеет функции графического интерфейса.

Надеюсь, это очень помогло ТАК вопрос, и я понял, что должен использовать виртуальный фреймбуфер X11 сервера.

Я попробовал совет из ТАК вопрос в командной строке R сессия, и это сработало! (Сейчас он выводит пустой файл, но две минуты назад он полностью работал. (Я скачал файл, вставил его в файл .xls, и мой график был открываемым и разгруппируемым.))

Но теперь я должен заставить его работать в пределах rpy2.

Я попробовал второй ответ в ранее процитированном ТАК вопрос, но он не работает, потому что он дает трюк, когда X11 проблематично при загрузке, но тогда он не нужен.

Я думаю, что сейчас я нахожусь: как мне запустить сеанс R благодаря rpy2, который будет использовать virtual framebuffer X11 server?

РЕДАКТИРОВАТЬ0:

Кажется, я нашел что-то полезное здесь. В нем объясняется, как настроить виртуальный буфер кадров на безголовых серверах Unix.

РЕДАКТИРОВАТЬ1:

В итоге что я сделал:

  • Запустите xvfb благодаря команде из основного окружения и привяжите его к нужному экрану (1) (не вспомню, где нашел именно эту строчку, но хорошо ее можно проанализировать благодаря тегу xvfb документация):

    Xvfb :1 -screen 0 1024x768x16 &
    
  • Присоедините сеанс tmux и экспортируйте переменную среды DISPLAY, связанную с правильным экраном (1):

    export DISPLAY=:1
    

И это работает!

Важное примечание: переменная среды должна быть установлена ​​внутри сеанса.

Кроме того: у меня нет проблемы «запуска во время загрузки», упомянутой в ссылке из EDIT0, вероятно, потому, что я нахожусь на VPS (папка xvfb-run все еще находится в tmp, и кажется, что она запускается, потому что я могу рисовать и сохранять в . ЭДС ;-))


person Pierre Cordier    schedule 21.01.2016    source источник
comment
Это действительно будет либо начало Xvfb, как вы указываете в своем редактировании, либо xvfb-run python. По крайней мере, я так думаю.   -  person lgautier    schedule 23.01.2016
comment
Я не думал о xvfb-run python ! Я использую gunicorn, думаю, я мог бы сделать xvfb-run gunicorn, но мне интересно, не окажет ли это неправильное влияние на некоторые другие функции приложения. В противном случае я запускаю приложение Flask в сеансе tmux, который никогда не завершается, поэтому я думаю, что могу запустить Xvfb только один раз в этом сеансе, и это может быть лучшим решением. Я постараюсь дать отзыв об этом.   -  person Pierre Cordier    schedule 25.01.2016