在python的學(xué)習(xí)過程中我看到一個模擬鳥群的例子,并可以用鼠標(biāo)左鍵創(chuàng)建一只新的鳥,用鼠標(biāo)右鍵驅(qū)散鳥群。在我運(yùn)行代碼的時候發(fā)現(xiàn),點(diǎn)擊鼠標(biāo)左鍵和右鍵均沒有反應(yīng)。于是查閱資料,最后找到了問題所在,現(xiàn)在將解決問題的過程記錄下來,(如果只要結(jié)果的同學(xué)直接拉到最底下就可以了)
測試環(huán)境:
Win10,python3.6.4,matplotlib 2.1.2
測試代碼:
(代碼來源:《python極客項目編程》第五章)
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 normwidth, height =
640,
480class Boids:"""class that represents Boids simulation"""def __init__(self, N):"""initialize the Boid simulation"""self.pos = [width/
2.0, height/
2.0] +
10*np.random.rand(
2*N).reshape(N,
2)angles =
2*math.pi*np.random.rand(N)self.vel = np.array(list(zip(np.sin(angles), np.cos(angles))))self.N = Nself.minDist =
25.0self.maxRuleVel =
0.03self.maxVel =
2.0def tick(self, frameNum, pts, beak):"""Update the simulation by one time step."""self.distMatrix = squareform(pdist(self.pos))self.vel += self.applyRules()self.limit(self.vel, self.maxVel)self.pos += self.velself.applyBC()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.maxVelbeak.set_data(vec.reshape(
2*self.N)[::
2],vec.reshape(
2*self.N)[
1::
2])
def limitVec(self, vec, maxVel):"""limit the magnitide of the 2D vector"""mag = norm(vec)
if mag > maxVel:vec[
0], vec[
1] = vec[
0]*maxVel/mag, vec[
1]*maxVel/mag
def limit(self, X, maxVel):"""limit the magnitide of 2D vectors in array X to maxValue"""for vec
in X:self.limitVec(vec, maxVel)
def applyBC(self):"""apply boundary conditions"""deltaR =
2.0for 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):D = self.distMatrix <
25.0vel = self.pos * D.sum(axis=
1).reshape(self.N,
1) - D.dot(self.pos)self.limit(vel, self.maxRuleVel)D = self.distMatrix <
50.0vel2 = D.dot(self.vel)self.limit(vel2, self.maxRuleVel)vel += vel2vel3 = D.dot(self.pos) - self.posself.limit(vel3, self.maxRuleVel)vel += vel3
return vel
def buttonPress(self, event):"""event handler for matplotlib button presses"""if event.button
is 1:print(
'left button')self.pos = np.concatenate((self.pos, np.array([[event.xdata, event.ydata]])), axis=
0)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 +=
1elif event.button
is 3:print(
'right button')self.vel +=
0.1*(self.pos - np.array([[event.xdata, event.ydata]]))
def tick(frameNum, pts, beak, boids):"""update function for animation"""boids.tick(frameNum, pts, beak)
return pts, beak
def main():print(
'starting boids...')parser = argparse.ArgumentParser(description=
"Implementing Craig Reynold's Boids...")parser.add_argument(
'--num-boids', dest=
'N', required=
False)args = parser.parse_args()N =
100if args.N:N = int(args.N)boids = Boids(N)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')fig.canvas.mpl_connect(
"button_press_event", boids.buttonPress)anim = animation.FuncAnimation(fig, tick, fargs=(pts, beak, boids), interval=
50)plt.show()
if __name__ ==
'__main__':main()
正常運(yùn)行,但是點(diǎn)擊鼠標(biāo)無反應(yīng)。
思路:
首先,我想到的原因是matplotlib的UI交互部分可能已過時或已修改過。所以我谷歌了下matplotlib的UI交互功能實(shí)現(xiàn)。找到了這個網(wǎng)頁(http://www.guofei.site/2017/09/26/matplotlib3.html)
這個網(wǎng)頁寫的比較清楚,而且配有例子,所以我單獨(dú)新建一個文件測試這個網(wǎng)頁上的兩個例子。兩個例子都是可以正常運(yùn)行的。這就令我十分好奇,因為源代碼中需要判斷的是 event.button 這個變量,所以我就將例子做了下修改,只輸出 event.button 變量。結(jié)果如下
測試代碼:
import matplotlib.pyplot
as plt
import numpy
as npfig, ax = plt.subplots()
x = np.linspace(
0,
10,
1000)
y = np.sin(x)
line = ax.plot(x, y)[
0]
def on_key_press(event):print(event.button)print(type(event.button))print(event.button
is 1)print(event.button ==
1)fig.canvas.mpl_disconnect(fig.canvas.manager.key_press_handler_id)
fig.canvas.mpl_connect(
'button_press_event', on_key_press)
plt.show()
結(jié)果當(dāng)運(yùn)行代碼后,我點(diǎn)擊鼠標(biāo)左鍵,輸出卻是:
1
<
class
False
True
這時我突然想起之前看到的 is 和 == 是有區(qū)別的。 is 判斷的是前后兩個值的地址是否相同,而 == 判斷的才是前后兩個值是否相同,如下:
>>> a =
1
>>> b =
1.0
>>> a
is b
False
>>> a == b
True
>>> id(a)
1356033504
>>> id(b)
1802191773368
所以只需要將源代碼中的 is 換為 == ,就可以創(chuàng)建和驅(qū)散鳥群了。
總結(jié):
通過這個模擬鳥群的代碼,學(xué)習(xí)到了在python中用matplotlib實(shí)現(xiàn)UI交互功能及 is 和 == 的區(qū)別。
總結(jié)
以上是生活随笔為你收集整理的python3环境下用matplotlib库实现UI交互的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。