前提
エージェントベースモデルでシミュレーションを行なっていて、その結果をmatplotlibのアニメーションで視覚化しています。
実現したいこと
2種類のエージェントが存在しているのですが、matplotlibでアニメーションで視覚化する際に
class AgentEdited(Agent)
で動かしているエージェントだけ区別し易くするために別の色で着色したいです。
発生している問題・エラーメッセージ
エラーメッセージ
該当のソースコード
python
1import numpy as np 2import matplotlib.pyplot as plt 3import matplotlib.animation as animation 4from IPython.display import HTML 5 6a1 = -0.034298 7b1 = 3.348394 8c1 = 4.252840 9d1 = -0.003423 10 11class Agent: 12 def __init__(self, name = None, pos = None, vel = None, SIZE = 10, VEL = 1, 13 RANGE_SEPARATE = 0.5): 14 self.name = name 15 self.pos = pos if pos else np.random.uniform(-SIZE, SIZE, 2) 16 self.vel = vel if vel else np.random.uniform(-VEL, VEL, 2) 17 self.SIZE = SIZE 18 self.VEL = VEL 19 self.RANGE_SEPARATE = RANGE_SEPARATE#分離範囲 20 self.vel_tmp = np.zeros(2)#移動 21 22 def distance(self, other):#ユークリッド距離 23 return np.linalg.norm(self.pos - other.pos) 24 25 def ruleSeparate(self, others, ratio = 1): 26 others = [other for other in others if self.distance(other) < self.RANGE_SEPARATE]#範囲内に入ったエージェントの選別 27 v = np.zeros(2) 28 if not others: 29 return 0 30 for other in others: 31 d = self.pos - other.pos#dが-になる時ある? 32 v += d / self.distance(other)#進行方向の単位ベクトル 33 self.vel_tmp += v / len(others) * ratio#平均を出してそれをratio倍する 34 return v / len(others) * ratio 35 36 37 38 def calculate(self, others): 39 self.ruleSeparate(others, 0.5) 40 41 def update(self) -> bool:#返り値の型名 42 self.vel += self.vel_tmp#進行速度ベクトル更新 43 v = np.linalg.norm(self.vel) 44 #壁に当たったら反転 45 if (abs(self.pos + self.vel)[0] > self.SIZE): 46 self.vel[0] = -self.vel[0] 47 if (abs(self.pos + self.vel)[1] > self.SIZE): 48 self.vel[1] = -self.vel[1] 49 50 self.pos += self.vel#位置更新 51 self.vel_tmp = np.zeros(2)##進行速度ベクトル初期化 52 return True 53 54class AgentEdited(Agent): 55 def __init__(self, *args, **kwargs): 56 super(AgentEdited, self).__init__(*args, **kwargs) 57 #クラス(子クラス)で別のクラス(親クラス)を継承できます。継承することで、親クラスのメソッドを子クラスから呼び出せる 58 #super().親クラスのメソッド # python3系での標準の書き方 59 #super(親クラスのオブジェクト, self).親クラスのメソッド # python2系での書き方 60 61 def ruleSeparate(self, others, ratio = 1): 62 others = [other for other in others if self.distance(other) < self.RANGE_SEPARATE] 63 v = np.zeros(2) 64 if not others: 65 return 0 66 for other in others: 67 d = self.pos - other.pos 68 vel = self.vel - other.vel 69 TTNP = d / (vel + 1e-5) # 0除算防止のため微小値を挿入 70 DINP = self.distance(other) 71 v += 1/(1+np.exp(-(c1+d1*TTNP))) * 1/(1+np.exp(-(b1+a1*DINP))) 72 self.vel_tmp += v / len(others) * ratio 73 return v / len(others) * ratio 74 75 def calculate(self, others): 76 self.ruleSeparate(others) # only separate 77 78def calc_rad(pos2, pos1):#角計算 79 return np.arctan2(pos2[1] - pos1[1], pos2[0] - pos1[0]) 80 81#np.arctan(x)は引数が一つでarctan(x)をラジアンで返す。返り値は-pi / 2からpi / 2(-90度から90度)の間になる。 82#np.arctan2(y, x)は引数が二つで、arctan(y / x)をラジアンで返す。この角度は、極座標平面において原点から座標(x, y)へのベクトルがx軸の正の方向となす角度(偏角)であり、返り値は-piからpi(-180度から180度)の間になる 83#print(np.degrees(np.arctan2(-1, 1))) 84# -45.0 85#print(np.degrees(np.arctan2(1, -1))) 86# 135.0 87 88def rotate_vec(vec, rad):#ベクトル更新 89 return np.dot(vec, np.array([[np.cos(rad), -np.sin(rad)], [np.sin(rad), np.cos(rad)]]).T) 90 91class AgentGoForWall(AgentEdited): 92 def __init__(self, *args, **kwargs): 93 super(AgentGoForWall, self).__init__(*args, **kwargs) 94 max_distance = 0 95 self.goal = None # 角が一番遠い場所 96 for px in [-self.SIZE, self.SIZE]: 97 for py in [-self.SIZE, self.SIZE]: 98 dist = np.linalg.norm(self.pos - np.array([px, py])) 99 if max_distance < dist: 100 max_distance = dist#最大値の更新 101 self.goal = np.array([px, py]) 102 self.vel = rotate_vec(np.array([self.VEL, 0]), calc_rad(self.goal, self.pos)) 103 104 def update(self) -> bool: 105 self.vel += self.vel_tmp 106 self.vel += rotate_vec(np.array([self.VEL, 0]), calc_rad(self.goal, self.pos)) 107 108 v = np.linalg.norm(self.vel) 109 110 if abs(self.pos + self.vel)[0] > self.SIZE or abs(self.pos + self.vel)[1] > self.SIZE: 111 return False # deactivate this Agent 112 113 self.pos += self.vel 114 self.vel_tmp = np.zeros(2) 115 return True 116 117class Boids: 118 def __init__(self, AGENT = 20):#Agent数 119 self.agents = [Agent() for _ in range(AGENT)] 120 121 def calculate(self): 122 for agent in self.agents: 123 agent.calculate([other for other in self.agents if agent != other]) 124 125 def update(self): 126 self.agents = [agent for agent in self.agents if agent.update()] 127 128 def simulation(self): 129 self.calculate() 130 self.update() 131 132 def positions(self):#showimageはpos_arrayを渡してた 133 x, y = list(), list() 134 for agent in self.agents: 135 x.append(agent.pos[0]) 136 y.append(agent.pos[1]) 137 return np.array(x), np.array(y) 138np.random.seed( 0 ) 139B = Boids(AGENT = 1) 140B.agents.append(AgentEdited()) 141#B.agents.append(Agent("Crazy", RANGE_SEPARATE = 1.5)) 142#B.agents.append(AgentGoForWall("Going to the far wall")) 143fig, ax = plt.subplots(figsize = (6, 6)) 144ax.set_xlim(-10, 10) 145ax.set_ylim(-10, 10) 146ax.grid(True) 147ims = [] 148for t in range(1000): 149 B.simulation() 150 plot_data = B.positions() 151 im=ax.plot(*plot_data,"o",ms=5,c="k") 152 ims.append(im) 153 154ani = animation.ArtistAnimation(fig, ims, interval=100, repeat=False) 155HTML(ani.to_jshtml())
試したこと
matplotlibについて検索したが、グラフの色変更などが多く一部のエージェントだけ着色する様な方法を見つけるには至リませんでした。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
回答2件
あなたの回答
tips
プレビュー
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2022/11/09 16:36