การสร้าง PNG ด้วย matplotlib เมื่อไม่แสดง DISPLAY


319

ฉันกำลังพยายามใช้ 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


9
ย้ายการเรียกไปยัง matplotlib.use ('Agg') เหนือการนำเข้าอื่น ๆ ของคุณโดยเฉพาะอย่างยิ่งควรเป็นก่อนการนำเข้า matplotlib.pyplot
Ivo Bosticky

@IvoBosticky ความคิดเห็นแก้ไขให้ฉันเช่นกัน: สิ่งเดียวที่ทำให้เข้าใจผิดคือ "เหนือการนำเข้าอื่น ๆ ของคุณ" มันควรจะชัดเจนว่าคุณต้องนำเข้า matplotlib ก่อน ... นี่คือการตั้งค่าทั้งหมดที่ทำงานสำหรับฉัน: import matplotlib // matplotlib.use ('Agg') // นำเข้า matplotlib.pyplot เป็น PLT
mrk

คำตอบ:


518

ปัญหาหลักคือว่า (ในระบบของคุณ) matplotlib เลือกแบ็กเอนด์ x โดยใช้เป็นค่าเริ่มต้น ฉันเพิ่งมีปัญหาเดียวกันบนเซิร์ฟเวอร์ตัวใดตัวหนึ่งของฉัน ทางออกสำหรับฉันคือการเพิ่มรหัสต่อไปนี้ในสถานที่ที่ได้รับการอ่านก่อนนำเข้าpylab / matplotlib / pyplot อื่น ๆ:

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

ทางเลือกคือการตั้งค่าใน. matplotlibrc ของคุณ


182
หมายเหตุสำคัญ: .use ต้องถูกเรียกก่อนนำเข้า pyplot ตัวอย่างเช่นหากคุณพยายามนำเข้า pyplot คุณต้องนำเข้า matplotlib ก่อนใช้งานการโทรและนำเข้า pyplot
seaotternerd

8
ความคิดเห็นข้างต้นอธิบายเพิ่มเติมโดยคำตอบนี้
Ioannis Filippidis

2
คุณจะ "ตั้งค่าใน. matplotlibrc" ของคุณอย่างไร?
tommy.carstensen

18
backend: aggใน~/.config/matplotlib'/matplotlibrc(เป็นตัวอย่าง seehttp: //matplotlib.org/faq/troubleshooting_faq.html#locating-matplotlib-config-dir) ดูเพิ่มเติมmatplotlib.org/users/customizing.htmlซึ่งมีไฟล์กำหนดค่าตัวอย่างที่ด้านล่างของหน้า ค้นหา "agg" ในหน้านั้นและคุณจะเห็นตัวเลือกการกำหนดค่าที่คุณต้องการ
Reinout van Rees

4
สำหรับการอ้างอิงนี่คือลิงค์ไปยังเอกสารประกอบของ matplotlib ที่อธิบายสิ่งนี้ (+1, คำตอบที่ดี, ช่วยฉันอย่างสมบูรณ์แบบ!)
ทิม S.

72

เช่นเดียวกับการเติมคำตอบของ Reinout

วิธีถาวรในการแก้ปัญหาประเภทนี้คือการแก้ไขไฟล์. matplotlibrc ค้นหาผ่าน

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

จากนั้นแก้ไขแบ็กเอนด์ในไฟล์backend : Aggนั้นเป็น อย่างนั้นแหละ.


5
เคล็ดลับสำหรับมืออาชีพ: ตั้งค่า$MATPLOTLIBRCเป็นไดเรกทอรีที่คุณต้องการโยน matplotlibrc ของคุณเอง
Kenneth Hoste

ค่อนข้างเกินความจริงสำหรับปัญหาเช่นนี้ แต่ฉันเดาว่าเซิร์ฟเวอร์ทำงานอยู่ตลอดเวลาหัวจะเหมาะสมที่จะแก้ไขไฟล์กำหนดค่า สิ่งนี้จะมีผลข้างเคียงใด ๆ เกี่ยวกับการทำงานของ matplotlib หรือไม่?
BruceJohnJennerLawso

ฉันกำลังเรียกใช้ matplotlib บนเว็บเซิร์ฟเวอร์ดังนั้นนี่คือคำตอบสำหรับฉัน ฉันไม่ได้สังเกตเห็นผลข้างเคียงใด ๆ
spitz

