Символы выходных данных в скриптах

Свойство символов параметра инструмента-скрипта позволяет вам связать файл отдельного слоя (.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 и передав его в аргумент символов функции SetParameterSymbology. Это избавляет от необходимости включать файл .lyrx в набор инструментов. Перед строкой JSON должно стоять JSONRENDERER=, JSONCIMDEF= или JSONCLASSDEF=, в зависимости от типа объекта и схемы. Существует несколько вариантов получения строки JSON объекта.

Символы схемы картографической информационной модели

Файлы слоя (.lyrx) хранят информацию о содержимом CIM в формате JSON и могут быть открыты с помощью текстового редактора. В следующем примере показано измененное представление JSON файла слоев, содержащего четыре слоя, с многоточиями (...), обозначающими пропущенные фрагменты.

Примечание:

Обратите внимание, что файлы .lyrx могут хранить символы для нескольких слоев и составных слоев, поэтому весь объект JSON не может быть использован непосредственно в SetParameterSymbology. Отдельные объекты слоя перечислены под ключом layerDefinitions ключа CIMLayerDocument JSON.

{
  "type" : "CIMLayerDocument",
  ...
  
  ],
  "layerDefinitions" : [
    {
      "type" : "CIMFeatureLayer",
      "name" : "SamplePolygon",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMFeatureLayer",
      "name" : "SampleLine",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMFeatureLayer",
      "name" : "SamplePoint",
      ...
      "renderer" : {
        ...
      }
    },
    {
      "type" : "CIMRasterLayer",
      "name" : "SampleRaster",
      ...
      "colorizer" : {
        ...
      }
    }
  ],
  ...
}

Определение JSON CIM отдельного слоя – все, что содержится в квадратных скобках для типа слоя, например, CIMFeatureLayer или CIMRasterLayer, включая пропущенные фрагменты. Каждый объект слоя содержит несколько других атрибутов корневого уровня, а также несколько вложенных объектов, включая объект 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 векторного или растрового слоя может использоваться с SetParameterSymbology в полном объеме с JSONCIMDEF=, или только объект renderer может быть передан в JSONRENDERER=. Полный список спецификаций для объектов CIM можно найти в документации по спецификации CIM. Воспользуйтесь файлом README.md репозитория, чтобы перейти к спецификации CIMLayerDocument, а затем перейдите по ключам, чтобы изучить их свойства).

Примечание:

Объект colorizer не может быть передан с помощью JSONRENDERER=.

Символы схемы веб-карты

Примечание:
Обратите внимание, что спецификация CIM предназначена для ArcGIS Pro, в то время как спецификация веб-карты применяется для ArcGIS Online. Спецификации CIM и веб-карты являются кроссплатформенными, однако преобразование между ними может быть затруднено. Поэтому для достижения наилучших результатов в ArcGIS Pro рекомендуется использовать спецификацию CIM.

Веб-карты хранят информацию о содержимом в соответствии со спецификацией веб-карты в формате JSON. Объект визуализации веб-карты может быть получен с сервиса объектов, размещенного на ArcGIS Online с помощью ArcGIS REST API. Подробнее см. в разделе Сервис объектов 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/CA_ozone/FeatureServer/2?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 layerDefinition. В приведенном ниже примере показано сокращенное представление всего объекта ответа.

Примечание:

layerDefinition не может использоваться в SetParameterSymbology в полном объеме. В примере выше объект renderer получен из ответа JSON.

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

Объект layerDefinition содержит несколько других атрибутов корневого уровня, а также несколько объектов, вложенных в него, включая объект drawingInfo веб-карты, содержащий объект renderer веб-карты. Ниже приведен пример полного объекта JSON отображения веб-карты для простого полигонального слоя.

{
  "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
    }
  }
}

Объект веб-карты renderer может быть передан в SetParameterSymbology как JSONRENDERER=. Полный список спецификаций для способов отображения веб-карт можно найти на странице Спецификации веб-карт для объектов отображения.

Определения классификации

Спецификация веб-карт поддерживает динамическое создание классифицированных или уникальных средств отображения значений с объектами определения классификации JSON. Они могут быть переданы в SetParameterSymbology как JSONCLASSDEF=.

Настройка выходных символов

При настройке символов либо через свойство 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