脚本中的输出符号系统

使用脚本工具参数的符号系统属性可将单个图层文件 (.lyrx) 与某个输出参数关联起来。 运行脚本工具时,会使用在图层文件的符号系统将输出添加到显示画面中。 您还可以使用 Parameter 对象的 symbology 属性在脚本的代码中设置符号系统属性,如下所示。

import arcpy

# Use the GetParameterInfo function to access tool parameters
params = arcpy.GetParameterInfo()
infc = params[0]
outfc = params[1]

# Copy features
arcpy.management.CopyFeatures(infc.valueAsText, outfc.valueAsText)

# Apply symbology to the copied features
outfc.symbology = "C:/Tools/Extractor/ToolData/polygon.lyrx"

通过定义字符串 JSON 制图信息模型 (CIM)Esri Web 地图规范对象并将其传递到 SetParameterSymbology 函数的符号系统参数中,可以将符号系统保留在脚本代码中。 这使得用户无需在工具箱中包含 .lyrx 文件。 JSON 字符串必须以 JSONRENDERER=JSONCIMDEF=JSONCLASSDEF= 开头,具体取决于对象和方案的类型。 可通过多个选项来获取对象的 JSON 字符串。

CIM 方案符号系统

图层 (.lyrx) 文件将以 JSON 格式存储 CIM 内容信息,并且可以使用文本编辑器将其打开。 以下示例显示了包含 4 个图层的图层文件的经修改 JSON 表示,其中带有表示省略部分的椭圆形 (...)。

注:

请注意,.lyrx 文件可以存储多个图层和图层组的符号系统,因此无法在 SetParameterSymbology 中直接使用整个 JSON 对象。 各个图层对象将在 JSON CIMLayerDocumentlayerDefinitions 键下方列出。

{
  "type" : "CIMLayerDocument",
  "version" : "2.6.0",
  "build" : 23961,
  "layers" : [
    "CIMPATH=map/samplepoly.xml",
    "CIMPATH=map/samplepoint.xml",
    "CIMPATH=map/sampleline.xml",
    "CIMPATH=map/sampleraster.xml"
  ],
  "layerDefinitions" : [
    {
      "type" : "CIMFeatureLayer",
      "name" : "SamplePolygon",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMFeatureLayer",
      "name" : "SampleLine",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMFeatureLayer",
      "name" : "SamplePoint",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMRasterLayer",
      "name" : "SampleRaster",
      ...
      "colorizer" : {

        ...
      }
    }
  ],
  ...
}

单个图层的 JSON CIM 定义是该图层类型的包含括号内的所有内容,例如 CIMFeatureLayerCIMRasterLayer(包括省略部分)。 每个图层对象都包含多个其他根级别属性以及多个嵌套对象,其中包括描述该图层符号系统的 CIM "renderer" 对象。 请注意,对于栅格图层,相应的对象为 colorizer。 以下示例显示了一个简单线图层的完整 JSON CIM 渲染器对象。

{
  "type" : "CIMSimpleRenderer",
  "patch" : "Default",
  "symbol" : {
    "type" : "CIMSymbolReference",
    "symbol" : {
      "type" : "CIMLineSymbol",
      "symbolLayers" : [
        {
          "type" : "CIMSolidStroke",
          "enable" : true,
          "capStyle" : "Round",
          "joinStyle" : "Round",
          "lineStyle3D" : "Strip",
          "miterLimit" : 10,
          "width" : 1,
          "color" : {
            "type" : "CIMRGBColor",
            "values" : [
              255,
              0,
              0,
              100
            ]
          }
        }
      ]
    }
  }
}

向量或栅格图层的 JSON CIM 对象可以通过 JSONCIMDEF= 全部与 SetParameterSymbology 一起使用,或者通过 JSONRENDERER= 仅传递 renderer 对象。 有关 CIM 对象规范的完整列表可在 CIM 规范的类型页面下方找到。

注:

colorizer 对象不能通过 JSONRENDERER= 进行传递。

