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

Свойство символов параметра инструмента-скрипта позволяет вам связать файл отдельного слоя (.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 объекта.

Символы схемы CIM

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

Примечание:

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

{
  "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 отдельного слоя – все, что содержится в квадратных скобках, например 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.

Примечание:

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

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

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

Веб-карты хранят информацию о содержании в соответствии со Спецификацией веб-карт в формате 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/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 layerDefinition. Пример ниже показывает укороченное отображение всего объекта ответа.

Примечание:

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

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

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

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