4

I am trying to use os.walk to go through a directory tree, pull out all the .shp files in it, create a grouplayer in the mxd, rename the grouplayer the folder name, then add the layers from that folder to the group. This is because I have a lot of folders with files in them that represent geologic formations and they don't mean anything once seperated from the name of the formation.

From what I read you can't just add a blank group layer in an mxd from python without first creating a blank one and adding that. The problem starts at the for group_name in rename_group_layer loop. It doesn't even make it through to the print group_name test. Basically it just falls out of the loop from what I can tell.

Then I need to figure out how to add the layers from the folder into the renamed group layer. I have two lines commented out that I think are a start, but I haven't gotten it to go through the renaming loop yet. It will rename the first "New Group Layer" if I put that line above the loop to the correct folder name. I am pretty new to python so any help you can give would be greatly appreciated.

import os
import arcpy

# Set workspace environment to a folder
WS = r'c:\test_define\Appalachian Basin'
arcpy.env.workspace = WS

mxd = arcpy.mapping.MapDocument(r"c:\test_define\test_python_add3.mxd")
df = arcpy.mapping.ListDataFrames(mxd, "layers")[0]

print ("#") *80
for (path, dirs, files) in os.walk(WS):
    for name in files:
        if name.endswith(".shp"):
        print path
           print "^^^^^^^^^^^^^^^^^^ path variable"

            try:
                layers = arcpy.mapping.ListLayers(mxd)
                for layer in layers:
                    if layer.isGroupLayer and layer.name == os.path.basename(path):
                        newLayer = arcpy.mapping.Layer(os.path.join(path, name))
                        arcpy.mapping.AddLayerToGroup(df, layer, newLayer, "BOTTOM")
                    else:
                        groupLayer =                       arcpy.mapping.Layer(r"c:\test_define\empty_group_layer.lyr")  
                        arcpy.mapping.AddLayer(df, groupLayer, "BOTTOM")

                        layers = arcpy.mapping.ListLayers(mxd)
                        for layer in layers:
                            if layer.isGroupLayer and layer.name == "New Group Layer":
                                layer.name = os.path.basename(path)

                        newLayer = arcpy.mapping.Layer(os.path.join(path, name))
                        arcpy.mapping.AddLayerToGroup(df, layer, newLayer, "BOTTOM")

#mxd.save()


# print messages when the tool runs successfully
            print(arcpy.GetMessages(0))
            #print ("+") *50
        except arcpy.ExecuteError:
            print(arcpy.GetMessages(2))

        except Exception as ex:
            print(ex.args[0])

mxd.saveACopy(r"c:\test_define\test.mxd")
2
  • Oh there is no error by the way. It runs to exit code 0 but just doesn't execute that loop.
    – SStreisel
    Commented May 1, 2013 at 16:28
  • You have a python27 tag which suggests you are using ArcGIS 10.1 or 10.1 SP1. If it is the latter you may want to consider using arcpy.da.Walk. Also, is there any chance that you can break that long first paragraph up into a series of steps to make it easier to digest? If you can include a question mark somewhere it should make the main focus of your Question more obvious too.
    – PolyGeo
    Commented May 2, 2013 at 10:38

3 Answers 3

3

This should work; it worked for me. This will give you a group layer named by the folder and a layer with the name of the shapefile. I built off what artwork21 posted.

import os
import arcpy

WS = r'c:\test_define'
arcpy.env.workspace = "in_memory"

mxd = arcpy.mapping.MapDocument(r"c:\test_define\test_python_add2.mxd")
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]

for (path, dirs, files) in os.walk(WS):
    for name in files:
        if name.endswith(".shp"):

            groupLayer = arcpy.mapping.Layer(r"c:\test_define\empty_group_layer.lyr")  
            arcpy.mapping.AddLayer(df, groupLayer, "BOTTOM")

            layers = arcpy.mapping.ListLayers(mxd)
            for layer in layers:
                if layer.isGroupLayer and layer.name == "New Group Layer":
                    layer.name = os.path.basename(path)

            newLayer = arcpy.mapping.Layer(os.path.join(path, name))
            arcpy.mapping.AddLayerToGroup(df, layer, newLayer, "BOTTOM")

mxd.save()

You have to make the shapefiles into layers and use AddLayerToGroup. If you want a single group layer for each folder you can recycle this code and modify the os.walk to check for folders with .shp's and go from there. Although, I would recommend trying to contain all these shapefiles into a geodatabase with a proper naming structure and metadata to fit your needs.

To elaborate on the nonrepeating,

import arcpy
import os 

WS = r'c:\test_define'
arcpy.env.workspace = "WS"
mxd = arcpy.mapping.MapDocument(r"c:\test_define\test_python_add2.mxd")
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
groupLayer = arcpy.mapping.Layer(r"c:\test_define\empty_group_layer.lyr")

