Python CIM 访问

arcpy.mp 模块是一个粗粒度 Python API,旨在提供对许多常见地图自动化任务的访问权限。 它包含一组不同的公开类、类属性和方法以及帮助程序函数,但不提供对 ArcGIS Pro 的所有可用属性、设置和功能的访问权限。 一个原因是保持 API 简化、简单且易于管理。 另一个原因是 ArcGIS Pro 的当前开发速度太快,arcpy.mp API 无法跟上。 可能需要一个或多个版本,然后才能通过公开的 API 进行访问(如果适用)。 从 ArcGIS Pro 2.4 开始,Python 开发人员可以对制图信息模型 (CIM) 进行细化访问,并可以访问工程或外部文档(例如图层文件 .lyrx)中永久保留的更多设置、属性和功能。 从 ArcGIS Pro 1.1 开始,.NET SDK 开发社区已具有 CIM 访问权限,现在它可供 Python 开发社区使用。

警告:

以下几个部分介绍了使用 CIM 可执行的操作。 在修改 CIM 之前,需要了解不应执行的操作。 有关详细信息,请参阅下面标题为“谨慎修改 CIM”的部分。

什么是 CIM 以及如何查看

CIM 是 Esri 制图信息模型。 它是一个地图内容规范,用于记录在读取或写入工程时各种工程组件描述信息的保留方式。 无论其首字母缩略词为何,都不要认为 CIM 仅限于制图设置。 通过 CIM 向这些类公开的功能远远不止如此,下面的示例演示了这些扩展功能中的一小部分。

该规范以 JSON 格式表示,将地图、布局、图层、样式和其他元素导出到 *.mapx*.pagx*.lyrx*.stylx*.*x 文件时,可以查看该规范。 查看和了解类属性如何保留在 JSON 规范中的最简单方式是在 JSON 查看器(例如 Notepad++)中打开这些文件之一。 JSON 文件中的结构与向 arcpy.mp 模块公开的 CIM 对象模型类似,因此有必要查看这些文件,以了解属性在结构中的位置以及该属性在 CIM 中的名称,因为它可能与应用程序中的名称不一致。

提示:

例如,将其中一个 JSON 文件从 *.pagx 重命名为 *.json 可能使其在编辑器中更容易阅读,因为代码的不同部分会根据其表示的内容设置为不同的颜色;如果不这样做,所有文本均采用相同的显示方式。

下面是 CIMLayerDocument (*.lyrx) 可用的经过修改的根级别属性缩写列表的 JSON 表示。 下方的一些项目(例如 featureTable)可以展开以显示更多缩进的设置。

