[GIS] List layers from current view using Arcpy

arcgis-10.4arcpylayers

I am using ArcGIS 10.4.1 and Python 2.7.10.

I have a mxd file of a rather large area which contain hundred of layers. I wish to work in a specific sub-area in that workspace, where only a few layers will be relevant.

I was looking for a way to output a list of the layers which are spatially overlapping with the current view (sub-area) in ArcMap. The layers could be visible or not, as checked (or not) in the workspace. The mxd is up to date with this view.

Is such a thing possible?

I am using as a basis the following code, which output all the layers in the workspace:

import arcpy

mxd = arcpy.mapping.MapDocument(r"C:\path\to\file.mxd")
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
print arcpy.mapping.ListLayers(mxd,"", df)

EDIT: a practical example to illustrate would resemble to this:
Let's say I have dozen of layers from topographical maps and ground features (water, river, topoline-level, roads, electric line, settlements, glaciers, reservations, highways, airports, and forests) at a country scale.

I zoom in a very remote forested area, where only the layers forest, river, topoline-level are overlapping the view. All other are not relevant. I am looking if it is possible to arcpy those forest, river and topoline layers in a list and discard the other.

Best Answer

A DataFrame object has an extent property, the extent property/object can be used in the basic spatial relationship methods of contains, within, equals, overlaps, touches and disjoint as well as distanceTo, see here for more details on those methods.

With that in mind you can loop over the layers you retrieve from calling arcpy.mapping.ListLayers(mxd,"", df) and retrieve each layers extent by calling the getExtent method on each layer. The spatial relationships discussed above can be tested between the extent.polygon object of each layer and the dataframe to determine if they are indeed within the extent of the dataframe. If you are using data driven pages the extent of each page can be retrieved with an mxd object with this call mxd.dataDrivePages.dataFrame.extent.

It is important to note that the extent of a layer often has a larger footprint that than the actual vector within the layer (e.g. the polygon, points, raster, etc.), so depending on the spatial relationship you choose to test it may include more layers than are actually visible. Here is an example (thanks @KHibma) of how you would use a spatial relationship method of the DataFrame with a Layer object:

mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd)[0]
for l in arcpy.mapping.ListLayers(df):
    if not df.extent.disjoint(l.getExtent()): 
        print l.name
Related Question