更新热力图绘制

This commit is contained in:
Zihan Ye 2026-04-17 07:09:09 +08:00
parent 05ef01d93f
commit 288f67ae50
4 changed files with 68 additions and 15 deletions

View File

@ -17,6 +17,7 @@ sumo:
environment: environment:
control_interval: 60 control_interval: 60
warmup_time: 900
control_segment_length_m: 1000 control_segment_length_m: 1000
detector_spacing_m: 100 detector_spacing_m: 100
detector_start_offset_m: 50 detector_start_offset_m: 50

View File

@ -59,7 +59,7 @@ class SUMOEdgeVSLEnvironment:
self.control_interval = env_cfg["control_interval"] self.control_interval = env_cfg["control_interval"]
self.steps_per_action = int(self.control_interval / self.step_length) self.steps_per_action = int(self.control_interval / self.step_length)
self.warmup_time = 900 self.warmup_time = int(env_cfg.get("warmup_time", 900))
self.episode_length = int( self.episode_length = int(
(self.end_time - self.begin_time - self.warmup_time) / self.control_interval (self.end_time - self.begin_time - self.warmup_time) / self.control_interval
) )
@ -301,7 +301,7 @@ class SUMOEdgeVSLEnvironment:
self._interval_mainline_travel_times = [] self._interval_mainline_travel_times = []
self._start_sumo(seed=seed) self._start_sumo(seed=seed)
warmup_steps = int(900 / self.control_interval) warmup_steps = int(self.warmup_time / self.control_interval)
for _ in range(warmup_steps): for _ in range(warmup_steps):
for _ in range(self.steps_per_action): for _ in range(self.steps_per_action):
traci.simulationStep() traci.simulationStep()

View File

