Update visualizer to remove none used links

This commit is contained in:
Ruben1729 2024-02-15 14:32:49 -05:00
parent 6c5bae5839
commit 50d7fbaca2
6 changed files with 76 additions and 54 deletions

2
.gitignore vendored
View File

@ -8,4 +8,4 @@ input_files/*
# Ignore all files inside the 'output_files' directory # Ignore all files inside the 'output_files' directory
output_files/* output_files/*
output/* output_files/output/*

Binary file not shown.

View File

@ -25,10 +25,12 @@ try:
ConstructionFactory(construction_format, city).enrich() ConstructionFactory(construction_format, city).enrich()
UsageFactory(usage_format, city).enrich() UsageFactory(usage_format, city).enrich()
Matsim(city, 'output_files').export() # Matsim(city, 'output_files').export()
MatSimEngine('output_files/Montreal_config.xml').run() # MatSimEngine('output_files/Montreal_config.xml').run()
# MatSimEngine('equil/config.xml').run()
visualizer = MatsimVisualizer('output_files/Montreal/output_network.xml.gz', 'output_files/Montreal/output_events.xml.gz', 'output_files') visualizer = MatsimVisualizer('output_files/Montreal/output_network.xml.gz', 'output_files/Montreal/output_events.xml.gz', 'output_files')
# visualizer = MatsimVisualizer('output/output_network.xml.gz', 'output/output_events.xml.gz', 'output_files')
visualizer.visualize() visualizer.visualize()
except Exception as ex: except Exception as ex:

View File

@ -1,6 +1,6 @@
import gzip import gzip
import xmltodict from lxml import etree
import networkx as nx import networkx as nx
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation from matplotlib.animation import FuncAnimation
@ -22,61 +22,74 @@ class MatsimVisualizer():
self._G = nx.Graph() self._G = nx.Graph()
self._traffic_per_tick = defaultdict(lambda: defaultdict(int)) self._traffic_per_tick = defaultdict(lambda: defaultdict(int))
self._cumulative_traffic = defaultdict(lambda: defaultdict(int))
self._cmap = cm.viridis self._cmap = cm.viridis
self._tick = 0
self._max_traffic = 0
def load_data(self): def load_data(self):
# Load network data # ====== LOAD NETWORK ====== #
with gzip.open(self._network_file_path, 'rb') as file: with gzip.open(self._network_file_path, 'rb') as file:
network_doc = xmltodict.parse(file.read().decode('utf-8')) network_doc = etree.parse(file)
# Parse nodes self._nodes = {node.get('id'): (float(node.get('x')), float(node.get('y')))
self._nodes = {node['@id']: (float(node['@x']), float(node['@y'])) for node in for node in network_doc.xpath('/network/nodes/node')}
network_doc['network']['nodes']['node']}
# Parse links
self._links = [{ self._links = [{
'id': link['@id'], 'id': link.get('id'),
'from': link['@from'], 'from': link.get('from'),
'to': link['@to'] 'to': link.get('to'),
} for link in network_doc['network']['links']['link']] 'vehicles': 0,
} for link in network_doc.xpath('/network/links/link')]
seen_links = set()
cumulative_traffic = defaultdict(int)
link_state = defaultdict(list) # ====== LOAD EVENTS ====== #
# Load and parse the events file
with gzip.open(self._events_file_path, 'rb') as file: with gzip.open(self._events_file_path, 'rb') as file:
events_doc = xmltodict.parse(file.read().decode('utf-8')) events_doc = etree.parse(file)
for event in events_doc['events']['event']: self._tick = 0
link_id = event.get('@link') last_time = None
event_type = event.get('@type') for event in events_doc.xpath('/events/event'):
tick = float(event.get('@time')) link_id = event.get('link')
vehicle_id = event.get('@vehicle') event_type = event.get('type')
time = float(event.get('time'))
vehicle_id = event.get('vehicle')
ticked = False
if link_id is not None and event_type is not None and tick is not None: if link_id is not None and event_type is not None and time is not None:
if event_type == 'entered link' or event_type == 'vehicle enters traffic': if event_type in ['entered link', 'vehicle enters traffic']:
self._traffic_per_tick[tick][link_id] += 1 self._traffic_per_tick[self._tick][link_id] += 1
link_state[link_id].append(vehicle_id) seen_links.add(link_id)
elif event_type == 'left link' or event_type == 'vehicle leaves traffic': cumulative_traffic[link_id] += 1
self._traffic_per_tick[tick][link_id] -= 1 if self._max_traffic < cumulative_traffic[link_id]:
link_state[link_id].remove(vehicle_id) self._max_traffic = cumulative_traffic[link_id]
ticked = True
elif event_type in ['left link', 'vehicle leaves traffic']:
self._traffic_per_tick[self._tick][link_id] -= 1
cumulative_traffic[link_id] -= 1
ticked = True
if ticked and last_time is not None and last_time != time:
self._tick += 1
last_time = time
# ====== FILTER LINKS ====== #
unique_links = []
for link in self._links: for link in self._links:
self._cumulative_traffic[0][link['id']] = 0 if link['id'] in seen_links:
unique_links.append(link)
self._links = unique_links
# Accumulate the counts to get the total number of vehicles on each link up to each tick # ====== FILTER NODES ====== #
actual_tick = 0 seen_nodes = set()
sorted_ticks = sorted(self._traffic_per_tick.keys()) for link in self._links:
for tick in sorted_ticks: seen_nodes.add(link['from'])
if actual_tick not in self._cumulative_traffic: seen_nodes.add(link['to'])
# Start with the vehicle counts of the previous tick
self._cumulative_traffic[actual_tick] = defaultdict(int, self._cumulative_traffic.get(actual_tick - 1, {}))
# Apply the changes recorded for the current tick filtered_nodes = {node_id: self._nodes[node_id] for node_id in seen_nodes if node_id in self._nodes}
for link_id, change in self._traffic_per_tick[tick].items(): self._nodes = filtered_nodes
self._cumulative_traffic[actual_tick][link_id] += change
actual_tick += 1 # Move to the next tick
def create_graph(self): def create_graph(self):
for node_id, coords in self._nodes.items(): for node_id, coords in self._nodes.items():
@ -86,23 +99,30 @@ class MatsimVisualizer():
self._pos = nx.get_node_attributes(self._G, 'pos') self._pos = nx.get_node_attributes(self._G, 'pos')
def setup_color_mapping(self): def setup_color_mapping(self):
# Find max traffic to setup the normalization instance self.norm = colors.Normalize(vmin=0, vmax=self._max_traffic)
max_traffic = max(max(self._cumulative_traffic[tick].values()) for tick in self._cumulative_traffic)
self.norm = colors.Normalize(vmin=0, vmax=max_traffic)
def update(self, frame_number): def update(self, frame_number):
tick = sorted(self._cumulative_traffic.keys())[frame_number] traffic_change = self._traffic_per_tick[self._tick]
traffic_data = self._cumulative_traffic[tick]
edge_colors = [self._cmap(self.norm(traffic_data.get(link['id'], 0))) for link in self._links] edge_colors = []
edge_widths = [1 + self.norm(traffic_data.get(link['id'], 0)) * 10 for link in self._links] edge_widths = []
for link in self._links:
for link_id, change in traffic_change.items():
if link_id == link['id']:
link['vehicles'] += change
break
edge_colors.append(self._cmap(link['vehicles']))
edge_widths.append(1 + self.norm(link['vehicles'])*10)
plt.cla() plt.cla()
nx.draw(self._G, self._pos, node_size=0, node_color='blue', width=edge_widths, edge_color=edge_colors, nx.draw(self._G, self._pos, node_size=0, node_color='blue', width=edge_widths, edge_color=edge_colors,
with_labels=False, with_labels=False,
edge_cmap=self._cmap) edge_cmap=self._cmap)
plt.title(f"Time: {tick}") plt.title(f"Time: {self._tick}")
self._tick += 1
def visualize(self): def visualize(self):
self.load_data() self.load_data()
@ -115,6 +135,7 @@ class MatsimVisualizer():
sm.set_array([]) sm.set_array([])
plt.colorbar(sm, ax=ax, label='Traffic Density') plt.colorbar(sm, ax=ax, label='Traffic Density')
ani = FuncAnimation(fig, self.update, frames=len(self._cumulative_traffic), repeat=False) 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.save(f"{self._output_file_path}/traffic_animation.gif", writer='ffmpeg', fps=5)
plt.show() plt.show()

View File

@ -3,6 +3,5 @@ geopandas~=0.14.2
shapely~=2.0.2 shapely~=2.0.2
lxml~=5.1.0 lxml~=5.1.0
pathlib~=1.0.1 pathlib~=1.0.1
xmltodict~=0.13.0
networkx~=3.2.1 networkx~=3.2.1
matplotlib~=3.8.2 matplotlib~=3.8.2