Select to view content in your preferred language

Issues with using Python to update field visibility in .aprx map document layers

145
1
3 weeks ago
MollyMoore
Frequent Contributor

I am upgrading a script that heavily relied on the arcpy.mapping package to work with ArcGIS Pro. I have gotten everything working okay EXCEPT for updating the visible fields in the map layers. I have tried a bunch of different suggestions, but none that have worked. The simplest approach seems to be using Python cim access: https://pro.arcgis.com/en/pro-app/latest/arcpy/mapping/python-cim-access.htm

My code runs okay, but when I open my .aprx, none of the fields have been hidden that are supposed to be hidden. Anyone have suggestions?

visible_fields = ['list', 'of', 'fields']

aprx = arcpy.mp.ArcGISProject(aprx_path)
map_doc = aprx.listMaps(map_frame_name)[0]

for lyr in map_doc.listLayers():
    if arcpy.Describe(lyr).dataType == "FeatureLayer":
        print(lyr.name)
        # Get the layer's CIM definition - using Pro 2.9
        cim_lyr = lyr.getDefinition('V2')

        # Make changes to field properties
        for fd in cim_lyr.featureTable.fieldDescriptions:
            if fd.fieldName not in visible_fields:
                fd.visible = False  # Do not display this field

        # Push the changes back to the layer object
        lyr.setDefinition(cim_lyr)

aprx.save()
1 Reply
HaydenWelch
MVP

You wrote everything correctly, I can't really see a better way to do it. Went ahead and just added some hinting and an overridden print function so you can monitor exactly what the code is doing depending on where you're running it from:

from builtins import print as _print
from typing import Literal
from _typeshed import SupportsWrite

from arcpy import AddMessage
from arcpy.mp import ArcGISProject
from arcpy._mp import Map, Layer
from arcpy.cim import CIMFeatureLayer, CIMFeatureTable, CIMFieldDescription

# Define a custom print function that also writes to the ArcGIS Pro messages
def print(
    *values: object,
    sep: str | None = " ",
    end: str | None = "\n",
    file: SupportsWrite[str] | None = None,
    flush: Literal[False] = False,
) -> None:
    _print(*values, sep=sep, end=end, file=file, flush=flush)
    AddMessage(sep.join(map(str, values)) + end if end != '\n' else '')

def update_field_visibility(
    aprx_path: str, 
    map_frame_name: str, 
    *, 
    visible_fields: tuple[str]= (), 
    use_alias: bool = False):
    
    # Open the project and get the layers
    aprx = ArcGISProject(aprx_path)
    map_doc: Map = aprx.listMaps(map_frame_name)[0]
    layers: list[Layer] = [layer for layer in map_doc.listLayers() if layer.isFeatureLayer]
    
    # Update the field visibility for each layer
    for layer in layers:
        # Get CIM objects
        cim_lyr: CIMFeatureLayer = layer.getDefinition('V2')
        cim_feature_table: CIMFeatureTable = cim_lyr.featureTable
        cim_field_descriptions: list[CIMFieldDescription] = cim_feature_table.fieldDescriptions
        
        # Update field visibility
        for fd in cim_field_descriptions:
            name = (use_alias and fd.alias) or fd.fieldName
            
            if name not in visible_fields and fd.visible:
                fd.visible = False
                print(f"Field {name} for {layer.name} is now hidden")
            
            elif name in visible_fields and not fd.visible:
                fd.visible = True
                print(f"Field {name} for {layer.name} is now visible")
        
        # Set the definition
        layer.setDefinition(cim_lyr)
    
    # Save the project
    aprx.save()
    
if __name__ == "__main__":
    aprx = r"Path\To\APRX"
    map_frame_name = "Map"
    visible_fields = ("Field1", "Field2", "Field3")
    
    update_field_visibility(aprx, map_frame_name, visible_fields=visible_fields)

 

That should at least tell you what fields are getting switched on and off. I've used this exact method before to great success, so I'm not sure exactly what could be happening.