我一直在使用python playground这本书作为学习python的一种方式。偶然发现了Boids代码的章节。它使用matlibplot来绘制有规则的圆圈“移动”。
我遇到的问题是button_press_event部分。该事件的目的是:左键单击-在鼠标位置添加boid。右键单击-在鼠标位置分散当前群集。
然而,当我点击该图时,我得到了一个错误。这不会使程序崩溃,它会弹出以下消息:
> 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,并进行了更正):
"""
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()发布于 2019-12-12 04:08:15
我认为你需要这样写(注意boids上的小"b“):
cid = fig.canvas.mpl_connect('button_press_event', boids.buttonPress)
因为boids是Boids类的实例,而Boids.buttonPress()不是静态函数,因此不能从Boids类直接调用
https://stackoverflow.com/questions/59289150
复制相似问题