未定义 DISPLAY 时使用 matplotlib 生成 PNG

Posted

技术标签:

【中文标题】未定义 DISPLAY 时使用 matplotlib 生成 PNG【英文标题】:Generating a PNG with matplotlib when DISPLAY is undefined 【发布时间】:2011-02-17 14:46:46 【问题描述】:

我正在尝试将 networkx 与 Python 一起使用。当我运行这个程序时,它会出现这个错误。有什么遗漏吗?

#!/usr/bin/env python

import networkx as nx
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt

G=nx.Graph()
G.add_node(1)
G.add_nodes_from([2,3,4,5,6,7,8,9,10])
#nx.draw_graphviz(G)
#nx_write_dot(G, 'node.png')
nx.draw(G)
plt.savefig("/var/www/node.png")


Traceback (most recent call last):
  File "graph.py", line 13, in <module>
    nx.draw(G)
  File "/usr/lib/pymodules/python2.5/networkx/drawing/nx_pylab.py", line 124, in draw
    cf=pylab.gcf()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 276, in gcf
    return figure()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 254, in figure
    **kwargs)
  File "/usr/lib/pymodules/python2.5/matplotlib/backends/backend_tkagg.py", line 90, in new_figure_manager
    window = Tk.Tk()
  File "/usr/lib/python2.5/lib-tk/Tkinter.py", line 1650, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

我现在得到一个不同的错误:

#!/usr/bin/env python

import networkx as nx
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt

matplotlib.use('Agg')

G=nx.Graph()
G.add_node(1)
G.add_nodes_from([2,3,4,5,6,7,8,9,10])
#nx.draw_graphviz(G)
#nx_write_dot(G, 'node.png')
nx.draw(G)
plt.savefig("/var/www/node.png")

/usr/lib/pymodules/python2.5/matplotlib/__init__.py:835: UserWarning:  This call to matplotlib.use() has no effect
because the the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

  if warn: warnings.warn(_use_error_msg)
Traceback (most recent call last):
  File "graph.py", line 15, in <module>
    nx.draw(G)
  File "/usr/lib/python2.5/site-packages/networkx-1.2.dev-py2.5.egg/networkx/drawing/nx_pylab.py", line 124, in draw
    cf=pylab.gcf()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 276, in gcf
    return figure()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 254, in figure
    **kwargs)
  File "/usr/lib/pymodules/python2.5/matplotlib/backends/backend_tkagg.py", line 90, in new_figure_manager
    window = Tk.Tk()
  File "/usr/lib/python2.5/lib-tk/Tkinter.py", line 1650, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

我现在得到一个不同的错误:

#!/usr/bin/env python

import networkx as nx
import matplotlib
import matplotlib.pyplot
import matplotlib.pyplot as plt

matplotlib.use('Agg')

G=nx.Graph()
G.add_node(1)
G.add_nodes_from([2,3,4,5,6,7,8,9,10])
#nx.draw_graphviz(G)
#nx_write_dot(G, 'node.png')
nx.draw(G)
plt.savefig("/var/www/node.png")

/usr/lib/pymodules/python2.5/matplotlib/__init__.py:835: UserWarning:  This call to matplotlib.use() has no effect
because the the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

  if warn: warnings.warn(_use_error_msg)
Traceback (most recent call last):
  File "graph.py", line 15, in <module>
    nx.draw(G)
  File "/usr/lib/python2.5/site-packages/networkx-1.2.dev-py2.5.egg/networkx/drawing/nx_pylab.py", line 124, in draw
    cf=pylab.gcf()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 276, in gcf
    return figure()
  File "/usr/lib/pymodules/python2.5/matplotlib/pyplot.py", line 254, in figure
    **kwargs)
  File "/usr/lib/pymodules/python2.5/matplotlib/backends/backend_tkagg.py", line 90, in new_figure_manager
    window = Tk.Tk()
  File "/usr/lib/python2.5/lib-tk/Tkinter.py", line 1650, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable

【问题讨论】:

Generating matplotlib graphs without a running X server的可能重复 将对 matplotlib.use('Agg') 的调用移至其他导入的上方,特别是它应该在导入 matplotlib.pyplot 之前 @IvoBosticky 评论也为我解决了这个问题:唯一具有误导性的是“高于你的其他进口”。很明显,您需要先导入 matplotlib... 这是对我有用的整个设置: import matplotlib // matplotlib.use('Agg') // import matplotlib.pyplot as plt 【参考方案1】:

