将Matplotlib图形绘制到Psychopy循环中

3
使用Psychopy和Matplotlib,我在屏幕左侧显示了100个具有随机方向(0-360)、大小和位置的矩形。将每个角度范围分配给一个唯一的颜色(例如:所有小于90度的为红色,大于90度且小于180度的为绿色,大于180度且小于270度的为蓝色,大于270度的为灰色)。然后统计每种角度范围内矩形的数量,并用Matplotlib绘制出来。将绘制出的图形保存下来,在右侧通过使用Psychopy Imagestim调用它来显示。将这个脚本保留在一个函数中,然后运行n次。我的想法是,在每次按键时,我都会得到新的矩形显示(左侧)和新的相应图表(右侧)。
我的问题是,虽然矩形和矩形计数显示良好,但图表没有正确更新。例如,在第一次试验中有24个红色部分,红色条将显示此内容。但是,在下一次试验中,如果只有22个红色部分,则红色部分的图表不会减少到23,而仍停留在24。这适用于整个图表(所有颜色),导致图表每次试验仅增加每个条形(没有减少)。我看不出这是为什么。我认为这可能是我将我的4个(颜色)变量传递给Matplotlib的方式有问题,但它们在每次试验开始时都被重置为0;因此我无法找出问题所在。
import random
import psychopy.visual
import psychopy.event
import psychopy.core
import numpy as np
import matplotlib.pyplot as plt

win = psychopy.visual.Window(
    size = [1200,550],
    units = "pix",
    fullscr=False,
    color=[-1,-1,-1]
)

def one():
    win.flip()
    rect=psychopy.visual.Rect(win=win,units="pix") 

    n_rect=100

    performance = []

    red   = 0
    green = 0
    blue  = 0
    grey  = 0

    for i_rect in range(n_rect):                               
        rect.width = random.uniform(10,100)
        rect.height = random.uniform(10,100)
        rect.ori = random.uniform(0,360)

        rect.pos = [
            random.uniform(-300,-10),
            random.uniform(-300,300)
        ]

        if rect.ori < 90:
            rect.fillColor = (1,-1,-1)
            red += 1

        elif rect.ori >90 and rect.ori <180:
            rect.fillColor = (-1,1,-1)
            green += 1

        elif rect.ori > 180 and rect.ori < 270:
            rect.fillColor = (-1,-1,1)
            blue += 1

        else:
            rect.fillColor = (0,0,0)
            grey += 1

        rect.draw()

    print ("red:   %i")%(red)
    print ("green: %i")%(green)
    print ("blue:  %i")%(blue)
    print ("grey:  %i")%(grey)

    red_text   =  psychopy.visual.TextStim(win,text =  red,  pos =  (165,-180))
    green_text =  psychopy.visual.TextStim(win,text =  green,pos = (295,-180))
    blue_text  =  psychopy.visual.TextStim(win,text =  blue, pos = (425,-180))
    grey_text  =  psychopy.visual.TextStim(win,text =  grey, pos = (555,-180)) 

    color_text_list = [red_text,green_text,blue_text,grey_text]

    for color in color_text_list:
        color.draw()

    # Here I pass the value of my colour variables to Matplotlib for plotting

    plt.style.use('ggplot')
    colors = ('red','green','blue','grey')
    y_pos = np.arange(len(colors))
    performance = [red,green,blue,grey]

    x = plt.bar(y_pos, performance, align='center')
    x[0].set_color('red')
    x[1].set_color('green')
    x[2].set_color('blue')
    x[3].set_color('grey')
    plt.xticks(y_pos, colors)
    plt.ylabel('count')

    plt.savefig('image.png',dpi=80,transparent=True)

    img = psychopy.visual.ImageStim(
        win=win,
        image="image.png",
        units="pix",
        pos = (350,50)
    )

    rect.draw()
    img.draw()
    win.flip()

    psychopy.event.waitKeys()

for i in range(20):
    one()

win.close()

如果有人想尝试,这段代码可以独立运行。代码相对简单,但这是我第一次使用Matplotlib,也许我忽略了一些显而易见的东西。

谢谢, 史蒂夫


+1 非常好的可重现示例。@Andrew Guy 正确指出每次迭代都需要清除图形。 - Michael MacAskill
1个回答

2

我无法验证,因为当前未安装psychopy,但我认为你的问题在于每次迭代后没有清除pyplot图形。

def one():
    ...
    ...
    performance = [red,green,blue,grey]
    #Clears the current plot figure, leaves the window open.
    plt.clf()
    x = plt.bar(y_pos, performance, align='center')
    ...
    ...
pyplot会跟踪当前活动的图表,并会一直在该图表上绘制(而不清除先前的数据),直到您告诉它停止为止。您也可以调用plt.figure()打开一个新的图表,但请确保关闭先前的图表以释放内存。
有关清除绘图的不同方式的更详细说明,请参见此问题:何时使用cla()、clf()或close()来清除matplotlib中的图表?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接