import json
import sys
# Define a dictionary to map abbreviations to full words for street types and directions
abbr_lookup = {
"ALY": "Alley",
"AVE": "Avenue",
"BAY": "Bay",
"BLVD": "Boulevard",
"CIR": "Circle",
"COR": "Corner",
"CRES": "Crescent",
"CRK": "Creek",
"CT": "Court",
"CTR": "Center",
"CV": "Cove",
"CYN": "Canyon",
"DR": "Drive",
"EST": "Estate",
"ESTS": "Estates",
"EXPY": "Expressway",
"FLT": "Flat",
"FRK": "Fork",
"FWY": "Freeway",
"GLN": "Glen",
"GRV": "Grove",
"GTWY": "Gateway",
"HL": "Hill",
"HOLW": "Hollow",
"HTS": "Heights",
"HWY": "Highway",
"JCT": "Junction",
"LN": "Lane",
"LNDG": "Landing",
"LOOP": "Loop",
"MDW": "Meadow",
"MDWS": "Meadows",
"MNR": "Manor",
"PARK": "Park",
"PASS": "Pass",
"PATH": "Path",
"PKWY": "Parkway",
"PL": "Place",
"PLZ": "Plaza",
"PT": "Point",
"RD": "Road",
"RDG": "Ridge",
"RNCH": "Ranch",
"ROW": "Row",
"RTE": "Route",
"RUN": "Run",
"SPUR": "Spur",
"SQ": "Square",
"ST": "Street",
"TER": "Terrace",
"TRCE": "Trace",
"TRL": "Trail",
"VIS": "Vista",
"VLG": "Village",
"VW": "View",
"WAY": "Way",
"XING": "Crossing",
"S": "South",
"N": "North",
"E": "East",
"W": "West"
}
direction_mapping = {
"N": "North",
"S": "South",
"E": "East",
"W": "West"
}
cartocode_lookup = {
"1": "interstate",
"2": "us-highway-separated",
"3": "us-highway-unseparated",
"4": "ut-highway-separated",
"5": "ut-highway-unseparated",
"6": "ut-highway-institutional",
"7": "ramp",
"8": "major-local-paved",
"9": "major-local-unpaved",
"10": "other-local",
"11": "other-local",
"12": "other",
"13": "non-road",
"14": "driveway",
"15": "proposed",
"16": "4WD-high-clearance",
"17": "service-access",
"18": "general-access"
}
bike_lookup = {
"1A": "At grade track, protected by parking",
"1B": "track protected with barrier",
"1C": "track separated by raised curb",
"1D": "track bidirectional",
"1E": "track center-running",
"2A": "lane buffered",
"2B": "lane",
"2C": "lane bidirectional buffered",
"3A": "shoulder bikeway",
"3B": "shared painted",
"3C": "shared signed",
"1": "track unspecified",
"2": "lane unspecified",
"3": "other unspecified"
}
def unabbreviate_name(name):
"""Transform the street name with unabbreviated street type and direction."""
parts = name.split()
for i, part in enumerate(parts):
if part in abbr_lookup:
parts[i] = abbr_lookup[part]
return ' '.join(parts).title()
def unabbreviate_direction(dir_abbrev):
"""Transform the direction abbreviation to the full word."""
return direction_mapping.get(dir_abbrev, "")
def process_feature(feature):
"""Process a single GeoJSON feature to add the required attributes."""
properties = feature["properties"]
# Extract relevant fields from the original GeoJSON properties
an_name = properties.get("AN_NAME", "")
an_postdir = properties.get("AN_POSTDIR", "")
fullname = properties.get("FULLNAME", "")
predir = properties.get("PREDIR", "")
max_speed = properties.get("SPEED_LMT", "")
# Transform the FULLNAME and PREDIR
name = unabbreviate_name(fullname)
name_prefix = unabbreviate_direction(predir)
name_full = f"{name_prefix} {name}".strip()
# Update the properties with the new fields
properties["name"] = name
properties["name:prefix"] = name_prefix
properties["name:full"] = name_full
# If AN_NAME is populated, process alt_name attributes
if an_name:
alt_name = unabbreviate_name(f"{an_name} {an_postdir}")
alt_name_prefix = name_prefix
alt_name_full = f"{alt_name_prefix} {alt_name}".strip()
properties["alt_name"] = alt_name
properties["alt_name:prefix"] = alt_name_prefix
properties["alt_name:full"] = alt_name_full
properties["maxspeed"] = f"{max_speed} mph"
cartocode = properties["CARTOCODE"]
properties["CARTOCODE"] = cartocode_lookup.get(cartocode, cartocode)
bikel = properties["BIKE_L"]
properties["BIKE_L"] = bike_lookup.get(bikel, bikel)
biker = properties["BIKE_R"]
properties["BIKE_R"] = bike_lookup.get(biker, biker)
oneway = properties["ONEWAY"]
if oneway == "0":
del properties["ONEWAY"]
elif oneway == "1":
properties["ONEWAY"] = "yes"
elif oneway == "2":
properties["ONEWAY"] = "-1"
unused = ["ACCESSCODE",
"BIKE_PLN_L", "BIKE_PLN_R",
"BIKE_REGPR",
"COUNTY_L", "COUNTY_R",
"CREATED",
"CREATOR",
"CUSTOMTAGS",
"DOT_AADT", "DOT_AADTYR",
"DOT_CLASS", "DOT_FCLASS", "DOT_F_MILE",
"DOT_HWYNAM",
"DOT_OWN_L", "DOT_OWN_R",
"DOT_RTNAME", "DOT_RTPART",
"DOT_SRFTYP",
"DOT_T_MILE",
"EDITOR",
"ER_CAD_ZONES",
"ESN_L", "ESN_R",
"FROMADDR_L", "FROMADDR_R",
"GlobalID",
"LOCAL_UID",
"MSAGCOMM_L", "MSAGCOMM_R",
"OBJECTID",
"PARITY_L", "PARITY_R",
"POSTCOMM_L", "POSTCOMM_R",
"QUADRANT_L", "QUADRANT_R",
"SOURCE",
"SPEED_LMT",
"STATE_L", "STATE_R",
"TOADDR_L", "TOADDR_R",
"UNINCCOM_L", "UNINCCOM_R",
"UNIQUE_ID",
"UPDATED",
"UTAHRD_UID",
"ZIPCODE_L", "ZIPCODE_R"]
for prop in unused:
del properties[prop]
return feature
def process_geojson(input_path, output_path):
"""Load, process, and save the GeoJSON file."""
# Load GeoJSON file
with open(input_path, 'r') as f:
geojson_data = json.load(f)
# Process each feature in the GeoJSON
for feature in geojson_data["features"]:
feature = process_feature(feature)
# Save the modified GeoJSON
with open(output_path, 'w') as f:
json.dump(geojson_data, f, indent=2)
# Specify input and output file paths
if len(sys.argv) != 3:
print("Usage: py road-name-transform.py <input_file> <output_file>")
sys.exit(1)
input_geojson_path = sys.argv[1]
output_geojson_path = sys.argv[2]
# Process the GeoJSON file
process_geojson(input_geojson_path, output_geojson_path)
print("GeoJSON file processed successfully.")
import json
import sys
# Define a dictionary to map abbreviations to full words for street types and directions
abbr_lookup = {
"ALY": "Alley",
"AVE": "Avenue",
"BAY": "Bay",
"BLVD": "Boulevard",
"CIR": "Circle",
"COR": "Corner",
"CRES": "Crescent",
"CRK": "Creek",
"CT": "Court",
"CTR": "Center",
"CV": "Cove",
"CYN": "Canyon",
"DR": "Drive",
"EST": "Estate",
"ESTS": "Estates",
"EXPY": "Expressway",
"FLT": "Flat",
"FRK": "Fork",
"FWY": "Freeway",
"GLN": "Glen",
"GRV": "Grove",
"GTWY": "Gateway",
"HL": "Hill",
"HOLW": "Hollow",
"HTS": "Heights",
"HWY": "Highway",
"JCT": "Junction",
"LN": "Lane",
"LNDG": "Landing",
"LOOP": "Loop",
"MDW": "Meadow",
"MDWS": "Meadows",
"MNR": "Manor",
"PARK": "Park",
"PASS": "Pass",
"PATH": "Path",
"PKWY": "Parkway",
"PL": "Place",
"PLZ": "Plaza",
"PT": "Point",
"RD": "Road",
"RDG": "Ridge",
"RNCH": "Ranch",
"ROW": "Row",
"RTE": "Route",
"RUN": "Run",
"SPUR": "Spur",
"SQ": "Square",
"ST": "Street",
"TER": "Terrace",
"TRCE": "Trace",
"TRL": "Trail",
"VIS": "Vista",
"VLG": "Village",
"VW": "View",
"WAY": "Way",
"XING": "Crossing",
"S": "South",
"N": "North",
"E": "East",
"W": "West"
}
direction_mapping = {
"N": "North",
"S": "South",
"E": "East",
"W": "West"
}
def unabbreviate_direction(dir_abbrev):
"""Expand a one-letter cardinal direction abbreviation."""
return direction_mapping.get(dir_abbrev, "")
def process_feature(feature):
"""
Process a single GeoJSON feature for an address point:
- Map "AddNum" to "addr:housenumber"
- Create "addr:street" by concatenating:
* Expanded "PrefixDir"
* "StreetName" in title case
* Expanded "StreetType" (or, if missing, expanded "SuffixDir")
- Map "UnitID" to "addr:unit"
- Remove any property key which contains "id" (case insensitive)
"""
properties = feature["properties"]
new_properties = {}
# Convert "AddNum" to "addr:housenumber" (if available)
housenum = properties.get("AddNum", "").strip()
if housenum:
new_properties["addr:housenumber"] = housenum
# Prepare street address parts
prefix = properties.get("PrefixDir", "").strip()
street_name = properties.get("StreetName", "").strip()
street_type = properties.get("StreetType", "").strip()
suffix = properties.get("SuffixDir", "").strip()
# Expand the directional prefix using direction_mapping
if prefix:
expanded_prefix = unabbreviate_direction(prefix)
else:
expanded_prefix = ""
# Convert the street name from all caps to title case
if street_name:
street_name = street_name.title()
else:
street_name = ""
# For street type, if provided, use the lookup; if not, try SuffixDir
if street_type:
expanded_type = abbr_lookup.get(street_type.upper(), street_type.title())
elif suffix:
expanded_type = unabbreviate_direction(suffix)
else:
expanded_type = ""
# Build "addr:street" by concatenating available parts
street_components = []
if expanded_prefix:
street_components.append(expanded_prefix)
if street_name:
street_components.append(street_name)
if expanded_type:
street_components.append(expanded_type)
street_full = " ".join(street_components).strip()
if street_full:
new_properties["addr:street"] = street_full
# Convert "UnitID" to "addr:unit" (if available)
unit = properties.get("UnitID", "").strip()
if unit:
new_properties["addr:unit"] = unit
city = properties.get("City", "").strip()
if city:
new_properties["addr:city"] = city
state = properties.get("State", "").strip()
if state:
new_properties["addr:state"] = state
# Copy over any other property that we want to keep, but remove
# any keys that contain "id" (in any case) or keys already processed.
ignore_keys = {"AddNum", "PrefixDir", "StreetName",
"StreetType", "SuffixDir", "UnitID"}
for key, value in properties.items():
if key in ignore_keys:
continue
if "id" in key.lower():
continue
new_properties[key] = value
feature["properties"] = new_properties
return feature
def process_geojson(input_path, output_path):
"""Load, process, and save the GeoJSON file."""
with open(input_path, 'r') as f:
geojson_data = json.load(f)
for i, feature in enumerate(geojson_data.get("features", [])):
geojson_data["features"][i] = process_feature(feature)
with open(output_path, 'w') as f:
json.dump(geojson_data, f, indent=2)
if len(sys.argv) != 3:
print("Usage: py address-point-transform.py <input_file> <output_file>")
sys.exit(1)
input_geojson_path = sys.argv[1]
output_geojson_path = sys.argv[2]
process_geojson(input_geojson_path, output_geojson_path)
print("GeoJSON file processed successfully.")