主要问题是(在您的系统上)matplotlib 默认选择使用 x 的后端。我只是在我的一台服务器上遇到了同样的问题。我的解决方案是将以下代码添加到任何其他 pylab/matplotlib/pyplot 导入之前读取的位置:

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

另一种方法是在你的 .matplotlibrc 中设置它

【讨论】:

重要提示:在导入pyplot之前需要调用.use。因此,例如,如果您只是尝试导入 pyplot,则需要先导入 matplotlib,调用 use,然后再导入 pyplot。 以上评论由this answer解释更多。 你如何“在你的 .matplotlibrc 中设置它”? backend: agg in ~/.config/matplotlib'/matplotlibrc(例如,参见 http://matplotlib.org/faq/troubleshooting_faq.html#locating-matplotlib-config-dir)。另请参阅matplotlib.org/users/customizing.html,页面底部有一个示例配置文件。在该页面上找到“agg”,您将看到所需的配置选项。 作为参考,here is the link 到解释这一点的 matplotlib 文档。 (+1,很好的答案,完美地帮助了我!)【参考方案2】:

作为 Reinout 答案的补充。

解决此类问题的永久方法是编辑 .matplotlibrc 文件。通过

找到它
>>> import matplotlib>>> matplotlib.matplotlib_fname()
# This is the file location in Ubuntu
'/etc/matplotlibrc'

然后将该文件中的后端修改为backend : Agg。就是这样。

【讨论】:

专业提示:将$MATPLOTLIBRC 设置为目录,您希望将自己的matplotlibrc 放入其中。 对于这样的问题有点矫枉过正,但我​​想如果服务器总是无头工作,那么修改配置文件是有意义的。这会对 matplotlib 的运行方式产生任何副作用吗? 我在 Web 服务器上运行 matplotlib,所以这就是我的答案。我没有注意到任何副作用。【参考方案3】:

正确的答案是花一点时间正确准备您的执行环境。

准备执行环境的第一个技巧是使用matplotlibrc 文件,as wisely recommended by Chris Q.,设置

backend : Agg

在那个文件中。您甚至可以控制——无需更改代码——how and where matplotlib looks for and finds the matplotlibrc file。

准备执行环境的第二个技巧是使用MPLBACKEND environment variable(并通知您的用户使用它):

export MPLBACKEND="agg"
python <program_using_matplotlib.py>

这很方便,因为您甚至不必在磁盘上提供另一个文件来完成这项工作。例如,我已将这种方法用于持续集成中的测试,以及在没有显示器的远程机器上运行。

在 Python 代码中将 matplotlib 后端硬编码为“Agg”就像用大锤子将方形钉子敲入圆孔,而相反,您可能只是告诉 matplotlib 它需要是一个方形孔。

【讨论】:

第二种技术在这种情况下看起来是最优雅的。 使用 MPLBACKEND 为我解决了这个问题。绝对是最优雅的方式!【参考方案4】:

我在通过 Spark 使用 matplotlib 时遇到错误。 matplotlib.use('Agg') 对我不起作用。最后,以下代码对我有用。更多here

import matplotlib.pyplot as plt.
plt.switch_backend('agg')

【讨论】:

这很好用,对导入 matplotlib 和其他库的顺序没有限制。 在 Spark 上运行时,您是否必须将其限制为在头节点上运行,还是在工作节点上运行时使其正常工作? 我在一个 django 项目中使用它,这是我让它工作的唯一方法。【参考方案5】:

我将重复@Ivo Bosticky 所说的可以忽略的内容。将这些行放在 py 文件的 VERY 开头。

import matplotlib
matplotlib.use('Agg') 

否则会出错

*/usr/lib/pymodules/python2.7/matplotlib/__init__.py:923:用户警告:对 matplotlib.use() 的调用无效 因为已经选择了后端; matplotlib.use() 必须在*pylab、matplotlib.pyplot、*之前调用

这将解决所有显示问题

【讨论】:

【参考方案6】:

我发现这个 sn-p 在 X 和 no-X 环境之间切换时效果很好。

import os
import matplotlib as mpl
if os.environ.get('DISPLAY','') == '':
    print('no display found. Using non-interactive Agg backend')
    mpl.use('Agg')
