Автоматическое обнаружение доступности дисплея с помощью matplotlib

Я генерирую цифры matplotlib в script, который я запускаю в качестве альтернативы с графическим дисплеем или без него. Я бы хотел, чтобы script настраивался автоматически: с дисплеем он должен показывать фигуры в интерактивном режиме, а без дисплея - просто сохранять их в файл.

Из ответа на вопрос Создание графиков matplotlib без запуска X-сервера я узнал, что для неинтерактивного построения можно использовать бэкэнд Agg.

Итак, я пытаюсь с помощью этого кода:

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")

Это работает как в случае с дисплеем. Однако без отображения вызов matplotlib.use неэффективен, так как дисплей уже выбран. Ясно, что я должен называть matplotlib.use до import matplotlib.pyplot, но тогда я не знаю, как проверить, доступен ли дисплей или нет.

Я также пытался использовать экспериментальную функцию matplotlib.switch_backend вместо matplotlib.use, но это создает RuntimeError.

Есть ли у кого-то идея, как сделать вышеуказанный код работать по назначению или предложить альтернативный способ определить, доступен ли дисплей для matplotlib или нет?

Ответ 1

Вы можете непосредственно определить, есть ли у вас дисплей с модулем ОС в Python. в моем случае это

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

Ответ 2

попробуйте это?

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

Код ниже работает для меня в Linux и Windows (предполагалось, что есть устройство отображения):

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

См. fooobar.com/questions/47848/....

Обратите внимание, что строка matplotlib.use('Agg') должна появиться после первого импорта matplotlib (иначе вы получите сообщение об ошибке).

Ответ 4

Объединив оба подхода выше, вы получите, возможно, лучшее решение:

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

Причиной этой комбо является то, что время выполнения команды os.system может занять некоторое время. Поэтому, когда вы уверены, что у вас есть дисплей (судя по значению os.environ), вы можете сохранить это время. С другой стороны, даже если ключ DISPLAY не задан в переменной os.environ, все же существует вероятность того, что методы построения графиков будут работать с графическим интерфейсом (например, при использовании командной строки Windows).

Ответ 5

когда используется GUI-сервер, объект фигуры имеет метод show(), вы можете использовать его для переключения:

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

Решение, предлагаемое @Oz123, вызвало синтаксическую ошибку для меня. Тем не менее, я смог легко обнаружить дисплей, используя:

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

Это была самая простая вещь, которую я мог найти, во всяком случае.