ArcPy - add multiple shapefiles with for loop

8030
10
02-10-2012 10:50 AM
ZackBartlett
New Contributor III
I have a folder that contains a few dozen shapefiles.  I want to create a script that adds all of these files to the current map document.  The script asks the user for a map ID (which decides what folder to load the shapefiles from).

I have the following thus far:

import arcpy, os, glob

# Set Workspace
base_Folder = r"N:\BASE_DATA\CANVEC\1_to_50k"
arcpy.env.Workspace = base_Folder
arcpy.env.OverwriteOutput = True

# User input for NTS mapsheet name.  This variable is also used to search for the correct mapsheet.
map_No = arcpy.GetParameterAsText(0)

# Canvec data is stored in folders, broken down by 1:50000 mapsheet number (eg: 031, 001, 045, etc).
# This variable extracts the folder name to be used when finding the correct folder
folder_Name = map_No[0:3]
# print folder_Name

#Established the correct folder to look in when loading the specified layers.
search_Folder = base_Folder + "\\" + folder_Name + "\\" + map_No
print search_Folder

##mxd = arcpy.mapping.MapDocument("CURRENT")
##dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
shp_List = arcpy.ListFiles("*.shp")
for layer in shp_List:
    mxd = arcpy.mapping.MapDocument("CURRENT")
    dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
    layer_Path = search_Folder + "\\" + layer
    addLayer = arcpy.mapping.Layer(layer_Path)
    arcpy.mapping.AddLayer(dataFrame, addLayer, "BOTTOM")
    arcpy.RefreshTOC()
    arcpy.RefreshActiveView()
    del addLayer, layer_Path, mxd


I load the script into ArcToolbox.  The script executes without error, but no layers are added to my map document.

I understand there are some redundant or unnecessary lines of code in here, but I think the problem is coming from the for loop.

Any ideas?

