为什么这会解决matplotlib的'no $ DISPLAY环境'问题?

时间:2015-03-23 18:19:17

标签: python matplotlib x11

在我的桌面PC上运行使用matplotlib库的代码时,使用该行没有任何问题:

import matplotlib.pyplot as plt

远离代码,这是我实际使用绘图函数的地方。

如果我在服务器中运行代码,但只有在之前导入matplotlib 时才会运行,并强制它使用Agg后端。即,我必须在代码的开头添加以下行:

import matplotlib
# Force matplotlib to not use any Xwindows backend.
matplotlib.use('Agg')

(参见this answer解释这一点)。否则,代码将与TclError: no display name and no $DISPLAY environment variable一起崩溃(例如,请参阅this question。)

问题是:为什么我需要这样做?该解决方案运行良好,但我不知道为什么我不必在我的台式机上执行此操作,但我必须在服务器中运行代码。

1 个答案:

答案 0 :(得分:9)

X11遵循客户端/服务器模型,其中X服务器接受来自客户端应用程序的图形输出请求(例如交互式matplotlib会话),并从键盘,鼠标等发回用户输入。为了使此模型起作用,客户端应用程序需要知道将哪些X服务器发送给他们。这由$DISPLAY环境变量控制。如果要连接到远程X会话(例如通过SSH连接),则远程会话中的$DISPLAY变量需要指向本地X服务器。

$DISPLAY变量的结构如下:

hostname:displaynumber.screennumber

并非所有部件都可能存在 - 本地会话通常省略主机名,如果只有一个屏幕,也会省略屏幕编号。在笔记本电脑上的本地终端会话中,我的$DISPLAY看起来像这样:

alistair@laptop:~$ echo $DISPLAY
:0

如果远程服务器也支持X11,则可以在远程计算机上打开图形窗口,并使用X11 forwarding将它们显示在本地计算机上。对于SSH连接,您可以通过传递-X(或-Y)标志来执行此操作。

例如:

alistair@laptop:~$ ssh -X alistair@workstation.address.co.uk
alistair@workstation:~$ echo $DISPLAY
localhost:10.0

远程SSH服务器应该在您打开连接时正确设置$DISPLAY变量。在这种特殊情况下,localhost:10.0实际上是在远程计算机上运行的“代理”X11服务器,它监听显示器10并通过SSH连接将命令中继到本地X服务器(take a look at this如果你是对细节感兴趣。)

现在,您应该可以启动远程IPython会话,使用交互式后端导入matplotlib,并创建将在本地计算机上显示的绘图窗口。由于您的键盘/鼠标输入和显示输出现在通过加密的网络连接传递,因此绘图窗口的响应速度将低于您用于本地会话的响应速度。

另一个警告:如果你打开一个运行交互式matplotlib会话的IPython会话,就不可能在不杀死IPython进程的情况下关闭SSH连接。在开始导入matplotlib的长时间运行进程之前,我有时也会调用matplotlib.use("Agg") - 这样我就可以断开与远程服务器的连接而不会终止进程。