在我的桌面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。)
问题是:为什么我需要这样做?该解决方案运行良好,但我不知道为什么我不必在我的台式机上执行此操作,但我必须在服务器中运行代码。
答案 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")
- 这样我就可以断开与远程服务器的连接而不会终止进程。