(python) matplotlib pyplot show() .. блокирует или нет?

Я снова и снова сталкивался с этой проблемой с show(), и я уверен, что делаю что-то не так, но не уверен в том, что "правильный" способ сделать то, что я хочу.

И [я думаю], что я хочу, чтобы какой-то способ заблокировать в основном потоке, пока событие не произойдет в потоке графического интерфейса, что-то вроде этого работает в первый раз:

from matplotlib import pyplot as p
from scipy import rand

im = (255*rand(480,640)).astype('uint8')
fig = p.figure()
ax = fig.add_subplot(111)
ax.imshow(im)

# just any mutable container for storing a click
s = [-1, -1]

def onclick(event):
  if event.xdata is not None and event.ydata is not None:
    s[0] = event.xdata
    s[1] = event.ydata
    p.close()

cid = fig.canvas.mpl_connect('button_press_event', onclick)
p.show()
print s

p.show() блокируется до тех пор, пока p.close() не будет вызвано в обработчике событий. Но когда тот же код запускается во второй раз, он проходит мимо p.show() и печатает исходный s, [-1, -1].

Я читал противоречивую информацию о том, можно ли и нужно ли вызывать p.show() более одного раза из одной и той же программы. Кажется, он был разработан для использования один раз, и только один раз в конце скрипта. Другие варианты использования, кажется, каким-то образом ломают pyplot (конечный автомат?).

Я пытался использовать комбинации p.draw() и p.ion() и p.ioff(), но не смог получить желаемое поведение (либо что-то не блокировалось должным образом, либо графики не появлялись в нужное время).

Я также смущен тем, как обработчик событий вообще может видеть s здесь, и является ли это плохим способом передачи информации в/из. Если я не использую изменяемый контейнер, такой как массив или список, информация, которую я хочу установить обработчиком событий, просто теряется как локальная переменная. есть ли какой-то другой метод, который я упускаю, когда поток графического интерфейса может передавать сигналы обратно в основной поток? есть ли способ заблокировать в основном, без периодического опроса или ожидания, для сигнала от обработчика событий, прежде чем продолжить?

Итак, я думаю, что в конечном итоге мой главный вопрос:

Есть ли аккуратная замена для p.show(), которая делает то, что я хочу (то же поведение, что и p.show() в первый раз), или такой код требует полного переосмысления/перезаписи?


person wim    schedule 31.05.2011    source источник


Ответы (3)


Пара идей разного качества:

Если вам не нравится, что s является глобальной переменной, вы можете сделать onclick() вызываемым объектом, прикрепив его к этому.

Ваш обратный вызов может получить/освободить блокировку для управления потоком программы (немного грязный).

Вы можете активно опрашивать s для управления потоком программы (очень грязно).

Вы можете вручную управлять рисованием ваших фигур с помощью fig.canvas.draw().

person matt    schedule 31.05.2011
comment
спасибо за ваши идеи. я смог изменить поведение блокировки show(), создав mpl из исходного кода. - person wim; 01.06.2011

Сегодня я смог решить свою проблему. если кто-то еще заинтересован в изменении поведения show(), читайте дальше, как вы можете это сделать:

Я заметил этот абзац под названием множественные вызовы для отображения поддерживаемых в разделе что нового часть веб-страницы matplotlib:

Давний запрос заключается в поддержке нескольких вызовов show(). Это было сложно, потому что трудно добиться согласованного поведения между операционными системами, наборами инструментов пользовательского интерфейса и версиями. Эрик Файринг (Eric Firing) проделал большую работу по рационализации show во всех бэкэндах, с желаемым поведением, чтобы show поднимало все вновь созданные фигуры и блокировало выполнение до тех пор, пока они не будут закрыты. Повторные вызовы show должны поднимать вновь созданные цифры с момента последнего вызова. Эрик много тестировал наборы инструментов пользовательского интерфейса, версии и платформы, к которым у него есть доступ, но невозможно протестировать их все, поэтому, пожалуйста, сообщайте о проблемах в список рассылки и систему отслеживания ошибок.

Это было в разделе «Что нового» для версии 1.0.1, на момент написания версия в синаптике все еще оставалась на 0.99.3. Мне удалось загрузить и собрать из источника v1.0.1. Дополнительные пакеты, которые мне также требовались для удовлетворения зависимостей, были libfreetype6-dev tk-dev tk8.5-dev tcl8.5-dev python-gtk2-dev.

Теперь с matplotlib.__version__ == 1.0.1 следующий код блокирует то, что я ожидал:

import matplotlib.pyplot as p
from scipy import eye
p.imshow(eye(3))
p.show()
print 'a' 
p.imshow(eye(6))
p.show()
print 'b' 
p.imshow(eye(9))
p.show()
print 'c' 
person wim    schedule 01.06.2011

Я заметил разницу между запуском кода

  1. Непосредственно в интерпретаторе Python (командная строка)

  2. Поместите его в скрипт Python и запустите из командной строки ("python script.py").

Оба дают блокирующее поведение, что нормально.

Из интерпретатора появляются оба изображения, из командной строки появляется только первое.

person RobW    schedule 26.08.2011