Tuesday, 21 September 2021

Hide single features in ArcMap

Here is a Python tool to hide selected features in ArcMap and to bring them back to screen. Useful if you need to create a screenshot / printout but want to hide certain features but not a whole layer. The tool applies a definition filter to "hide" selected features (across multiple layers) and removes the filters to display the features again. Filter condition is added to existing query.

Initial idea found on gis.stackexchange:

https://gis.stackexchange.com/questions/368848/creating-definition-query-from-selected-features-using-arcgis-pro

First the toolbox definition - save as PYT file:

 # -*- coding: utf-8 -*-  
 """  
 Created on Fri Feb 28 08:49:34 2020  
 """  
 import arcpy , m_main_layer  
 class Toolbox(object):  
   def __init__(self):  
     """Define the toolbox (the name of the toolbox is the name of the .pyt file)."""  
     self.label = "My Toolbox"  
     self.alias = ""  
     # List of tool classes associated with this toolbox  
     self.tools = [FeatureOff, FeatureOn]  
 class FeatureOff(object):  
   def __init__(self):  
     """Define the tool (tool name is the name of the class)."""  
     self.label = "Hide selected features"  
     self.description = "Hides selected features by applying a layer definition query"  
     self.canRunInBackground = False  
   def getParameterInfo(self):  
     """Define parameter definitions"""  
     return  
   def isLicensed(self):  
     """Set whether tool is licensed to execute."""  
     return True  
   def updateParameters(self, parameters):  
     """Modify the values and properties of parameters before internal  
     validation is performed. This method is called whenever a parameter  
     has been changed."""      
     return  
   def updateMessages(self, parameters):  
     """Modify the messages created by internal validation for each tool  
     parameter. This method is called after internal validation."""  
     return  
   def execute(self, parameters, messages):      
     reload(m_main_layer)       
     m_main_layer.main_off()  
     return  
 class FeatureOn(object):  
   def __init__(self):  
     """Define the tool (tool name is the name of the class)."""  
     self.label = "Display hidden features"  
     self.description = "displays hidden features by removing layer definition query"  
     self.canRunInBackground = False  
   def getParameterInfo(self):  
     """Define parameter definitions"""  
     return  
   def isLicensed(self):  
     """Set whether tool is licensed to execute."""  
     return True  
   def updateParameters(self, parameters):  
     """Modify the values and properties of parameters before internal  
     validation is performed. This method is called whenever a parameter  
     has been changed."""      
     return  
   def updateMessages(self, parameters):  
     """Modify the messages created by internal validation for each tool  
     parameter. This method is called after internal validation."""  
     return  
   def execute(self, parameters, messages):      
     reload(m_main_layer)       
     m_main_layer.main_on()  
     return            
Here the main Python script:
 # -*- coding: utf-8 -*-  
 """  
 Created on Fri Mar 20 09:11:37 2020  
 """  
 # -*- coding: utf-8 -*-  
 import arcpy  
 # mark start of query condition  
 # comments such as /* -- */ do not work with FGDB  
 # therefore we add a dummy condition as start marker  
 query_start_marker = "'A'='A'"  
 query_concat = " AND "  
 # max value might be different for each database system in use:  
 max_num_selected_features_per_layer = 999  
 def remove_filter_features(lyr):    
   if not lyr.isFeatureLayer:  
     return   
   desc = arcpy.Describe(lyr.name)      
   query = lyr.definitionQuery  
   start = query.find(query_start_marker)         
   if start >= 0:  
     query_front = query[:start]                 
     len_query_conact = len(query_concat)  
     if len(query_front) > len_query_conact and query_front[-len_query_conact:] == query_concat:  
       query_front = query_front[:-len_query_conact]              
     lyr.definitionQuery = query_front  
 def apply_filter_selected_features(lyr):    
   if not lyr.isFeatureLayer:  
     return                
   desc = arcpy.Describe(lyr.name)        
   if desc.FIDSet != '':                   
     fid_list = desc.FIDSet.split(";")  
     if len(fid_list) > max_num_selected_features_per_layer:  
       arcpy.AddMessage("Too many features selected ({0}), max: {1}.".format(len(fid_list),max_num_selected_features_per_layer))  
       return  
     query = ' {} NOT IN ({}) '.format(desc.OIDFieldName, ",".join(fid_list))      
     existing_query = lyr.definitionQuery  
     if existing_query:  
       query = existing_query + query_concat + query_start_marker+ ' AND ' + query  
     else:  
       query = query_start_marker + ' AND ' + query      
     lyr.definitionQuery = query      
     arcpy.SelectLayerByAttribute_management(lyr, "CLEAR_SELECTION")  
 def main_off():          
   arcpy.AddMessage("hide selected features....")  
   mxd = arcpy.mapping.MapDocument("CURRENT")       
   df = arcpy.mapping.ListDataFrames(mxd)[0]    
   for l in arcpy.mapping.ListLayers(df):  
     apply_filter_selected_features(l)  
   arcpy.AddMessage("hide selected features....finished")  
 def main_on():  
   arcpy.AddMessage("display hidden features....")  
   mxd = arcpy.mapping.MapDocument("CURRENT")       
   df = arcpy.mapping.ListDataFrames(mxd)[0]    
   for l in arcpy.mapping.ListLayers(df):  
     remove_filter_features(l)  
   arcpy.RefreshActiveView()            
   arcpy.AddMessage("display hidden features....finished")  

Example:

select features...
...hidden...


...bringing them back to screen...










No comments:

Post a Comment