Hello everyone,
I am not that experienced with python, but I'm trying to copy and paste and filter(by floor) each layer in a map in Pro into 4 "Floor" group layers (Basement,Floor1-3). I am able to get correctly named and filtered layers based off floor when I use the addLayer method. However, when I use the addLayerToGroup method, I get each layer off by 1 in the name and filter and group, with the last layer not in a group at all.
Both methods are in the snippet here. Could it be a limitation to addLayerToGroup?
Any help would be much appreciated, thank you!
aprx = arcpy.mp.ArcGISProject("Current")
m = aprx.listMaps("Group Layers")[0];
# Create list of layer names for copy layers based off floor
lyr_list = m.listLayers()
# Groups to add too
groups = ("Basement", "Floor 1","Floor 2", "Floor 3")
for copy_lyr in lyr_list:
# If layer is a group layer, continue
if copy_lyr.isGroupLayer:
continue
# If layer does not have floor field, continue
field_list = arcpy.ListFields(copy_lyr,"FLOOR*")
if len(field_list) == 0:
continue
# create list with each floor plus layer name, in order to iterate through and create a corresponding layer filtered based off floor
lyr_name = copy_lyr.name
new_layers = (lyr_name + " 0", lyr_name + " 1", lyr_name + " 2" , lyr_name + " 3")
i = 0
for new_name in new_layers:
# Designate layer to floor
group_name = str(groups[i])
targetGroupLayer = m.listLayers(group_name)[0]
print(targetGroupLayer)
# m.addLayer(copy_lyr, "BOTTOM")
m.addLayerToGroup(targetGroupLayer,copy_lyr, "BOTTOM")
copy_lyr.name = new_name
print(copy_lyr.name)
# add new definition query to conincide with floor and remove old one
def_q_list = copy_lyr.listDefinitionQueries()
sql_def_q = "FLOOR = " + "\'" + str(i) + "\'"
def_q_list.append({'name': 'Floor Query', 'sql': sql_def_q, 'isActive': True})
def_q_list.pop(0)
copy_lyr.updateDefinitionQueries(def_q_list)
print(sql_def_q)
# add to counter (new value will be used for next floor def query)
print(str(i))
i += 1
Solved! Go to Solution.
I modified script to loop through groups first then layers, and got better results. Since the addToGroupLayer (and addLayer) in this script essentially is copy paste, I still had to account for the original layer that was copied from the map. After each layer is add to group, I remove extra layer.
Sorry @DanPatterson for the spam!
# Script that will copy and paste layers into specified groups
import string
aprx = arcpy.mp.ArcGISProject("Current")
m = aprx.listMaps("Group Layers")[0];
# Create list of layer names for copy layers based off floor
lyr_list = m.listLayers()
# Groups to add too
groups = ("Basement", "Floor 1","Floor 2", "Floor 3")
# Iterate through each group
i = 0
for group in groups[0:]:
for copy_lyr in lyr_list:
# If layer is a group layer, continue
if copy_lyr.isGroupLayer:
continue
# If layer does not have floor field, continue
field_list = arcpy.ListFields(copy_lyr,"FLOOR*")
if len(field_list) == 0:
continue
# If layer is one of the floor layers
if "Floor" in copy_lyr.name or "Room" in copy_lyr.name:
continue
else:
# Designate layer to floor
targetGroupLayer = m.listLayers(group)[0]
print(targetGroupLayer)
# add new definition query to conincide with floor and remove old one
def_q_list = copy_lyr.listDefinitionQueries()
sql_def_q = "FLOOR = " + "\'" + str(i) + "\'"
def_q_list.append({'name': 'Floor Query', 'sql': sql_def_q, 'isActive': True})
def_q_list.pop(0)
copy_lyr.updateDefinitionQueries(def_q_list)
print("New Filter: " + sql_def_q)
# Create variable with layer name, in order to create a corresponding layer filtered based off floor
lyr_name = copy_lyr.name
print(lyr_name)
new_layer_name = lyr_name.rstrip(string.digits).rstrip(" ") + " " + str(i)
print(new_layer_name)
copy_lyr.name = new_layer_name
# Add New Layer
m.addLayerToGroup(targetGroupLayer,copy_lyr, "BOTTOM")
# If all floor layers added, remove orginal layer (not really original, but since addLayer method is essentially copy pasting, we have one extra layer to account for)
if i == 3:
m.removeLayer(copy_lyr)
# add to counter (new value will be used for next floor def query)
print("I = " + str(i))
i += 1
python indexing is 0-based, so without looking at your code in detail, make sure that the "first" of anything is referenced as index 0
Hey Dan, I couldnt tell you why, but when i set i = -1 and add an extra element to the new layers list, and add 1to i ( in the definition query), I get the layers in the right group, albeit with an additional extra layer. It works! So ill just remove the layer at the end of the loop.
Im hoping there's a good explanation for this, because im not knowledgeable enough to see it lol.
# Script to create function that will copy and paste layers
import string
aprx = arcpy.mp.ArcGISProject("Current")
m = aprx.listMaps("Group Layers")[0];
# Create list of layer names for copy layers based off floor
lyr_list = m.listLayers()
# Groups to add too
groups = ("Basement", "Floor 1","Floor 2", "Floor 3")
for copy_lyr in lyr_list:
# If layer is a group layer, continue
if copy_lyr.isGroupLayer:
continue
# If layer does not have floor field, continue
field_list = arcpy.ListFields(copy_lyr,"FLOOR*")
if len(field_list) == 0:
continue
# create list with each floor plus layer name, in order to iterate through and create a corresponding layer filtered based off floor
lyr_name = copy_lyr.name
new_layers = (lyr_name + " 0", lyr_name + " 1", lyr_name + " 2" , lyr_name + " 3", "lol")
i = -1
for new_name in new_layers[0:]:
print(new_name)
# Designate layer to floor
group_name = str(groups[i])
targetGroupLayer = m.listLayers(group_name)[0]
print(targetGroupLayer)
# m.addLayer(copy_lyr, "BOTTOM")
m.addLayerToGroup(targetGroupLayer,copy_lyr, "BOTTOM")
copy_lyr.name = new_name
print("New Layer Name: " + copy_lyr.longName)
# add new definition query to conincide with floor and remove old one
def_q_list = copy_lyr.listDefinitionQueries()
sql_def_q = "FLOOR = " + "\'" + str(i + 1) + "\'"
def_q_list.append({'name': 'Floor Query', 'sql': sql_def_q, 'isActive': True})
def_q_list.pop(0)
copy_lyr.updateDefinitionQueries(def_q_list)
print("New Filter: " + sql_def_q)
# add to counter (new value will be used for next floor def query)
print("I = " + str(i))
i += 1
# Remove orignal non floor based layer
# og_lyr_name = str(lyr_name.rstrip(string.digits).rstrip(" "))
# list_remove = (og_lyr_name)
# new_list = m.listLayers(list_remove)
# for og_lyr in new_list:
# print("remove og layer")
# m.removeLayer(og_lyr)
Hey Dan, thank you for the help!
Gotcha, I've incorporated the counter i = 0 into the filter of each new layer ( in our data we have basement value as 0, floor 1 as 1 etc, until floor 3). And have also incorporated it when grabbing the name of the targetGroupLayer (list of 4) . I am able to print the would be correct layer order after each operation, but for some reason I cant actually get the right order.
I modified script to loop through groups first then layers, and got better results. Since the addToGroupLayer (and addLayer) in this script essentially is copy paste, I still had to account for the original layer that was copied from the map. After each layer is add to group, I remove extra layer.
Sorry @DanPatterson for the spam!
# Script that will copy and paste layers into specified groups
import string
aprx = arcpy.mp.ArcGISProject("Current")
m = aprx.listMaps("Group Layers")[0];
# Create list of layer names for copy layers based off floor
lyr_list = m.listLayers()
# Groups to add too
groups = ("Basement", "Floor 1","Floor 2", "Floor 3")
# Iterate through each group
i = 0
for group in groups[0:]:
for copy_lyr in lyr_list:
# If layer is a group layer, continue
if copy_lyr.isGroupLayer:
continue
# If layer does not have floor field, continue
field_list = arcpy.ListFields(copy_lyr,"FLOOR*")
if len(field_list) == 0:
continue
# If layer is one of the floor layers
if "Floor" in copy_lyr.name or "Room" in copy_lyr.name:
continue
else:
# Designate layer to floor
targetGroupLayer = m.listLayers(group)[0]
print(targetGroupLayer)
# add new definition query to conincide with floor and remove old one
def_q_list = copy_lyr.listDefinitionQueries()
sql_def_q = "FLOOR = " + "\'" + str(i) + "\'"
def_q_list.append({'name': 'Floor Query', 'sql': sql_def_q, 'isActive': True})
def_q_list.pop(0)
copy_lyr.updateDefinitionQueries(def_q_list)
print("New Filter: " + sql_def_q)
# Create variable with layer name, in order to create a corresponding layer filtered based off floor
lyr_name = copy_lyr.name
print(lyr_name)
new_layer_name = lyr_name.rstrip(string.digits).rstrip(" ") + " " + str(i)
print(new_layer_name)
copy_lyr.name = new_layer_name
# Add New Layer
m.addLayerToGroup(targetGroupLayer,copy_lyr, "BOTTOM")
# If all floor layers added, remove orginal layer (not really original, but since addLayer method is essentially copy pasting, we have one extra layer to account for)
if i == 3:
m.removeLayer(copy_lyr)
# add to counter (new value will be used for next floor def query)
print("I = " + str(i))
i += 1