Select to view content in your preferred language

I need Help on any Python script that can clip a data frame to a selected feature

8851
27
Jump to solution
08-10-2012 06:02 PM
OLANIYANOLAKUNLE
Frequent Contributor
I am in bear need of any python script that can clip the data frame extent to a selected feature, a script different from the clipping under the geoprocesssing tool?
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RichardFairhurst
MVP Alum
Getting back to the original question of this thread, by using suggestions from Leo Donahue I have found a way to create a C# ArcMap Console Application using Visual Studio 2010 that can be triggered by Python to change the data frame clip geometry.  This should work for ArcGIS 10.0 and above and the C# code should compile in Visual Studio 2010 express and above.

While there are a number of ways to obtain the geometry for use in updating the data frame, I designed my routine to use a single polygon feature obtained from a map layer.  I can set up Python to execute the console application and pass string parameters that provide the console application with the mxd name, the data frame name, and the layer name that will be used as the feature geometry of the data frame clip shape.  Normally prior to running this code arcpy would set a Definition Query filter on the layer to restrict it to a single polygon feature.  The code also assumes that the layer is found in the same data frame that is to be clipped. 

It should be possible to adapt this code to use a graphic in a layout, or a geometrybag combination of multple polygon features as the clipping geometry instead of, or in addition to, a single feature's geometry, but this does what I wanted.

Here is the Python code to call the Console Application:

from subprocess import check_call # format is check_call([ConsoleApp_Path_and_Name, MXD_Name, Data_Frame_Name, Layer_Name]) check_call(["SetFrameClipGeometry.exe", "Collision_Segment_Diagram2.mxd", "Bottom_Split", "Bottom Clip Shape Left"]) # perform a refresh of the data frame using arcpy after setting the data frame geometry.


Here is the Code I used in the C# ArcMap Desktop Console Application:

