Field Calculation Between Two Feature Classes

1678
15
Jump to solution
10-02-2013 01:03 AM
MarkYoung
Occasional Contributor
Hi,
I have a feature class containing two summed values (two attributes). I need to find out if one is less than or more than 20% of the other.
Is it possible to field calculate this in the same feature class? I have tried to export to two separate feature classes but cannot see a tool to call different fields from different feature classes in the same calculation.
Thanks in advance,
Mark
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
Mark, I was very much interested in how you could do this without scripting and without any of the advanced tools -- and after I read your posts today, I think there's a fairly direct solution with a model (ModelBuilder).  See this graphic first:

[ATTACH=CONFIG]28105[/ATTACH]

Now let me make sure I understand what basic proportion figure you want - is it correct that for every summary value by type, you want to compare this value with the remaining values, ie divide by the sum of the remaining values?  (Then, of course, if that is the case multiplying by 100 yields percentage.)

I'm not very good with ModelBuilder but managed to put together in 10.1 a model with a companion map and file gdb, everything is relative-pathed, so you should be able to save the zip to your local drive somewhere, open the map provided and run the model - you should be able to open the model in edit mode to see how it works.  If for some reason it doesn't work or not as expected, let me know.  For me, it was mainly a matter of understanding how ModelBuilder handles model params and in-line variable substitution.

