Select to view content in your preferred language

Create current status for a layer of overlap polygons

920
4
Jump to solution
02-16-2023 12:02 AM
mody_buchbinder
Occasional Contributor III

I have a polygon layer with many overlap polygons, each one have a time stamp.

I would like to create a "current status" polygon layer that will not have overlap and each polygon will be the latest.

Some polygons that have partially overlap will be changed.

For example I have one polygon from 2020 that have cross polygon from 2019 and anther cross polygon from 2021

The 2020 polygon will be cut by 2021 polygon but not by 2019 polygon.

The only way I could think about is to take the polygons from the original layer one by one the oldest to the newest, with each one to to an Erase and Append on the result layer.

Is there any better way?

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

That sketch helped alot.

It turns out to be relatively easy:

# parameters
polygon_fc = "TestPolygons"
id_field = "IntegerField"
date_field = "DateField"
out_path = "memory/CurrentState"


# copy the feature class
out_fc = arcpy.management.CopyFeatures(polygon_fc, out_path)

# read the input fc
fields = [id_field, date_field, "SHAPE@"]
polygons = [dict(zip(fields, row))
            for row in arcpy.da.SearchCursor(polygon_fc, fields)
            ]

# get unique ids
unique_ids = {p[id_field]
              for p in polygons
              }

# iterate over the unique ids
for uid in unique_ids:
    # get all states of that polygon, sort by date
    states = [p
              for p in polygons
              if p[id_field] == uid
              ]
    states.sort(key=lambda s: s[date_field])
    # start updating the output fc for this id
    with arcpy.da.UpdateCursor(out_fc, ["SHAPE@"], where_clause=f"{id_field} = {uid}", sql_clause=[None, f"ORDER BY {date_field}"]) as cursor:
        # cursor and states are in the same order (oldest to newest)
        for i, row in enumerate(cursor):
            # get the geometry of this row
            state_geometry = states[i]["SHAPE@"]  # == row[0]
            # erase/subtract each newer state
            for k in range(i+1, len(states)):
                newer_state_geometry = states[k]["SHAPE@"]
                state_geometry -= newer_state_geometry  # we can use "-" to get the difference between two polygons
            # update the geometry
            cursor.updateRow([state_geometry])

 

Original:

JohannesLindner_0-1676567318235.png

 

 

Current state:

JohannesLindner_1-1676567341112.png

 


Have a great day!
Johannes

View solution in original post

0 Kudos
4 Replies
JohannesLindner
MVP Frequent Contributor

You can probably whip up some Python script.

But this part is very unclear:

Some polygons that have partially overlap will be changed.

For example I have one polygon from 2020 that have cross polygon from 2019 and anther cross polygon from 2021

The 2020 polygon will be cut by 2021 polygon but not by 2019 polygon.

 

Can you clarify that, maybe with a sketch?


Have a great day!
Johannes
0 Kudos
mody_buchbinder
Occasional Contributor III

Hi

 

At the top the layer I have, at the bottom the layer I would like to create

Thanks

0 Kudos
JohannesLindner
MVP Frequent Contributor

That sketch helped alot.

It turns out to be relatively easy:

# parameters
polygon_fc = "TestPolygons"
id_field = "IntegerField"
date_field = "DateField"
out_path = "memory/CurrentState"


# copy the feature class
out_fc = arcpy.management.CopyFeatures(polygon_fc, out_path)

# read the input fc
fields = [id_field, date_field, "SHAPE@"]
polygons = [dict(zip(fields, row))
            for row in arcpy.da.SearchCursor(polygon_fc, fields)
            ]

# get unique ids
unique_ids = {p[id_field]
              for p in polygons
              }

# iterate over the unique ids
for uid in unique_ids:
    # get all states of that polygon, sort by date
    states = [p
              for p in polygons
              if p[id_field] == uid
              ]
    states.sort(key=lambda s: s[date_field])
    # start updating the output fc for this id
    with arcpy.da.UpdateCursor(out_fc, ["SHAPE@"], where_clause=f"{id_field} = {uid}", sql_clause=[None, f"ORDER BY {date_field}"]) as cursor:
        # cursor and states are in the same order (oldest to newest)
        for i, row in enumerate(cursor):
            # get the geometry of this row
            state_geometry = states[i]["SHAPE@"]  # == row[0]
            # erase/subtract each newer state
            for k in range(i+1, len(states)):
                newer_state_geometry = states[k]["SHAPE@"]
                state_geometry -= newer_state_geometry  # we can use "-" to get the difference between two polygons
            # update the geometry
            cursor.updateRow([state_geometry])

 

Original:

JohannesLindner_0-1676567318235.png

 

 

Current state:

JohannesLindner_1-1676567341112.png

 


Have a great day!
Johannes
0 Kudos
mody_buchbinder
Occasional Contributor III

It is a nice code. I did not know I can use minus on geometry.

It is after all doing the erase and append that I suggested

Thanks

 

0 Kudos