Menghasilkan PNG dengan matplotlib ketika DISPLAY tidak ditentukan

319

Saya mencoba menggunakan networkx dengan Python. Ketika saya menjalankan program ini ia mendapatkan kesalahan ini. Apakah ada yang hilang?

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

Saya mendapatkan kesalahan yang berbeda sekarang:

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

Saya mendapatkan kesalahan yang berbeda sekarang:

#!/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
krisdigitx
sumber
3
kemungkinan duplikat dari pembuatan grafik matplotlib tanpa server X yang sedang berjalan
Jouni K. Seppänen
9
Pindahkan panggilan ke matplotlib.use ('Agg') di atas impor Anda yang lain, khususnya sebelum impor matplotlib.pyplot
Ivo Bosticky
Komentar @IvoBosticky menyelesaikannya untuk saya juga: Satu-satunya hal yang menyesatkan adalah "di atas impor Anda yang lain". Seharusnya jelas bahwa Anda perlu mengimpor matplotlib sebelum ... Ini adalah seluruh pengaturan yang berfungsi untuk saya: impor matplotlib // matplotlib.use ('Agg') // impor matplotlib.pyplot sebagai plt
mrk

Jawaban:

518

Masalah utama adalah bahwa (pada sistem Anda) matplotlib memilih backend x-using secara default. Saya baru saja mengalami masalah yang sama pada salah satu server saya. Solusi bagi saya adalah menambahkan kode berikut di tempat yang dapat dibaca sebelum impor pylab / matplotlib / pyplot lainnya :

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

Alternatifnya adalah mengaturnya di .matplotlibrc Anda

Reinout van Rees
sumber
182
Catatan penting: .use perlu dipanggil sebelum pyplot diimpor. Jadi, jika Anda, misalnya, hanya mencoba mengimpor pyplot, Anda perlu mengimpor matplotlib terlebih dahulu, panggil penggunaan, dan kemudian impor pyplot.
seaotternerd
8
Komentar di atas dijelaskan lebih lanjut oleh jawaban ini .
Ioannis Filippidis
2
Bagaimana Anda "mengaturnya di .matplotlibrc Anda"?
tommy.carstensen
18
backend: aggdi ~/.config/matplotlib'/matplotlibrc(sebagai contoh, lihat http: //matplotlib.org/faq/troubleshooting_faq.html#locating-matplotlib-config-dir). Lihat juga matplotlib.org/users/customizing.html , yang memiliki contoh file konfigurasi di bagian bawah halaman. Temukan "agg" di halaman itu dan Anda akan melihat opsi konfigurasi yang Anda butuhkan.
Reinout van Rees
4
Untuk referensi, berikut adalah tautan ke dokumentasi matplotlib yang menjelaskan hal ini. (+1, jawaban yang bagus, membantu saya dengan sempurna!)
Tim S.
72

Sama seperti pelengkap dari jawaban Reinout.

Cara permanen untuk memecahkan masalah semacam ini adalah dengan mengedit file .matplotlibrc. Temukan via

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

Kemudian modifikasi backend di file itu menjadi backend : Agg. Hanya itu saja.

Chris.Q
sumber
5
Kiat pro: atur $MATPLOTLIBRCke direktori tempat Anda ingin memasukkan matplotlibrc Anda sendiri.
Kenneth Hoste
Agak berlebihan untuk masalah seperti ini, tapi saya kira jika server selalu bekerja tanpa kepala, masuk akal untuk memodifikasi file konfigurasi. Apakah ini memiliki efek samping pada bagaimana matplotlib akan berfungsi?
BruceJohnJennerLawso
Saya menjalankan matplotlib di server web jadi ini adalah jawaban untuk saya. Saya belum melihat adanya efek samping.
spitz
42

Jawaban bersihnya adalah mengambil sedikit waktu dengan benar mempersiapkan lingkungan eksekusi Anda.

Teknik pertama yang harus Anda persiapkan untuk lingkungan eksekusi Anda adalah dengan menggunakan matplotlibrcfile, seperti yang direkomendasikan oleh Chris Q. , pengaturan

backend : Agg

dalam file itu. Anda bahkan dapat mengontrol - tanpa perubahan kode - bagaimana dan di mana matplotlib mencari dan menemukanmatplotlibrc file .

Teknik kedua yang harus Anda persiapkan untuk lingkungan eksekusi Anda adalah dengan menggunakan MPLBACKENDvariabel lingkungan (dan beri tahu pengguna Anda untuk menggunakannya):

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

Ini berguna karena Anda bahkan tidak perlu menyediakan file lain pada disk untuk membuatnya berfungsi. Saya telah menggunakan pendekatan ini dengan, misalnya, pengujian dalam integrasi berkelanjutan, dan berjalan pada mesin jarak jauh yang tidak memiliki tampilan.

Hard-coding backend matplotlib Anda ke "Agg" dalam kode Python Anda seperti bashing pasak persegi ke dalam lubang bundar dengan palu besar, ketika, sebaliknya, Anda bisa saja mengatakan matplotlib itu perlu lubang persegi.

Gotgenes
sumber
Teknik kedua terlihat paling elegan dalam situasi ini.
Dmitry Kabanov
Menggunakan MPLBACKEND memecahkannya untuk saya. Pasti cara yang paling elegan!
SaturnFromTitan
41