Any questions, please fire away.  The expression which I placed as a label at the bottom of the graphic is, I suppose, the most important part...the Get Value tool was interesting, a little trick on the 2nd summary stat execution to simply fetch the grand total area value of the single output record.  I guess not everything had to be a 'hard output' to the gdb provided, but maybe helps to see what's going on.  The hab60 is a provided input layer with a Type1 field - this is summarized out to 3 types to sum polygon areas (you can adapt it very easily to line lengths).  The 2nd summary already mentioned is for the total - Calculate Value or Calculate Field with a python expression could have done this too, but my objective was to either do it all in Python or all in ModelBuilder ---- because I'm a glutton for punishment I suppose.  (Just kidding, I just didn't want to unnecessarily introduce any Python in this forum.)

Hope that helps, certainly I needed a better handle on in-line var sub - and also the ability to troubleshoot better some, well, monstrous models....perhaps?

Sorry, didn't include a ReadMe file...if you really need one I'll see what I can do.  It appears the initial attachment was too large, it was the gdb, so I've greatly reduced it, and it successfully uploaded.  The added 'test' field in the summary table added to the TOC of the map should result in the 3 records where the added field is updated (the overwrite property in Geoprocessing Options should be turned on) --- results (in percent) may be a little ridiculous, but accurate given the sample set.

Enjoy,
Wayne

View solution in original post

0 Kudos
15 Replies
TimWitt
Frequent Contributor
You can create a new field and then use the field calculator, via python, using if statements to return values.

i.e. if it is more than 20% return 1, if it is less than 20% return 2 and if it is exactly 20% return 3.

You would then be able to use this field identify what you need.

I'm sorry I can't help you with the code, but you maybe should ask in the python forum here to get the code you need.

I know this is not exactly what you want to hear, but I'm just letting you know it is possible :)
0 Kudos
JimCousins
MVP Regular Contributor
Mark,
Tim is correct, you can do this in the field calculator. Sample input in attachment.
Where FID_1 is your compare to value, and FID_2 is the value to be compared.
A simple python function called Percent is fed the 2 values, and 3 if statements decide how to proceed based on the comparison outcome.
If it is more than 20% return 1, if it is less than 20% return 2 and if it is exactly 20% return 0
Regards,
Jim
0 Kudos
MarkYoung
Occasional Contributor
Hi,
Thanks you for the code. However the values I want to compare are in the same field.
Thanks
Mark

[ATTACH=CONFIG]27966[/ATTACH]
0 Kudos
TimDonoyou
Occasional Contributor
Hi Mark,

For rows in the same table you can use a search cursor to iterate through and get the required value for each field:

http://resources.arcgis.com/en/help/main/10.1/index.html#//002z0000001q000000

if there are only 2 records in your table you could quickly use 2 search cursors with a where clause to get the required row values...

something like:

import arcpy

fc = "c:/...your featureclass"
use_field = "UseClass"
length_field = "SUM_SHAPE_Length"

# Create an expression with proper delimiters
#
a1expression = arcpy.AddFieldDelimiters(fc, Use_field) + " = A1"

with arcpy.da.SearchCursor(fc, (use_field, length_field),
                           where_clause=a1expression) as a1cursor:
    for row in a1cursor:
        a1value = row[1]

d1expression = arcpy.AddFieldDelimiters(fc, Use_field) + " = D1"

with arcpy.da.SearchCursor(fc, (use_field, length_field),
                           where_clause=d1expression) as d1cursor:
    for row in d1cursor:
        d1value = row[1]

## you can then use a1value and d1value in an if statement to calculate the percentages in the same way as field calculator

if d1value > (a1value * .2):
   print "more than 20%" ## if you are running as a script tool then use arcpy.AddMessage("more than 20%")
elif d1value < (a1value * .2):
   print "less than 20%" ## if you are running as a script tool then use arcpy.AddMessage("less than 20%")
elif d1value == (a1value * .2):
   print "exactly 20%" ## if you are running as a script tool then use arcpy.AddMessage("exactly 20%")
else:
   print "invalid calculation - please check inputs and try again"

del a1value, d1value, a1cursor, d1cursor, a1expression, d1expression, row, use_field, length_field, fc

hope this makes sense - I have just typed as thought and not checked at all so might need some syntax corrections but hope it gives you the right idea.

Cheers

Tim
0 Kudos
MarkYoung
Occasional Contributor
Hi Tim,
Thank you very much for the code! I copied the code to a txt file, renamed txt file to .py then aded as a script to the model - is that correct?
It seems to run OK but nothing seems to be updated (I specified the file path to my feature class) do I need to set field parameters when importing the script?. I have ran out of time this week but shall investigate on Monday.
Thanks again,
Mark
0 Kudos
TimDonoyou
Occasional Contributor
no worries mark - if you are working in arcmap then in the first instance I would just run the code line by line in the python window:

http://resources.arcgis.com/en/help/main/10.1/index.html#//002100000017000000

you can then copy my code statement by statement into this, hit return after each line and see if it runs ok - you'll get red error messages if it doesn't which will help to resolve any issues - there might be a couple.

when you have fixed all the niggles and run it a few times then you can save it as a python script, add to a toolbox and define your input/output parameters:

http://resources.arcgis.com/en/help/main/10.1/index.html#/Adding_a_script_tool/00150000001r000000/

cheers

Tim
0 Kudos
RichardFairhurst
MVP Honored Contributor
no worries mark - if you are working in arcmap then in the first instance I would just run the code line by line in the python window:

http://resources.arcgis.com/en/help/main/10.1/index.html#//002100000017000000

you can then copy my code statement by statement into this, hit return after each line and see if it runs ok - you'll get red error messages if it doesn't which will help to resolve any issues - there might be a couple.

when you have fixed all the niggles and run it a few times then you can save it as a python script, add to a toolbox and define your input/output parameters:

http://resources.arcgis.com/en/help/main/10.1/index.html#/Adding_a_script_tool/00150000001r000000/

cheers

Tim


Tim:

it looks like he wants you to rewrite the script to use an update cursor.  As far as I can tell, all your script does is read the table and print to screen, but he does not want that.  He wants it to actually change a field value somewhere and does not know how to adapt the script to do that.  I am not sure what field or table he wants to update, so I think he needs to provide more information about his end goal.  But I am sure he wants the script to actually do the update for him like a field calculation would.
0 Kudos
T__WayneWhitley
Frequent Contributor
Hi,
Thanks you for the code. However the values I want to compare are in the same field.
Thanks
Mark

[ATTACH=CONFIG]27966[/ATTACH]


Consider the following, especially in light of the fact Jim posted field calculator code following Tim's suggestion and since this is not the Python forum.  You'll have to experiment, but the tool Pivot Table may help support that solution, review this webhelp:

Pivot Table (Data Management)
Desktop » Geoprocessing » Tool reference » Data Management toolbox
http://resources.arcgis.com/en/help/main/10.1/index.html#//0017000000n8000000


It appears (on initial inspection of what you provided) you may be able to utilize a table format where instead your field headers are values from what is currently your UserClass field i.e. 'A1, 'D1', etc... and your sum_shape_length values would then be accessible to you for further processing via the field calculation mentioned.

So, in effect, UserClass is your 'pivot field', sum_shape_length is your 'value field', and since your 'input fields' determine what makes your records unique and it appears you do not need to summarize further to 'flatten' the table so to speak, I believe you can just specify your source table unique identifier (OBJECTID or similar field).  See the illustration at the top of the webhelp page - again, experiment...

Once you have that (I imagine this intermediate step is quick), you can ask Jim if he's still available to post his full code block from his illustration...or someone else can do that, no problem.

Hope that helps,
Wayne
0 Kudos
T__WayneWhitley
Frequent Contributor
I was looking at some of the toolbox tools again that I've been meaning to test, some are new to me, and experimented further with the Pivot Table tool (in the Table toolset of the Data Management toolbox) and I need to clarify something about my last post, so bear with me below:

I noticed that in your attached picture you only had 2 fields and 2 records.  Well you can in fact use the Pivot Table tool on this although usually you'd probably run it on more...it works pretty much the same.  Take for instance this 2 record input:

[ATTACH=CONFIG]28032[/ATTACH]

This, if you cannot already tell, is a summary table of area based on SUBDIVISIO (other fields not important at this time).

What I did not mention earlier is the Pivot Table tool requires at least 1 input field, so I've simply added a dummy field (called dummy) and coded it for both records to 1 (the value doesn't matter).  So, then running a Pivot Table execution with the SUBDIVISIO field as the pivot field and the SUM_Shape_Area the value field, you get this:

[ATTACH=CONFIG]28028[/ATTACH]

...which I think is what you were after in the beginning to run the field calculator on to compare area values, correct?  Now, without knowing how you arrived at this point in the processing is kind of irrelevant at this point, to you anyway.  I would likely also employ the search/update cursor approach because that is likely easier for me....but the important thing here is that you have an option!

OK, so this is basically how the tool interface looks, notice the entered input, pivot, and value field params:

[ATTACH=CONFIG]28029[/ATTACH]


Finally, to impress upon you the likely 'normal' mode you'd be using this tool, possibly in the future, here are successive analogous pics of the multiple record processing:

[ATTACH=CONFIG]28030[/ATTACH]

This time I want to use an input field, C1...it'll be clear in a moment why...

[ATTACH=CONFIG]28031[/ATTACH]

Now does it make sense?  I now have 3 records summarized by G, M, Q - no idea what these are, just codes to me just like the ones you have presented - all that matters is they are unique).  The input values specified are again summarized by SUBDIVISIO that are values side-by-side...incidentally values that I could now compare via the field calculator.

I hope this drill helps you...I hope I have adequately explained, and if not just let me know, please.

Thanks for that, I learned something new today.

Enjoy,
Wayne
0 Kudos