42

คำตอบที่ชัดเจนคือการใช้เวลาเล็กน้อยในการเตรียมสภาพแวดล้อมในการดำเนินการของคุณอย่างถูกต้อง

เทคนิคแรกที่คุณต้องเตรียมสภาพแวดล้อมการดำเนินการของคุณคือการใช้matplotlibrcไฟล์ตามคำแนะนำอย่างชาญฉลาดโดยคริสคิว , การตั้งค่า

backend : Agg

ในไฟล์นั้น คุณสามารถควบคุมได้แม้ไม่มีการเปลี่ยนแปลงรหัส - วิธีและตำแหน่งที่ matplotlib ค้นหาและค้นหาmatplotlibrcไฟล์ไฟล์

เทคนิคที่สองที่คุณต้องเตรียมสภาพแวดล้อมการดำเนินการของคุณคือการใช้MPLBACKENDตัวแปรสภาพแวดล้อม (และแจ้งให้ผู้ใช้ของคุณเพื่อใช้ประโยชน์จากมัน):

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

สิ่งนี้มีประโยชน์เพราะคุณไม่ต้องให้ไฟล์อื่นบนดิสก์เพื่อใช้งานได้ ฉันได้ใช้วิธีการนี้กับตัวอย่างเช่นการทดสอบในการรวมอย่างต่อเนื่องและทำงานบนเครื่องระยะไกลที่ไม่มีจอแสดงผล

การเข้ารหัสแบ็กเอนด์ matplotlib ของคุณให้เป็น "Agg" ในรหัส Python ของคุณก็เหมือนกับการทุบหมุดสี่เหลี่ยมเข้าไปในรูกลมด้วยค้อนขนาดใหญ่เมื่อคุณสามารถบอก matplotlib ได้ว่าต้องเป็นรูสี่เหลี่ยม


เทคนิคที่สองดูเหมือนหรูหราที่สุดในสถานการณ์นี้
Dmitry Kabanov

การใช้ MPLBACKEND แก้ไขให้ฉันแล้ว วิธีที่งดงามที่สุดแน่นอน!
SaturnFromTitan

41

ฉันพบข้อผิดพลาดขณะใช้ matplotlib ผ่าน Spark matplotlib.use('Agg')ไม่ได้ผลสำหรับฉัน ในที่สุดรหัสต่อไปนี้ใช้งานได้สำหรับฉัน เพิ่มเติมที่นี่

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

ใช้งานได้ดีโดยไม่มีข้อ จำกัด ในการสั่งซื้อที่นำเข้า matplotlib และห้องสมุดอื่น ๆ
PabTorre

เมื่อรันบน Spark คุณต้อง จำกัด สิ่งนี้ให้ทำงานบนโหนดใหญ่หรือคุณได้รับสิ่งนี้เพื่อทำงานเมื่อทำงานบนโหนดงานหรือไม่?
Saca

ฉันใช้สิ่งนี้ในโครงการ django และนี่เป็นวิธีเดียวที่ฉันจะทำให้มันใช้งานได้
HenryM

31

ฉันจะทำซ้ำสิ่งที่ @Ivo Bosticky พูดซึ่งสามารถมองข้ามได้ วางบรรทัดเหล่านี้ที่จุดเริ่มต้นVERYของไฟล์ py

import matplotlib
matplotlib.use('Agg') 

หรือจะได้รับข้อผิดพลาด

* / usr / lib / pymodules / python2.7 / matplotlib / __ init__.py:923: UserWarning: การเรียกไปยัง matplotlib.use () นี้ไม่มีผลใด ๆ
เพราะแบ็กเอนด์ได้ถูกเลือกแล้ว;
matplotlib.use () ต้องเรียกว่า * ก่อน * pylab, matplotlib.pyplot, *

สิ่งนี้จะแก้ไขปัญหาการแสดงผลทั้งหมด


15

ฉันพบว่าข้อมูลโค้ดนี้ทำงานได้ดีเมื่อสลับระหว่างสภาพแวดล้อม 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

ในความคิดของฉันนี่เป็นวิธีแก้ปัญหาที่เหนือกว่าที่ยอมรับแม้ว่ามันจะไม่ตอบคำถามโดยตรงและตอบคำถามที่ไม่ได้ถาม
ไดสุเกะอารามาคิ

