Подтвердить что ты не робот

Как манипулировать цифрами, пока в Python работает script?

Введение

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

IPython может имитировать поведение Matlab с помощью волшебной команды %pylab или %matplotlib, которая делает то, что я еще не понимаю, и что является самой точкой моего вопроса.

Моя цель заключается в том, чтобы позволить автономным скриптам Python работать, как это делает Matlab (или как IPython с %matplotlib). Другими словами, я хотел бы, чтобы этот script выполнялся из командной строки. Я ожидаю появления новой фигуры каждые 3 секунды. Во время выполнения я мог бы увеличить, изменить размер или даже закрыть фигуру.

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

def do_some_work(): 
    time.sleep(3)

for i in range(10):
    plt.plot([1,2,3,4])
    plt.show() # this is way too boilerplate, I'd like to avoid it too. 
    do_some_work()

Какую альтернативу %matplotlib я могу использовать для управления фигурами, а script работает в Python (не IPython)?

Какие решения я уже исследовал?

В настоящее время я нашел 3 способа получить сюжетное шоу.

1. %pylab/%matplotlib

Как tom, следует избегать использования %pylab, чтобы предотвратить загрязнение пространства имен.

>>> %pylab
>>> plot([1,2,3,4])

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

К сожалению, команда %matplotlib доступна только на IPython.

2. from pylab import * или from matplotlib.pyplot import plt

>>> from pylab import *
>>> plot([1,2,3,4])

Здесь все совсем другое. Мне нужно добавить команду show(), чтобы отобразить мою фигуру, которая блокирует. Я не могу ничего сделать, кроме закрытия фигуры, чтобы выполнить следующую команду, такую ​​как grid(), которая не будет иметь никакого эффекта, поскольку фигура теперь закрыта...

** 3. from pylab import * или from matplotlib.pyplot import plt + ion() ** В некоторых предложениях рекомендуется использовать команду ion() следующим образом:

>>> from pylab import *
>>> ion()
>>> plot([1,2,3,4])
>>> draw()
>>> pause(0.0001)

К сожалению, даже если график показывает, я не могу закрыть фигуру вручную. Мне нужно выполнить close() на терминале, что не очень удобно. Кроме того, необходимость в двух дополнительных командах, таких как draw(); pause(0.0001), не то, что я ожидаю.

Резюме

С %pylab все замечательно, но я не могу использовать его за пределами IPython

С from pylab import *, за которым следует plot, я получаю поведение блокировки, и вся мощность IPython теряется.

from pylab import *, за которым следует ion, предлагает хорошую альтернативу предыдущей, но я должен использовать команду weird pause(0.0001), которая приводит к тому, что я не могу закрыть окно вручную (я знаю, что pause не нужен с некоторыми backend.Я использую WxAgg, который является единственным, который хорошо работает на Cygwin x64.

В этом question рекомендуется использовать matplotlib.interactive(True). К сожалению, он не работает и дает то же поведение, что и ion().

4b9b3361

Ответ 1

Измените функцию do_some_work на следующую и она должна работать.

def do_some_work(): 
    plt.pause(3)

Для интерактивных бэкэнд plt.pause(3) запускает цикл событий в течение 3 секунд, чтобы он мог обрабатывать события изменения размера. Обратите внимание, что документация говорит, что это экспериментальная функция, и что для сложных анимаций вы должны использовать модуль анимации.

Магические команды, %pylab и %matplotlib также запускают цикл событий, поэтому возможно взаимодействие с пользователями. Кроме того, вы можете запустить цикл событий с помощью %gui wx и отключить его с помощью %gui. Вы можете использовать функцию IPython.lib.guisupport.is_event_loop_running_wx(), чтобы проверить, запущена ли она.

Причина использования ion() или ioff() очень хорошо объясняется на странице 'What is interactive mode'. В принципе, взаимодействие с пользователем возможно без IPython. Однако я не смог получить интерактивный пример с этой страницы для работы с бэкэнд Qt4Agg, только с бэкэнд MacOSX (на моем Mac). Я не пытался использовать бэкэнд WX.

Edit

Мне удалось заставить интерактивный пример работать с бэкендом Qt4Agg, используя PyQt4 вместо PySide (поэтому, установив backend.qt4 : PyQt4 в мой файл ~/.config/matplotlibrc). Я думаю, что пример не работает со всеми бэкэндами. Я отправил вопрос здесь.

Изменить 2

Я боюсь, что не могу придумать способ манипулирования фигурой, пока выполняется длинный расчет без использования потоков. Как вы упомянули: Matplotlib не запускает нить, и IPython тоже. Команды% pylab и% matplotlib чередуются между командами обработки из цикла read-eval-print и позволяют графическим интерфейсам обрабатывать события на короткое время. Они делают это последовательно.

На самом деле, я не могу воспроизвести ваше поведение, даже с помощью маты matplotlib или% pylab. (Просто чтобы быть ясным: в ipython я сначала вызываю %matplotlib, а затем %run yourscript.py). Матрица% matplotlib помещает Matplotlib в интерактивный режим, что делает вызов plt.show() неблокирующим, так что функция do_some_work выполняется немедленно. Однако во время вызова time.sleep(3) фигура не реагирует (это становится еще более очевидным, если я увеличиваю период сна). Я не понимаю, как это может работать с вашей стороны.

Если я ошибаюсь, вам придется разбить ваш расчет на более мелкие части и использовать plt.pause (или даже лучше, модуль анимации), чтобы обновить цифры.

Ответ 2

Мой совет будет заключаться в том, чтобы продолжать использовать IPython, поскольку он управляет контуром событий GUI для вас (что делает pylab/pylot). Я пробовал интерактивный график в обычном интерпретаторе, и он работал так, как ожидается, даже без вызова ion() (Debian unstable, Python 3.4.3+, Matplotlib 1.4.2-3.1). Если я помню это правильно, это довольно новая функция в Matplotlib.

В качестве альтернативы вы также можете использовать возможности анимации Matplotlib для периодического обновления графика:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time

plt.ion()

tt = np.linspace(0, 1, 200)
freq = 1  # parameter for sine
t0 = time.time()  # for measuring ellapsed time

fig, ax = plt.subplots()


def draw_func(i):
    """ This function gets called repeated times """ 
    global freq  # needed because freq is changed in this function
    xx = np.sin(2*np.pi*freq*tt)/freq
    ax.set_title("Passed Time: %.1f s, " % (time.time()-t0) +
                 "Parameter i=%d" % i)
    ax.plot(tt, xx, label="$f=%d$ Hz" % freq)
    ax.legend()
    freq += 1


# call draw_func every 3 seconds 1 + 4 times (first time is initialization):
ani = animation.FuncAnimation(fig, draw_func,  np.arange(4), interval=3000,
                              repeat=False)
# plt.show()

Оформить заказ matplotlib.animation.FuncAnimation для деталей. Дальнейшие примеры вы найдете в разделе .