salem-import/README.md

180 lines
5.5 KiB
Markdown
Raw Normal View History

2022-10-23 21:35:04 +00:00
# Salem Oregon Address Import
See [https://wiki.openstreetmap.org/wiki/Salem_Oregon_Address_Import](https://wiki.openstreetmap.org/wiki/Salem_Oregon_Address_Import)
## Data Source
- Salem GIS department's FTP server
- Also https://data.cityofsalem.net/datasets/salem::primary-address/explore
- No copyright, public domain
2023-10-26 04:34:41 +00:00
<img src="Screenshot_2023-10-25_213128.png"/>
2022-10-23 21:35:04 +00:00
## Field Mapping
2023-10-26 05:11:21 +00:00
- ADD_NUM -> addr:housenumber (int)
- formatstreet(FULL_ST_NAME) -> addr:street (text)
- SUB_VAL -> addr:unit (text)
- title(CITY) -> addr:city (text)
- ZIP -> addr:postcode (text)
- addr:state 'OR' (manually added)
2022-10-23 21:35:04 +00:00
## Processing
2023-10-26 05:11:21 +00:00
- Get `Primary_Addresses.geojson` from the City GIS server linked above.
- Open the file in QGIS and open the layer attribute table
2023-11-10 08:56:22 +00:00
- Use the field calculator and the below script to add new virtual fields per the mapping above. (You may have to hit Save and Load Functions again to refresh QGIS's memory)
2023-10-26 05:11:21 +00:00
- Export the layer to geojson with "EPSG:4326 - WGS 84" projection. Deselect all fields besides those above.
2022-10-23 21:35:04 +00:00
- Save as `processed.geojson`
## Import steps
- Load processed.geojson into JOSM
- Zoom in to the area you wish to work on and Download OSM data to a New Layer
- In the geojson layer, select one neighborhood or city block worth of addresses
- Click Edit > Merge Selection
2023-10-26 05:29:35 +00:00
- Delete the selected items you just merged (so you don't try merging them again later)
2022-10-23 21:35:04 +00:00
- Switch to Data Layer 1 and run the JOSM Validator
2023-10-26 05:23:51 +00:00
- An easy way to only validate changes is to press the Upload button, but cancel before actually uploading.
- We don't need to worry about validation errors that don't involve our changes.
2022-10-23 21:35:04 +00:00
- Fix all duplicate housenumber warnings and nearby street not found warnings
2023-10-26 05:23:51 +00:00
- An easy way to auto-fix all duplicate housenumbers is to select all duplicates, Search within the selection for `new`, and delete.
- Pay special attention to errors like "East Street Northeast" -> "E Street Northeast" which can be mass-corrected.
2023-10-26 05:29:35 +00:00
- Search for all `new "addr:housenumber" = "0"` elements and delete them.
2022-10-23 21:35:04 +00:00
- Click Upload, verify there are no further warnings or errors in the changeset
- Make sure there are no erroneous Relations or other unwanted objects about to be uploaded.
- Upload with this changeset comment:
```
comment=Addresses near Salem Oregon #salemimport
import=yes
website=https://wiki.openstreetmap.org/wiki/Salem_Oregon_Address_Import
source=City of Salem GIS
source:url=https://data.cityofsalem.net/datasets/salem::primary-address/explore
```
- Review imported data in Achavi or Osmcha to ensure it looks proper.
## QGIS Processing script
```
2023-10-26 05:11:21 +00:00
import qgis.core
import qgis.gui
2022-10-23 21:35:04 +00:00
import re
2023-10-26 05:11:21 +00:00
#
# This will keep street names like SR 574A as SR 574A however
# will lowercase other number-digit suffixes with <2 or >4 numbers
# or >1 suffix-letters, like 12th Street or 243rd Ave.
#
2022-10-23 21:35:04 +00:00
@qgsfunction(args='auto', group='Custom', referenced_columns=[])
2023-10-26 05:11:21 +00:00
def getstreetfromaddress(value1, feature, parent):
2022-10-23 21:35:04 +00:00
parts = value1.split()
2023-10-26 05:11:21 +00:00
parts.pop(0) # Ignore the first bit (i.e. "123" in "123 N MAIN ST")
2022-10-23 21:35:04 +00:00
parts = map(formatstreetname, parts)
return " ".join(parts)
@qgsfunction(args='auto', group='Custom', referenced_columns=[])
2023-10-26 05:11:21 +00:00
def formatstreet(value1, feature, parent):
2022-10-23 21:35:04 +00:00
parts = value1.split()
2023-11-10 08:56:22 +00:00
# Handle the special case of a street name starting with "ST"
# which is almost always "Saint __" and not "Street __"
if parts[0] == "ST":
parts[0] = "Saint"
2022-10-23 21:35:04 +00:00
parts = map(formatstreetname, parts)
return " ".join(parts)
2023-10-26 05:11:21 +00:00
# Internal function
2022-10-23 21:35:04 +00:00
def formatstreetname(name):
2023-10-26 05:11:21 +00:00
# Acryonyms
if name == "CR":
return "County Road"
if name == "SR":
return "SR" # State Route
if name == "NFS":
return "NFS" # National Forest Service?
2022-10-23 21:35:04 +00:00
if name == "US":
return "US"
# Directions
if name == "N":
return "North"
if name == "NE":
return "Northeast"
if name == "E":
return "East"
if name == "SE":
return "Southeast"
if name == "S":
return "South"
if name == "SW":
return "Southwest"
if name == "W":
return "West"
if name == "NW":
return "Northwest"
# Suffixes
2023-10-26 05:37:33 +00:00
if name == "AV":
return "Avenue"
2022-10-23 21:35:04 +00:00
if name == "AVE":
return "Avenue"
if name == "BLVD":
return "Boulevard"
if name == "BND":
return "Bend"
if name == "CIR":
return "Circle"
2023-10-26 05:11:21 +00:00
if name == "CR":
return "Circle"
2022-10-23 21:35:04 +00:00
if name == "CT":
return "Court"
if name == "DR":
return "Drive"
if name == "FLDS":
return "Fields"
if name == "GRV":
return "Grove"
2023-10-26 05:11:21 +00:00
if name == "HL":
return "Hill"
2022-10-23 21:35:04 +00:00
if name == "HOLW":
return "Hollow"
2023-10-26 05:37:33 +00:00
if name == "HW":
return "Highway"
2022-10-23 21:35:04 +00:00
if name == "HWY":
return "Highway"
if name == "LN":
return "Lane"
if name == "LOOP":
return "Loop"
2023-10-26 05:11:21 +00:00
if name == "LP":
return "Loop"
2022-10-23 21:35:04 +00:00
if name == "PATH":
return "Path"
if name == "PL":
return "Place"
if name == "RD":
return "Road"
if name == "RUN":
return "Run"
2023-10-26 05:11:21 +00:00
if name == "SQ":
return "Square"
2022-10-23 21:35:04 +00:00
if name == "ST":
return "Street"
if name == "TER":
return "Terrace"
if name == "TRL":
return "Trail"
if name == "VW":
return "View"
if name == "WAY":
return "Way"
2023-10-26 05:11:21 +00:00
if name == "WY":
return "Way"
2022-10-23 21:35:04 +00:00
if name == "XING":
return "Crossing"
2023-10-26 05:11:21 +00:00
if re.match('^[0-9]{2,4}[A-Za-z]$', name) != None:
return name
2022-10-23 21:35:04 +00:00
return name.capitalize()
```