using System; using System.Collections.Generic; using System.Text; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Framework; using ESRI.ArcGIS.ArcMapUI; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.ADF; using ESRI.ArcGIS.Geometry;  namespace SetFrameClipGeometry {     class Program     {         private static LicenseInitializer m_AOLicenseInitializer = new SetFrameClipGeometry.LicenseInitializer();              [STAThread()]         static int Main(string[] args)         {             //ESRI License Initializer generated code.             if (!m_AOLicenseInitializer.InitializeApplication(new esriLicenseProductCode[] { esriLicenseProductCode.esriLicenseProductCodeArcView, esriLicenseProductCode.esriLicenseProductCodeArcEditor, esriLicenseProductCode.esriLicenseProductCodeArcInfo },             new esriLicenseExtensionCode[] { }))             {                 System.Console.WriteLine(m_AOLicenseInitializer.LicenseMessage());                 System.Console.WriteLine("This application could not initialize with the correct ArcGIS license and will shutdown.");                 m_AOLicenseInitializer.ShutdownApplication();                 return 1;             }             //ESRI License Initializer generated code.             String mxdName = null;             String dfName = null;             String layerName = null;              if (args.Length < 3)             {                 System.Console.WriteLine("Insufficient parameters.  Expected Three Strings");                 return 1;             }             else             {                 mxdName = args[0];                 dfName = args[1];                 layerName = args[2];             }             try             {                 IAppROT aprot = new AppROT();                 if (aprot.Count == 0)                 {                     System.Console.WriteLine("No ArcMap application is open");                     return 1;                 }                 IApplication application = null;                 IMxDocument mxd = null;                 for (int a = 0; a < aprot.Count; a++)                 {                     application = aprot.get_Item(a);                     System.Console.WriteLine("Search Application Title: " + application.Document.Title);                     if (application.Document.Title == mxdName)                     {                         System.Console.WriteLine("Found Open ArcMap Document Named: " + mxdName);                         mxd = application.Document as IMxDocument;                         break;                     }                 }                 IMap pMap = null;                 IMaps pMaps = null;                 if (mxd == null)                 {                     System.Console.WriteLine("No ArcMap Document Named " + mxdName + " Was Found");                     return 1;                 }                 pMaps = mxd.Maps;                 for (int i = 0; i <= pMaps.Count - 1; i++)                 {                     pMap = pMaps.get_Item(i);                     if (pMap.Name == dfName)                     {                         Console.WriteLine("Found Data Frame Named: " + pMap.Name);                         break;                     }                 }                 if (pMap == null)                 {                     System.Console.WriteLine("No DataFrame Exists In " + mxdName);                     return 1;                 }                 if (pMap.Name != dfName)                 {                     System.Console.WriteLine("No Data Frame Named " + dfName + " Was Found");                     return 1;                 }                 if (pMap.LayerCount == 0)                 {                     return 1;                 }                 // Fetch all the feature layers in the focus map                 // to determine if at least one is selectable.                 UIDClass uid = new UIDClass();                 uid.Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}";                 IEnumLayer pEnumLayer = pMap.get_Layers(uid, true);                 pEnumLayer.Reset();                 ILayer pLayer = pEnumLayer.Next();                 while (pLayer != null)                 {                     if (pLayer.Name == layerName)                     {                         Console.WriteLine("Found Layer Named: " + pLayer.Name);                         break;                     }                     pLayer = pEnumLayer.Next();                 }                 if (pLayer == null)                 {                     System.Console.WriteLine("No Layer Named " + layerName + " Was Found");                     return 1;                 }                 using (ComReleaser comReleaser = new ComReleaser())                 {                     IFeatureLayer pFLayer = pLayer as IFeatureLayer;                     IFeatureCursor pFCursor = pFLayer.Search(null, false);                     comReleaser.ManageLifetime(pFCursor);                     IFeature pFeat = null;                     IGeometry pGeom = null;                     while ((pFeat = pFCursor.NextFeature()) != null)                     {                         pGeom = (IGeometry)pFeat.Shape;                     }                     if (pGeom == null)                     {                         System.Console.WriteLine("No Feature Geometry Was Found!");                         return 1;                     }                     pMap.ClipGeometry = pGeom;                     System.Console.WriteLine("Feature Geometry Set!");                 }             }             catch (Exception e)             {                 Console.WriteLine("{0} Exception caught.", e);                 System.Console.ReadLine();                 return 1;             }             //System.Console.ReadLine();  // Uncomment this line if you want to pause the Console application before it closes.             //Do not make any call to ArcObjects after ShutDownApplication()             m_AOLicenseInitializer.ShutdownApplication();             return 0;         }     } }

View solution in original post

0 Kudos
27 Replies
BruceBacia
Frequent Contributor
I think this could be scripted something like this:

Arguments:
The input feature class to clip

Logic:
Get the extent of your current mxd through arcpy.mapping
Create a polygon object using these coordinates, setting its spatial reference to that of the input feature class
Clip the input feature class to the geometry object
0 Kudos
markdenil
Frequent Contributor
Do you wish to actually clip the data to fit the data frame?
or do you want the data frame to fit the selected feature? (zoom and / or pan)

The suggestion above more or less addresses the first option.

The second requires you to get the extent property of the selected feature polygon Geometry object.
(Read "Reading polyline or polygon geometries" on the "Reading geometries" help page)
you then use the extent values to set the extent property of the data frame.
(read the "DataFrame" help page)

There is a bug in version 10.0 that sometimes ignores the setting of data frame extents.... so it is good practice to set it twice.
0 Kudos
BruceBacia
Frequent Contributor
This worked for me.  You zoom to the extent you want to clip to, open the script, and then select the layers in the drop down that you want to clip to that extent.  They are saved as shapefiles with the date and time in the same directory as your open mxd.  

You will need to:
-Add a script to a toolbox
-Source it back to this code on your computer
-Add a parameter "Select the layers you want to clip to this extent".  Data Type:  Feature Layer.  MultiValue:  Yes

Run the script with an mxd open.  It will work on a single dataframe, but if you have multiple dataframes in your map, it will only work on the first dataframe.  It would need tweaking to work on maps with multiple dataframes. 

#ClipToExtent.py
#Clips selected feature layers to the extent of your current mxd
#written by Bruce Bacia, 8/12/2012
import arcpy,os,gc,time

#define layer to clip
exportLayer = arcpy.GetParameterAsText(0)
exportLayer = exportLayer.split(";")
#set map document to the current open mxd
mxd = arcpy.mapping.MapDocument("CURRENT")
path = mxd.filePath
#get the root path of the mxd
path = path.replace(os.path.basename(path),"")
#set the tool to overwrite output
arcpy.env.workspace = path
arcpy.env.overwriteOutput = True
#set the dataframe as a polygon
df = arcpy.mapping.ListDataFrames(mxd)[0]
dfAsFeature = arcpy.Polygon(arcpy.Array([df.extent.lowerLeft, df.extent.lowerRight, df.extent.upperRight, df.extent.upperLeft]),df.spatialReference)

#clip the layer to the dataframe extent polygon
#send the output feature class to the same folder as the mxd
for layer in exportLayer:
    outFC = path + layer + "_Clip_" + time.strftime('%m_%d_%Y_%H_%M') + ".shp"
    gc.collect()
    arcpy.AddMessage("Clipping..... " + outFC)
    arcpy.Clip_analysis(layer,dfAsFeature,outFC)
    gc.collect()
del mxd
del df
0 Kudos
BruceBacia
Frequent Contributor
I'm assuming you wanted to clip a Selected layer to the current data frame extent.  If you wanted to change the dataframe's extent to the extent of the selected features and export, you would probably be better off right clicking on the layer and clicking data>export.  No scripting necessary
0 Kudos
OLANIYANOLAKUNLE
Frequent Contributor
Thanks for the suggestion, but its not working like the data frame clipping option.
0 Kudos
BruceBacia
Frequent Contributor
Hmmm...I guess you would need to be more descriptive as to what it is you are trying to do.  This script works great for clipping user-defined layers to the current extent of an open mxd and sending them to shapefiles.
0 Kudos
RichardFairhurst
MVP Alum
I do not believe that this questions is about clipping a feature or matching a data frame's extent rectangle to bound a feature.  I believe he is trying to do the clipping of a data frame to a shape as shown in this help description where the data frame only displays mapped information inside or outside of a non-rectangular shape that is specified by the user.  I would also like in code to be able to reset the data frame to clip what is shown to the same shape as a feature.  I am sure it can be done with ArcObjects with the IMap.ClipGeometry property, but I do not see any data frame property that would let me do this in Python.  It seems the data frame extent property only takes rectangular coordinates.

I have not figured out how to call ArcObjects from Python, but if someone knows how, it would be nice if they could share a way to call the ArcObjects IMap.ClipGeometry property from Python.
0 Kudos
OLANIYANOLAKUNLE
Frequent Contributor
Thanks rfairhur24 thats exactly what im saying.
0 Kudos
OLANIYANOLAKUNLE
Frequent Contributor
I also want to create a custom form where i can enter a particular plot_no for a parcel layer, the layer definitionquery and a custom scale for may layout. I have tried to use the esri python addin to i did not get what i want. Please any suggestion would be highly appreciated. Thanks
0 Kudos