В matplotlib, есть ли способ вывести фигуру асинхронно?

В matplotlib существует ли простой способ построения фигуры без прерывания потока управления script?

Использование псевдокода для ясности, вот чего я пытаюсь достичь:

fig1 = figure()
fig1.plot_a_figure(datasets)

for dataset in datasets:
   results = analyze(dataset)    # this takes several minutes
   update(fig1)
   pop_up_another_figure(results) # would like to have a look at this one
                                  # while the next dataset is being processed

Конечно, я могу просто сохранить() эти промежуточные цифры, но мне нужно только быстро взглянуть на них, и было бы лучше, если бы они просто появлялись на экране в реальном времени.

EDIT: пример выполнения:

#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt

fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)

ax.plot([1,2,3],[4,5,6],'ro-')

#fig1.show()  # this does not show a figure if uncommented
plt.show()    # until the plot window is closed, the next line is not executed

print "doing something else now"

Мне не хватает чего-то очень элементарного?

Ответ 1

Прежде всего, не забудьте простую альтернативу - просто создать новые окна с цифрами plt.figure(2), plt.figure(3) и т.д. Если вы действительно хотите обновить существующее окно фигуры, вам лучше держать ручку на своем объектов с

h = ax.plot([1,2,3],[4,5,6],'ro-')

И потом вы будете делать что-то вроде:

h[0].set_data(some_new_results)
ax.figure.canvas.draw()

Что касается реального мяса вопроса, если вы все еще сражаетесь с этим, читайте дальше.


Вам нужно включить интерактивный режим, если вы хотите, чтобы plt.show() не блокировался. Чтобы изменить пример выполнения, чтобы "сделать что-то еще сейчас" напечатал сразу, в отличие от ожидания закрытия окна фигуры, следующее:

#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt

fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)

ax.plot([1,2,3],[4,5,6],'ro-')

#fig1.show()  # this does not show a figure if uncommented
plt.ion()     # turns on interactive mode
plt.show()    # now this should be non-blocking

print "doing something else now"
raw_input('Press Enter to continue...')

Однако это просто царапает поверхность вещей - есть много осложнений, когда вы начинаете хотеть делать фоновые работы во время взаимодействия с сюжетами. Это естественное следствие окраски, в которой, по существу, находится машина состояния, она не хорошо впитывается потоками и программированием в объектно-ориентированной среде.

  • Дорогостоящие вычисления должны будут идти в рабочие потоки (или, альтернативно, в подпроцессы), чтобы избежать замораживания GUI.
  • Queue следует использовать для передачи входных данных и получения результатов из рабочих функций поточно-безопасным способом.
  • В моем опыте небезопасно вызывать draw() в рабочем потоке, поэтому вам также нужно настроить способ запланировать перерисовку.
  • Различные бэкенды могут начинать делать странные вещи, а TkAgg кажется единственной, которая работает на 100% (см. здесь).

Самое простое и лучшее решение - не использовать интерпретатор vanilla python, но использовать ipython -pylab (как правильно предположил ianalis), потому что они уже выяснили большинство трюков, необходимых для бесперебойной работы интерактивного материала. Это можно сделать без ipython/pylab, но это значительный объем дополнительной работы.

Примечание. Мне по-прежнему часто приходится обрабатывать рабочие потоки при использовании графических окон ipython и pyplot GUI, а также для бесперебойной работы потоков. Мне также нужно использовать другой аргумент командной строки ipython -pylab -wthread. Я нахожусь на python 2.7.1+ с matplotlib v1.1.0, ваш пробег может отличаться. Надеюсь, это поможет!

Примечание для пользователей Ubuntu: хранилища все еще вернутся на v0.99 уже довольно давно, стоит обновить ваш matplotlib потому что было множество улучшений, которые появились в версии v1.0, включая марафон Bugfix и основные изменения в поведении of show().

Ответ 2

Наверное, самым простым решением является использование IPython в качестве оболочки python. Запустите его с опцией -pylab.

ipython -pylab