Web 地图方案符号系统

注:
请注意,CIM 规范适用于 ArcGIS Pro,而 Web 地图规范适用于 ArcGIS Online。 CIM 和 Web 地图规范均为跨平台规范,但两者之间的转换可能会产生损耗。 因此,建议使用 CIM 规范以在 ArcGIS Pro 中获得最佳效果。

Web 地图将根据 Web 地图规范以 JSON 格式存储内容信息。 可以使用 ArcGIS REST API 通过以下方式从托管在 ArcGIS Online 上的要素服务中获取 Web 地图渲染器对象,有关详细信息请参阅 ArcGIS REST API 要素服务

import json
import requests

# endpoint URL queried to expect a JSON formatted response
html = "https://services.arcgis.com/vHwtjnCAEWmDBZo5/arcgis/rest/services/My_Hosted_Feature/FeatureServer/0?f=json"

# Obtain JSON response object with requests.get()
response = requests.get(html, verify=False).json()

# Retrieve the renderer object nested within the response JSON
jsonren = response["drawingInfo"]["renderer"]

# Dump renderer JSON to a string using json.dumps()
renderer = json.dumps(jsonren)

响应对象为 JSON Web 地图 layerDefinition。 下面的示例显示了整个响应对象的简化表示。

注:

layerDefinition 不能全部用于 SetParameterSymbology。 在以上示例中,将从响应 JSON 中检索 renderer 对象。

{
  "currentVersion": 10.7,
  "id": 0,
  "name": "TestPoly",
  "type": "Feature Layer",
  ...
  "drawingInfo": {
    "renderer": {
      ...
    },
    ...
  },
  ...
}

layerDefinition 对象包含多个其他根级别属性以及多个嵌套在其中的对象,其中包括含有 Web 地图 drawingInfo 对象的 Web 地图 renderer 对象。 以下是用于简单面图层的完整 JSON Web 地图渲染器对象的示例。

{
  "type": "simple",
  "symbol": {
    "type": "esriSFS",
    "style": "esriSFSSolid",
    "color": [
      255,
      0,
      0,
      255
    ],
    "outline": {
      "type": "esriSLS",
      "style": "esriSLSSolid",
      "color": [
        110,
        110,
        110,
        255
      ],
      "width": 0.7
    }
  }
}

可将 Web 地图 renderer 对象传入具有 JSONRENDERER=SetParameterSymbology。 有关 Web 地图渲染器规范的完整列表可在渲染器对象的 Web 地图规范页面上找到。

分类定义

Web 地图规范还支持使用 JSON 分类定义对象动态生成分类或唯一值渲染器。 可将其传入具有 JSONCLASSDEF=SetParameterSymbology

设置输出符号系统

通过 symbology 属性或 SetParameterSymbology 函数设置符号系统时,只能将一个图层文件或 JSON 对象字符串与输出参数相关联。 如果明确定义了输出,则只能有一个符号系统正常工作。 但如果未明确定义输出结果会如何呢? 例如,您了解输出是一个要素类,但是在工具运行之前您不知道其中是否包含点、折点或面要素。 图层文件和 JSON 对象依赖于几何类型,这意味着要符号化多种要素类型时不能只有一个符号系统。 在本例中,需要具有三个图层文件或 JSON 对象,一种几何类型一个,并基于输出几何类型关联正确的符号系统。 以下代码片段使用 symbology 属性对此进行了演示。

# Set the symbology of the output. 

output = self.params[1].value
if output:
    desc = arcpy.Describe(output)
    
    if desc.shapeType == "Polygon":
        self.params[2].symbology = "C:/Tools/Extractor/ToolData/polygon.lyrx"
    elif desc.shapeType == "Polyline":
        self.params[2].symbology = "C:/Tools/Extractor/ToolData/polyline.lyrx"
    else:
        self.params[2].symbology = "C:/Tools/Extractor/ToolData/point.lyrx"

