Selectable Layer(s) in Python - Not TOC buttons

1836
4
06-23-2014 08:38 AM
ChrisHanes1
New Contributor
I have a Python Addin that selects a feature by mouse click location and updates the attributes (to a per-determined value) or deletes it based on the button I click in the toolbar (I am flagging the layer on the fly).  This layer I am updating is simply a reference layer (a result of  QC script).  The layer the QC script was run on, will be edited to correct mistakes, so I really only want that as my selectable layer, so I can continue editing after flagging a QC polygon as resolved, ignored, etc.

The problem is that when I run my tool to update the polygon, it changes the list of selectable layers in my table of contents and adds the layer I updated through the tool.  I want to be able to set that back/set it to a particular layer after using my button.  Otherwise I have to keep setting it manually. 

Anyone know how to set the selectable layers through a script and not by clicking buttons in the TOC?

It should be part of arcpy.mapping, but it is not:
http://resources.arcgis.com/en/help/main/10.1/index.html#//00s300000008000000
Tags (2)
0 Kudos
4 Replies
KerryAlley
Occasional Contributor
I don't know of a way to make a layer un-selectable through Python scripts, which I'm guessing is intentional because layers are always selectable from a script's perspective.  (For example, arcpy.SelectLayerByLocation_management works on a layer even if it is not selectable in ArcMap, and the layer remains un-selectable even after running arcpy.SelectLayerByLocation_management via script or toolbox.)

If you are updating a layer from a layer file, just make sure the layer file (layer.lyr) you are referencing was created from a layer that was not selectable, then it should preserve that property when brought into your map document.

Kerry
0 Kudos
ChrisHarlow1
New Contributor
I have a Python Addin that selects a feature by mouse click location and updates the attributes


Would you be willing to share the code for this?  I'm trying to do a similar thing but take an attribute value from one selected feature and input it along with a string into an attribute field of another feature class.

Thanks
0 Kudos
KerryAlley
Occasional Contributor
Here's the code for the Python add-in I was referring to.  Keep in mind that it is meant to work with our own data, so it would require significant changes to perform similarly with someone else's data.

#ShieldToolAddin.py
#By Kerry Alley 2013-03-12
#Vermont Agency of Transportation
#
#Python Add-In for ArcMap 10.1, 10.2
#
#SELECT_ROAD (button)
#When activated, will select features within 20 map-meters of the mouse click on the map.
#The features are selected only from the top-most layer with the GDB_HMS.HMSADMIN.rdsmall_arc
#  data source, regardless of layer name.
#
#CREATE_SHIELD (button)
#Requires that a single rdsmall_arc feature already be selected
#User makes a single click on the map to indicate the location of the highway shield, and
#  makes a double-click where the leader line extending from the highway shield will end.
#Both a point feature and a line feature are created, with relevant attributes transferred
#  from the selected rdsmall_arc feature.
#There is an un-commentable option in this script that sets the length of the leader line to
#  a fixed length, for uniformity.
#
#NOTE: This addin works "normally" if there is not an active editing session in ArcMap, but if
#  there is an active editing session, the addin "crashes" at the call to stopEditing().  The
#  features will still be created, but the screen will not refresh if there is a pre-existing
#  editing session active.

import arcpy, time, os, math
import pythonaddins

class SelectRoadClass(object):
    """Implementation for ShieldToolAddinA_addin.tool (Tool)"""
    def __init__(self):
        self.enabled = True
        self.shape = "NONE"
 
    def onMouseDownMap(self, x, y, button, shift):
 #start_time = time.time() #only used to compare run-times of different versions of the script
 arcpy.env.overwriteOutput = True
 
 rdsmall_dataSource = r"GDB_HMS.HMSADMIN.rdsmall_arc"
 
 mxd = arcpy.mapping.MapDocument('current')
 flag_rdsmall = 0 #flag_rdsmall is used to flag the first occurence of a layer having the desired dataSource in TOC
 for lyr in arcpy.mapping.ListLayers(mxd):
     if lyr.supports("dataSource"):
  if str(lyr.dataSource).endswith(rdsmall_dataSource) and not flag_rdsmall:
      rdsmall_lyr = lyr
      flag_rdsmall = 1
 point = arcpy.Point()
 point.X = x
 point.Y = y
 pointGeometry = arcpy.PointGeometry(point)
 arcpy.SelectLayerByLocation_management(rdsmall_lyr, "WITHIN_A_DISTANCE", pointGeometry, "20 Meters", "NEW_SELECTION")
 #print time.time() - start_time, "seconds"
 
 