{
  "type" : "CIMLayerDocument",
  "version" : "3.2.0",
  "layers" : [
    "CIMPATH=map/greatlakes.xml"
  ],
  "layerDefinitions" : [
    {
      "type" : "CIMFeatureLayer",
      "name" : "GreatLakes",
      "uRI" : "CIMPATH=map/greatlakes.xml",
      "useSourceMetadata" : true,
      "description" : "GreatLakes",
      "layerType" : "Operational",
      "showLegends" : true,
      "visibility" : true,
      "displayCacheType" : "Permanent",
      "maxDisplayCacheAge" : 5,
      "showPopups" : true,
      "serviceLayerID" : -1,
      "autoGenerateFeatureTemplates" : true,
      "featureElevationExpression" : "0",
      "featureTable" : {
      "htmlPopupEnabled" : true,
      "selectable" : true,
      "featureCacheType" : "Session",
      "scaleSymbols" : true,
      "snappable" : true

在上方截图中,基本元数据在描述文档和图层的文件的顶部显示。 同时存在许多根级别 layerDefinitions 属性。 该列表取决于对象中永久保留的设置。 有必要了解的是,IDE 代码完成公开的属性比您通常在 JSON 文件中看到的属性多得多。 这是因为 JSON 文件仅存储当前工程设置,而不是所有可能的默认设置。 这样做是为了提高性能,避免不必要的冗余。 能够说明 JSON 文件如何不显示所有可能属性的一个示例是布尔值。 仅当前设置为 true 的属性才会出现在 JSON 文件中。 例如,在 IDE 中图层 CIM 对象的代码完成应显示附加属性 expandedshowMapTips,但因为它们在上方截图中当前设置为 false,所以不会显示在上方 JSON 文件中。

修改 CIM 定义

主要访问点是通过以下 arcpy.mp 类:LayerLayoutMapReport。 所有这些类均可以保存为 JSON 文件格式:.lyrx.mapx.pagx.rptx。 基本工作流如下:使用 getDefinition() 方法返回其中一个对象的 CIM 定义,对 CIM API 进行适当的更改,然后使用 setDefinition() 方法将更改推送回同一对象。

要检索对象的 CIM 定义时,必须指定 cim_version。 Esri 遵循语义版本规范。 这意味着在主要版本(例如 2.0 或 3.0)中允许破坏性 API 更改。 这使 Python 脚本作者能够控制在运行脚本时使用哪个版本的 CIM,以避免可能的破坏性更改。 如果您正在为 ArcGIS Pro 2.x 创作脚本,将 cim_version 指定为 'V2'。 如果您正在为 ArcGIS Pro 3.x 创作脚本,将 cim_version 指定为 'V3'。 使用 cim_version 'V2' 编写的脚本可继续在 ArcGIS Pro 3.x 中使用,但是将使用 CIM 的 2x 版本。

返回 CIM 定义后,可以尝试在 IDE 中通过查看其代码完成来导航其结构,也可以使用上方提及的方法直接查看 JSON 文件。 在 IDE 中导航代码完成时,在单独的查看器中读取 JSON 结构会很有帮助。

警告:
不要直接编辑这些文件。 请务必使用 API 执行更改。

示例 1:基本布尔值,根级别属性

以下 arcpy.mp 脚本将修改名为 l_cim 的 CIM 图层对象的一些根级别属性。 selectable 属性将出现在上面的 JSON 文件中,因为其当前值为 true,但它在 Python 脚本中将设置为 FalseshowMapTipsexpanded 属性当前不会出现在 JSON 文件中,因为二者的值为 false,但它们将设置为 True。 如果将图层保存到另一个图层文件 (*.lyrx),则 JSON 文件中将显示相应的更改。

# Reference a project, map, and layer using arcpy.mp
p = arcpy.mp.ArcGISProject('current')
m = p.listMaps('Map')[0]
l = m.listLayers('GreatLakes')[0]

# Return the layer's CIM definition
l_cim = l.getDefinition('V3')

# Modify a few boolean properties
l_cim.showMapTips = True  #Turn on map tips for bubble tips to appear
l_cim.selectable = False  #Set the layer to not be selectable
l_cim.expanded = True     #Expand the Layer in the Contents pane

# Push the changes back to the layer object
l.setDefinition(l_cim)

# Save changes
p.save()

注:

ArcGIS Pro 3.2 版本中,通过提供多个构造函数,扩展了支持 getDefinitionsetDefinition 方法的类的数量。 这提高了性能,并使修改单个布局元素变得更加容易,例如,不必获取整个布局定义,找到元素,执行更改,再将更改推送回到布局。 支持 getDefinitionsetDefinition 方法的新类包括:BookmarkMapSeriesGraphicElementGroupElementLegendElementMapFrameMapSeriesMapSurroundElementPictureElementTextElement

示例 2:修改字段属性

上面的 JSON 和 Python 示例相对简单,因为仅修改了根级别属性。 可以根据每个 CIM 类的复杂性及其嵌套功能集来嵌套 CIM 对象模型。 一个 CIM 类可以具有零到多个设置为其他 CIM 类的成员,且这些类也可以具有对其他类的依赖性。 每个相关 CIM 类都将在 JSON 结构中缩进。 缩进到同一级别的所有内容都可以作为该 CIM 类的属性。 您可通过在 JSON 编辑器中查看 JSON 结构来展开和折叠该类等级。 使用 JSON 文件的另一个优势是可以搜索属性,然后使用 CIM API 确定如何访问嵌套结构。

提示:

在 IDE 中导航 CIM 结构时,代码完成仅支持四个级别,因此如果您需要查看超过第四个级别的代码完成,需要创建一个中间变量。

此示例深入到比根级别更深的对象模型中。 如果将上方 JSON 截图示例中的 featureTable 成员展开,则您将看到其具有附加成员:type(表示 CIMClass 名称)、displayFieldeditablefieldDescriptionsfieldDescriptions 属性表示 CIMFieldDescription 类的列表,并且根据字段类型,该类可能具有将 CIMNumericFormat 类作为值的 numberFormat 属性。 请注意如何很好地使用缩进来组织各个级别的相关类。

     "featureTable" : {
        "type" : "CIMFeatureTable",
        "displayField" : "NAME",
        "editable" : true,
        "fieldDescriptions" : [
          {
            "type" : "CIMFieldDescription",
            "alias" : "OBJECTID",
            "fieldName" : "OBJECTID",
            "numberFormat" : {
              "type" : "CIMNumericFormat",
              "alignmentOption" : "esriAlignRight",
              "alignmentWidth" : 0,
              "roundingOption" : "esriRoundNumberOfDecimals",
              "roundingValue" : 0
            },
            "readOnly" : true,
            "visible" : true,
            "searchMode" : "Exact"
          },

例如,常见的请求是能够修改表的字段别名或可见性,尤其是在使用 MakeFeatureLayer 动态创建表时。 使用托管 arcpy.mp API 无法完成此操作。 以下脚本使用 CIM 访问可从中设置 aliasvisible 属性的要素图层 featureTable 对象及其 fieldDescriptions 对象。 Python 语法遵循 CIM 对象模型,其中每个点基于 JSON 结构的缩进显示下一个对象的属性集。

# Reference a project, map, and layer using arcpy.mp
p = arcpy.mp.ArcGISProject('current') 
m = p.listMaps('Map')[0]
lyr = m.listLayers('GreatLakes')[0]

# Get the layer's CIM definition
cim_lyr = lyr.getDefinition('V3')

# Make changes to field properties
for fd in cim_lyr.featureTable.fieldDescriptions:
    if fd.fieldName == "OBJECTID":
        fd.visible = False            #Do not display this field
    if fd.fieldName == "Shape_Area":
        fd.alias = "Area (hectares)"  #Change field alias

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

注:

前面的代码示例完美地演示了如何导航 CIM 对象模型,也体现了前面提到的一点,即并非所有属性和类都保留在 CIM 中。 如果您向地图中添加新的要素类或表,CIM 不会包含任何 fieldDescriptions,因此您将无法修改字段属性。 如上所述,CIM 仅保留非默认属性,因此如果之前没有更改字段描述,fieldDescriptions 属性将返回一个空列表。 在这种情况下,有两种方法。 第一种方法是创建所需的 CIM 类,此方法将在下方的“创建 CIM 类”部分进行讨论。 此特定示例的第二种方法是通过使用名为 arcpy.AlterField 的函数,强制使用这些字段描述更新 CIM。 在大多数情况下,没有可用的解决方法,因此您需要创建 CIM 类。

以下脚本演示了如何将字段描述强制更新到 CIM 定义中。 如果图层没有字段描述,它将在第一个字段上调用 AlterField 函数,这将会将信息强制送入 CIM,而不对字段进行更改。 针对要素类运行后,脚本应显示不同的字段计数。

p = arcpy.mp.ArcGISProject('current')
m = p.listMaps()[0]
lyr = m.listLayers('NE_State_Boundaries')[0]

lyr_cim = lyr.getDefinition('V3')
featTab = lyr_cim.featureTable
if len(featTab.fieldDescriptions) == 0: #No CIM field descriptions
  print(f'LYR desc count PRE mod: {len(featTab.fieldDescriptions)}')
  lyrFld = arcpy.ListFields(lyr)[0]             #First field
  arcpy.management.AlterField(lyr, lyrFld.name) #Force CIM update  

lyr_cim = lyr.getDefinition('V3')
featTab = lyr_cim.featureTable
print(f'LYR desc count POST mod: {len(featTab.fieldDescriptions)}')

示例 3:修改图层符号系统

此示例演示了 CIM 对象模型可以有多少层嵌套,同时显示了 CIM 级别访问的优势。 托管的 arcpy.mp API 对渲染器和属性深度的访问权限有限。 它只能修改符号的默认图层的简单属性。 但是,CIM 可以访问具有多个图层的符号。 以下屏幕截图显示了应用程序中 arcpy.mp API 无法使用的设置:

面要素图层的“符号系统”窗格

下方是一个经过编辑的简化 JSON 文件,仅显示图层符号系统的渲染器信息。 renderer 是一个 CIMSimpleRenderer,有一个表示 CIMSymbolReferencesymbol 属性和一个 symbol 属性 CIMPolygonSymbol,此外还包含两个 symbolLayersCIMSolidStrokeCIMSolidFill,两者均显示符号系统窗格中可用的属性。

  "layerDefinitions" : [
    {
      "renderer" : {
        "type" : "CIMSimpleRenderer",
        "patch" : "Default",
        "symbol" : {
          "type" : "CIMSymbolReference",
          "symbol" : {
            "type" : "CIMPolygonSymbol",
            "symbolLayers" : [
              {
                "type" : "CIMSolidStroke",
                "effects" : [
                  {
                    "type" : "CIMGeometricEffectDashes",
                    "dashTemplate" : [ 5, 5],
                    "lineDashEnding" : "NoConstraint",
                    "controlPointEnding" : "NoConstraint"
                  }
                ],
                "enable" : true,
                "capStyle" : "Round",
                "joinStyle" : "Round",
                "lineStyle3D" : "Strip",
                "miterLimit" : 10,
                "width" : 3,
                "color" : {
                  "type" : "CIMRGBColor",
                  "values" : [0, 0, 0, 100]
                }
              },
              {
                "type" : "CIMSolidFill",
                "enable" : true,
                "color" : {
                  "type" : "CIMRGBColor",
                  "values" : [ 255, 127, 0, 100 ]
                }
              }

以下 Python 代码使用 CIM 访问修改图层的符号系统。 将修改两个符号图层。

# Reference a project, map, and layer using arcpy.mp
p = arcpy.mp.ArcGISProject('current')
m = p.listMaps('Trail Routes')[0]
lyr = m.listLayers('Loops')[0]

# Return the layer's CIM definition
cim_lyr = lyr.getDefinition('V3')

# Modify the color, width and dash template for the SolidStroke layer
symLvl1 = cim_lyr.renderer.symbol.symbol.symbolLayers[0]
symLvl1.color.values = [250, 250, 40, 50]
symLvl1.width = 8
ef1 = symLvl1.effects[0]    #Note, deeper indentation 
ef1.dashTemplate = [20, 30] #Only works if there is an existing dash template

# Modify the color/transparency for the SolidFill layer
symLvl2 = cim_lyr.renderer.symbol.symbol.symbolLayers[1]
symLvl2.color.values = [140, 70, 20, 20]

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

谨慎修改 CIM

CIM 显示许多有用的功能,但稍不谨慎,事情就会出错。 应用程序和托管 API 旨在阻止您进行可能使应用程序处于受影响状态的更改。 CIM 显示了所有内容,因此可能会做出在应用程序中无法实现的冲突更改。 需要测试用于修改 CIM 的脚本。 确保应用程序不会在进行此类更改后作出奇怪的响应。 仅限于更改对其他设置没有依赖性的设置。

示例 1:无法更改空间参考

您可能认为更改地图空间参考很直接,因为 JSON 描述包含名为 spatialReference 的标记。

  "mapDefinition" : {
    "type" : "CIMMap",
    "name" : "Map",
    "uRI" : "CIMPATH=map/map.xml",
    "metadataURI" : "CIMPATH=Metadata/a7afc904584d1037910b2cfe65fe94f8.xml",
    "useSourceMetadata" : true,
    "illumination" : {
    "layers" : [
    "standaloneTables" : [
    "defaultViewingMode" : "Map",
    "mapType" : "Map",
    "datumTransforms" : [
    "defaultExtent" : {
    "elevationSurfaces" : [
    "spatialReference" : {
      "wkid" : 4326,
      "latestWkid" : 4326
    },

如果您尝试仅修改地图的 wkidlatestWkid 属性,则无法获得预期结果。 这是因为应用程序中有许多其他部分与空间参考相关联,并且需要对地图的 CIM 进行许多更改才能使更改正常工作。 例如,对空间参考所做的更改也会影响基准转换、许多范围、裁剪几何等。 此类操作应在将作出所有适当更改的应用程序中或使用托管 API 进行。 这就是我们将继续扩展 arcpy.mp API 的原因。 对于此情况,您应该使用 Map 类的 spatialReference 属性,而非使用 CIM。

示例 2:不要将应用程序置于奇怪状态

在此示例中,将在 CIM 中修改与图层标注属性关联的表达式引擎。 在下面的屏幕截图中,表达式引擎从默认的 Arcade 更改为 Python。 下图显示了其在 UI 中的外观以及 JSON 部分的显示方式。

要素图层的“标注类”表达式窗格

      "labelClasses" : [
        {
          "type" : "CIMLabelClass",
          "expression" : "$feature.NAME",
          "expressionEngine" : "Arcade",
          "featuresToLabel" : "AllVisibleFeatures",
          "maplexLabelPlacementProperties" : {
          "name" : "Class 1",
          "priority" : -1,
          "standardLabelPlacementProperties" : {
          "textSymbol" : {
          "useCodedValue" : true,
          "visibility" : true,
          "iD" : -1
        }

下面的 Python 脚本仅更改 expressionEngine,而不会更改 expression。 这会导致应用程序行为不规律。 例如,在运行下面的代码后,查看图层的标注属性时,expressionEngine 已正确设置为 Python,但 expression 仍以 Arcade 格式显示。 在用户界面中,当将表达式引擎更改回 Arcade 时,表达式将以 Python 格式显示,与预期格式相反。 要避免发生这种情况,需要更新 expressionEngineexpression 属性。

# Update the label expression engine from Arcade, the default, to Python.
# You must also update the expression otherwise the UI won't behave correctly after.

p = arcpy.mp.ArcGISProject('current')
m = p.listMaps('Map')[0]
l = m.listLayers()[0]

l_cim = l.getDefinition('V3')

lc = l_cim.labelClasses[0]
lc.expressionEngine = 'Python'    #From 'Arcade'
lc.expression = '[STATE_NAME]'    #From '$feature.STATE_NAME'

l.setDefinition(l_cim)

修改 CIM 属性的提示

有时,JSON 文件中的属性标注不容易找到,因为它不够直观,与应用程序不匹配,或者可能嵌套在对象模型中。 要解决此问题,一种技巧是将值设置为真正唯一的值,并在 JSON 文件中搜索该值。 例如,将布局元素的宽度设置为 0.7777 或将 RGB 颜色设置为 111

您可能会在 JSON 文件中看到一个表示要更改的枚举常量的值,但您不知道新的正确值应该是什么。 解决方案是在应用程序中设置正确的值,将其保存到 JSON 导出文件,然后评估更新的值。

另一个技巧是创建修改前和修改后的 JSON 文件,并使用 WinMerge、DeltaJSON、JSON Diff 等应用程序比较更改。 这在创建 CIM 类时非常重要,下一节将进一步讨论这一点。

ArcGIS.Core.CIM 命名空间 .NET SDK API 参考帮助主题提供了每个类成员的 CIM 对象和文档列表。

创建 CIM 类

在 2.5 之前的版本中,Python CIM API 仅允许更改现有属性。 从版本 2.5 开始,出现了一种用于创建 CIM 类的新技术,可将其用于扩展在对象的 CIM 定义中显示的功能。 该函数名为 CreateCIMObjectFromClassName,位于 arcpy.cim 模块中。 cim_class_name 参数是 CIM 类在 type 属性中显示的名称,且 cim_version 参数的用法与上一节中定义的 getDefiniton 函数相同。 CreateCIMObjectFromClassName 将返回包含适当成员的对象,但不会自动创建其他对象依赖项。 例如,如果所创建类的成员需要将另一个类作为其值,则您需要再次运行该函数以生成该类。 必须对所有相关 CIM 类和子类执行该过程;这可能需要付出大量努力。 该问题将在后面的示例中解决,但您可以先从一个简单的场景开始;在该场景中,只需创建一个对象即可完成解决方案。

示例 1:单个类 - RGB 颜色

如果您插入新的默认地图并返回地图的 CIM backgroundColor,则该值将为 NoneType,原因是该值未在 CIM 中定义。 默认情况下,新地图的背景颜色将设置为“无颜色”。 您甚至都不会看到在 JSON 文件中定义该成员。 确定需要执行哪些操作的一种简单的方法就是:使用背景颜色创作地图,然后将更改前后的内容另存为地图文件 (.mapx) 并比较差异。 下面左边的图形表示更改前的 JSON 屏幕截图,右边是更改后的屏幕截图。 它们正在被一个名为 WinMerge 的文本比较应用程序查看。 请注意,在右侧,backgroundColor 成员已插入到 mapTypebookmarks 属性之间。 要设置地图的 backgroundColor,您需要创建一个颜色对象;在此示例中为 CIMRGBColor 对象。 该颜色可能已使用其他颜色模型进行了定义,且表示类的类型的 CIM 对象 type 将有所不同。

将背景颜色插入到 JSON 文件中之前和之后结果的屏幕截图

以下代码将创建一个 CIMRGBColor 类,用于设置地图的背景颜色。 请注意,您可能需要关闭底图或其他图层才能看到更改。

p = arcpy.mp.ArcGISProject('current')
m = p.listMaps()[0]
m_cim = m.getDefinition('V3')        #Get the map's CIM definition

#Check to see if a background color exists, if not create a color
if m_cim.backgroundColor is None:
  RGBColor = arcpy.cim.CreateCIMObjectFromClassName('CIMRGBColor', 'V3')
  RGBColor.values = [115, 178, 255, 100]
  m_cim.backgroundColor = RGBColor   #Set the property to the new object
m.setDefinition(m_cim)               #Set the map's CIM definition

示例 2:单个类 - 空间地图系列

使用 CIM 创建空间地图系列几乎与创建 RGB 颜色一样简单。 空间地图系列也是单个对象,但它具有更多的属性。 下图显示了如何将空间地图系列保留在 JSON 文件中的屏幕截图。 indexLayerURI 是 CIM 独有的概念,不会在用户界面中作为一项设置显示出来。 URI 是保留在 CIM 中以确保引用唯一性的对象的唯一标识符。 对于图层,即使您更改图层名称,URI 也不会更改。 获取 indexLayerURI 值的唯一方法就是通过图层的 CIM 定义进行获取。

将空间地图系列插入到 JSON 文件中的结果的屏幕截图

以下代码将创建一个 CIMSpatialMapSeries 类,用于为布局创作新的空间地图系列。 该示例中包括用于获取图层 URI 值的额外代码行。 注意,需要再次调用 get/setDefinition 函数,以确保内容窗格中的地图系列页面选项卡刷新。

p = arcpy.mp.ArcGISProject('current')
m = p.listMaps('GreatLakes')[0]
l = m.listLayers('GreatLakes')[0]

l_cim = l.getDefinition('V3')         #Get layer's CIM / Layer URI
lURI = l_cim.uRI                      #Needed to specific the index layer 

lyt = p.listLayouts('GreatLakes')[0]
lyt_cim = lyt.getDefinition('V3')     #Get Layout's CIM definition

#Create CIM Spatial Map Series Object and populate its properties
ms = arcpy.cim.CreateCIMObjectFromClassName('CIMSpatialMapSeries', 'V3')
ms.enabled = True
ms.mapFrameName = "Great Lakes MF"
ms.startingPageNumber = 1
ms.currentPageID = 2
ms.indexLayerURI = lURI               #Index layer URI from Layer's CIM 
ms.nameField = "NAME"
ms.sortField = "NAME"
ms.sortAscending = True
ms.scaleRounding = 1000
ms.extentOptions = "BestFit"
ms.marginType = "Percent"
ms.margin = 10

lyt_cim.mapSeries = ms                #Set new map series to layout
lyt.setDefinition(lyt_cim)            #Set the Layout's CIM definition

#Force a refresh of the layout and its associated panes
lyt_cim = lyt.getDefinition('V3')
lyt.setDefinition(lyt_cim)

示例 3:一个相关类 - 书签地图系列

前两个示例显示了具有简单属性的 CIM 类。 如本主题前面所述,有时新创建的 CIM 对象将具有依赖于其他 CIM 对象的属性值。 CreateCIMObjectFromClassName 函数不会自动创建所有相关子类,且您也可以使用相同的方法来创建那些相关对象。 CIMBookmarkMapSeries 类是一个示例。 该类具有一个名为 pages 的属性,且该属性为单个 CIMBookmarkMapSeriesPage 对象的集合。 以下是如何将“书签地图系列”保留在 JSON 文件中的屏幕截图。 您将发现 CIMBookmarkMapSeriesPage 类嵌套在 CIMBookmarkMapSeries 类中。 每个页面均由其 bookmarkName 进行定义,且每个书签都有一个 mapURI,即该书签所关联地图的唯一标识符。

将书签地图系列插入到 JSON 文件中的结果的屏幕截图

以下代码将创建一个 CIMBookmarkMapSeries 类和多个 CIMBookmarkMapSeriesPage 类,用于为布局创作新的书签地图系列。 书签地图系列需要引用地图的 URI 且该 URI 与图层的 URI 类似,您只能从地图的 CIM 定义中获取该值。

p = arcpy.mp.ArcGISProject('current')
m = p.listMaps('Map')[0]

#Get map URI from map CIM
m_cim = m.getDefinition('V3')           
mURI = m_cim.uRI

#Get Layout CIM
lyt = p.listLayouts('No Map Series')[0] 
lyt_cim = lyt.getDefinition('V3')

#Create the CIMBookmarkMapSeriesPage(s) necessary for creating the CIMBookmarkMapSeries
#Iterate through each bookmark in the order you want them added to the map series
bkmkNames = ["Northeast", "Southeast", "Northwest",]  
pageList = []
for bkmk in bkmkNames:
  bkmkPage = arcpy.cim.CreateCIMObjectFromClassName('CIMBookmarkMapSeriesPage', 'V3')
  bkmkPage.bookmarkName = bkmk
  bkmkPage.mapURI = mURI                
  pageList.append(bkmkPage)             

#Create a Bookmark Object and populate
bmMS = arcpy.cim.CreateCIMObjectFromClassName('CIMBookmarkMapSeries', 'V3')
bmMS.enabled = True
bmMS.mapFrameName = "Map Frame"
bmMS.startingPageNumber = 1
bmMS.currentPageID = 0
bmMS.extentOptions = "BestFit"
bmMS.marginType = "Percent"
bmMS.pages = pageList                   

#Set map series to layout and set the layout CIM definition
lyt_cim.mapSeries = bmMS                
lyt.setDefinition(lyt_cim)              

#Force a refresh of the layout and its associated panes
lyt_cim = lyt.getDefinition('V3')
lyt.setDefinition(lyt_cim)

示例 4:多个相关类 - 在布局上创建面元素

嵌套相关对象的数量可能会变得复杂,具体取决于您要尝试创建的对象。 如果可能,建议您在尝试使用 CIM 创建对象之前先使用托管 API。 接下来的代码示例是一个典型情况。 您将看到在布局上创建像面元素一样简单的内容将具有许多对象依赖项。 同样,最简捷的方法就是使用单个面元素来创建简单布局,然后将布局导出到 .pagx 文件并查看 JSON 结构。 还有一种方法可以处理这些更为复杂的情况,那就是按照相反顺序来构建对象。 先从最缩进的相关子类开始,然后逐步处理到最后生成的对象。 下面的示例代码将使用该模式。

以下代码最终将在布局上创建面 CIMGraphicElement。 该代码将针对构造面图形元素所需的所有相关 CIM 类多次使用 CreateCIMObjectFromClassName

# A simplified JSON structure outlining the objects needed to be generated for
# creating a polygon graphic element on a layout.
#
# CIMGraphicElement
#   CIMPolygonGraphic
#     CIMSymbolReference
#       CIMPolygonSymbol
#         CIMSolidStroke
#           CIMRGBColor
#         CIMSolidFill
#           CIMRGBColor

#Reference layout and its CIM definition
p = arcpy.mp.ArcGISProject('current')
lyt = p.listLayouts()[0]
lyt_cim = lyt.getDefinition('V3')       

#CIMSolidStoke/CIMRGBColor 
strokeRGBColor = arcpy.cim.CreateCIMObjectFromClassName('CIMRGBColor', 'V3')
strokeRGBColor.values = [0, 0, 0, 100]

symLyr1 = arcpy.cim.CreateCIMObjectFromClassName('CIMSolidStroke', 'V3')
symLyr1.capStyle = "Round"
symLyr1.joinStyle = "Round"
symLyr1.width = 1
symLyr1.color = strokeRGBColor

#CIMSolidFill/CIMRGBColor
fillRGBColor = arcpy.cim.CreateCIMObjectFromClassName('CIMRGBColor', 'V3')
fillRGBColor.values = [130, 130, 130, 100] 

symLyr2 = arcpy.cim.CreateCIMObjectFromClassName('CIMSolidFill', 'V3')
symLyr2.color = fillRGBColor

#CIMPolygonSymbol
polySym = arcpy.cim.CreateCIMObjectFromClassName('CIMPolygonSymbol', 'V3')
polySym.symbolLayers = [symLyr1, symLyr2]

#CIMSymbolReference
symRef = arcpy.cim.CreateCIMObjectFromClassName('CIMSymbolReference', 'V3')
symRef.symbol = polySym

#CIMPolygonGraphic
polyGraphic = arcpy.cim.CreateCIMObjectFromClassName('CIMPolygonGraphic', 'V3')
polyGraphic.symbol = symRef
polyGraphic.blendingMode = "Alpha"
polyGraphic.placement = "Unspecified"
polyGraphic.polygon =  {"hasZ": True, "rings": [[[5, 6, None], [1, 6, None], [1, 9, None], [5, 9, None], [5, 6, None]]]}

#CIMGraphicElement
graphicElm = arcpy.cim.CreateCIMObjectFromClassName('CIMGraphicElement', 'V3')
graphicElm.anchor = "BottomLeftCorner"
graphicElm.name = "New Rectangle Graphic"
graphicElm.visible = True
graphicElm.rotationCenter = {"x" : 1, "y": 6}
graphicElm.graphic = polyGraphic

#Add element to EMPTY layout element list and set CIM definition
lyt_cim.elements = [graphicElm]
lyt.setDefinition(lyt_cim)

其他资源和示例脚本

有关详细的 CIM 规范和 GIT 存储库,请参阅制图信息模型 (cim-spec)

有关以各种方式使用 Python CIM 访问的 30 个打包示例脚本集合,请参阅 ArcGIS Pro Python CIM 示例

Python CIM 访问对于更新数据源工作流可能也很有用。 有关更多的 CIM 示例,请参阅更新和修复数据源帮助主题。