336

I am trying to use networkx with Python. When I run this program it get this error. Is there anything missing?

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

I get a different error now:

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

I get a different error now:

#!/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
Joel
  • 22,598
  • 6
  • 69
  • 93
krisdigitx
  • 7,068
  • 20
  • 61
  • 97
  • 3
    possible duplicate of [Generating matplotlib graphs without a running X server](http://stackoverflow.com/questions/4931376/generating-matplotlib-graphs-without-a-running-x-server) – Jouni K. Seppänen Feb 21 '11 at 21:26
  • 9
    Move the call to matplotlib.use('Agg') above your other imports, in particular it should be before import of matplotlib.pyplot – Ivo Bosticky Jun 25 '11 at 01:18
  • @IvoBosticky comment solved it for me as well: The only thing which is misleading is "above your other imports". It should be obvious that you need to import matplotlib before... This is the whole setting that worked for me: import matplotlib // matplotlib.use('Agg') // import matplotlib.pyplot as plt – mrk Jun 20 '17 at 07:52
  • Related: ["UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure." when plotting figure with pyplot on Pycharm](/questions/56656777) – Karl Knechtel Apr 26 '23 at 19:06

13 Answers13

534

The main problem is that (on your system) matplotlib chooses an x-using backend by default. I just had the same problem on one of my servers. The solution for me was to add the following code in a place that gets read before any other pylab/matplotlib/pyplot import:

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

The alternative is to set it in your .matplotlibrc

Reinout van Rees
  • 13,486
  • 2
  • 36
  • 68
  • 191
    Important note: .use needs to be called before pyplot is imported. So if you are, for instance, just trying to import pyplot, you need to import matplotlib first, call use, and than import pyplot. – seaotternerd Nov 08 '13 at 09:15
  • 9
    The above comment is explained more by [this answer](http://stackoverflow.com/a/4706614/1959808). – 0 _ Feb 28 '14 at 06:15
  • 2
    How do you "set it in your .matplotlibrc"? – tommy.carstensen Jul 05 '15 at 20:32
  • 18
    `backend: agg` in `~/.config/matplotlib'/matplotlibrc` (as an example, seehttp://matplotlib.org/faq/troubleshooting_faq.html#locating-matplotlib-config-dir). See also http://matplotlib.org/users/customizing.html, which has an example config file at the bottom of the page. Find "agg" on that page and you'll see the config option you need. – Reinout van Rees Jul 06 '15 at 08:48
  • 4
    For reference, [here is the link](http://matplotlib.org/faq/howto_faq.html#matplotlib-in-a-web-application-server) to the matplotlib documentation that explains this. (+1, great answer, helped me perfectly!) – Tim S. Feb 04 '16 at 20:24
  • I can't find documentation for this, but based on my experience, if you use `seaborn`, you also need to call `matplotlib.use('Agg')` before `import seaborn`. – eclark Nov 08 '16 at 23:10
  • You might have to restart the shell for this to take effect – binaryfunt Nov 22 '16 at 15:11
  • See further down http://stackoverflow.com/a/36271874/1358283 for a somewhat cleaner solution using env-vars - no need to modify your python code – kratenko Jan 11 '17 at 17:29
  • Works flawlessly. Solved my dilemma where running plotting code on a Raspberry Pi would work, but not on a Macbook Pro. Way to go. – Spencer H Mar 21 '17 at 22:26
  • works and very importantly as already said --- "place that gets read before any other pylab/matplotlib/pyplot import:" Thanks !! – Naresh MG Jun 12 '17 at 22:23
  • Doesn't work. Says `This call to matplotlib.use() has no effect because the backend has already been chosen; matplotlib.use() must be called *before* pylab, matplotlib.pyplot, or matplotlib.backends is imported for the first time.` – Dims Jul 28 '17 at 13:23
  • @Dims: it *does* work. Like mentioned in my answer and in other comments, you noeed to call `matplotlib.use()` *before* doing any other matplotlib import (just like the error message says). – Reinout van Rees Aug 10 '17 at 12:22
  • @ReinoutvanRees I'm still getting the error despite the above steps. I'm trying to create and save a scatterplot, and it throws the error when I call plt.scatter(). Is this just not possible? – rschwieb May 30 '18 at 17:32
  • For almost everybody, it works. So it *is* definitively possible :-) Make sure you double-check that you (or some library) isn't import pyplot too early. Perhaps the `matplotlibrc` config file helps in your case? – Reinout van Rees May 31 '18 at 08:53
  • @ReinoutvanRees imagine several libraries which all wish to be imported first and using each other – Dims Oct 17 '18 at 17:48
  • In the end, something somewhere you wrote has to get called first. A django settings file, a `main.py` script, etc. If necessary, write a tiny wrapper script that runs whatever you normally run *after* the `.use()` call. – Reinout van Rees Oct 18 '18 at 13:37
  • @Reinout van Rees Holy Smokes! This answer has just solved days of hair pulling and the Question I posted: https://stackoverflow.com/questions/57400461/create-png-without-show-figure/57400587#57400587 Thanks! – Marinaio Aug 08 '19 at 16:35
74

Just as a complement of Reinout's answer.

The permanent way to solve this kind of problem is to edit .matplotlibrc file. Find it via

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

Then modify the backend in that file to backend : Agg. That is it.

Chris.Q
  • 1,370
  • 16
  • 21
  • 5
    Pro tip: set `$MATPLOTLIBRC` to the *directory* where you want to throw your own matplotlibrc in. – Kenneth Hoste Aug 29 '13 at 18:19
  • Kinda overkill for a problem like this, but I guess if the server is always working headless it makes sense to modify a configuration file. Would this have any side effects on how matplotlib will function? – BruceJohnJennerLawso Sep 13 '16 at 01:45
  • I'm running matplotlib on a web server so this was the answer for me. I have not noticed any side effects. – spitz Nov 25 '17 at 12:14
46

The clean answer is to take a little bit of time correctly prepare your execution environment.

The first technique you have to prepare your execution environment is to use a matplotlibrc file, as wisely recommended by Chris Q., setting

backend : Agg

in that file. You can even control — with no code changes — how and where matplotlib looks for and finds the matplotlibrc file.

The second technique you have to prepare your execution environment is to use the MPLBACKEND environment variable (and inform your users to make use of it):

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

This is handy because you don't even have to provide another file on disk to make this work. I have employed this approach with, for example, testing in continuous integration, and running on remote machines that do not have displays.

Hard-coding your matplotlib backend to "Agg" in your Python code is like bashing a square peg into a round hole with a big hammer, when, instead, you could have just told matplotlib it needs to be a square hole.

Community
  • 1
  • 1
gotgenes
  • 38,661
  • 28
  • 100
  • 128
44

I got the error while using matplotlib through Spark. matplotlib.use('Agg') doesn't work for me. In the end, the following code works for me. More here

import matplotlib.pyplot as plt.
plt.switch_backend('agg')
Jeril
  • 7,858
  • 3
  • 52
  • 69
user3282611
  • 870
  • 1
  • 9
  • 9
  • This works great, without the restrictions on the order used to import matplotlib and other libraries. – PabTorre Sep 05 '17 at 15:40
  • When running on Spark, did you have to restrict this to run on the head node or did you get this to work when running on worker nodes? – Saca Sep 24 '17 at 06:57
  • I'm using this in a django project and this was the only way I could get it working. – HenryM Feb 03 '18 at 16:28
31

I will just repeat what @Ivo Bosticky said which can be overlooked. Put these lines at the VERY start of the py file.

import matplotlib
matplotlib.use('Agg') 

Or one would get error

*/usr/lib/pymodules/python2.7/matplotlib/__init__.py:923: 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,*

This will resolve all Display issue

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Somum
  • 2,382
  • 26
  • 15
17

I found this snippet to work well when switching between X and no-X environments.

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
  • 882
  • 9
  • 15
  • In my opinion, this is a superior solution than the one accepted, although it does not directly answer the question, and answers a question not asked. – Daisuke Aramaki Feb 14 '17 at 11:53
14

When signing into the server to execute the code use this instead:

ssh -X username@servername

the -X will get rid of the no display name and no $DISPLAY environment variable error

:)

DaveShaw
  • 52,123
  • 16
  • 112
  • 141
  • 1
    I need to use '-X' in order to have the .png image saved. Many thanks. – nos Mar 12 '12 at 22:02
  • This will fail for a long process if ssh times out, or if you need to disconnect for whatever reason. Note that a timeout may even occur if the connecting client goes into sleep. – posdef Dec 13 '16 at 16:00
  • You can prevent timeouts by adding `-o ServerAliveCountMax=120 -o ServerAliveInterval=30` which will make ssh client send an empty packet every 30 seconds for max 1 hour. – Alex Jul 15 '19 at 15:42
6
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

It works for me.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Qing En
  • 61
  • 1
  • 3
5

What system are you on? It looks like you have a system with X11, but the DISPLAY environment variable was not properly set. Try executing the following command and then rerunning your program:

export DISPLAY=localhost:0
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • but why does it eed to set a display variable, i am remotely logged on to this server, all it should do is generate a PNG file??? – krisdigitx May 10 '10 at 10:41
  • 1
    @krisdigitx, if you are remotely connected, don't set a display variable; instead use the "-XY" flag when you connect. In order to display, it needs to know which Xserver to send the image to; in this case, it would be the display of your computer, instead of the remote computer. Using the "-XY" flag causes SSH to set the DISPLAY variable automatically to point to the display of the connecting computer. – Michael Aaron Safyan May 10 '10 at 14:12
  • @krisdigitx, I agree, it is very strange that it does that; my guess, though, is that it paints the image using X11, and then saves the result using X11. – Michael Aaron Safyan May 10 '10 at 14:14
  • Using this setting for $DISPLAY doesn't work on EC2 running Ubuntu 16 -- couldn't connect to display "localhost:0" – PabTorre Sep 05 '17 at 15:39
3

To make sure your code is portable across Windows, Linux and OSX and for systems with and without displays, I would suggest following snippet:

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

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

Shital Shah
  • 63,284
  • 17
  • 238
  • 185
3

One other thing to check is whether your current user is authorised to connect to the X display. In my case, root was not allowed to do that and matplotlib was complaining with the same error.

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

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

Alex
  • 1,313
  • 14
  • 28
1

For Google Cloud Machine Learning Engine:

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

And then to print to 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()

and to create the PDF:

multi_page(report_name)
Kim Miller
  • 886
  • 8
  • 11
0
import matplotlib
matplotlib.use('Agg')

worked for me as long as I was calling the plotting functions/code directly. But if you are using

from joblib import Parallel, delayed

Parallel and delayed modules for parallelizing your code then you need to add

matplotlib.rcParams.update({'backend': 'Agg'})

line inside your function in order for agg backend to work.

KSD
  • 33
  • 6