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
output_files/*
output/*
output_files/output/*

Binary file not shown.

View File

@ -25,10 +25,12 @@ try:
ConstructionFactory(construction_format, city).enrich()
UsageFactory(usage_format, city).enrich()
Matsim(city, 'output_files').export()
MatSimEngine('output_files/Montreal_config.xml').run()
# Matsim(city, 'output_files').export()
# 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/output_network.xml.gz', 'output/output_events.xml.gz', 'output_files')
visualizer.visualize()
except Exception as ex:

View File

@ -1,6 +1,6 @@
import gzip
import xmltodict
from lxml import etree
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
@ -22,61 +22,74 @@ class MatsimVisualizer():
self._G = nx.Graph()
self._traffic_per_tick = defaultdict(lambda: defaultdict(int))
self._cumulative_traffic = defaultdict(lambda: defaultdict(int))
self._cmap = cm.viridis
self._tick = 0
self._max_traffic = 0
def load_data(self):
# Load network data
# ====== LOAD NETWORK ====== #
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['@id']: (float(node['@x']), float(node['@y'])) for node in
network_doc['network']['nodes']['node']}
self._nodes = {node.get('id'): (float(node.get('x')), float(node.get('y')))
for node in network_doc.xpath('/network/nodes/node')}
# Parse links
self._links = [{
'id': link['@id'],
'from': link['@from'],
'to': link['@to']
} for link in network_doc['network']['links']['link']]
'id': link.get('id'),
'from': link.get('from'),
'to': link.get('to'),
'vehicles': 0,
} for link in network_doc.xpath('/network/links/link')]
seen_links = set()
cumulative_traffic = defaultdict(int)
link_state = defaultdict(list)
# Load and parse the events file
# ====== LOAD EVENTS ====== #
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']:
link_id = event.get('@link')
event_type = event.get('@type')
tick = float(event.get('@time'))
vehicle_id = event.get('@vehicle')
self._tick = 0
last_time = None
for event in events_doc.xpath('/events/event'):
link_id = event.get('link')
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 event_type == 'entered link' or event_type == 'vehicle enters traffic':
self._traffic_per_tick[tick][link_id] += 1
link_state[link_id].append(vehicle_id)
elif event_type == 'left link' or event_type == 'vehicle leaves traffic':
self._traffic_per_tick[tick][link_id] -= 1
link_state[link_id].remove(vehicle_id)
if link_id is not None and event_type is not None and time is not None:
if event_type in ['entered link', 'vehicle enters traffic']:
self._traffic_per_tick[self._tick][link_id] += 1
seen_links.add(link_id)
cumulative_traffic[link_id] += 1
if self._max_traffic < cumulative_traffic[link_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:
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
actual_tick = 0
sorted_ticks = sorted(self._traffic_per_tick.keys())
for tick in sorted_ticks:
if actual_tick not in self._cumulative_traffic:
# Start with the vehicle counts of the previous tick
self._cumulative_traffic[actual_tick] = defaultdict(int, self._cumulative_traffic.get(actual_tick - 1, {}))
# ====== FILTER NODES ====== #
seen_nodes = set()
for link in self._links:
seen_nodes.add(link['from'])
seen_nodes.add(link['to'])
# Apply the changes recorded for the current tick
for link_id, change in self._traffic_per_tick[tick].items():
self._cumulative_traffic[actual_tick][link_id] += change
actual_tick += 1 # Move to the next tick
filtered_nodes = {node_id: self._nodes[node_id] for node_id in seen_nodes if node_id in self._nodes}
self._nodes = filtered_nodes
def create_graph(self):
for node_id, coords in self._nodes.items():
@ -86,23 +99,30 @@ class MatsimVisualizer():
self._pos = nx.get_node_attributes(self._G, 'pos')
def setup_color_mapping(self):
# Find max traffic to setup the normalization instance
max_traffic = max(max(self._cumulative_traffic[tick].values()) for tick in self._cumulative_traffic)
self.norm = colors.Normalize(vmin=0, vmax=max_traffic)
self.norm = colors.Normalize(vmin=0, vmax=self._max_traffic)
def update(self, frame_number):
tick = sorted(self._cumulative_traffic.keys())[frame_number]
traffic_data = self._cumulative_traffic[tick]
traffic_change = self._traffic_per_tick[self._tick]
edge_colors = [self._cmap(self.norm(traffic_data.get(link['id'], 0))) for link in self._links]
edge_widths = [1 + self.norm(traffic_data.get(link['id'], 0)) * 10 for link in self._links]
edge_colors = []
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()
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)
plt.title(f"Time: {tick}")
plt.title(f"Time: {self._tick}")
self._tick += 1
def visualize(self):
self.load_data()
@ -115,6 +135,7 @@ class MatsimVisualizer():
sm.set_array([])
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)
plt.show()

View File

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