311 Requests With No Location: Missing Coordinates and Placeholder Addresses
On this page
Problem statement
Map New York's 311 requests and some never appear: they have no latitude or longitude. In July 2025 that is 5,177 requests, only 1.64% of the month, but they are not a random 1.64% β one agency and a handful of complaint types account for most of them, so a map silently under-represents exactly those problems. Other location fields have their own placeholders: an "Unspecified" borough, missing ZIP codes, and one coordinate shared by more than a thousand requests. This page finds the gaps, explains them, and shows which can be filled.
Quick answer
Count missing coordinates by agency, complaint type and address_type before mapping. Most are street-segment (BLOCKFACE) requests, which describe a stretch of street rather than a point; geocode them from their cross streets or map them at a coarser level, such as community board.
nol = july.latitude.isna()
print(f"July 2025 requests without coordinates: {nol.sum():,} ({nol.mean():.2%})")
print("by agency (share without):", nol.groupby(july.agency).mean().sort_values(ascending=False).head(5).round(3).to_dict())
print("by complaint type (count):", july[nol].complaint_type.value_counts().head(5).to_dict())
July 2025 requests without coordinates: 5,177 (1.64%)
by agency (share without): {'DOT': 0.131, 'TLC': 0.033, 'DSNY': 0.024, 'DEP': 0.017, 'DHS': 0.012}
by complaint type (count): {'Street Condition': 1668, 'Derelict Vehicles': 355, 'Illegal Parking': 341, 'Water System': 339, 'Highway Condition': 296}
5,177 July requests (1.64%) have no coordinates. The transportation department is the outlier: 13.1% of its requests lack them, against 3.3% or less for every other agency. By type, street conditions lead (1,668), then derelict vehicles, illegal parking, water system and highway conditions.
Where the location went
1. Address types
print(pd.crosstab(july.address_type.fillna("missing"), nol, normalize="index").round(3).rename(columns={False: "has coords", True: "no coords"}).to_string())
latitude has coords no coords
address_type
ADDRESS 1.000 0.000
BLOCKFACE 0.070 0.930
INTERSECTION 0.973 0.027
PLACE 1.000 0.000
PLACENAME 1.000 0.000
missing 0.391 0.609
The address type explains it. Requests at an address, place or intersection almost always have coordinates; 93.0% of BLOCKFACE requests β "on this street between these two cross streets" β do not, and neither do 60.9% of requests with no address type. A street segment has no single point, and the geocoder leaves it blank.
2. Placeholder values
print(f"borough 'Unspecified': {(july.borough == 'Unspecified').sum():,}; incident ZIP missing: {july.incident_zip.isna().sum():,}")
z = july.incident_zip.dropna().astype(str)
bad = z[~z.str.fullmatch(r"\d{5}")]
print(f"ZIP codes not five digits: {len(bad):,}; examples {bad.unique()[:4].tolist()}")
borough 'Unspecified': 258; incident ZIP missing: 2,408
ZIP codes not five digits: 1; examples ['3723']
258 requests have borough "Unspecified" and 2,408 no ZIP code. Only one ZIP is malformed (3723, four digits); the ZIP column is otherwise clean when read as text, which keeps leading zeros intact.
3. Coordinates that are there but wrong
c = july.dropna(subset=["latitude", "longitude"])
out = ~(c.latitude.between(40.49, 40.92) & c.longitude.between(-74.27, -73.68))
print(f"coordinates outside New York City's bounding box: {out.sum():,}")
dup = c.groupby(["latitude", "longitude"]).size().sort_values(ascending=False)
print(f"most-used single coordinate: {dup.iloc[0]:,} requests at ({dup.index[0][0]:.5f}, {dup.index[0][1]:.5f})")
at = c[(c.latitude == dup.index[0][0]) & (c.longitude == dup.index[0][1])]
print(f"addresses at that point: {at.incident_address.value_counts().head(2).to_dict()}")
coordinates outside New York City's bounding box: 0
most-used single coordinate: 1,590 requests at (40.72196, -73.80970)
addresses at that point: {'78-15 PARSONS BOULEVARD': 1590}
No coordinates fall outside the city's bounding box, but one point (40.72196, β73.80970) carries 1,590 requests. Every one of them is at 78-15 Parsons Boulevard in Queens, so it is a real address with many reports, not a placeholder; still, check any coordinate shared by hundreds of rows before treating it as many separate locations.
4. Recover some from the address
rec = july[nol & july.incident_address.notna()]
print(f"no coordinates but an address: {len(rec):,}; no coordinates and no address: {(nol & july.incident_address.isna()).sum():,}")
print(f"of those with an address, also with a BBL tax lot: {rec.bbl.notna().mean():.1%}")
no coordinates but an address: 3,849; no coordinates and no address: 1,328
of those with an address, also with a BBL tax lot: 0.0%
3,849 requests without coordinates do have an address and could be geocoded; 1,328 have neither. None of those with an address carries a BBL tax-lot number, so the lot cannot be used as a shortcut to a location.
What a map leaves out
The data used on this page
NYC 311 requests created in July 2025 (NYC Open Data, saved copy).
from pathlib import Path
import geopandas as gpd
import numpy as np
import pandas as pd
import requests
Path("data").mkdir(exist_ok=True)
# NYC 311 Service Requests (NYC Open Data, dataset erm2-nwe9) as queried on 15 October 2026 and saved on this site,
# because requests that are still open keep changing: every request created in July 2025, and the 2025 daily counts by
# agency, complaint type, borough and channel. The queries are in data/README.txt; the live API is
# https://data.cityofnewyork.us/resource/erm2-nwe9.csv
FILES = ["nyc-311-2025-daily-counts-2026-10-15.zip", "nyc-311-2025-07-requests-2026-10-15.zip", "nyc-census-2020-by-geography-2026-10-15.xlsx"]
for name in FILES:
if not Path(f"data/{name}").exists():
Path(f"data/{name}").write_bytes(requests.get(f"https://data.spatialworkflow.io/{name}", timeout=600).content)
daily = pd.read_csv("data/nyc-311-2025-daily-counts-2026-10-15.zip", parse_dates=["day"])
july = pd.read_csv("data/nyc-311-2025-07-requests-2026-10-15.zip", low_memory=False,
dtype={"unique_key": str, "incident_zip": str, "bbl": str, "community_board": str},
parse_dates=["created_date", "closed_date", "resolution_action_updated_date"])
cen = pd.read_excel("data/nyc-census-2020-by-geography-2026-10-15.xlsx", sheet_name="2010, 2020, and Change", skiprows=3)
boro_pop = cen[cen.GeoType == "Boro"].assign(b=lambda d: d.Name.str.upper()).set_index("b").Pop_20
print(f"NYC 311: {daily.n.sum():,} requests in the 2025 daily counts; {len(july):,} requests created in July 2025")
NYC 311: 3,655,042 requests in the 2025 daily counts; 315,883 requests created in July 2025
Example 1: what a map leaves out
by = july.groupby("complaint_type").latitude.apply(lambda s: s.isna().mean())
n = july.complaint_type.value_counts()
big = by[n[n >= 500].index].sort_values(ascending=False)
print("types with 500+ requests most often missing coordinates:", big.head(4).round(3).to_dict())
types with 500+ requests most often missing coordinates: {'Street Condition': 0.272, 'Derelict Vehicles': 0.085, 'Traffic': 0.081, 'Street Sweeping Complaint': 0.079}
Among complaint types with at least 500 July requests, street conditions are missing coordinates most often (27.2%), then derelict vehicles, traffic and street sweeping. A pothole map built from coordinates alone shows about three quarters of the reported street conditions.
Example 2: community board as a fallback
cb = july.community_board.fillna("missing")
print(f"no coordinates but a valid community board: {(nol & ~cb.str.startswith(('0 ', 'Unspecified', 'missing'))).sum():,} of {nol.sum():,}")
no coordinates but a valid community board: 2,226 of 5,177
2,226 of the 5,177 requests without coordinates still have a valid community board, so they can be counted at community-board level even if they cannot be mapped as points.
Points, segments and nothing
311 requests can be located at an address, an intersection, a named place, or a street segment between two cross streets. The first three geocode to a point; a segment does not, and New York's data leaves its coordinates blank rather than inventing a midpoint. Street-condition and highway requests are often made this way because the problem is along a stretch of road, which is why the transportation department has the most missing coordinates.
For a map, the honest options are to geocode segments to their midpoints from the cross streets (and say so), to draw them as lines using the city's street centreline, or to aggregate everything β points and segments β to an area such as the community board.
Related location traps
- ZIP codes as numbers lose leading zeros in other states' data; read them as text.
- Community board codes such as "0 Unspecified" are placeholders; filter them.
- Shared coordinates usually mean one building, but some datasets use a borough centroid as a placeholder; check the most common points.
- Geocoding adds its own errors; see how to batch geocode addresses.
Internal links
- How to map 311 complaints per resident β the map these rows drop out of
- How to batch geocode addresses in Python β filling missing coordinates
- 311 data explained β the address fields
FAQ
Why do some 311 requests have no latitude and longitude?
Mostly because they describe a street segment (BLOCKFACE) rather than a point; 93.0% of those had no coordinates in July 2025.
How many 311 requests are missing coordinates?
1.64% in July 2025 (5,177 requests), but 13.1% of transportation department requests.