From 2ab91cfaebae5d2ab922a3bcdbd3d6babb96a565 Mon Sep 17 00:00:00 2001 From: Ruben1729 Date: Tue, 5 Mar 2024 15:14:36 -0500 Subject: [PATCH] Visualizer upgrades --- __pycache__/matsim.cpython-39.pyc | Bin 11174 -> 11259 bytes __pycache__/matsim_engine.cpython-39.pyc | Bin 737 -> 737 bytes __pycache__/matsim_visualizer.cpython-39.pyc | Bin 4666 -> 7247 bytes main.py | 10 +- matsim.py | 21 ++-- matsim_visualizer.py | 105 ++++++++++++++----- output_files/.gitignore | 2 - 7 files changed, 95 insertions(+), 43 deletions(-) delete mode 100644 output_files/.gitignore diff --git a/__pycache__/matsim.cpython-39.pyc b/__pycache__/matsim.cpython-39.pyc index 23725b71602c03666e039e6b58501c55104454f7..0a7fc622a38c599384bf21db8558278c9b72df79 100644 GIT binary patch delta 2401 zcmZ`)Yit`u5Wc-TpU*z~{7h`;;WTM+>$FviS_QTAmFCq#la$tKD;H|H*^6;%$Ladg z2iUkGMQTAQDhm>brbHsJ z%1HY(7Lt+4Z{Z~FzH#H~?eC(ZA$~@P!c}<-@$wz= zE)wU@%kwQ7IAPu;&|zjN#<__SGdJ=#92;~$NL=vrz*83aZO4Y%fvQxI#vG;s=%kLA zFhv&T3eIx^bzYOJvZ;dJHASd$N@k;`o2pafMbK6q)KSHEUA@9Ho2$->b4(laz}g!Y z0QIl{T9o-fuUFNIW7c0$=Liu_zkb@RNVTzm8JrDOlsRICD-Lkrx+Ya!rZC%35vjW( zQ!OUEEx_nm7`-@B{hBl#JOt8E4C)-K z2{dePyeJT8!-{nyu4x1v5jG-co!6EInY{!%^8_kFr9Tm;k0ye=sVglym zDN^;A&0{SUPmaKw(pW2vo|qP^-imiN4uUpt6PponBU2b#1@Sl0X4*0>&9>9lIa1XZ zY|s`;2G(sea@A*cRD2bkt}<7Hq zRrpFfLI*%nWQ{Ob(g-Wxjcz(QnJ-X&+%=h4!(@~@`wB+U7&jSST&WgF$kb7iLR zb?*0^N_Jub9PnH2t{x_$iFa^#D0Qf>`#|PEUw;a&)Z#KVe9+RDR)_Wv>`Pg`rS;z7 zRBCvTi&`SW@J?8&St^?hTv-Y=MoQG+yR{a{&oq8Q+tSQ1PgZd8IGOUuvj&|k7-iPV zKh*}FQqSa#vv||eQjU&V+PPvOGg2BiAskC9O_~#vW@a>BFjm}8hF7u+p7Kcm!66cH zUU7s)UF3&6{n{!~CNfdx6*$0H zF9e#}mY88@=>d@zO3yzDbdUyqC(u)~E$uCr*k)71k_tx7l8cabphuQ1BaL#Ocq?9d zKq~n^^-%~W#S(yQEkY;4dVW2)^~4644kZIN=h#M+Bj3QSX;|8!zQg-_`-W2cyAQB! zwm1(Jbg=Ar&S1OHcoRY&LO;T?B;#^`Zw@s!+MW0auJLAB^4StQ#hm=<&|~2h>Bp>3 z*FOkpP-b3_43o&aQk0NrU5@n-(o)~obVKt0D-1EdVdQ=oo@HU+@ho>HOKD~z%d*9V z+T$^7h6f&~4AWp`!(0}}fc~r6T_$&nk=Kc9XNiIm;(U&NZA9R64j@=)O~;lnWNs@zLxB^TU8q&syLYW+sXTjWWk+7Ps|rS};slL~tcH?)a(1!w0F{&&Nd zK|52wvSyx;)qFa!m2Bf*Ci>%excl90MLl*^ubZ)QN$A1Og?L){R>_OO#uos~l0h4M+ z$neMv&%w~evJ5R%z*2X>O@r>W3qJ*AWRmQJLf~IiiJt_C$L>6`6vhSwe@U+iHNjMM Hs8jntua5)A delta 2329 zcmZ`)O>7%Q6yDiguh(mP?KsYV>cmN!$W0ZJ{-spVHp)*GTBU&oS{WhB&1~Jc{_E_f zKXk1K(hH@awu34`TS$aJf&&*{>473HNJxm|0+kRT#DOb^0)_V`Y0?CUv){aV@6Ej5 zef!7p509JKaM+OGuQKwL^}~VdW;?lgz5mIRM52Vsg+S4eB_b7r>5$;4g>cbKn?U>0 z5vrx5)Ss?9BvG9PE=x49D5qo8pux*hx}Jt;7}hv7X#~~=8lzEKcbTLcseDXI)nE7S z>%{X-m*+|j|C+p8yCL5t#K))Aog~CBtNTea|6G08j^44*8iaxJH0wg8%$z>{y>Gi& z2b=&rqwv_Byh+=>@K#lEmAr3Edg)+Qb=AC<_XEA7>T?P8wMa`kNCUT|WkMw2XvlF4 z*GK&=5}@89Ey^f6yZ`JC)O3P?A(SqXRT_0j4nn@IRy8LKa&wVT{fx>!aUu)USR}84 zxaz0=DjGAv{9rZU2J+E-9qeOq39vpcffRXhkegM*^@D4MF#X-xPeG%>X&a;ecM=5oOeiquMZ@KU5(6EXEVt@$>W zxKdupx6_t4NaI|^-ERG}xkp|5&ge#YQQ{ZzLP+95?4E-a4FfIt9#MM$YE&X@EThc#q3 zBeWn}Sy5hNuvQecA+!T{zH`~ayv4Tg;Xtyh1KFJjNq`jblv!p!=$u&dOXU z7CdueWOVY#N-BnAnQ80l2F8=45HL?+rpO*Qy*ypjJH z>S^2y+LTmb)>LJ96&2_JmHPPB@XuNgh}bqBHJiIJ5RotuxM$e&Co8NxYuUD^u=x_y z(%^^9uJ|UWqHydIf5nUwxpve1TRtIby|JL1%Kbne+`DgZ5dI(NL#tHEzg~Zln)P;B zEk6IPu8YKZG&Z^*I%Q)|iRSQ>f|c{sBGd)CB+DLa8*SzKO@}%$X3B9m@+oH-2n#YH@<5UU&th@6_(~JS3!xf7ZK; z4DsK4Clcr!6BBJcKoQ#k5PZbbeM96x?P}i^Wpk!5v0w7L+meToO371GsV2{#$E&YFC0v+{W$V%oG7Xvs)IjS7n3O@s|0?Exgae_=XDcm Gmiz}seDJ{l diff --git a/__pycache__/matsim_engine.cpython-39.pyc b/__pycache__/matsim_engine.cpython-39.pyc index bdf04f856796a51b20071b01c53198ba79da7e96..a7227acf94e9aa0881fc6a56ce065117e93b3b58 100644 GIT binary patch delta 20 acmaFJ`jC}7k(ZZ?0SHc|Ki|lGjR^odY6b}a delta 20 acmaFJ`jC}7k(ZZ?0SH3)&Tizs#smO0m<1pJ diff --git a/__pycache__/matsim_visualizer.cpython-39.pyc b/__pycache__/matsim_visualizer.cpython-39.pyc index e80f40ff7a3820d986892b568a86d0b6a6c9ae05..ec8867fa321b8461f844126c7737cfd52ef5abc5 100644 GIT binary patch literal 7247 zcmb_h%a0?+dGD@nHk;4kydS&X(2AlpZDm%H9|<;t%|q+e28buJR<;vjolXy{In$ix zW2%d@Geq+c&jMNjURX(vmH>bmfRMkSPeF1p_GZ|InzIPSSr?qeS zG7h`n4dbC7g`+?`XgPE5r#7+hHh%F>074@%JY%0ASOH`TS_(pXz~mHk6wD_UFmA#C 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 y > self._viewport[3]: + self._nodes[f"facility_{node.get('id')}"] = (x, y) + # ====== LOAD NETWORK ====== # with gzip.open(self._network_file_path, 'rb') as file: network_doc = etree.parse(file) @@ -103,54 +118,86 @@ class MatsimVisualizer(): if ticked: self._tick += 1 - def create_graph(self): + def _create_graph(self): for node_id, coords in self._nodes.items(): - self._G.add_node(node_id, pos=coords) + self._G.add_node(node_id, pos=coords, is_facility=node_id.startswith('facility_')) for link in self._links: - self._G.add_edge(link['from'], link['to']) + self._G.add_edge(link['from'], link['to'], id=link['id']) self._pos = nx.get_node_attributes(self._G, 'pos') - def setup_color_mapping(self): - self.norm = colors.Normalize(vmin=0, vmax=self._max_traffic) + if self._show_nearby_nodes: + self._identify_close_nodes(radius=100) # TODO: move to load data - def update(self, frame): + def _identify_close_nodes(self, radius): + facility_coords = {node: self._pos[node] for node in self._G.nodes if self._G.nodes[node].get('is_facility')} + + for node, coords in self._pos.items(): + if self._G.nodes[node].get('is_facility'): + continue + + for facility_node, facility_coord in facility_coords.items(): + if self._euclidean_distance(coords, facility_coord) <= radius: + self._close_to_facility_nodes.add(node) + break + + def _setup_color_mapping(self): + self.norm = colors.Normalize(vmin=0, vmax=self._max_traffic/2) + + def _update(self, frame): traffic_change = self._traffic_per_tick[self._tick] - edge_colors = [] - edge_widths = [] + edge_colors_dict = {} + edge_widths_dict = {} for link in self._links: for link_id, change in traffic_change.items(): if link_id == link['id']: link['vehicles'] += change - edge_colors.append(self._cmap(link['vehicles'])) - edge_widths.append(1 + self.norm(link['vehicles']) * 10) + edge_colors_dict[link['id']] = self._cmap(self.norm(link['vehicles'])) + edge_widths_dict[link['id']] = 1 + self.norm(link['vehicles']) + + edgelist = [(link['from'], link['to']) for link in self._links] + edge_colors = [edge_colors_dict[link["id"]] for link in self._links] + edge_widths = [edge_widths_dict[link["id"]] for link in self._links] plt.cla() - nx.draw(self._G, self._pos, node_size=0, node_color='blue', width=edge_widths, edge_color=edge_colors, - with_labels=False, - edge_cmap=self._cmap) + # Draw Facilities + if self._show_facilities: + facility_nodes = {node: pos for node, pos in self._pos.items() if self._G.nodes[node]['is_facility']} + nx.draw_networkx_nodes(self._G, facility_nodes, facility_nodes.keys(), node_size=1, node_color='red') + + # Draw Network + if self._show_nearby_nodes: + close_nodes = {node: self._pos[node] for node in self._close_to_facility_nodes if node in self._pos} + nx.draw_networkx_nodes(self._G, self._pos, close_nodes.keys(), node_size=1, node_color='blue') + nx.draw_networkx_edges(self._G, self._pos, edgelist=edgelist, width=edge_widths, edge_color=edge_colors, edge_cmap=self._cmap) plt.title(f"Time: {self._tick}") self._tick += 1 - def visualize(self): - self.load_data() - self.create_graph() - self.setup_color_mapping() + def visualize(self, fps=15, colormap='inferno'): + self._load_data() + self._create_graph() + self._setup_color_mapping() fig, ax = plt.subplots() - ax.set_aspect((self._max_x - self._min_x) / (self._max_y - self._min_y)) + if hasattr(cm, colormap): + self._cmap = getattr(cm, colormap) + else: + print(f"Colormap '{colormap}' not recognized. Falling back to 'inferno'. Please select from: 'inferno', 'plasma', 'magma', 'spring', 'summer', 'autumn', or 'winter'.") + self._cmap = cm.inferno + sm = plt.cm.ScalarMappable(cmap=self._cmap, norm=self.norm) sm.set_array([]) plt.colorbar(sm, ax=ax, label='Traffic Density') self._tick = 0 - ani = FuncAnimation(fig, self.update, frames=len(self._traffic_per_tick), repeat=False) - ani.save(f"{self._output_file_path}/traffic_animation.gif", writer='ffmpeg', fps=5) + ani = FuncAnimation(fig, self._update, frames=len(self._traffic_per_tick), repeat=False) + ani.save(f"{self._output_file_path}/traffic_animation.gif", writer='ffmpeg', fps=fps) plt.show() - print(f"Largest amount of vehicles ({self._max_traffic}) seen at {self._max_traffic_tick} on link {self._max_traffic_link}") + def _euclidean_distance(self, coord1, coord2): + return ((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2) ** 0.5 diff --git a/output_files/.gitignore b/output_files/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/output_files/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file