I'm currently in the process of cleaning up a municipality's address point data. I'm working with two data sets: address points and parcel polygons. Both the address point data and the parcel polygons have a parcel ID which allows for a spatial join and a way to verify where an address is supposed to be.

There are about 50,000 geocoded address points in my dataset. An overwhelming majority of these points fall within their corresponding parcel (aka they are spatially correct).

The problem I have is that many address points were not geocoded correctly and do not fall within their corresponding parcels. Oftentimes an address point is many parcels away from the parcel it should exist in.

Is there a a process within ArcMap (or ArcPy) that would allow me to move address points that aren't within their correct parcel polygon to where they should be? Essentially, I want to identify all of the address points that do not exist within their proper parcel (using the Parcel ID) and then redistribute those points into the parcel using the matching Parcel ID.


The following (untested) code should do the trick. This first gets the geometry of the points and polygons into dictionaries, then uses the polygon dictionary with the contains method of the arcpy.Polygon to test if the correct point is inside it. If not it is added to a new dict and used to update the point geometry.

import arcpy

def move_points(addresses, pt_pin_field,  parcels, parcel_pin_field,):

    # get address geometry
    with arcpy.da.SearchCursor(addresses, [pt_pin_field, 'SHAPE@']) as rows:
        point_geom = {r[0]: r[1] for r in rows}

    # get parcel geometry
    with arcpy.da.SearchCursor(parcels, [parcel_pin_field, 'SHAPE@']) as rows:
        par_geom = {r[0]: r[1] for r in rows}

    # move geometry dict
    move_dict = {}
    for pin, pt in point_geom.iteritems():
        if pin in par_geom:
            if not par_geom[pin].contains(pt):
                move_dict[pin] = par_geom[pin].centroid

    # loop through address points and move if point pin doesnt match spatial join pin
    if move_dict:
        with arcpy.da.UpdateCursor(addresses, ['SHAPE@', pt_pin_field]) as rows:
            for row in rows:
                if row[1] in move_dict:
                    row[0] = move_dict[row[1]]
    print 'moved {0} points'.format(len(move_dict))

if __name__ == '__main__':

    addresses = r'C:\path\to\address_points.shp'
    add_pin = 'Address_PIN'
    parcel_pin = 'PID'
    parcels = r'C:\path\to\Parcels.shp'

    # run it
    move_points(addresses, add_pin, parcels, parcel_pin)

Well, there very well may be a better method of doing this than comes readily to my mind, but, I do have some thoughts, so, here they are.

First thing I would do is make sure you have some fields in your parcels with the X/Y centroid of the polygon, (making sure the point is actually within the polygon for odd-shaped/non-rectangular parcels). Optionally, you could instead just use the Feature to Point Geoprocessing tool (checking the "inside" option) against your parcels and then running the Add XY Coordinates GP Tool against the newly created point FC.

Then, once you have the above done (aka: you have a table with parcel IDs and the X & Y coordinates for a point inside that parcel) and you have the address points spatially joined with the parcels to ID by attribute which structures are in the wrong parcel, which you indicate you already have done, you then have two options to proceed:

If you want to do it without coding, you would want to join the table with parcel centroids to the addresses and select the addresses needing moved. Then, export those records (with the tables still joined) to a new table. Take the new table and run it through the Make XY Event Layer GP Tool, using the parcel XY values. Finally, you could use the Append GP tool with field mapping turned on (schema type: No Test) to copy those newly created address points into your original addresses FC. Presumably, you would also want to delete/archive/retire as appropriate for your workflow the then unnecessary incorrectly placed addresses.

The easier method, using python, would be to take the parcels XY tale, join it by PID to the addresses table, and run an update cursor on the Shape@XY field, querying within the cursor for only the miss-matched addresses, and updating the XY values for the addresses to the XY values from the parcels.


A very simple code that moves all points to the centroid of their respective polygons. Screw checking if they are correct or not to begin, says I. It sounds like it doesn't matter where the point falls as long as they're in the polygon. Just moving all the points should save time. And you'll have prettier looking data.

The only wonkiness is that I perform an initial feature to point conversion. This is to make sure points fall inside their polygons ("INSIDE" option). If you have a u-shaped parcel I think the da.SearchCursor will put the point outside the parcel. I then use an initial cursor and a dictionary to get the geometries of the polygon centroid point feature class, and then I apply them to the points.

from arcpy import *

parcelFC = r"{path to parcel feature class}"
PolyKey = "{key field name}"

pointFC = r"{path to point fc}"
Pointkey = "{key field name}"

#Empty dictionary
di = []

#Feature to point - get centroid inside polygon
feat2pnt = r"in_memory\feat2pnt"
FeatureToPoint_management (parcelFC, feat2pnt, "INSIDE")

#Assign XYs to key through dictionary
cursor = da.SearchCursor (feat2pnt, ["SHAPE@XY", PolyKey])
for row in cursor:
    di[row[1]] = row[0]
del cursor

#Move points
cursor = da.UpdateCursor (pointFC, ["SHAPE@XY", Pointkey])
for row in cursor:
    if row[1] in di:
        row[0] = di[row[1]]
del cursor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.