- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNormalizeFields.py
More file actions
Latest commit
114 lines (99 loc) · 4.89 KB
/
Copy pathNormalizeFields.py
File metadata and controls
114 lines (99 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# Normalize Fields GP Tool for ArcGIS Desktop
# Author: Mark Deaton (mark4238)
# Inputs:
# * feature class
# * fields to normalize (multiple-select, numeric)
# * field to normalize against (numeric)
# * new fieldname suffix (default to )
importarcpy
importsys
# Parameter helper function
defgetParam(param_num):
returnsys.argv[param_num+1] #arcpy.GetParameter(param_num)
# Main function, all functions run in NearByGroup
defnormalize_fields(in_featureclass, in_field_names, norm_field, new_field_suffix="_norm"):
# CONSTS
FIELD_MAP_IN=0
FIELD_MAP_OUT=1
# Progressor: calculating will probably take much longer than creating fields
PROGRESSOR_INC_CREATEFIELD=1
PROGRESSOR_INC_CALCFIELD=5
# This should support all licenses: basic, standard, advanced
# if arcpy.ProductInfo().lower() not in ['arcinfo']:
# arcpy.AddError("An ArcGIS for Desktop Advanced license is required.")
# sys.exit()
PROGRESSOR_MAX_VAL= (len(in_field_names) *PROGRESSOR_INC_CREATEFIELD) + \
(len(in_field_names) *PROGRESSOR_INC_CALCFIELD)
progressor_current_val=0
arcpy.SetProgressor('step', '', 0, PROGRESSOR_MAX_VAL)
existing_fields=arcpy.ListFields(in_featureclass)
existing_fieldnames=list(map((lambdafield: field.name), existing_fields))
field_map= []
# Create fields to hold normalized values
forin_fieldnameinin_field_names:
in_field_idx=existing_fieldnames.index(in_fieldname)
in_field=existing_fields[in_field_idx]
norm_fieldname_proposed=in_fieldname+new_field_suffix
try:
existing_fieldnames.index(norm_fieldname_proposed)
# if we continue, the field was found, so we need to keep trying
forxinrange(1, 100):
norm_fieldname_proposed=in_fieldname+new_field_suffix+str(x)
existing_fieldnames.index(norm_fieldname_proposed)
# gotta stop somewhere; if more than 99 exist, throw an error
arcpy.AddError('Cannot create normalized field for '+in_fieldname+
' because too many similar fields already exist.'+
'\nPlease use a different suffix or delete some fields.')
sys.exit(0)
except: # here we've found an unused field name
field_map.append([in_field, norm_fieldname_proposed])
# Add fields to Input
forfield_setinfield_map:
in_field=field_set[FIELD_MAP_IN]
out_field=field_set[FIELD_MAP_OUT]
field_type=get_field_type(in_field.type)
try:
sStatus='Creating normalized field \''+out_field+'\''
arcpy.AddMessage(sStatus)
arcpy.SetProgressorLabel(sStatus)
res=arcpy.management.AddField(in_featureclass, out_field, field_type,
in_field.precision, in_field.scale, in_field.length)
progressor_current_val+=PROGRESSOR_INC_CREATEFIELD
arcpy.SetProgressorPosition(progressor_current_val)
exceptarcpy.ExecuteErroraserrExec:
arcpy.AddError('Error adding field \''+out_field+'\': '+errExec.message)
raiseerrExec
# Now all fields for normalized values should exist; do the calculation
forfield_setinfield_map:
out_field=field_set[FIELD_MAP_OUT]
in_field=field_set[FIELD_MAP_IN].name
try:
sStatus='Calculating field \''+out_field+'\''
arcpy.AddMessage(sStatus)
arcpy.SetProgressorLabel(sStatus)
res=arcpy.management.CalculateField(in_featureclass, out_field,
'norm(!'+in_field+'!, !'+norm_field+'!)', 'PYTHON',
'def norm(infld, normfld):'+'\n\t'+'if normfld == 0: return None'+'\n\t'+
'else: return float(infld) / normfld')
progressor_current_val+=PROGRESSOR_INC_CALCFIELD
arcpy.SetProgressorPosition(progressor_current_val)
exceptarcpy.ExecuteErroraserrExec:
arcpy.AddError('Error calculating field \''+out_field+'\': '+errExec.message)
raiseerrExec
# Field type name remapping is necessary. http://desktop.arcgis.com/en/arcmap/latest/analyze/arcpy-classes/field.htm
defget_field_type(field_type):
# Actually, since it's division, we'll always create a double field
return'DOUBLE'
# if field_type.lower() == 'integer': return 'LONG'
# elif field_type.lower() == 'smallinteger': return 'SHORT'
# else: return field_type
# Run the script
if__name__=='__main__':
# Get Parameters
in_workspace=getParam(0)
in_fields=getParam(1).split(";") ifgetParam(1).find(";") >-1else [
getParam(1)]
norm_field=getParam(2)
new_field_suffix=getParam(3)
normalize_fields(in_workspace, in_fields, norm_field, new_field_suffix)
print ("finished")