0

我很抱歉,因为我之前就相关主题打开了另一张票。感谢我现在得到的答案,我可以更具体。我也收到了一些基于 Tkinter 的解决方案,但我想用事件和循环来解决我的问题。

我正在处理的特殊情况如下:我有一个数组数组。我希望 matplotlib 绘制它的第一个元素,允许我按一个键(带有关联事件),然后程序绘制第二个数组,相同的行为,等等。

举个简单的例子:

import matplotlib.pyplot as plt
import numpy as np

# Define the event
def ontype(event):
    if event.key == '1':
        print 'It is working'
        plt.clf()

# Create figure an connect the event to it
fig=plt.figure(figsize=(16,8))
plt.gcf().canvas.mpl_connect('key_press_event',ontype)

# Loop
for element in xrange(10):
    #This mimicks the "array of arrays" generating a random array in each loop
    vector = np.random.random(10)  
    plt.plot(vector)
    plt.show()

我希望得到第一个图(循环第一次运行),并且在我按 1 之前它一直保持打开状态。但是,我得到的是一个绘制了十个向量的图,当我按 1 时,这个图是清除并通过终端显示“它正在工作”。我需要程序来绘制第一个元素,并在按下一个键后移至下一个元素。对此有任何提示吗?我究竟做错了什么?

感谢你们!

编辑:

请记住,原则上,程序的结构不能改变,并且在绘制任何东西之前需要 for 循环来计算不同的东西。因此,该程序应该去

def ontype(event):
     define event

Some stuff
elements = array of arrays
for element in elements:
    do more stuff
    plot element and "stay" in this plot untill any event key is pressed. And then, go to the next element in elements and do the same

编辑2:

我认为我没有正确解释自己,并且可能会误解这种数据。就我而言,我正在阅读一个巨大的数据表,每一行都是不同的来源。我试图绘制的是列的信息。我是一名物理学家,所以我对时尚编程或任何东西知之甚少。问题是......如果没有办法用 for 循环做到这一点,谁能解释我如何在没有它的情况下完成这种工作?

4

2 回答 2

2

下一个块就是你想要的for循环。

def ugly_math():
    print 'you will hit this once'
    for j in range(10):
        print 'loop ', j
        # insert math here
        yield  np.random.random(10) * j

您的for循环进入函数ugly_math,而您想要绘制的是后面的内容yield。请参阅Python 中的“yield”关键字有什么作用?. 简而言之,yield将带有循环的函数变成生成器工厂。

fun = ugly_math()

然后是生成器。当您调用fun.next()它时,它将运行该函数ugly_math,直到它到达yield. 然后它将返回产生的值(在本例中为np.random.random)。下次您调用fun.next()它时,它将从循环中停止的地方开始并运行,直到yield再次命中。因此,它完全符合您的要求。

然后从 Holger 那里大量借用:

fun = ugly_math()
cid_dict = {}
# Define the event
def ontype(event):
    if event.key == '1':
        print 'It is working'
        try:
            vector = fun.next()
            plt.plot(vector)
            fig.canvas.draw()
        except StopIteration:
            plt.gcf().canvas.mpl_disconnect(cid_dict['cid'])
            del cid_dict['cid']

# Create figure an connect the event to it
fig=plt.figure(figsize=(16,8))
cid_dict['cid'] = plt.gcf().canvas.mpl_connect('key_press_event',ontype)

vector = np.random.random(10)  
plt.plot(vector)
plt.show()

cid_dict那里,我们可以在我们用尽生成器后删除回调。

我们可以将这一切包装成一个类

class push_to_advance(object):
    def __init__(self):
        self.fig = plt.figure()
        self.ax = self.fig.gca()
        self.bound_keys = []
        self.bound_cid = {}

    def add_step_through(self, gen, key):
        key = key[0] # make a single char
        if key in self.bound_keys:
            raise RuntimeError("key %s already bound"%key)
        first_data = gen.next()
        self.ax.plot(first_data)
        self.fig.canvas.draw()
        self.bound_keys.append(key)
        def ontype(event):
            if event.key == key:
                try:
                    self.ax.plot(gen.next())
                    self.fig.canvas.draw()
                except StopIteration:
                    self.fig.canvas.mpl_disconnect(self.bound_cid[key])
                    del self.bound_cid[key]
                    self.bound_keys.remove(key)

        self.bound_cid[key] = self.fig.canvas.mpl_connect('key_press_event', ontype)

这是这样使用的:

 pta = push_to_advance()
 gen = ugly_math()
 pta.add_step_through(gen,'a')

任何可迭代的都需要一些技巧:

 test_array = np.arange(100).reshape(10,10)
 pta.add_step_through(test_array.__iter__(), 'b')

这让我很开心,我把它保存为要点

于 2013-01-16T05:41:27.583 回答
1

您不需要循环。ontype使用命令重新绘制事件函数中的新图fig.canvas.draw()

import matplotlib.pyplot as plt
import numpy as np

# Define the event
def ontype(event):
    if event.key == '1':
        print 'It is working'
        vector = np.random.random(10)  
        plt.plot(vector)
        fig.canvas.draw()

# Create figure an connect the event to it
fig=plt.figure(figsize=(16,8))
plt.gcf().canvas.mpl_connect('key_press_event',ontype)

vector = np.random.random(10)  
plt.plot(vector)
plt.show()
于 2013-01-15T22:22:00.983 回答