import matplotlib.pyplot as plt

【讨论】:

在我看来,这是一个比接受的解决方案更好的解决方案,尽管它不直接回答问题,而是回答未提出的问题。【参考方案7】:

登录服务器执行代码时 改用这个:

ssh -X username@servername

-X 将去掉 no display name 和 no $DISPLAY 环境变量 错误

:)

【讨论】:

我需要使用 '-X' 来保存 .png 图像。非常感谢。 如果 ssh 超时,或者由于任何原因需要断开连接,这将在很长的过程中失败。请注意,如果连接的客户端进入睡眠状态,甚至可能发生超时。 您可以通过添加 -o ServerAliveCountMax=120 -o ServerAliveInterval=30 来防止超时,这将使 ssh 客户端每 30 秒发送一个空数据包,最长 1 小时。【参考方案8】:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

它对我有用。

【讨论】:

【参考方案9】:

你在什么系统上?看起来您有一个带有 X11 的系统,但是 DISPLAY 环境变量没有正确设置。尝试执行以下命令,然后重新运行您的程序:

export DISPLAY=localhost:0

【讨论】:

但是为什么它需要设置一个显示变量,我远程登录到这个服务器,它应该做的就是生成一个PNG文件??? @krisdigitx,如果你是远程连接的,不要设置显示变量;而是在连接时使用“-XY”标志。为了显示,它需要知道将图像发送到哪个 Xserver;在这种情况下,它将是您计算机的显示器,而不是远程计算机。使用“-XY”标志会导致 SSH 自动设置 DISPLAY 变量以指向连接计算机的显示器。 @krisdigitx,我同意,这样做很奇怪;不过,我的猜测是它使用 X11 绘制图像,然后使用 X11 保存结果。 对 $DISPLAY 使用此设置在运行 Ubuntu 16 的 EC2 上不起作用——无法连接以显示“localhost:0”【参考方案10】:

要检查的另一件事是您的当前用户是否有权连接到 X 显示器。在我的情况下,不允许 root 这样做,并且 matplotlib 抱怨同样的错误。

user@debian:~$ xauth list         
debian/unix:10  MIT-MAGIC-COOKIE-1  ae921efd0026c6fc9d62a8963acdcca0
root@debian:~# xauth add debian/unix:10  MIT-MAGIC-COOKIE-1 ae921efd0026c6fc9d62a8963acdcca0
root@debian:~# xterm

来源:http://www.debian-administration.org/articles/494https://debian-administration.org/article/494/Getting_X11_forwarding_through_ssh_working_after_running_su

【讨论】:

【参考方案11】:

为确保您的代码可在 Windows、Linux 和 OSX 以及有和没有显示器的系统上移植,我建议遵循 sn-p:

import matplotlib
import os
# must be before importing matplotlib.pyplot or pylab!
if os.name == 'posix' and "DISPLAY" not in os.environ:
    matplotlib.use('Agg')

# now import other things from matplotlib
import matplotlib.pyplot as plt

信用:https://***.com/a/45756291/207661

【讨论】:

【参考方案12】:

对于谷歌云机器学习引擎:

import matplotlib as mpl
mpl.use('Agg')
from matplotlib.backends.backend_pdf import PdfPages

然后打印到文件:

#PDF build and save
    def multi_page(filename, figs=None, dpi=200):
        pp = PdfPages(filename)
        if figs is None:
            figs = [mpl.pyplot.figure(n) for n in mpl.pyplot.get_fignums()]
        for fig in figs:
            fig.savefig(pp, format='pdf', bbox_inches='tight', fig_size=(10, 8))
        pp.close()

并创建 PDF:

multi_page(report_name)

【讨论】:

以上是关于未定义 DISPLAY 时使用 matplotlib 生成 PNG的主要内容,如果未能解决你的问题,请参考以下文章

使用内连接 SQL 语句时未定义的索引

STM32“未定义对‘HAL_DELAY’的引用”

什么是“ReferenceError:错误 #1065:未定义变量 qnx.display::IowWindow”?

使用 matplot 的熊猫在 x 轴日期上显示不正确的年份

未使用 ssh 设置 $DISPLAY 环境 [关闭]

VNC未设置display参数错误导致Oracle安装报错