Case 03 · Commercial real estate · ArcGIS Pro · Python
Finding the optimal location for a workforce
A custom ArcGIS Pro tool that answers a concrete question: given where employees live, where is the central location that minimizes everyone’s drive time? Built over a dozen iterations into a fast, reproducible, shareable production tool.
The automation need
A useful script that couldn’t keep up with the real question.
A global commercial real estate team had a script that computed a single network center of gravity — the point minimizing average drive time from a set of employees. It worked, but the real need was broader and recurring.
They needed one COG per group — department, region, business unit — in a single run. It had to finish in minutes, produce reproducible and physically sensible results, and run for international colleagues on their own road networks. That’s the signature of a task worth automating properly.
- Group-aware: one optimal location per segment, not a manual re-run each time.
- Fast: an analyst should never wait more than ~15 minutes.
- Trustworthy: results feed real estate decisions, so they must be reproducible.
- Portable: usable on regional road networks worldwide, unchanged.
The pivotal fix
A run that never finished — and the defect hiding behind it.
A real analysis ran for over an hour without completing. The log told the story: the tool had generated 52,793,600 candidate locations for a requested 200. The generator was placing the requested count inside every one of the network’s 263,968 road segments.
~13.7 billion OD pairs
runtime > 1 hour (non-terminating)
~51,800 OD pairs
runtime: minutes
The insight: candidates never needed to be pre-placed on roads at all — the OD solver snaps each one to the nearest network edge when it loads. Removing the entire road-extraction step and generating exactly N points inside a single boundary collapsed the matrix by five orders of magnitude, removed a vendor-data restriction, and simplified the tool. This fix was invisible to code review; it only appeared on a real run.
The iteration arc
The sequence was the real lesson.
Most of the highest-impact changes came not from the initial review, but from running the tool on real data and reading the vendor’s primary documentation.
Per-group analysis
Refactored a single-COG script into a reusable per-group engine with optional headcount weighting — one COG per department, region, or unit in a single run, at no extra solve cost.
Explicit hierarchical routing
Hierarchy was being inherited invisibly from the travel mode. Built an explicit travel-mode object with hierarchy forced on or off, and recorded the choice in the output.
No silent truncation
The OD docs confirmed a cutoff drops destinations with no “not reached” flag — a silent bias across origins. Set no cutoff and no destination limit so every origin reaches every candidate.
The candidate explosion
Diagnosed the 52.8-million-candidate defect and generated exactly N points instead — cutting runtime from over an hour to minutes. (Detailed above.)
The “#” crash
ArcGIS passes a blank optional parameter as the literal string #. A normalization helper now treats # and "" as “not provided” everywhere.
Physically reachable output
The COG is now reported at its network-snapped coordinates — it always lands on a routable road, never in water or a roadless gap, and matches where travel time was actually measured.
Reproducible, unbiased sampling
A fixed random seed made runs repeatable; candidates are drawn from the buffered convex hull of the employees — which excludes oceans and lakes and is provably where the optimum must lie.
Robust to enterprise data
A grouped run on joined, group-layer data crashed. The tool now copies in-boundary employees to a clean standalone feature class first — flattening joins and qualified names, and guaranteeing group ∩ boundary.
Defensive coding
Own the inputs, remove whole classes of bugs.
A recurring source of fragility was the shape of the input. Small, disciplined helpers — like normalizing ArcGIS’s blank-parameter placeholder — quietly eliminate entire categories of runtime failure.
def clean_param(value, default=None): """Normalize ArcGIS optional-parameter placeholders. A blank optional script-tool parameter arrives as the literal string '#' (or ''), not None. Treat both as 'not provided'.""" if value is None: return default s = str(value).strip() return default if s in ("", "#") else value
Final architecture
How a run works now.
Clean-copy origins
Select employees in the boundary and copy them to a clean in-memory feature class — the robustness keystone that flattens joins and nesting.
Build OD once
Construct the OD Cost Matrix a single time with an explicit travel mode, local time zone, no cutoff, and no destination limit.
Sample per group
For each group, draw exactly N candidates inside the buffered convex hull of its origins, clipped to the boundary.
Solve & select
Solve, compute the (optionally weighted) mean travel time per candidate with a fast array operation, and pick the minimum.
Report the snapped winner
Write one COG per group at its network-snapped, correctly-projected location, with full metadata — travel mode, hierarchy, origin count, candidates evaluated, and analysis date.
Outcome & impact
What changed.
Hour → minutes
A single-COG run on ~260 origins finishes in about six and a half minutes — most of it one-time network loading.
Group-aware in one run
A real grouped run (179 origins, two groups) completed and wrote one COG per group automatically.
Zero credits, portable
Consumes no ArcGIS Online credits on a local network and runs unchanged on international StreetMap Premium packs.
Trustworthy by design
Results are reproducible, physically reachable, boundary-respecting, and robust to enterprise data structures.
Skills demonstrated
What this shows.
arcpy · NumPy
Network Analyst — OD Cost Matrix solver
Performance diagnosis & algorithmic optimization
Defensive coding for messy enterprise data
Reading primary docs to prevent silent errors
Reproducible, shareable, international-ready delivery
Have a spatial analysis worth automating?
If a recurring location question is eating hours of manual work, I build tools that make it fast, reproducible, and trustworthy.