Select to view content in your preferred language

confusion with ListDataFrames and Listlayers

2381
11
08-22-2012 08:41 AM
JonPedder
Deactivated User
I have a script that moves a group layer from one mxd to others, the layer is saved from the current mxd then written to a list of other mxd???s, the group layer is Base_Data.

My script is working well but I???d like to clean it up a bit by first removing any existing Base_Data layer groups in the target mxd before writing the layer source. As it is, if I run the script 3 time I get 3 copies of Base_Data in the target.

I???m trying to use the following but am seeing unexpected results.

Using the ListDataFrames function I assumed I???d get back a list of the DataFrames in the mxd, such as ???New Data Frame???
df = arcpy.mapping.ListDataFrames(mxd,"")[0]
instead when I iterate the list df I get a list of all the layers.
For i in df:
                Print i


So when I try to list the layers to select the Base_Data I just get a list of layers the first group layer 
basedata = arcpy.mapping.ListLayers(mxd)[0]
       for i in basedata:
                arcpy.AddMessage(i)



All I???m really trying to accomplish it to detete any layers in the target mxd that contain ???Base_Data???

Thanks
Tags (2)
0 Kudos
11 Replies
MathewCoyle
Honored Contributor
You aren't getting a list since you specify the index position of your data frame.

This returns the first data frame.
df = arcpy.mapping.ListDataFrames(mxd)[0]

This returns a list of all data frames.
df = arcpy.mapping.ListDataFrames(mxd)
0 Kudos
JonPedder
Deactivated User
The structure of my mxd is a single data frame, which has 14 layer groups, several layers within each group.

What I'd like to do is delete the 14th layer group "Base_Data" on a target mxd, I'm having no luck accomplishing this.
0 Kudos
ChristopherThompson
Frequent Contributor
If your base data are always in a group layer that has Base_Data in the name somehow then you can query a layer to determine if its a group layer, if it is, then you can inspect its name to see if it has the string 'Base_Data' in it.  Unless you need to process this dataframe by data frame I think you can skip the work with ListDataFrames.