for (path, dirs, files) in os.walk(WS):
    for name in files:
        if name.endswith(".shp"):

            layers = arcpy.mapping.ListLayers(mxd)
            name_list = []
            for layer in layers:
                if layer.isGroupLayer:
                    name_list.append(layer.name)

            if os.path.basename(path) not in name_list:
                arcpy.mapping.AddLayer(df, groupLayer, "BOTTOM")
                layers = arcpy.mapping.ListLayers(mxd)
                for layer in layers:
                    if layer.isGroupLayer and layer.name == "New Group Layer":
                        layer.name = os.path.basename(path)
                        newLayer = arcpy.mapping.Layer(os.path.join(path, name))
                        arcpy.mapping.AddLayerToGroup(df, layer, newLayer, "BOTTOM")

            if os.path.basename(path) in name_list:
                layers = arcpy.mapping.ListLayers(mxd)
                for layer in layers:
                    if layer.isGroupLayer and layer.name == os.path.basename(path):
                        newLayer = arcpy.mapping.Layer(os.path.join(path, name))
                        arcpy.mapping.AddLayerToGroup(df, layer, newLayer, "BOTTOM")


mxd.save()

This will check to see if a group layer already exists and will add to it, if so. Else, it will create a new group layer and add the layer.

9
  • To have nonreapting groupfiles: list the layers, and if the group layer is not present - make and add, else skip to AddLayerToGroup.
    – gm70560
    Commented May 2, 2013 at 20:45
  • I am sorry. I just got back to this and made the changes you suggested. Thank you so much for your help. Forgive my ignorance and newness to this, but I am stuck on this "to have nonreapeating groupfiles" though. I am getting a new group for every file in the folder which makes sense after going over the code. You would have to put the list and the skip above the add grouplayer line correct? I am just struggling to figure out where this would go in the code. Again I appreciate all of your help.
    – SStreisel
    Commented May 13, 2013 at 17:31
  • I have updated my answer to incorporate the non-repeating issue.
    – gm70560
    Commented May 13, 2013 at 21:25
  • With the new code you suggested GM it doesn't do anything. It just creates a blank MXD doc. the map document (mxd = c:\test_define\test_python_add3.mxd) is blank that its using to add these groups to. The group layer doesn't get created unless the first layers loop is false. So it doesn't create the first group layer to run the test on until after the test fails. Is it kicking it out of the loop because there is no layer to list?
    – SStreisel
    Commented May 14, 2013 at 18:25
  • How in the heck do you add a code snippet in here?
    – SStreisel
    Commented May 15, 2013 at 16:45
0

You can get group names within map document by:

layers = arcpy.mapping.ListLayers(mxd)

for layer in layers:

    if layer.isGroupLayer and layer.name == "Group":
       newname = str(yourfoldername) 
       layer.name = newname

       mxd.save()
6
  • So I can replace the whole section from rename_group_layer = arcpy.mapping.ListLayers(mxd, "", )[0] to the end with your code and substitue "New Group Layer" for "Group"?
    – SStreisel
    Commented May 1, 2013 at 17:23
  • Yes, not removing your defining of group layer and adding it in first.
    – artwork21
    Commented May 1, 2013 at 17:39
  • This is what I changed the code to.
    – SStreisel
    Commented May 1, 2013 at 19:22
  • It still doesn't get down to where it will print newname in the loop. It creates 3 group layers with the name of the first folder. No clue why its doing this..
    – SStreisel
    Commented May 1, 2013 at 19:40
  • I put the changes you suggested in the main code box.. Any more suggestions?
    – SStreisel
    Commented May 1, 2013 at 19:48
0

This is pretty bare bones but it'll get the job done. One thing to point out is that you can change a layer's name before you add it to the map document, so you don't have to ListLayers to find it in the TOC. The assumptions made by this code are:

  1. Every folder has at least one shapefile (otherwise you'll get some empty group layers)
  2. The folders have unique names
  3. You have an empty group layer saved as a .lyr file somewhere

It could be modified to deal with more complications, but should work for you as is.

import arcpy
import os

topfolder = r"c:\path\to\top\folder" #this one contains the folders full of shapefiles
mxd_path = r"c:\path\to\mapdocument.mxd"
grplyrpath = r"c:\path\to\blankgrouplyr.lyr"

mxd = arcpy.mapping.MapDocument(mxd_path)
df = arcpy.mapping.ListDataFrames(mxd)[0]   

for path, dirs, files in os.walk(topfolder):

    for d in dirs:
        grplyr = arcpy.mapping.Layer(grplyrpath)
        grplyr.name = d
        arcpy.mapping.AddLayer(df,grplyr,"BOTTOM")
        grplyrTOC = arcpy.mapping.ListLayers(mxd,grplyr.name,df)[0]

        for shp in os.listdir(os.path.join(path,d)):
            if not os.path.splitext(shp)[1] == ".shp":
                continue
            lyr = arcpy.mapping.Layer(os.path.join(path,d,shp)
            arcpy.mapping.AddLayerToGroup(df,grplyrTOC,bnd_grplayer,"BOTTOM")

mxd.save()

Not the answer you're looking for? Browse other questions tagged or ask your own question.