@ -935,14 +935,12 @@ def plot_model_heatmaps(edge_df: pd.DataFrame, detector_df: pd.DataFrame, output
occ_grid = detector_model_df.pivot(index="cell_id", columns="step", values="occupancy").reindex(ordered_cell_ids).values occ_grid = detector_model_df.pivot(index="cell_id", columns="step", values="occupancy").reindex(ordered_cell_ids).values
edge_order = ( edge_order = (
edge_model_df[["edge_index", "edge_id"]] edge_model_df[edge_model_df["action_applied"].astype(bool)][["edge_index", "edge_id"]]
.drop_duplicates() .drop_duplicates()
.sort_values("edge_index") .sort_values("edge_index")
) )
ordered_edge_ids = edge_order["edge_id"].tolist() ordered_edge_ids = edge_order["edge_id"].tolist()
action_plot_df = edge_model_df.copy() action_plot_df = edge_model_df[edge_model_df["action_applied"].astype(bool)].copy()
if "action_applied" in action_plot_df.columns:
action_plot_df.loc[~action_plot_df["action_applied"].astype(bool), "action_speed_kmh"] = np.nan
action_grid = ( action_grid = (
action_plot_df.pivot(index="edge_id", columns="step", values="action_speed_kmh") action_plot_df.pivot(index="edge_id", columns="step", values="action_speed_kmh")
.reindex(ordered_edge_ids) .reindex(ordered_edge_ids)
@ -956,18 +954,23 @@ def plot_model_heatmaps(edge_df: pd.DataFrame, detector_df: pd.DataFrame, output
f"{MODEL_LABELS[model_name]} Measured Speed (km/h)", f"{MODEL_LABELS[model_name]} Measured Speed (km/h)",
"Detector Cell (bottom=upstream, top=downstream)", "Detector Cell (bottom=upstream, top=downstream)",
), ),
]
if ordered_edge_ids:
panels.append(
build_action_panel( build_action_panel(
action_grid, action_grid,
ordered_edge_ids, ordered_edge_ids,
f"{MODEL_LABELS[model_name]} Applied VSL (km/h)", f"{MODEL_LABELS[model_name]} Applied VSL (km/h)",
), )
)
panels.append(
build_occupancy_panel( build_occupancy_panel(
occ_grid, occ_grid,
ordered_cell_ids, ordered_cell_ids,
f"{MODEL_LABELS[model_name]} Occupancy (%)", f"{MODEL_LABELS[model_name]} Occupancy (%)",
"Detector Cell (bottom=upstream, top=downstream)", "Detector Cell (bottom=upstream, top=downstream)",
), )
] )
save_heatmap_panels( save_heatmap_panels(
os.path.join(heatmap_dir, f"{model_name}_heatmaps.png"), os.path.join(heatmap_dir, f"{model_name}_heatmaps.png"),
panels, panels,

View File

@ -220,6 +220,39 @@ def _build_detector_rows_from_xml(log_dir: str, episode: int) -> List[Dict]:
return detector_rows return detector_rows
def _align_detector_rows_to_decision_steps(
detector_rows: Sequence[Dict],
step_rows: Sequence[Dict],
) -> List[Dict]:
if not detector_rows or not step_rows:
return list(detector_rows)
detector_step_values = sorted({int(row["step"]) for row in detector_rows})
decision_step_values = sorted({int(row["step"]) for row in step_rows})
if not detector_step_values or not decision_step_values:
return list(detector_rows)
excess_steps = len(detector_step_values) - len(decision_step_values)
if excess_steps <= 0:
return list(detector_rows)
kept_detector_steps = detector_step_values[excess_steps:]
step_mapping = {
old_step: new_step
for old_step, new_step in zip(kept_detector_steps, decision_step_values)
}
aligned_rows: List[Dict] = []
for row in detector_rows:
old_step = int(row["step"])
if old_step not in step_mapping:
continue
aligned_row = dict(row)
aligned_row["step"] = step_mapping[old_step]
aligned_rows.append(aligned_row)
return aligned_rows
def _plot_episode_heatmap( def _plot_episode_heatmap(
path: str, path: str,
edge_rows: Sequence[Dict], edge_rows: Sequence[Dict],
@ -246,7 +279,21 @@ def _plot_episode_heatmap(
step_to_col = {step: idx for idx, step in enumerate(step_values)} step_to_col = {step: idx for idx, step in enumerate(step_values)}
panels = [] panels = []
if has_action: if has_action:
ordered_edge_ids = list(edge_ids) active_edge_ids = {
str(row["edge_id"])
for row in edge_rows
if bool(row.get("action_applied", True))
}
ordered_edge_ids = [edge_id for edge_id in edge_ids if edge_id in active_edge_ids]
if not ordered_edge_ids and active_edge_ids:
ordered_edge_ids = [
str(row["edge_id"])
for row in sorted(edge_rows, key=lambda item: int(item["edge_index"]))
if bool(row.get("action_applied", True))
]
ordered_edge_ids = list(dict.fromkeys(ordered_edge_ids))
if not ordered_edge_ids:
ordered_edge_ids = []
edge_to_row = {edge_id: idx for idx, edge_id in enumerate(ordered_edge_ids)} edge_to_row = {edge_id: idx for idx, edge_id in enumerate(ordered_edge_ids)}
action_grid = np.full((len(ordered_edge_ids), num_steps), np.nan, dtype=np.float32) action_grid = np.full((len(ordered_edge_ids), num_steps), np.nan, dtype=np.float32)
for row in edge_rows: for row in edge_rows:
@ -258,6 +305,7 @@ def _plot_episode_heatmap(
row_idx = edge_to_row[edge_id] row_idx = edge_to_row[edge_id]
col_idx = step_to_col[int(row["step"])] col_idx = step_to_col[int(row["step"])]
action_grid[row_idx, col_idx] = _safe_float(row["action_speed_kmh"]) action_grid[row_idx, col_idx] = _safe_float(row["action_speed_kmh"])
if ordered_edge_ids:
panels.append(build_action_panel(action_grid, ordered_edge_ids, f"{title_prefix} Applied VSL (km/h)")) panels.append(build_action_panel(action_grid, ordered_edge_ids, f"{title_prefix} Applied VSL (km/h)"))
if has_detector: if has_detector:
@ -350,6 +398,7 @@ def save_training_episode_artifacts(
step_rows, edge_rows, edge_ids = _normalize_step_rows(episode, episode_metrics) step_rows, edge_rows, edge_ids = _normalize_step_rows(episode, episode_metrics)
detector_rows = _build_detector_rows_from_xml(log_dir, episode) detector_rows = _build_detector_rows_from_xml(log_dir, episode)
detector_rows = _align_detector_rows_to_decision_steps(detector_rows, step_rows)
if control_edges and len(control_edges) >= len(edge_ids): if control_edges and len(control_edges) >= len(edge_ids):
edge_ids = list(control_edges[: len(edge_ids)]) edge_ids = list(control_edges[: len(edge_ids)])
for row in edge_rows: for row in edge_rows: