首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python Playground错误: Boids在MatlibPlot中交互式单击

Python Playground错误: Boids在MatlibPlot中交互式单击
EN

Stack Overflow用户
提问于 2019-12-11 23:31:26
回答 1查看 100关注 0票数 1

我一直在使用python playground这本书作为学习python的一种方式。偶然发现了Boids代码的章节。它使用matlibplot来绘制有规则的圆圈“移动”。

我遇到的问题是button_press_event部分。该事件的目的是:左键单击-在鼠标位置添加boid。右键单击-在鼠标位置分散当前群集。

然而,当我点击该图时,我得到了一个错误。这不会使程序崩溃,它会弹出以下消息:

代码语言:javascript
复制
>   File
> "C:\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\cbook\__init__.py",
> line 388, in process
>     proxy(*args, **kwargs)   File "C:\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\cbook\__init__.py",

> line 228, in __call__
>     return mtd(*args, **kwargs) TypeError: buttonPress() missing 1 required positional argument: 'event'

根据我的理解,这意味着它实际上不能接受事件(左键或右键单击),或者输入中缺少该事件。

是什么导致了这个错误?如何解决这个问题?谢谢

这是本书章节中的代码(来自github,并进行了更正):

代码语言:javascript
复制
"""
boids.py
Implementation of Craig Reynold's BOIDs
Author: Mahesh Venkitachalam
"""

import sys, argparse
import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.spatial.distance import squareform, pdist, cdist
from numpy.linalg import norm

width, height = 640, 480

class Boids:
    """Class that represents boids simulation"""
    def __init__(self, N):
        # init position & veclocites
        self.pos = [width/2.0, height/2.0] + 10*np.random.rand(2*N).reshape(N, 2)
        # normalized random velocities
        angles = 2*math.pi*np.random.rand(N)
        self.vel = np.array(list(zip(np.sin(angles), np.cos(angles))))
        self.N = N
        # min dist of approach
        self.minDist = 25.0
        # max magnitude of velocities calculated by "rules"
        self.maxRuleVel = 0.03
        # max maginitude of final velocity
        self.maxVel = 2.0

    def tick(self, frameNum, pts, beak):
        """Update the simulation by one time step"""
        # get pairwise distances
        self.distMatrix = squareform(pdist(self.pos))
        # apply rules:
        self.vel += self.applyRules()
        self.limit(self.vel, self.maxVel)
        self.pos += self.vel
        self.applyBC()
        # update data
        pts.set_data(self.pos.reshape(2*self.N)[::2],
                     self.pos.reshape(2*self.N)[1::2])
        vec = self.pos + 10*self.vel/self.maxVel
        beak.set_data(vec.reshape(2*self.N)[::2],
                      vec.reshape(2*self.N)[1::2])

    def limitVec(self, vec, maxVal):
        """Limit magnitude of 2D Vector"""
        mag = norm(vec)
        if mag > maxVal:
            vec[0], vec[1] = vec[0]*maxVal/mag, vec[1]*maxVal/mag

    def limit(self, X, maxVal):
        """Limit magnitide of 2D vectors in array X to maxValue"""
        for vec in X:
            self.limitVec(vec, maxVal)

    def applyBC(self):
        """apply boundary conditions"""
        deltaR = 2.0
        for coord in self.pos:
            if coord[0] > width + deltaR:
                coord[0] = - deltaR
            if coord[0] < - deltaR:
                coord[0] = width + deltaR
            if coord[1] > height + deltaR:
                coord[1] = - deltaR
            if coord[1] < - deltaR:
                coord[1] = height + deltaR

    def applyRules(self):
        # apply rule #1 - Separation
        D = self.distMatrix < 25.0
        vel = self.pos*D.sum(axis=1).reshape(self.N, 1) - D.dot(self.pos)
        self.limit(vel, self.maxRuleVel)

        # different distance threshold
        D = self.distMatrix < 50.0

        # apply rule #2 - Alignment
        vel2 = D.dot(self.vel)
        self.limit(vel2, self.maxRuleVel)
        vel += vel2

        # apply rule #3 - Cohesion
        vel3 = D.dot(self.pos) - self.pos
        self.limit(vel3, self.maxRuleVel)
        vel += vel3

        return vel

    def buttonPress(self, event):
        """event handler for matplotlib button presses"""
        # left click - add a boid
        if event.button == 1:
            self.pos = np.concatenate((self.pos,
                                       np.array([[event.xdata, event.ydata]])),
                                      axis=0)
            # random velocity
            angles = 2*math.pi*np.random.rand(1)
            v = np.array(list(zip(np.sin(angles), np.cos(angles))))
            self.vel = np.concatenate((self.vel, v), axis=0)
            self.N += 1
        # right click - scatter
        elif event.button == 3:
            # add scattering velocity
            self.vel += 0.1*(self.pos-np.array([[event.xdata, event.ydata]]))


def tick(frameNum, pts, beak, boids):
    #print frameNum
    """update function for animation"""
    boids.tick(frameNum, pts, beak)
    return pts, beak

# main fuction
def main():
    # use sys.arv if needed
    print('starting boids...')

    parser = argparse.ArgumentParser(description="Implementing Craig Reynolds's Boids..")
    # add arguments
    parser.add_argument('--num-boids', dest='N', required=False)
    args = parser.parse_args()

    # number of boids
    N = 100
    if args.N:
        N = int(args.N)


    # create boids
    boids = Boids(N)

    # setup plot
    fig = plt.figure()
    ax = plt.axes(xlim=(0, width), ylim=(0, height))

    pts, = ax.plot([], [], markersize=10,
                   c='k', marker='o', ls='None')
    beak, = ax.plot([],[], markersize=4,
                    c='r', marker='o', ls='None')
    anim = animation.FuncAnimation(fig, tick, fargs=(pts, beak, boids),
                                   interval=50)

    # add a "button press" event handler
    cid = fig.canvas.mpl_connect('button_press_event', Boids.buttonPress)

    plt.show()

# call main()
if __name__ == '__main__':
    main()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-12 04:08:15

我认为你需要这样写(注意boids上的小"b“):

cid = fig.canvas.mpl_connect('button_press_event', boids.buttonPress)

因为boidsBoids类的实例,而Boids.buttonPress()不是静态函数,因此不能从Boids类直接调用

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59289150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档