Select to view content in your preferred language

Calculate value function that reads feature class path

744
4
08-29-2022 12:15 PM
2Quiker
Frequent Contributor

I know I can do it with Dissolve, but the issue with Dissolve is that it creates a separate layer and I know I can do this a script but I need to in Model Builder. I need the function to merge feature class based on two attributes. Can this be down with Calculate value in model builder? I have tried the following, but it never seems to finish the process. The model function does seem to work, I check the feature class and the feature class features are merged. I have to manually hit stop. 

 

Expression:

f(fc)

Code block:

 

 

 

import sys, arcpy, os
from arcpy import env
from arcpy import da
from itertools import groupby
from operator import itemgetter
from functools import reduce

fc = r"C:/TEMP/FEMA.gdb/FEMA_TempLyrs"

def f(fc):
    
    case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
    sort_field, sort_order = "OBJECTID", "ASC"
    shape_field = "SHAPE@"

    fields = case_fields + [sort_field, shape_field]
    sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)

    with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
        case_func = itemgetter(*range(len(case_fields)))
        merged_polys = {
            key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
            for key, group
            in groupby(cur, case_func)
        }
        cur.reset()
        for key, group in groupby(cur, case_func):
            row = next(group)
            cur.updateRow(row[:-1] + [merged_polys[key]])
            for row in group:
                cur.deleteRow()
    del cur
    return fc

 

 

 

 

0 Kudos
4 Replies
by Anonymous User
Not applicable

I would look at separating your operations.  If you are building a dictionary in the first part, do that in a SearchCursor.  Drop the cur.reset().  Then with an UpdateCursor, iterate over the key, group dictionary and do your update.

0 Kudos
2Quiker
Frequent Contributor

Thanks for the reply, I guess I am not understand how to put the code/model together to work.

Is there another way that this can be accomplished?

0 Kudos
by Anonymous User
Not applicable

This is untested and to just show you the splitting of two operations that you are doing that I think would replace the reset().  Probably need an iterator in the each cursor somewhere? That's something you'll have to test and see. 

merged_polys = None
with da.SearchCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
        case_func = itemgetter(*range(len(case_fields)))
        merged_polys = {
            key:reduce(arcpy.Geometry.union, (r[-1] for r in group))
            for key, group
            in groupby(row, case_func)
        }

with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as uCur:
    for key, group in groupby(uCur, case_func):
        row = next(group)
        uCur.updateRow(row[:-1] + [merged_polys[key]])
        for row in group:
            uCur.deleteRow()

 

Alternative is add print statements to see where it is getting stuck in the loop and go from there.

0 Kudos
2Quiker
Frequent Contributor

Sorry for the late response. I wasn't sure if you meat separate the two into two separate calculate values, how I was suppose to call the first calculate value to the second calculate value. So I figured why the model didn't stop, FLD_ZONE had some empty attributes.

 

I tried the following it runs but nothing is merged, no errors.

 

 

fc = r"C:\Temp\FEMA.gdb\FEMA_TempLyrs

def f(fc):
    
    case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
    sort_field, sort_order = "OBJECTID", "ASC"
    shape_field = "SHAPE@"

    fields = case_fields + [sort_field, shape_field]
    sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)

    with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
        for row in cur:
            print (row)
            if row[0] == None:
                case_func = itemgetter(*range(len(case_fields)))
                merged_polys = {
                    key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
                    for key, group
                    in groupby(cur, case_func)
                    }
                cur.reset()
                for key, group in groupby(cur, case_func):
                    row = next(group)
                     cur.updateRow(row[:-1] + [merged_polys[key]])
                    for row in group:
                        cur.deleteRow()
    del cur
    return fc

 

 

 

I also tried separating the operations like you stated but nothing gets merged, with error.

 

Error:

ERROR 000539: Traceback (most recent call last):
File "<expression>", line 1, in <module>
File "<string>", line 38, in fc1
TypeError: 'NoneType' object is not subscriptable

 

 

 

import sys, arcpy, os
from arcpy import env
from arcpy import da
from itertools import groupby
from operator import itemgetter
from functools import reduce


fc = r"C:\Temp\FEMA.gdb\FEMA_TempLyrs" 
def f(fc):

    case_fields = ["FLD_ZONE",'ZONE_SUBTY'] # field(s) to group records for merging
    sort_field, sort_order = "OBJECTID", "ASC"
    shape_field = "SHAPE@"

    fields = case_fields + [sort_field, shape_field]
    sql_orderby = "ORDER BY {}, {} {}".format(", ".join(case_fields), sort_field, sort_order)

    merged_polys = None
    with da.SearchCursor(fc, fields, sql_clause=(None, sql_orderby)) as cur:
        case_func = itemgetter(*range(len(case_fields)))
        for row in cur:
            print (row)
            if row[0] == None:
                merged_polys = {
                    key:reduce(arcpy.Geometry.union, (row[-1] for row in group))
                    for key, group
                    in groupby(cur, case_func)
                    }
            else:
                pass

    del cur

    with da.UpdateCursor(fc, fields, sql_clause=(None, sql_orderby)) as uCur:
        for key, group in groupby(uCur, case_func):
            row = next(group)
            uCur.updateRow(row[:-1] + [merged_polys[key]])
            for row in group:
                uCur.deleteRow()
    return fc

 

 

 

0 Kudos