Tạo một PNG với matplotlib khi HIỂN THỊ không xác định


319

Tôi đang cố gắng sử dụng networkx với Python. Khi tôi chạy chương trình này, nó nhận được lỗi này. Có thiếu gì không?

#!/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

Bây giờ tôi gặp một lỗi khác:

#!/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

Bây giờ tôi gặp một lỗi khác:

#!/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


9
Di chuyển cuộc gọi đến matplotlib.use ('Agg') phía trên các mục nhập khác của bạn, đặc biệt là trước khi nhập matplotlib.pyplot
Ivo Bosticky vào

Nhận xét @IvoBosticky cũng đã giải quyết nó cho tôi: Điều duy nhất gây hiểu lầm là "trên các hàng nhập khẩu khác của bạn". Rõ ràng là bạn cần nhập matplotlib trước ... Đây là toàn bộ cài đặt phù hợp với tôi: nhập matplotlib // matplotlib.use ('Agg') // nhập matplotlib.pyplot dưới dạng plt
mrk

Câu trả lời:


518

Vấn đề chính là (trên hệ thống của bạn) matplotlib chọn một phụ trợ x sử dụng theo mặc định. Tôi chỉ gặp vấn đề tương tự trên một trong các máy chủ của mình. Giải pháp cho tôi là thêm đoạn mã sau vào nơi được đọc trước khi nhập bất kỳ pylab / matplotlib / pyplot nào khác :

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

Cách khác là đặt nó trong .matplotlibrc của bạn


182
Lưu ý quan trọng: .use cần được gọi trước khi nhập pyplot. Vì vậy, nếu bạn đang cố gắng nhập pyplot, trước tiên bạn cần nhập matplotlib, sử dụng cuộc gọi và hơn là nhập pyplot.
seaotternerd

8
Nhận xét trên được giải thích nhiều hơn bởi câu trả lời này .
Ioannis Filippidis

2
Làm thế nào để bạn "thiết lập nó trong .matplotlibrc" của bạn?
tommy.carstensen

18
backend: aggtrong ~/.config/matplotlib'/matplotlibrc(như một ví dụ, xemhttp: //matplotlib.org/faq/troubledh Boot_faq.html#locating-matplotlib-config-dir). Xem thêm matplotlib.org/users/customizing.html , có tệp cấu hình ví dụ ở cuối trang. Tìm "agg" trên trang đó và bạn sẽ thấy tùy chọn cấu hình bạn cần.
Tái tạo van Rees

4
Để tham khảo, đây là liên kết đến tài liệu matplotlib giải thích điều này. (+1, câu trả lời tuyệt vời, đã giúp tôi hoàn hảo!)
Tim S.

72

Cũng như một phần bổ sung cho câu trả lời của Rebout.

Cách vĩnh viễn để giải quyết loại vấn đề này là chỉnh sửa tệp .matplotlibrc. Tìm nó qua

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

Sau đó sửa đổi phụ trợ trong tập tin đó thành backend : Agg. Thế là xong.


5
Mẹo chuyên nghiệp: được đặt $MATPLOTLIBRCvào thư mục mà bạn muốn ném matplotlibrc của riêng mình vào.
Kenneth Hoste

Có thể quá mức cho một vấn đề như thế này, nhưng tôi đoán rằng nếu máy chủ luôn hoạt động không đầu thì việc sửa đổi tệp cấu hình là điều hợp lý. Điều này sẽ có bất kỳ tác dụng phụ nào về cách matplotlib sẽ hoạt động?
BruceJohnJennerLawso

Tôi đang chạy matplotlib trên máy chủ web nên đây là câu trả lời cho tôi. Tôi đã không nhận thấy bất kỳ tác dụng phụ.
Spitz

42

Câu trả lời rõ ràng là dành một chút thời gian chuẩn bị chính xác môi trường thực thi của bạn.

Kỹ thuật đầu tiên bạn phải chuẩn bị môi trường thực thi của mình là sử dụng một matplotlibrctệp, theo khuyến cáo khôn ngoan của Chris Q. , cài đặt

backend : Agg

trong tập tin đó Bạn thậm chí có thể kiểm soát - không có thay đổi mã - cách thức và nơi matplotlib tìm và tìm matplotlibrctệp .

Kỹ thuật thứ hai bạn phải chuẩn bị môi trường thực thi của mình là sử dụng MPLBACKENDbiến môi trường (và thông báo cho người dùng của bạn để sử dụng nó):

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

Điều này rất hữu ích vì bạn thậm chí không phải cung cấp một tệp khác trên đĩa để thực hiện công việc này. Tôi đã sử dụng phương pháp này với, ví dụ, thử nghiệm tích hợp liên tục và chạy trên các máy từ xa không có màn hình.

Mã hóa cứng phần phụ trợ matplotlib của bạn thành "Agg" trong mã Python của bạn giống như đâm một cái chốt vuông vào một cái lỗ tròn bằng một cái búa lớn, thay vào đó, khi đó, bạn có thể vừa nói với matplotlib rằng nó cần phải là một lỗ vuông.


Kỹ thuật thứ hai trông giống như thanh lịch nhất trong tình huống này.
Dmitry Kabanov

