Select to view content in your preferred language

addLayerToGroup

827
4
Jump to solution
05-22-2023 06:14 PM
Oliver_Sandoval_e
New Contributor III

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
             

 

 

 

 

 

 

 

 

 

1 Solution

Accepted Solutions
Oliver_Sandoval_e
New Contributor III

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
        

            

 

 

 

View solution in original post

0 Kudos
4 Replies
DanPatterson
MVP Esteemed Contributor

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


... sort of retired...
Oliver_Sandoval_e
New Contributor III

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)

 

 

 

0 Kudos
Oliver_Sandoval_e
New Contributor III

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.

 

 

 

0 Kudos
Oliver_Sandoval_e
New Contributor III

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
        

            

 

 

 

0 Kudos