I'm working with a FGDB FC that has data, of sorts, stored in the symbology.
What I mean is: there is UNIT information in the symbology as labels, yet that UNIT information doesn't exist in a field in the attribute table of the FC anywhere.
Using ArcPy, is there a way to print a list of the layer’s symbology class values and symbol labels? I have 20+ layers, all with different symbology, so it would be ideal if I could do it programmatically.
If I could get a list, then I could manually:
I’m new to ArcPy. I’ve tried to modify a couple of sample scripts online. But I don’t really know what I’m doing yet. Any tips would be appreciated.
ArcGIS Pro 3.0.3.
Related: Export symbology classes to a table
Solved! Go to Solution.
You can get the symbology of a layer. Form there, you'll have to follow the rabbit hole to the single symbology items.
This script will loop through a list of layers in the active map, analyze their symbology and add a new field to each layer with the symbology's label value:
layer_names = ["TestPolygons"]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# get the symbology fields and items
renderer = layer.symbology.renderer
fields = renderer.fields
items = renderer.groups[0].items
# create a dict {values: label}
item_dict = {tuple(i.values[0]): i.label for i in items}
# add a new field
arcpy.management.AddField(layer, "Unit", "TEXT")
# insert the label values
with arcpy.da.UpdateCursor(layer, ["Unit"] + fields) as cursor:
for row in cursor:
key = tuple([str(x) for x in row[1:]]) # item.values stores values as string
try:
row[0] = item_dict[key]
cursor.updateRow(row)
except KeyError: # no symbology found
pass
You can get the symbology of a layer. Form there, you'll have to follow the rabbit hole to the single symbology items.
This script will loop through a list of layers in the active map, analyze their symbology and add a new field to each layer with the symbology's label value:
layer_names = ["TestPolygons"]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# get the symbology fields and items
renderer = layer.symbology.renderer
fields = renderer.fields
items = renderer.groups[0].items
# create a dict {values: label}
item_dict = {tuple(i.values[0]): i.label for i in items}
# add a new field
arcpy.management.AddField(layer, "Unit", "TEXT")
# insert the label values
with arcpy.da.UpdateCursor(layer, ["Unit"] + fields) as cursor:
for row in cursor:
key = tuple([str(x) for x in row[1:]]) # item.values stores values as string
try:
row[0] = item_dict[key]
cursor.updateRow(row)
except KeyError: # no symbology found
pass
Hi Johannes,
I found your python script really interesting as there is no easy solution to export symbology labels to table or field. However, I still get an error when trying to run your script.
I simply changed the first line in order to drag & drop layers from the current/active projects, using:
layer_names = sys.argv[1]
And I get the following error:
layer = aprx.activeMap.listLayers(name)[0]
IndexError: list index out of range
It should be obvious to fix but I do not have much experience with the arcpy mp module and I am stuck.
Any help would be appreciated. Thanks
layer_names = sys.argv[1]
aprx = arcpy.mp.ArcGISProject("current")
for name in layer_names:
# get the layer
layer = aprx.activeMap.listLayers(name)[0]
# get the symbology fields and items
renderer = layer.symbology.renderer
fields = renderer.fields
items = renderer.groups[0].items
# create a dict {values: label}
item_dict = {tuple(i.values[0]): i.label for i in items}
# add a new field
arcpy.management.AddField(layer, "Unit", "TEXT")
# insert the label values
with arcpy.da.UpdateCursor(layer, ["Unit"] + fields) as cursor:
for row in cursor:
key = tuple([str(x) for x in row[1:]]) # item.values stores values as string
try:
row[0] = item_dict[key]
cursor.updateRow(row)
except KeyError: # no symbology found
pass
layer_names has to be a list (or other collection type).
My guess is that sys.argv[1] is a string, which the script iterates through, taking each letter as layer name. listLayers("a") returns an empty list, and then it correctly raises the IndexError when you try to access the first element of that empty list.
You think setting up a dialog box properties for the Python script with a parameter (sys.arg[1]) defined as Layer multiple value, is read as a String? Should I read this parameter in a loop and assign the values to the List?
I though it may come from the script expecting a layer name only, and not the entire layer name with path... I will try to 'hard-code' the layer name making a list with a single entry...
sys.argv is used to call scripts from command line, right? I have absolutely no experience with that. The script above is supposed to be executed in the ArcGIS Pro Python window.