something like this might work (concept only! hasn't been tested):
map = arcpy.mapping.MapDocument('some map name')
lyr_list = arcpy.mapping.ListLayers(map) #leaving out the dataframe argument returns a list of all layers in all dataframes
for lyr in lyr_list:
         if lyr.isGroupLayer:
                  if 'Base_Data' in lyr.name:
                             continue
                  else:
                        ... your code to copy to new mxd...


you can also examine other attributes of a Layer object such as the name and longname.  The name is the name of a layer as it appears in arcmap, the long name will have a reference to a group layer (like base_data\roads where roads is the layer and base_data is the group).  You can always check to see if the name and long name are equal, if so, move them, if not, then check to see if the long name contains Base_Data or other string you are interested in filtering with.
0 Kudos
JonPedder
Deactivated User
If your base data are always in a group layer that has Base_Data in the name somehow then you can query a layer to determine if its a group layer, if it is, then you can inspect its name to see if it has the string 'Base_Data' in it.  Unless you need to process this dataframe by data frame I think you can skip the work with ListDataFrames.

something like this might work (concept only! hasn't been tested):
map = arcpy.mapping.MapDocument('some map name')
lyr_list = arcpy.mapping.ListLayers(map) #leaving out the dataframe argument returns a list of all layers in all dataframes
for lyr in lyr_list:
         if lyr.isGroupLayer:
                  if 'Base_Data' in lyr.name:
                             continue
                  else:
                        ... your code to copy to new mxd...


you can also examine other attributes of a Layer object such as the name and longname.  The name is the name of a layer as it appears in arcmap, the long name will have a reference to a group layer (like base_data\roads where roads is the layer and base_data is the group).  You can always check to see if the name and long name are equal, if so, move them, if not, then check to see if the long name contains Base_Data or other string you are interested in filtering with.


Thanks Chris, here's what I tried as a test from shell, it "appeared" to work but didn't actually delete anything

mxd = arcpy.mapping.MapDocument("C:\tester.mxd")
lyr = arcpy.mapping.ListLayers(mxd,"14*")[0]
for i in lyr:
 arcpy.Delete_management(lyr)
mxd.save()


The delete command returned <Result 'true'> after every iteration

I'll try your code next
0 Kudos
ChristopherThompson
Frequent Contributor
this at least is what is giving you fits:
lyr = arcpy.mapping.ListLayers(mxd,"14*")[0]

the part i flagged in red is being interpreted by python as "give me the layer with an index of 0" so your code is finding the first layer in your table of contents, not the 14th which is what I think is what you want. Since python indexes are 0 based your 14th layer would have an index of 13.

Also, Delete_management is not the function you want, that will delete a file off disk, not something from an mxd. I think you need the arcpy.mapping.RemoveLayer function instead
http://resources.arcgis.com/en/help/main/10.1/index.html#/RemoveLayer/00s300000039000000/
0 Kudos
JonPedder
Deactivated User
Your code does appear to work, however teh deletion isn't working

>>> map = arcpy.mapping.MapDocument('C:\test.mxd')
>>> lyr_list = arcpy.mapping.ListLayers(map)
>>> for lyr in lyr_list:
 print lyr

# result of the above displays a list of layers correctly

# next to delete the layers in question

>>> for lyr in lyr_list:
 if 'Base_Data' in lyr.name:
  arcpy.Delete_management(lyr)

  
<Result 'true'>
<Result 'true'>
<Result 'true'>
<Result 'true'>



however nothing was actually deleted
0 Kudos
JonPedder
Deactivated User
Sorry for all the posts but I keep trying.... 🙂

I found a RemoveLayer, however I now get an error when trying to save the file after processing.

>>> mxd = arcpy.mapping.MapDocument('C:\test.mxd')
>>> df = arcpy.mapping.ListDataFrames(mxd,"")[0]
>>> lyr_list = arcpy.mapping.ListLayers(mxd)
>>> for lyr in lyr_list:
 if 'Base_Data' in lyr.name:
  arcpy.mapping.RemoveLayer(df,lyr)
mxd.save()


error below
Traceback (most recent call last):
  File "<pyshell#60>", line 4, in <module>
    mxd.save()
  File "C:\Program Files\ArcGIS\Desktop10.0\ArcPy\arcpy\utils.py", line 181, in fn_
    return fn(*args, **kw)
  File "C:\Program Files\ArcGIS\Desktop10.0\ArcPy\arcpy\_mapping.py", line 643, in save
    return convertArcObjectToPythonObject(self._arc_object.save(*gp_fixargs((), True)))
IOError: MapDocObject: Unable to save.  Check to make sure you have write access to the specified file and that there is enough space on the storage device to hold your document.
0 Kudos
ChristopherThompson
Frequent Contributor
That is the error you typically get when you're trying to overwrite an existing map document.  Python may have it stuck in memory.  If you're doing this from the python shell then close it down, look and see if the map document you're trying to create was saved, delete it and try again.
0 Kudos
JonPedder
Deactivated User
Here's my entire code file, it probably appears rather brute force as I'm very new to python/coding and learning as I go.

I have 2 user parameters, the first is a folder, so the script can iterate through each file. Kinda abandoned that until I can get a singel file working. The second is a document type which provides the target.



import glob
import arcpy
 
from arcpy import env
 
# Set overwrite option
arcpy.env.overwriteOutput = True
 
# Gather user input parameters
TargetDir = arcpy.GetParameterAsText(0)
TargetFile = arcpy.GetParameterAsText(1)

arcpy.AddMessage(TargetDir)
arcpy.AddMessage(TargetFile)

if TargetFile > "":
        arcpy.AddMessage("Target File is True")
        
        # Save base data layer file to disk
        LayerFile = "./Base_Layer"
        arcpy.SaveToLayerFile_management("14_Base_Data_Group",LayerFile,"RELATIVE")
        arcpy.AddMessage("Base Data Saved as "+ LayerFile)

        mxd = arcpy.mapping.MapDocument(TargetFile)
        arcpy.AddMessage(mxd)
        df = arcpy.mapping.ListDataFrames(mxd,"")
        lyr_list = arcpy.mapping.ListLayers(mxd)
        for lyr in lyr_list:
                if 'Base_Data' in lyr.name:
                        arcpy.mapping.RemoveLayer(df,lyr)

        path = LayerFile + '.lyr'
        arcpy.AddMessage("1" +path)
                         
        addLayer = arcpy.mapping.Layer(path)
        arcpy.AddMessage("2")
        arcpy.mapping.AddLayer(df, addLayer, "BOTTOM")
        mxd.save()
        
elif TargetDir > "":
        arcpy.AddMessage("Target Directory is true")
        
        # Save base data layer file to disk
        LayerFile = "./Base_Layer"
        arcpy.SaveToLayerFile_management("14 Base_Data_Group",LayerFile,"RELATIVE")
        arcpy.AddMessage("Base Data Saved as "+ LayerFile)

        # Get list of files from directory
        path = TargetDir +"\*.mxd"
        mxds = glob.glob(path)
        arcpy.AddMessage(mxds)
        for row in mxds:
                note = '"'+row+'"'
                arcpy.AddMessage("Applying base data to mxd...")
                arcpy.AddMessage(row)
                
                mxd = arcpy.mapping.MapDocument(row)
                df = arcpy.mapping.ListDataFrames(mxd)[0]
                basedata = arcpy.mapping.ListLayers(mxd, "14 Base_Data", df)[0]
                for i in basedata:
                        arcpy.AddMessage(i)
                        
                path = LayerFile + '.lyr'
                              
                addLayer = arcpy.mapping.Layer(path)

                arcpy.mapping.AddLayer(df, addLayer, "BOTTOM")
                mxd.save()

del mxd, addLayer

0 Kudos