ArcPy Python Add-in – Selecting and Copying Features in ArcMap

arcgis-10.1arcmaparcpypython-addin

I'm trying to add a tool to an add-in toobar to select features from an existing feature class and copy them across to another feature class. I need two tools, one for a point and one for a rectangle. Add-in tools only handle rectangles, so I'm trying to generate the point coordinate off the onMouseDown event and simply use the X and Y feedback I get. The problem is that I can't seem to pass these coordinates to anything usefull to extract the features. I've tried using Environment extents and then doing a simple CopyFeatures, but that's not working as it copies the entire fc and doesn't seem to honour the environment settings I set.

Can I pass coordinates to the Select by Location tool somehow or is there another way of passing coordinates to something to extract by that extent?

This is what I have now:

import arcpy
import pythonaddins
arcpy.overWriteOutput = True

# Replace this with the SDE layer once it's available.
global ELAtemplate, fc
ELAtemplate = r'C:\Data\nsw_map_units.shp'
fc = ""

class DefineUnitsbyPoint(object):
    """Implementation for DefineUnitsbyPoint.tool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.shape = "Rectangle" # Use onMouseDown to get initial extent of the rectangle.
    def onMouseDownMap(self, x, y, button, shift):
        # fc can be assigned from a combo box selection in another class
        global ELAtemplate, fc
        if fc == "":
            pythonaddins.MessageBox('Choose a layer to select from.', 'Choose a Layer', 0)
        else:
            mxd = arcpy.mapping.MapDocument("CURRENT")
            pointGeom = arcpy.PointGeometry(arcpy.Point(x,y), mxd.activeDataFrame.spatialReference)
            arcpy.SelectLayerByLocation_management(ELAtemplate, "INTERSECT", pointGeom, "", "ADD_TO_SELECTION")
            arcpy.CopyFeatures(ELAtemplate, fc)

Best Answer

You will probably want to use onMouseDownMap rather than onMouseDown as this returns the location in map coordinates, not window coordinates.

Additionally, be sure to pass in a valid SpatialReference object to the PointGeometry constructor, otherwise it will most likely not work. In the example below I use the spatial reference of the active data frame.

Lastly you may want to specify a search_distance on your SelectLayerByLocation so that point and line features can be selected without clicking on them exactly. In ArcObjects you would normally use ArcMap's selection tolerance in pixels and expand your point's envelope by that amount in map coordinates. I couldn't find a way to access ArcMap's selection tolerance setting in arcpy, but if you want to go with the default of 3 pixels (or pass in your own), you can pass the output of the function in this answer as a search_distance (in inches) to SelectLayerByLocation.

def onMouseDownMap(self, x, y, button, shift):
    mxd = arcpy.mapping.MapDocument("CURRENT")
    pointGeom = arcpy.PointGeometry(arcpy.Point(x, y), mxd.activeDataFrame.spatialReference)
    searchdistance = getSearchDistanceInches(mxd.activeDataFrame.scale)
    lyr = arcpy.mapping.ListLayers(mxd)[0] # assumes you want to select features from 1st layer in TOC
    arcpy.SelectLayerByLocation_management(lyr, "INTERSECT", pointGeom, "%d INCHES" % searchdistance)
    arcpy.RefreshActiveView()
Related Question