class CreateShieldClass(object):
    """Implementation for ShieldToolAddinB_addin.tool (Tool)"""
    def __init__(self):
 self.enabled = True
 self.cursor = 3
 self.shape = "LINE" 
    def onLine(self, line_geometry):
 #start_time = time.time() #only used to compare rough run-times of different versions of the script
 arcpy.env.overwriteOutput = True
 
 #Hard-wiring the exact feature classes that will be edited with shield tool.
 shield_points_dataSource = r"GDB_HMS.HMSADMIN.hms_shields_points"
 shield_arcs_dataSource = r"GDB_HMS.HMSADMIN.hms_shields_arcs"
 rdsmall_dataSource = r"GDB_HMS.HMSADMIN.rdsmall_arc"
 
 mxd = arcpy.mapping.MapDocument('current')
 
 #for new shields to appear in current mxd, this script must refer to layers in the current mxd
 lyrs = arcpy.mapping.ListLayers(mxd)
 flag_points = 0
 flag_arcs = 0
 flag_rdsmall = 0
 for lyr in arcpy.mapping.ListLayers(mxd):
     if lyr.supports("dataSource"):
  if str(lyr.dataSource).endswith(shield_points_dataSource) and flag_points == 0:
      shield_points_lyr = lyr
      flag_points = 1
  if str(lyr.dataSource).endswith(shield_arcs_dataSource) and flag_arcs == 0:
      shield_arcs_lyr = lyr
      flag_arcs = 1
  if str(lyr.dataSource).endswith(rdsmall_dataSource) and flag_rdsmall == 0:
      rdsmall_lyr = lyr
      flag_rdsmall = 1
      
 if not (shield_points_lyr and shield_arcs_lyr and rdsmall_lyr):
     print "Must have 3 layers in this mxd: shield points, shield arcs, and rdsmall"
 
 #only allow shield creation if a single road arc is selected
 num_road_arcs = int(arcpy.GetCount_management(rdsmall_lyr).getOutput(0))
 print "%s rdsmall arc(s) selected" %num_road_arcs
 if num_road_arcs == 1:
     workspace = rdsmall_lyr.workspacePath  #(refers to .sde file in DatabaseConnections)
     arcpy.env.workspace = workspace
     edit = arcpy.da.Editor(workspace)
     edit.startEditing(True, True) #with undo, multiuser mode
     
     #identify maximum SHI_GRP_ID value currently used in shields feature class
     max_id = sorted(arcpy.da.SearchCursor(shield_points_lyr.dataSource, "SHI_GRP_ID"), reverse = 1)[0][0]
     #print max_id + 1
     
     #collect selected road arc attributes
     rdsmall_values = sorted(arcpy.da.SearchCursor(rdsmall_lyr, ["UA", "FAID_S", "CTCODE", "RTNUMBER", "AOTCLASS"]))
     
     #uncomment the last line of this block of code to turn off the truncation of the leader line
     #determine line coordinates, slope, and truncated line geometry based on first and last point.
     a_pt = line_geometry.firstPoint
     b_pt = line_geometry.lastPoint
     slope = (b_pt.Y - a_pt.Y)/(b_pt.X - a_pt.X)
     theta = math.atan(slope)
     #fixed_length = 150.
     fixed_length = 185.
     if b_pt.X - a_pt.X < 0:
  x = fixed_length * math.cos(theta) * -1
  y = fixed_length * math.sin(theta) * -1
     else:
  x = fixed_length * math.cos(theta)
  y = fixed_length * math.sin(theta)
     point = arcpy.Point()
     point.X = a_pt.X + x
     point.Y = a_pt.Y + y
     array = arcpy.Array()
     array.add(line_geometry.firstPoint)
     array.add(point)
     fixed_line = arcpy.Polyline(array)
     #To remove the constraint of fixed shield arc lengths, uncomment the following line:
     fixed_line = line_geometry #this line reverts the fixed_line to the original input geometry
     
     #create shield point feature and populate attributes
     new_points_Cur = arcpy.da.InsertCursor(shield_points_lyr, ["SHAPE@XY", "UA", "FAID_S", "CTCODE", "RTNUMBER", "AOTCLASS", "SHI_GRP_ID", "INSET", "ISVISIBLE", "SUBINSET"])
     test = (fixed_line.firstPoint,) + tuple(rdsmall_values) + (max_id + 1,)
     test_tuple = ((test[0].X, test[0].Y), test[1][0], test[1][1], str(test[1][2]), str(test[1][3]), test[1][4], test[2], "N", 1, "N")
     #test_tuple = ((test[0].X, test[0].Y), rdsmall_values[0], str(rdsmall_values[2]), str(rdsmall_values[3]), rdsmall_values[4], max_id + 1, "N", 1, "N")
     edit.startOperation()
     new_points_Cur.insertRow(test_tuple)
     edit.stopOperation()
     del new_points_Cur
     
     #create shield arc feature and populate SHI_GRP_ID, CTCODE, UA, INSET, ISVISIBLE, and SUBINSET fields
     new_arc_Cur = arcpy.da.InsertCursor(shield_arcs_lyr.dataSource, ["SHAPE@", "SHI_GRP_ID", "CTCODE", "UA", "INSET", "ISVISIBLE", "SUBINSET"])
     edit.startOperation()
     new_arc_Cur.insertRow([fixed_line, max_id + 1, str(rdsmall_values[0][2]), rdsmall_values[0][0], "N", 1, "N"])
     edit.stopOperation()
     del new_arc_Cur
     
     edit.stopEditing(True) #save changes (doesn't work if an editing session is open in ArcMap, but )
     arcpy.SelectLayerByAttribute_management(rdsmall_lyr, "CLEAR_SELECTION")
     arcpy.RefreshActiveView()
 else:
     print "Shield Not Created"
     print "Must select a single arc from rdsmall"
 #print time.time() - start_time, "seconds"
0 Kudos
ChrisHarlow1
New Contributor
Thanks!  I have my process built and it works in pieces, but when combined it fails.  I more just want to see how other people are doing a similar process so hopefully I'll be able to get mine to work.
0 Kudos