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()
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.