Thanks
Tags (2)
0 Kudos
10 Replies
DarrenWiens2
MVP Honored Contributor
That follows pretty closely to this example, which apparently works. The only difference is they refresh TOC after ActiveView, which I doubt matters. When you print layer_Path, does it give the approriate path (including .shp)?
0 Kudos
ZackBartlett
New Contributor III
I tried stripping down this script in hopes of simply printing a list of the files in the folder and various paths used throughout.  I keep getting hung up on the arcpy.ListFiles()
function.  (I'm running the script in the Python Shell now, not within ArcToolbox as a tool.)

I tried replacing "arcpy.ListFiles" with "os.listdir" and it worked fine.

Here's the error I get:

Traceback (most recent call last):
  File "N:/DOCUMENTATION/PYTHON/Canvec_Symbolization/test2.py", line 44, in <module>
    for layer in arcpy.ListFiles():
0 Kudos
StacyRendall1
Occasional Contributor III
You must set the workspace, ListFiles lists files within it... I.e.:
import arcpy

# Set Workspace
base_Folder = r"N:\BASE_DATA\CANVEC\1_to_50k"

# User input for NTS mapsheet name.  This variable is also used to search for the correct mapsheet.
map_No = arcpy.GetParameterAsText(0)

# Canvec data is stored in folders, broken down by 1:50000 mapsheet number (eg: 031, 001, 045, etc).
# This variable extracts the folder name to be used when finding the correct folder
folder_Name = map_No[0:3]
# print folder_Name

#Established the correct folder to look in when loading the specified layers.
search_Folder = base_Folder + "\\" + folder_Name + "\\" + map_No
arcpy.env.Workspace = search_Folder
print search_Folder

# list files in workspace
fileList = arcpy.ListFiles()
for file in fileList:
  #...
0 Kudos
ZackBartlett
New Contributor III
This is what I originally thought.  Unfortunately, I want to list files within a subfolder of the Workspace, hence the folder_Name variable, which is then concatenated with other variables to make the search_Folder variable.  The search_Folder variable identifies the folder path I want to list files from (and ultimately add shapefiles to the map document from-see my original post).

-Zack
0 Kudos
BenHolmes
New Contributor
0 Kudos
RaphaelR
Occasional Contributor II
hi Zack,

i think with glob (you even imported it in your code snippet) this should be possible.
http://www.doughellmann.com/PyMOTW/glob/

could you give an example of your exact folder/filename structure?
0 Kudos
RaphaelR
Occasional Contributor II
made a sample file structure and edited your code a bit:
basefolder\
              031\
                   031L1\
                           --map1.shp
                           --map2.shp
                   031L33\
                           --map3.shp
                           --map4.shp


when typing "031L33" in the tool´s parameter the code below will add map3 and map4:
import arcpy, os, glob

# Set Workspace
base_Folder = r"e:\test"
arcpy.env.Workspace = base_Folder
arcpy.env.OverwriteOutput = True

# User input for NTS mapsheet name.  This variable is also used to search for the correct mapsheet.
map_No = arcpy.GetParameterAsText(0)
#map_No = "031L33"
arcpy.AddMessage("Map Number: " + map_No)

# Canvec data is stored in folders, broken down by 1:50000 mapsheet number (eg: 031, 001, 045, etc).
# This variable extracts the folder name to be used when finding the correct folder
folder_Name = map_No[0:3]
arcpy.AddMessage("Folder Name: " + folder_Name)
# print folder_Name

#Established the correct folder to look in when loading the specified layers.
search_Folder = base_Folder + "\\" + folder_Name + "\\" + map_No
arcpy.AddMessage("Search Folder: " + search_Folder)
print search_Folder

##mxd = arcpy.mapping.MapDocument("CURRENT")
##dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
shp_List = glob.glob(str(search_Folder) + "\*.shp")
arcpy.AddMessage("Shp List: ")
for lyr in shp_List:
    arcpy.AddMessage(lyr)
print shp_List


for layer in shp_List:
    mxd = arcpy.mapping.MapDocument("CURRENT")
    dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
    
    addLayer = arcpy.mapping.Layer(layer)
    arcpy.mapping.AddLayer(dataFrame, addLayer, "BOTTOM")
    arcpy.RefreshTOC()
    arcpy.RefreshActiveView()
    del addLayer, mxd


hope this helps!
0 Kudos
ZackBartlett
New Contributor III
Thanks Rafael.  It worked perfectly!

I guess my error was not converting my 'search_Folder' to a string before running the glob.glob function.
0 Kudos
ZachErbe
New Contributor
I too am looking to merge multiple shapefiles into one from shapefiles in different directories. 

I have only two variables that I want to account for, the base folder "C:\test" and the shapefile that I want to merge, "zones.shp" 

The C:\test directory contains thousands of subdirectories with a zones.shp in each subdirectory.

EG:
C:\test
[INDENT]\1001[/INDENT]
[INDENT][INDENT]zones.shp[/INDENT][/INDENT]
[INDENT]\1002[/INDENT]
[INDENT][INDENT]zones.shp[/INDENT][/INDENT]
[INDENT]\1003[/INDENT]
[INDENT][INDENT]zones.shp[/INDENT][/INDENT]

I've attempted to use the code provided above, but am not having much luck.  Appreciate your assistance!

code:
import arcpy, os, glob

# Set Workspace
base_Folder = r"c:\test"
arcpy.env.Workspace = base_Folder
arcpy.env.OverwriteOutput = True

# User input for NTS mapsheet name.  This variable is also used to search for the correct mapsheet.
map_No = arcpy.GetParameterAsText(0)
arcpy.AddMessage("Map Number: " + map_No)

# Canvec data is stored in folders, broken down by 1:50000 mapsheet number (eg: 031, 001, 045, etc).
# This variable extracts the folder name to be used when finding the correct folder
folder_Name = map_No[1000:9999]
arcpy.AddMessage("Folder Name: " + folder_Name)
# print folder_Name

#Established the correct folder to look in when loading the specified layers.
search_Folder = base_Folder + "\\" + folder_Name + "\\" + map_No
arcpy.AddMessage("Search Folder: " + search_Folder)
print search_Folder

##mxd = arcpy.mapping.MapDocument("CURRENT")
##dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
shp_List = glob.glob(str(search_Folder) + "zones.shp")
arcpy.AddMessage("Shp List: ")
for lyr in shp_List:
    arcpy.AddMessage(lyr)
print shp_List


for layer in shp_List:
    mxd = arcpy.mapping.MapDocument("CURRENT")
    dataFrame = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
   
    addLayer = arcpy.mapping.Layer(layer)
    arcpy.mapping.AddLayer(dataFrame, addLayer, "BOTTOM")
    arcpy.RefreshTOC()
    arcpy.RefreshActiveView()
    del addLayer, mxd


Maybe map_No should just be the zones.shp?
0 Kudos