Automatic detection of display availability with m

2020-02-09 03:00发布

问题:

I'm generating matplotlib figures in a script which I run alternatively with or without a graphical display. I'd like the script to adjust automatically: with display, it should show the figures interactively, while without a display, it should just save them into a file.

From an answer to the question Generating matplotlib graphs without a running X server, I learnt that one can use the Agg backend for non-interactive plotting.

So I am trying with this code:

import matplotlib
try:
    import matplotlib.pyplot as plt
    fig = plt.figure()
    havedisplay = True
except:
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig = plt.figure()
    havedisplay = False
# do the plotting
if havedisplay:
    plt.show()
else:
    fig.savefig("myfig.png")

This works as excepted in the case with a display. However, without a display, the call to matplotlib.use is not effective, since the display has already been chosen. It's clear that I should call matplotlib.use before import matplotlib.pyplot, but then I don't know how to test whether a display is available or not.

I have also tried with the experimental function matplotlib.switch_backend instead of matplotlib.use, but this generates a RuntimeError.

Does someone have an idea how to make the above code work as intended, or can suggest an alternative way to detect whether a display is available for matplotlib or not?

回答1:

You can detect directly if you have a display with the OS module in python. in my case it's

>>> import os
>>> os.environ["DISPLAY"]
':0.0'


回答2:

try this?

import matplotlib,os
r = os.system('python -c "import matplotlib.pyplot as plt;plt.figure()"')
if r != 0:
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    fig = plt.figure()
    fig.savefig('myfig.png')
else:
    import matplotlib.pyplot as plt
    fig = plt.figure()
    plt.show()


回答3:

The code below works for me in Linux and Windows (where it assumes there is a display device):

import os
import matplotlib
if os.name == 'posix' and "DISPLAY" not in os.environ:
    matplotlib.use('Agg')

See https://stackoverflow.com/a/1325587/896111.

Note that the line matplotlib.use('Agg') must appear after the first import of matplotlib (otherwise you will get an error).



回答4:

By combining both of the approaches above, you'll get perhaps the best solution:

havedisplay = "DISPLAY" in os.environ
if not havedisplay:
    exitval = os.system('python -c "import matplotlib.pyplot as plt; plt.figure()"')
    havedisplay = (exitval == 0)

The reason for this combo is that the run time of the os.system command may take a while. So when you are sure you have the display (judging by the os.environ value), you can save that time. On the other hand, even if the DISPLAY key is not set in the os.environ variable, there is still a chance that the plotting methods will work with the graphical interface (e.g. when using Windows command line).



回答5:

when use GUI backend the figure object has show() method, you can use it to do the switch:

import matplotlib
#matplotlib.use("Agg")

import matplotlib.pyplot as plt
fig = plt.figure()
havedisplay = False
if hasattr(fig, "show"):
    plt.show()
else:
    print "save fig"
    fig.savefig("myfig.png")


回答6:

The solution offered by @Oz123 generated a syntax error for me. However, i was able to easily detect the display using:

import os
havedisplay = "DISPLAY" in os.environ
#plotting...

That was the simplest thing i could find, anyway.



回答7:

import os
have_display = bool(os.environ.get('DISPLAY', None))

have_display is False if DISPLAY is not in the environment or is an empty string. otherwise, it's True