上述脚本中的逻辑相对比较简单:测试几何(形状)类型并相应设置符号系统。 即使您具有更复杂的逻辑,模式仍然是相同的:

  • 创建一个将对各个可能的输出进行符号化的图层文件或 JSON 对象字符串。
  • 基于脚本中的逻辑,确定应使用的图层文件或 JSON 对象并使用参数的符号系统属性对其进行设置。

在脚本与 ToolValidator 类中设置符号系统

如果您熟悉 ToolValidator 类中的编程工具验证逻辑,则会发现上述代码片段可能会被重新编写以供在 updateParameters 方法中使用。 事实上,如果只需引用一个图层文件或 JSON 对象,则应在脚本工具的属性中或在 initializeParameters 方法中执行此操作。 但是如果需要为多个图层文件或 JSON 对象中的任意一个设置符号系统,则应在脚本工具中执行此操作。 将此类逻辑置于 ToolValidator 类中会使您的代码由于具有与工具验证无关的逻辑而变得冗长,且在某些情况下,在执行工具之前您可能不知道要使用哪个图层文件。

脚本示例

下面的脚本将基于要素距波特兰市的公园的距离来创建要素。 共有三个参数:输入要素、距离和输出要素。 输出要素将被符号化以便在地图上可将其与其他要素(非默认符号系统内的对象,很难区分)区分开。 由于输入要素可以是点、折线或面,因此需要三个图层文件。

此脚本还演示了多个提供可移植性的编码技术。 使用的可移植性技术如下所示:

  • 使用 __file__ 来检索脚本文件的完整路径
  • 使用 Python os 模块来创建数据的路径
  • 使用 CreateScratchName 函数来创建临时要素类

# ExtractData.py
# Description: Script that will extract features from an input layer within a 
#              specified distance from a park.
# Parameters:
#  0 - input features
#  1 - distance from parks (linear units)
#  2 - output feature class

import arcpy
import os

arcpy.env.overwriteOutput = True

# This tool uses a system folder with a Scripts and ToolData subfolder. 
# You can discover the pathname of this folder using the Python __file__
# attribute, which is the pathname to the script 
# (example: 'E:\examples\symbology\scripts\ExtractData.py'.)  You
# then use the toolSharePath variable to create paths to your 
# shapefile data and layer files ('E:\examples\symbology\ToolData\points.lyrx').

scriptPath = __file__
toolSharePath = os.path.dirname(os.path.dirname(scriptPath))
dataPath = os.path.join(toolSharePath, 'ToolData')
parkPath = os.path.join(dataPath, 'PortlandParks.shp')
pointLyrPath = os.path.join(dataPath, 'point.lyrx')
polygonLyrPath = os.path.join(dataPath, 'polygon.lyrx')
polylineLyrPath = os.path.join(dataPath, 'polyline.lyrx')
    
# Buffer the parks by the specified distance.  The output is a scratch
#  feature class in the same workspace as the output feature class
arcpy.SetProgressorLabel('Buffering parks ...')
scrname = arcpy.CreateScratchName('xxx', '', 'featureclass', 
                                  os.path.dirname(arcpy.GetParameterAsText(2)))
arcpy.Buffer_analysis(parkPath, scrname, arcpy.GetParameterAsText(1))

# Clip the defined layer with the buffered parks
arcpy.SetProgressorLabel('Clipping {} ...'.format(arcpy.GetParameterAsText(0)))
output = arcpy.Clip_analysis(arcpy.GetParameterAsText(0), scrname, 
                             arcpy.GetParameterAsText(2))

# Delete the intermediate dataset
try:
    arcpy.Delete_management(scrname)
except:
    pass

# Set the symbology of the output. 
params = arcpy.GetParameterInfo()
desc = arcpy.Describe(output)
if desc.shapeType == 'Polygon':
    params[2].symbology = polygonLyrPath
elif desc.shapeType == 'Polyline':
    params[2].symbology = polylineLyrPath
else:
    params[2].symbology = pointLyrPath