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")
-
Oh there is no error by the way. It runs to exit code 0 but just doesn't execute that loop.SStreisel– SStreisel2013年05月01日 16:28:28 +00:00Commented 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– PolyGeo ♦2013年05月02日 10:38:12 +00:00Commented May 2, 2013 at 10:38
3 Answers 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.
-
To have nonreapting groupfiles: list the layers, and if the group layer is not present - make and add, else skip to AddLayerToGroup.gm70560– gm705602013年05月02日 20:45:33 +00:00Commented 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– SStreisel2013年05月13日 17:31:51 +00:00Commented May 13, 2013 at 17:31
-
I have updated my answer to incorporate the non-repeating issue.gm70560– gm705602013年05月13日 21:25:10 +00:00Commented 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– SStreisel2013年05月14日 18:25:45 +00:00Commented May 14, 2013 at 18:25
-
How in the heck do you add a code snippet in here?SStreisel– SStreisel2013年05月15日 16:45:13 +00:00Commented May 15, 2013 at 16:45
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()
-
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– SStreisel2013年05月01日 17:23:14 +00:00Commented May 1, 2013 at 17:23
-
Yes, not removing your defining of group layer and adding it in first.artwork21– artwork212013年05月01日 17:39:14 +00:00Commented May 1, 2013 at 17:39
-
This is what I changed the code to.SStreisel– SStreisel2013年05月01日 19:22:54 +00:00Commented 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– SStreisel2013年05月01日 19:40:37 +00:00Commented May 1, 2013 at 19:40
-
I put the changes you suggested in the main code box.. Any more suggestions?SStreisel– SStreisel2013年05月01日 19:48:15 +00:00Commented May 1, 2013 at 19:48
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:
- Every folder has at least one shapefile (otherwise you'll get some empty group layers)
- The folders have unique names
- 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()
Explore related questions
See similar questions with these tags.