Select to view content in your preferred language

How do I add a field for the predominant geologic formation within a polygon?

266
11
Jump to solution
3 weeks ago
Labels (1)
BrianTickle
Emerging Contributor

Screenshot 2025-01-23 064032.pngI have a polygon shapefile (selected in the attached pic) and a geologic table shapefile containing rock types (text) and an arbitrary corresponding number value (integer). Most polygons exist completely within a certain rock type.  However, some polygons cross over multiple, different rock types. I would like to perform some kind of spatial join that determines what the most predominant rock type is within each polygon and assigns a single rock type. None of the merge rules (ie, first, last, max, min, etc) seem to accomplish this. In the screenshot, there are three geologic rock types within the selected polygon. I wish to add only "Kch" as the final attribute. This would seem to be a "majority" rule. However, I don't see an option anywhere for majority other than zonal statistics which produces a raster which I don't want.  Thanks!

0 Kudos
3 Solutions

Accepted Solutions
DanPatterson
MVP Esteemed Contributor

there is no "one" tool, but a process which may include

Tabulate Intersection (Analysis)—ArcGIS Pro | Documentation

Summarize Within (Analysis)—ArcGIS Pro | Documentation

or some of the other summary tools


... sort of retired...

View solution in original post

0 Kudos
BarryNorthey
Frequent Contributor

Error 100014 is explained here.

Try exporting your shapefiles to fGDB feature classes and try it again.

 

View solution in original post

0 Kudos
DavidPike
MVP Frequent Contributor

I'd recommend Tabulate intersection as Dan suggested.  Then probably create a new field and use Calculate Field with Python or Arcade to return the Field Name of the rock type field which has the highest Area. 

Then you can clean up by deleting all the rock fields if necessary.

I'd certainly just run the Tabulate Intersection first and you'll understand what I mean when you look at the output.  Also definitely check out the link dan provided which explains the tool. 

View solution in original post

11 Replies
DanPatterson
MVP Esteemed Contributor

there is no "one" tool, but a process which may include

Tabulate Intersection (Analysis)—ArcGIS Pro | Documentation

Summarize Within (Analysis)—ArcGIS Pro | Documentation

or some of the other summary tools


... sort of retired...
0 Kudos
BrianTickle
Emerging Contributor

I keep getting "Error 100014" when summarize within fails.  I've tried shortening the path, etc.  Maybe I'm trying to work with too many polygons (over 25,000)?

0 Kudos
DavidPike
MVP Frequent Contributor

I'd recommend Tabulate intersection as Dan suggested.  Then probably create a new field and use Calculate Field with Python or Arcade to return the Field Name of the rock type field which has the highest Area. 

Then you can clean up by deleting all the rock fields if necessary.

I'd certainly just run the Tabulate Intersection first and you'll understand what I mean when you look at the output.  Also definitely check out the link dan provided which explains the tool. 

BrianTickle
Emerging Contributor

What code/function would I use in calculate field? I've tried getMaxField(!Field1!,!Field2!,!Field3!) with no luck.

0 Kudos
DanPatterson
MVP Esteemed Contributor

python's is max 

I don't know what your field names are, but the pythons examples can be found here

Solved: Re: How do I add a field for the predominant geolo... - Esri Community

max([!field1!, !field2!, !field3!])

you provide the ! enclosed field names within [ ] brackets, which is a list, hence the expression finds the maximum in a list of entities


... sort of retired...
0 Kudos
BrianTickle
Emerging Contributor

This is a partial screenshot of my table. I've created the Rock Type field and want to populate it with the corresponding field name containing the highest value. So not the actual value. Most cells are null. When using the max function, i get an error that "Certain rows set to NULL due to error while evaluating python expression: TypeError: '>' not supported between instances of 'NoneType' and 'NoneType'". 

BrianTickle_0-1738072722376.png

 

0 Kudos
DavidPike
MVP Frequent Contributor

I can see getMaxField() used for another post.  It's not a native function and is defined in the code block at the bottom of field calculator.

This works for me.  Ensure you past the following into the 'Code Block' at the bottom of the Field Calculator window.

def maxValue(*args):
    filtered = [arg for arg in args if arg is not None]
    return (max(filtered)) if filtered else None

 

then above the Code Block you will have something that looks like <fieldname being calculated> =
in the box below that enter (obviously replace with your fieldnames:

maxValue(!yourField1!, !yourField2! .... )

0 Kudos
BrianTickle
Emerging Contributor

That returns the max value across all the fields. However, I need to return the field name containing the highest value.  In my screen shot above, I need the "Rock Type" field to be calculated in such a way that the resulting values are "Qal_AU", etc.

0 Kudos
DavidPike
MVP Frequent Contributor

Ah Ok.  Can't be done in Field Calculator as the fieldnames aren't exposed as variables.  locals() return nothing useful from what I can see.

Easy enough in a standalone script or Python window with arcpy UpdateCursor.

Update the below with your field names and filepath.

This will modify the input data with no undo.  Advise making a copy of your data from testing and sanity-check the results on a subset of data.

 

import arcpy

#note does not account for equal Max values
#just chooses one of the rock types even if both 50%

#path to your data
#remove from Pro ToC if lock encountered
filepath = r'C:\ArcGIS\GeologyRocks.gdb\Rock_stuff'

#list of field names countaining values
#to get max of
value_fields = ['Granite', 'Sand', 'Clay']
#name of field to be updated with rock types
max_field = ['Predominant_Geology']
fields = value_fields + max_field
#value to write if null or error etc.
null_string = 'unknown'


with arcpy.da.UpdateCursor(filepath, fields) as cursor:
    for row in cursor:
        values = {fields[i] : row[i] for i in range(len(fields)) if row[i] is not None}

        if values:
            max_field = max(values, key=values.get)
            row[-1] = max_field

        else:
            row[-1] = null_string

        cursor.updateRow(row)
0 Kudos