14

เมื่อลงชื่อเข้าใช้เซิร์ฟเวอร์เพื่อรันโค้ดให้ใช้สิ่งนี้แทน:

ssh -X username@servername

-Xจะได้รับการกำจัดของชื่อที่แสดงและไม่มีข้อผิดพลาด $ DISPLAY ตัวแปรสภาพแวดล้อม

:)


1
ฉันต้องใช้ '-X' เพื่อให้รูปภาพ. png ถูกบันทึก ขอบคุณมาก.
nos

สิ่งนี้จะล้มเหลวเป็นเวลานานหาก ssh หมดเวลาหรือถ้าคุณต้องการยกเลิกการเชื่อมต่อด้วยเหตุผลใดก็ตาม โปรดทราบว่าการหมดเวลาอาจเกิดขึ้นหากไคลเอ็นต์การเชื่อมต่อเข้าสู่โหมดสลีป
posdef

คุณสามารถป้องกันการหมดเวลาโดยการเพิ่ม-o ServerAliveCountMax=120 -o ServerAliveInterval=30ซึ่งจะทำให้ไคลเอนต์ ssh ส่งแพ็คเก็ตที่ว่างเปล่าทุก 30 วินาทีนานสูงสุด 1 ชั่วโมง
อเล็กซ์

5

คุณใช้ระบบอะไร ดูเหมือนว่าคุณมีระบบที่มี X11 แต่ตัวแปรสภาพแวดล้อม DISPLAY ไม่ได้ตั้งค่าอย่างเหมาะสม ลองเรียกใช้คำสั่งต่อไปนี้จากนั้นเรียกใช้โปรแกรมของคุณอีกครั้ง:

export DISPLAY=localhost:0

แต่ทำไมมันถึงตั้งค่าตัวแปรการแสดงผล, ฉันเข้าสู่ระบบเซิร์ฟเวอร์นี้จากระยะไกล, สิ่งที่ควรทำคือสร้างไฟล์ PNG ???
krisdigitx

1
@krisdigitx หากคุณเชื่อมต่อจากระยะไกลอย่าตั้งค่าตัวแปรแสดงผล ใช้แฟล็ก "-XY" แทนเมื่อคุณเชื่อมต่อ ในการแสดงมันจำเป็นต้องรู้ว่า Xserver ใดที่จะส่งภาพไปให้ ในกรณีนี้มันจะเป็นการแสดงผลคอมพิวเตอร์ของคุณแทนที่จะเป็นคอมพิวเตอร์ระยะไกล การใช้แฟล็ก "-XY" ทำให้ SSH ตั้งค่าตัวแปร DISPLAY โดยอัตโนมัติเพื่อให้ชี้ไปที่จอแสดงผลของคอมพิวเตอร์ที่เชื่อมต่อ
Michael Aaron Safyan

@krisdigitx ฉันเห็นด้วยมันแปลกมากที่ทำเช่นนั้น อย่างไรก็ตามฉันเดาว่ามันวาดภาพด้วย X11 แล้วบันทึกผลลัพธ์โดยใช้ X11
Michael Aaron Safyan

การใช้การตั้งค่านี้สำหรับ $ DISPLAY ไม่ทำงานบน EC2 ที่ใช้ Ubuntu 16 - ไม่สามารถเชื่อมต่อเพื่อแสดง "localhost: 0"
PabTorre


3

อีกสิ่งหนึ่งที่ควรตรวจสอบคือผู้ใช้ปัจจุบันของคุณได้รับอนุญาตให้เชื่อมต่อกับจอแสดงผล X หรือไม่ ในกรณีของฉันรูทไม่ได้รับอนุญาตให้ทำเช่นนั้นและ 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-administrator.org/articles/494 https://debian-administr.org/article/494/Getting_X11_forwarding_through_ssh_working_after_running_su


2

เพื่อให้แน่ใจว่ารหัสของคุณเป็นแบบพกพาใน Windows, Linux และ OSX และสำหรับระบบที่มีและไม่มีจอแสดงผลฉันขอแนะนำตัวอย่างข้อมูลต่อไปนี้:

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://stackoverflow.com/a/45756291/207661


1

สำหรับกลไกการเรียนรู้ของ Google Cloud Machine:

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.