質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

482閲覧

matplotlibのアニメーションに色付け

IT_takumin

総合スコア8

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/11/08 20:13

前提

エージェントベースモデルでシミュレーションを行なっていて、その結果を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/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

plotのかわりにscatterを使うと、点ごとに色を指定することができます。

Python

1import matplotlib.pyplot as plt 2import matplotlib.animation as animation 3 4fig, ax = plt.subplots(figsize = (3,3)) 5ax.set_xlim(-1, 10) 6ax.set_ylim(-1, 10) 7ax.grid(True) 8ims = [] 9for t in range(3): 10 im=ax.scatter([1,2,3],[t,2*t,3*t], s=5, c=['r','g','b'], marker='o') 11 ims.append([im]) 12 13ani = animation.ArtistAnimation(fig, ims, interval=500, repeat=False) 14ani.save('ret.gif')

イメージ説明

投稿2022/11/09 01:23

can110

総合スコア38258

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IT_takumin

2022/11/09 16:36

ありがとうございます!
guest

0

ベストアンサー

can110さんの解答に補足までに何パターンか示しておきます.

1. Agentに付けたい色を設定しておく方法

全部のAgentに異なる色を割り振れるので,こちらの方が汎用性が高い.
Agentの種類ごとにデフォルト色を用意する方法とする.

Python

1class Agent: 2 def __init__(self, name = None, pos = None, vel = None, SIZE = 10, VEL = 1, 3 RANGE_SEPARATE = 0.5, color = None): 4 # (略) 5 self.color = color if color or 'k' 6 7class AgentEdited(Agent): 8 def __init__(self, *args, **kwargs): 9 super(AgentEdited, self).__init__(*args, **kwargs) 10 self.color = kwargs.get('color', 'r') 11 12# (略) 13 14class AgentGoForWall(AgentEdited): 15 def __init__(self, *args, **kwargs): 16 super(AgentGoForWall, self).__init__(*args, **kwargs) 17 self.color = kwargs.get('color', 'b') 18 19class Boids: 20 # (略) 21 def positions(self): 22 x, y, c = list(), list(), list() 23 for agent in self.agents: 24 x.append(agent.pos[0]) 25 y.append(agent.pos[1]) 26 c.append(agent.color) 27 return (np.array(x), np.array(y)), c 28 29# (略) 30for t in range(1000): 31 B.simulation() 32 plot_data, plot_color = B.positions() 33 im=ax.scatter(*plot_data,"o",ms=5,c=plot_color)

エージェントのタイプごとにデフォルト色の設定をしておいた上で,個別に色設定B.append(AgentEdited(color = 'y'))とかができるようになる.
なんなら解析の途中から色を変化させることもできる.その際はagent.color = 'g'とか書けたりして,エージェントの状態を表現できる.

2. isinstanceを利用してAgentインスタンスを調べて色付ける方法

生成元インスタンスからしか判断できないこっちの方が汎用性は低い.
さっきはデフォルト色を用意して生成元が同じタイプのエージェントでも別の色を割り振れたが,下記コードでそれを実現しようとするのはめんどくさい.
なんならisinstance(AgentEdited(), Agent)Trueになってしまう等の問題もあって条件分岐/管理がめんどくさい.

Python

1class Boids: 2 # (略) 3 def positions(self): 4 x, y, c = list(), list(), list() 5 for agent in self.agents: 6 x.append(agent.pos[0]) 7 y.append(agent.pos[1]) 8 if isinstance(agent, AgentGoForWall): 9 c.append('b') 10 elif isinstance(angent, AgentEdited): 11 c.append('r') 12 else: # 残りは Agent しかないので isinstance(agent, Agent) と等価 13 c.append('k') 14 return (np.array(x), np.array(y)), c 15 16# (略) 17for t in range(1000): 18 B.simulation() 19 plot_data, plot_color = B.positions() 20 im=ax.scatter(*plot_data,"o",ms=5,c=plot_color)

投稿2022/11/09 06:44

編集2022/11/09 07:23
PondVillege

総合スコア1579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IT_takumin

2022/11/11 01:36 編集

教えて頂いた1.の手法を実装したところ, ''' im=ax.scatter(*plot_data,"o",ms=5,c=plot_color) ''' で下記の様なエラーが出てしまっているみたいなのですが、調べても何が問題なのかもわからず、解決方法が分からなかったので可能であれば教えて頂けないでしょうか。 ''' TypeError Traceback (most recent call last) <ipython-input-3-f29fe7fc65f3> in <module> 10 B.simulation() 11 plot_data,plot_color = B.positions() ---> 12 im=ax.scatter(*plot_data,"o",ms=5,c=plot_color) 13 ims.append(im) 14 4 frames /usr/local/lib/python3.7/dist-packages/matplotlib/collections.py in set_sizes(self, sizes, dpi) 883 self._sizes = np.asarray(sizes) 884 self._transforms = np.zeros((len(self._sizes), 3, 3)) --> 885 scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor 886 self._transforms[:, 0, 0] = scale 887 self._transforms[:, 1, 1] = scale TypeError: ufunc 'sqrt' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' '''
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問