Sử dụng MPLBACKEND đã giải quyết nó cho tôi. Chắc chắn là cách thanh lịch nhất!
SaturnFromTitan

41

Tôi đã gặp lỗi khi sử dụng matplotlib thông qua Spark. matplotlib.use('Agg')không làm việc cho tôi. Cuối cùng, đoạn mã sau hoạt động với tôi. Thêm ở đây

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

Điều này hoạt động rất tốt, không có giới hạn về thứ tự được sử dụng để nhập matplotlib và các thư viện khác.
PabTorre

Khi chạy trên Spark, bạn có phải hạn chế điều này để chạy trên nút đầu hoặc bạn đã làm cho nó hoạt động khi chạy trên các nút worker?
Saca

Tôi đang sử dụng điều này trong một dự án django và đây là cách duy nhất tôi có thể làm cho nó hoạt động.
HenryM

31

Tôi sẽ chỉ nhắc lại những gì @Ivo Bosticky nói có thể bỏ qua. Đặt các dòng này ở đầu RẤT của tệp py.

import matplotlib
matplotlib.use('Agg') 

Hoặc người ta sẽ gặp lỗi

* / usr / lib / pymodules / python2.7 / matplotlib / __ init__.py:923: UserWarning: Cuộc gọi này đến matplotlib.use () không có hiệu lực
bởi vì phần phụ trợ đã được chọn;
matplotlib.use () phải được gọi * trước * pylab, matplotlib.pyplot, *

Điều này sẽ giải quyết tất cả vấn đề Hiển thị


15

Tôi thấy đoạn mã này hoạt động tốt khi chuyển đổi giữa môi trường X và không 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

Theo tôi, đây là một giải pháp ưu việt hơn giải pháp được chấp nhận, mặc dù nó không trả lời trực tiếp câu hỏi và trả lời một câu hỏi không được hỏi.
Daisuke Aramaki

14

Khi đăng nhập vào máy chủ để thực thi mã, hãy sử dụng mã này thay thế:

ssh -X username@servername

những -Xsẽ thoát khỏi sự không có tên hiển thị và không có $ DISPLAY biến môi trường lỗi

:)


1
Tôi cần sử dụng '-X' để lưu hình ảnh .png. Cảm ơn nhiều.
số

Điều này sẽ thất bại trong một quá trình dài nếu ssh hết thời gian, hoặc nếu bạn cần ngắt kết nối vì bất kỳ lý do gì. Lưu ý rằng thời gian chờ thậm chí có thể xảy ra nếu máy khách kết nối chuyển sang chế độ ngủ.
posdef

Bạn có thể ngăn thời gian chờ bằng cách thêm -o ServerAliveCountMax=120 -o ServerAliveInterval=30sẽ khiến khách hàng ssh gửi một gói trống cứ sau 30 giây trong tối đa 1 giờ.
Alex

5

Bạn đang trên hệ thống nào? Có vẻ như bạn có một hệ thống với X11, nhưng biến môi trường HIỂN THỊ không được đặt đúng. Hãy thử thực hiện lệnh sau và sau đó chạy lại chương trình của bạn:

export DISPLAY=localhost:0

Nhưng tại sao nó lại đặt một biến hiển thị, tôi đã đăng nhập từ xa vào máy chủ này, tất cả những gì cần làm là tạo một tệp PNG ???
krisdigitx

1
@krisdigitx, nếu bạn được kết nối từ xa, đừng đặt biến hiển thị; thay vì sử dụng cờ "-XY" khi bạn kết nối. Để hiển thị, nó cần biết Xserver nào sẽ gửi hình ảnh đến; trong trường hợp này, nó sẽ là màn hình máy tính của bạn, thay vì máy tính từ xa. Việc sử dụng cờ "-XY" khiến SSH tự động đặt biến HIỂN THỊ để trỏ đến màn hình của máy tính đang kết nối.
Michael Aaron Safyan

@krisdigitx, tôi đồng ý, thật lạ khi nó làm điều đó; Tuy nhiên, tôi đoán là nó vẽ hình ảnh bằng X11, và sau đó lưu kết quả bằng X11.
Michael Aaron Safyan

Sử dụng cài đặt này cho $ HIỂN THỊ không hoạt động trên EC2 chạy Ubuntu 16 - không thể kết nối để hiển thị "localhost: 0"
YAMTorre

5
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

Nó làm việc cho tôi.


3

Một điều khác để kiểm tra là liệu người dùng hiện tại của bạn có được phép kết nối với màn hình X hay không. Trong trường hợp của tôi, root không được phép làm điều đó và matplotlib đã phàn nàn với cùng một lỗi.

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

nguồn: http : //www.debian-ad dùng.org


2

Để đảm bảo mã của bạn có thể di động trên Windows, Linux và OSX và cho các hệ thống có và không có màn hình, tôi sẽ đề xuất đoạn trích sau:

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

Tín dụng: https://stackoverflow.com/a/45756291/207661


1

Đối với Google Cloud Machine Learning Engine:

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

Và sau đó để in thành tập tin:

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

và để tạo PDF:

multi_page(report_name)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.