Saya mendapat kesalahan saat menggunakan matplotlib melalui Spark. matplotlib.use('Agg')tidak bekerja untuk saya. Pada akhirnya, kode berikut ini berfungsi untuk saya. Lebih lanjut di sini

import matplotlib.pyplot as plt.
plt.switch_backend('agg')
pengguna3282611
sumber
Ini berfungsi dengan baik, tanpa batasan pada urutan yang digunakan untuk mengimpor matplotlib dan perpustakaan lain.
PabTorre
Ketika menjalankan pada Spark, apakah Anda harus membatasi ini untuk berjalan di head node atau apakah Anda membuatnya bekerja ketika berjalan pada node pekerja?
Saca
Saya menggunakan ini dalam proyek Django dan ini adalah satu-satunya cara saya bisa membuatnya bekerja.
HenryM
31

Saya hanya akan mengulangi apa yang dikatakan @Ivo Bosticky yang bisa diabaikan. Masukan garis-garis ini di sangat mulai dari file py.

import matplotlib
matplotlib.use('Agg') 

Atau seseorang akan mendapatkan kesalahan

* / usr / lib / pymodules / python2.7 / matplotlib / __ init__.py:923: UserWarning: Panggilan ini ke matplotlib.use () tidak memiliki efek
karena backend telah dipilih;
matplotlib.use () harus dipanggil * sebelum * pylab, matplotlib.pyplot, *

Ini akan menyelesaikan semua masalah Tampilan

Somum
sumber
15

Saya menemukan potongan ini berfungsi dengan baik ketika beralih antara lingkungan X dan tidak-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
Matthias123
sumber
Menurut pendapat saya, ini adalah solusi yang lebih baik daripada yang diterima, meskipun tidak langsung menjawab pertanyaan, dan menjawab pertanyaan yang tidak ditanyakan.
Daisuke Aramaki
14

Saat masuk ke server untuk menjalankan kode, gunakan ini sebagai gantinya:

ssh -X username@servername

itu -Xakan menghilangkan nama tampilan dan tidak ada kesalahan variabel lingkungan $ DISPLAY

:)

rajol kochlashvili
sumber
1
Saya perlu menggunakan '-X' agar gambar .png disimpan. Terimakasih banyak.
no
Ini akan gagal untuk proses panjang jika ssh habis, atau jika Anda perlu memutuskan koneksi untuk alasan apa pun. Perhatikan bahwa batas waktu bahkan dapat terjadi jika klien yang terhubung tidur.
posdef
Anda dapat mencegah timeout dengan menambahkan -o ServerAliveCountMax=120 -o ServerAliveInterval=30yang akan membuat klien ssh mengirim paket kosong setiap 30 detik selama maksimal 1 jam.
Alex
5

Sistem apa yang Anda pakai? Sepertinya Anda memiliki sistem dengan X11, tetapi variabel lingkungan DISPLAY tidak diatur dengan benar. Coba jalankan perintah berikut dan jalankan kembali program Anda:

export DISPLAY=localhost:0
Michael Aaron Safyan
sumber
tapi mengapa itu untuk mengatur variabel tampilan, saya login ke server ini dari jarak jauh, semua yang harus dilakukan adalah menghasilkan file PNG ???
krisdigitx
1
@krisdigitx, jika Anda terhubung dari jarak jauh, jangan atur variabel tampilan; alih-alih gunakan bendera "-XY" saat Anda terhubung. Untuk menampilkan, perlu mengetahui Xserver mana yang akan dikirimi gambar; dalam hal ini, itu akan menjadi tampilan komputer Anda, bukan komputer jarak jauh. Menggunakan bendera "-XY" menyebabkan SSH untuk mengatur variabel DISPLAY secara otomatis untuk menunjuk ke tampilan komputer yang menghubungkan.
Michael Aaron Safyan
@ Krisdigitx, saya setuju, itu sangat aneh bahwa ia melakukan itu; tebakan saya, meskipun, adalah bahwa itu melukis gambar menggunakan X11, dan kemudian menyimpan hasilnya menggunakan X11.
Michael Aaron Safyan
Menggunakan pengaturan ini untuk $ DISPLAY tidak berfungsi pada EC2 yang menjalankan Ubuntu 16 - tidak dapat terhubung untuk menampilkan "localhost: 0"
PabTorre
5
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

Ini bekerja untuk saya.

Qing En
sumber
3

Satu hal lagi yang perlu diperiksa adalah apakah pengguna Anda saat ini berwenang untuk terhubung ke layar X. Dalam kasus saya, root tidak diizinkan untuk melakukan itu dan matplotlib mengeluh dengan kesalahan yang sama.

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

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

Alex
sumber
2

Untuk memastikan kode Anda portabel di Windows, Linux dan OSX dan untuk sistem dengan dan tanpa tampilan, saya sarankan cuplikan berikut:

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

Kredit: https://stackoverflow.com/a/45756291/207661

Shital Shah
sumber
1

Untuk Mesin Pembelajaran Mesin Google Cloud:

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

Dan kemudian untuk mencetak ke file:

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

dan untuk membuat PDF:

multi_page(report_name)
Kim Miller
sumber