When people think about traffic safety analysis, they often start with accident locations.
- Where did accidents occur?
- Which intersections have the highest counts?
- Where are the current hotspots?
Those are useful questions. But they are not always the most important ones. During our technical session "Spatial Data Science in ArcGIS", we explored a different question:
Which locations show persistent risk over time?
Rather than analyzing individual traffic accidents, we used historical accident data from Frankfurt am Main between 2019 and 2024 to identify spatial patterns that remained stable across multiple years. The goal was not to explain a single incident. The goal was to understand whether some locations consistently exhibit elevated risk regardless of short-term fluctuations.
%load_ext dotenv
%dotenv
from arcgis.gis import GIS
from arcgis.map import Map
import dotenv
import os
import pandas as pd
from traffic_safety.utils import combine_yearly_hotspots, list_feature_classes, summarize_hotspot_bins, generate_hotspots_renderer, filter_hotspot_bins, publish_hotspot_layer
home_portal = GIS("home")
gdb_path = os.getenv("HOTSPOT_GDB")
feature_classes = list_feature_classes(gdb_path)
Looking Beyond Individual Hotspots
A hotspot analysis performed for a single year provides a snapshot. However, cities are dynamic systems. Traffic volumes change. Construction projects appear and disappear. Public transportation evolves. Human behavior shifts over time. A hotspot identified in one year may disappear in the next. To better understand long-term risk, we performed annual Getis-Ord Gi* Hot Spot Analyses for each year and then compared the results across time.
The challenge is that hotspot polygons are not identical between years. Their boundaries shift as underlying conditions change. To address this, we created a spatial alignment workflow:
- Run annual Hot Spot Analysis
- Calculate centroids for hotspot bins
- Use a common spatial reference framework
- Match hotspot locations across years
- Build a temporal profile for each location
- Calculate hotspot persistence scores
- Normalize the results into a risk index
This transformed multiple independent analyses into a single, interpretable risk surface.
from ipywidgets import HBox, VBox, Label, Layout
from traffic_safety.utils import generate_hotspots_renderer, read_feature_classes
def show_hotspot_map(portal: GIS, df: pd.DataFrame):
basemap_item_id = os.getenv("CUSTOM_BASEMAP_ITEM_ID")
if basemap_item_id:
portal_item = portal.content.get(basemap_item_id)
map_view = Map(portal_item)
else:
map_view = portal.map("Germany")
map_view.basemap.basemap = "osm"
drawing_info = {
"renderer": generate_hotspots_renderer()
}
fset = df.spatial.to_featureset()
map_view.content.add(fset, drawing_info=drawing_info, options={"opacity": 0.7})
map_view.zoom_to_layer(fset)
return map_view
hotspots_dict = read_feature_classes(gdb_path, [feature_classes[0], feature_classes[-1]])
hotspots_2019_df, hotspots_2025_df = hotspots_dict.values()
left_map = show_hotspot_map(home_portal, hotspots_2019_df)
right_map = show_hotspot_map(home_portal, hotspots_2025_df)
def side_by_side(left_map, left_label, right_map, right_label):
# sync maps' navigation
#left_map.sync_navigation(right_map)
"""
def sync_navigation(change):
if right_map.center != left_map.center:
right_map.center = left_map.center
if right_map.zoom != left_map.zoom:
right_map.zoom = left_map.zoom
left_map.observe(sync_navigation, names=["center", "zoom"])
"""
# Create VBoxes for each map and label
box1 = VBox([Label(left_label), left_map], layout=Layout(width='50%'))
box2 = VBox([Label(right_label), right_map], layout=Layout(width='50%'))
# Place the VBoxes side by side using an HBox
hbox = HBox([box1, box2])
# Display the HBox
display(hbox)
side_by_side(left_map, "2019", right_map, "2025")
left_map.sync_navigation(right_map)
From Accident Data to a Risk Layer
The resulting layer did not represent accident counts. It represented something arguably more valuable: evidence of persistent risk.
Locations that repeatedly appeared as statistically significant hotspots received higher persistence scores. Locations with occasional hotspot behavior received lower scores. This distinction is important. A single severe accident may attract attention, but recurring spatial patterns often reveal deeper characteristics of the transportation system. Persistent risk can indicate infrastructure constraints, traffic behavior patterns, mobility hubs, or other underlying factors that deserve investigation.
base_feature_class = feature_classes[0]
combined_df: pd.DataFrame = combine_yearly_hotspots(gdb_path, base_feature_class)
summarized_df: pd.DataFrame = summarize_hotspot_bins(combined_df, min_years_observed=len(feature_classes))
show_hotspot_map(home_portal, combined_df)
hottest_df = filter_hotspot_bins(summarized_df, min_value=2, max_value=3)
hottest_df.sort_values(by="Gi_Bin_median", ascending=False).head()
What We Learned
One of the most interesting observations was that some of the highest-risk locations were not necessarily the places with the highest traffic volume. Instead, risk often emerged from the interaction of multiple factors. In related work around the Frankfurt Urban Digital Twin, we found that operationally relevant locations frequently emerged where several indicators reinforced one another. Historical accident patterns, traffic simulations, infrastructure context, and mobility behavior together created a richer picture than any individual dataset could provide.
This highlights one of the strengths of spatial data science: Location provides context. Spatial relationships often reveal patterns that remain invisible when datasets are analyzed independently.
Why This Matters
Many organizations face similar challenges. Whether the problem involves transportation safety, utility infrastructure, environmental monitoring, public health, or asset management, decision-makers often need to distinguish between temporary anomalies and persistent patterns. Spatial Data Science helps answer questions such as:
- Which locations consistently exhibit elevated risk?
- Which patterns remain stable over time?
- Which areas deserve further investigation?
- Where should limited resources be prioritized?
These questions are increasingly important as organizations seek to move from descriptive analytics toward evidence-based decision support.
Spatial Data Science as the Foundation
For us, the risk layer became more than an analytical output. It became the foundation for the next stages of the Frankfurt showcase. The workflow followed a simple progression:
- Spatial Data Science identifies persistent risk.
- Agentic AI with Spatial Grounding uses that evidence to generate explainable recommendations.
- Trusted GeoAI introduces governance and human oversight before action is taken.
This progression reflects an important principle: AI does not replace evidence. AI becomes more useful when it can reason over trusted evidence produced through spatial analysis.
Final Thoughts
One of the core messages from the session was simple:
We are not identifying where accidents happened. We are identifying where risk persists.
Persistent spatial patterns provide the evidence needed for explainable recommendations, trustworthy AI systems, and ultimately better decisions. As organizations explore Spatial Data Science, GeoAI, and Agentic AI, the challenge is often not collecting more data. The challenge is identifying the patterns that matter. And in many cases, those patterns are spatial.
Traffic Safety Notebook @Github