Предварительный текст

Данный пример является предварительным и будет заменен в будущем

Изменение концепции

Примерно в середине написания примера его концепция была изменена на более репрезентативную. Не обращайте внимание на то, что на части скриншотов есть описание остановок Твери, а также на карте разное количество элементов. Все конфигурации и описания текстов были исправлены на новый вариант

Определение клиента

Под клиентом в этом описании подразумевается не физическое/юридическое лицо использующее ЭверГИС, а клиентская часть самой системы (по простому - программа, которая работает внутри браузера и отвечает за взаимодействие с сервером)

Создание инструментов карты

В данном разделе мы создадим инструмент, который рассчитывает определенный показатель и по нему обновляет диаграмму. В ЭверГИС инструменты создаются при помощи редактирования конфигурации. В ней создается специальный блок, ссылающийся на Python код, который необходимо запустить. Инструмент может принимать в себя различные аргументы. Пользователь может задать их при помощи других элементов дашборда, указав их в конфигурации инструмента.

Виды инструментов

Инструменты могут быть созданы как в карточке объекта, так и на дашборде карты. В последнем случае они будут видны как отдельный элемент интерфейса. В зависимости от места расположения будет различаться и объект, конфигурацию которого мы редактируем. В данном примере мы разберем создание инструмента в интерфейсе всей карты. Для того, чтобы разобраться с тем, как создавать инструмент в карточке, перейдите в соответствующий раздел (ВСТАВИТЬ ССЫЛКУ)

В этом примере мы создадим инструмент, который будет вычислять число жилых зданий в пределах определенного расстояния от поликлиник. Расстояние от поликлиники будет определяться при помощи фильтра. Далее данные будут записываться во вспомогательный слой на основе которого будет строиться диаграмма.

Исходные данные

Мы будем создавать инструмент на основе данных из geopackage Tver_upd.gpkg. Нам потребуется всего один слой, который сохранен в карту Создание инструментов (eromakh.instrument_analysis). :

  • Здание Твери инструмент (eromakh.buildings_tver_instr) – выгрузка данных OSM через сервис geofabrik на территорию города Тверь

В этом примере мы будем использовать атрибут type_1 из слоя Здание Твери инструмент. В нем сконцентрирована информация о назначении здания. Категории apartments, detached, semidetached_houses, house отнесены к категориям жилых зданий, hospitals – к категории поликлиник.

Фильтр расстояния

В первую очередь создадим фильтр, при помощи которого будем задавать расстояние для построения зоны доступности от поликлиник. На данный момент в системе можно построить зону доступности по времени в минутах. В этом фильтре будут четыре опции: 5, 10, 15 и 20 минут.

Объект фильтра

Для начала создадим объект фильтра среди списка filters внутри объекта dashboardConfiguration.

{
	"name": "duration",
	"defaultValue": 5
}

Ключевым полем является name. Далее мы будем использовать значение этого атрибута для того, чтобы связать фильтр и код. Название может быть любым, но оно должно быть одинаковым для объекта фильтра, элемента конфигурации, а также в коде.

instrument filter 1

Создание фильтра на карте

На данном этапе фильтр существует только в конфигурации, никаких видимых изменений на карте вы не увидите. Для того, чтобы задавать значения фильтра нам необходимо создать видимую пользователю конструкцию. Отображение фильтра может быть разным: можно сделать список со значениями, как в примере с дашбордом для зданий Нижнего Новгорода, можно просто дать пользователю самому вписать значения, а можно сделать бины с предварительно заготовленными значениями. Мы пойдем по последнему пути. Для этого нам нужно создать элемент в конфигурации в списке children, который находится под baseMapSettings. Этот элемент будет иметь четыре элемента:

  • id – идентификатор элемента в конфигурации
  • options – особенности дашборда
  • children – список дочерних объектов
  • templateName – системный параметр, отвечающий за предназначение объекта на карте

В списке дочерних объектов нужны:

Показать фрагмент конфигурации

{
	"id": "duration_selector",
	"options": {
		"bgColor": "transparent"
	},
	"children": [
		{
			"id": "title",
			"type": "text",
			"style": {
				"fontSize": 16
			},
			"value": "Время движения от поликлиники пешком"
		},
		{
			"id": "titleIcon",
			"type": "image",
			"value": "da901842fb0941baa29e4bd3875ff822",
			"options": {
				"width": 18,
				"height": 18
			}
		},
		{
			"id": "duration",
			"type": "chips",
			"options": {
			"width": 275,
			"variants": [
				{
				"text": "5 мин",
				"value": 5
				},
				{
				"text": "10 мин",
				"value": 10
				},
				{
				"text": "15 мин",
				"value": 15
				},
				{
				"text": "20 мин",
				"value": 20
				}
			],
			"filterName": "duration",
			"placeholder": "Длительность"
			}
		}
	],
	"templateName": "Filters"
}

filter map bins

Обратите внимание на следующие строки конфигурации:

  • "bgColor": "transparent" – без значения transparent бины будут находиться внутри серого прямоугольника. Также если вы захотите добавить возможность сворачивать фильтр на карте, то добавьте также параметры expanded и expandable
  • "filterName": "duration" – filterName обязательно должен совпасть со значением параметра “name” из предыдущего раздела
  • "templateName": "Filters" – мы должны явно указать в конфигурации, что объект является фильтром

Создание заготовки инструмента

Следующим шагом мы создадим простой инструмент, которой просто будет выводить на экран значение параметра duration, выбранного пользователем в фильтре. Для этого нам надо предварительно создать проект в инструментах разработчика, внутри которого написать код и далее пробросить параметр из конфигурации в этот инструмент. Создадим инструмент и простейший код (подробно о его создании написано в одном из предыдущих примеров):

В заготовке достаточно написать две строки кода:

def run(**kwargs):
	print(kwargs)

kwargs – используется в Python для того, чтобы получить произвольное число именованных аргументов. В случае нашего инструмента именованным аргументом будет значение фильтра из конфигурации карты. Если список аргументов строго определен, то мы можем заменить его на конкретное название входного параметра из принимающей функции.

Для того, чтобы вывести элемент с этим кодом на карту нам необходимо вставить еще один фрагмент в конфигурацию в списке дочерних элементов dashboardConfiguration.

Последовательность отображения

Обратите внимание, что последовательность отображения элемента на карте зависит от его его позиции в dashboardConfiguration. Если вы хотите, чтобы элемент располагался выше, то перенесите его вверх в списке дочерних элементов dashboardConfiguration

В этом объекте будут следующие элементы:

  • id – идентификатор объекта
  • style – задает отступы внутри объекта (опциональный аргумент)
  • options – в нем находится описание всех элементов запуска скрипта
    • icon – тип иконки. В системе есть несколько заранее загруженных общедоступных вариантов. Мы уже работали с ними в примере создания фильтров дашборда
    • title – отображаемое название
    • center – центрирование названия
    • statusColors – в нем находятся HEX коды цвета в зависимости от статуса выполнения задачи
    • relatedResources – в нем описаны связанные с элементом конфигурации ресурсы
      • fileName – название .py файла
      • methodName – название вызываемой функции внутри этого файла
      • parameters – параметры, которые мы передаем в эту функцию (и которые далее извлекаются из kwargs в функции). Обратите внимание на то, что названия параметров должны совпадать между объектами фильтров и объектом инструмента в конфигурации. В нашем случае это параметр duration
      • resourceId – уникальный идентификатор инструмента в каталоге. Обратите внимание, что инструмент в каталоге не равен файлу кода, это другая сущность. В списке ресурсов инструментов разработчика инструмент отмечен иконкой с шестеренками
      • useNotifications – параметр, который отвечает за вывод лога работы инструмента на экран
    • responseFilters – ключевой элемент нашего инструмента. Он принимает возвращаемое из кода значение. При помощи параметров, перечисленных в этом объекте можно обновлять или модифицировать источники данных, а также использовать его в качестве фильтра
  • children – опциональный элемент, в нем может быть записаны название и иконка объекта конфигурации так же как и у других объектов в конфигурации
  • templateName – системный параметр, отвечающий за тип элемента в конфигурации
Показать фрагмент конфигурации

{
	"id": "run_isochrone_analysis",
	"style": {
		"marginBottom": -10
	},
	"options": {
		"icon": "run",
		"title": "Запустить",
		"center": true,
		"statusColors": {
			"Error": "#9C2020",
			"Process": "#00C2FF",
			"Unknown": "#FF7E25",
			"Completed": "#00AD56"
		},
		"responseFilters": {
			"base_object_task": "target_gid"
		},
		"relatedResources": [
			{
				"fileName": "building_counter.py",
				"methodName": "run",
				"parameters": {
					"duration": "%duration"
				},
				"resourceId": "56a67e43fd5e4700ac1c46ec24d326c0"
			}
		],
		"useNotifications": true
	},
	"children": [
		{
			"id": "title",
			"type": "text",
			"style": {
				"fontSize": 16
			},
		"value": "Анализ количества зданий в зонах доступности"
		}
	],
	"templateName": "Task"
}

instr task 1

При нажатии на кнопку Запустить произойдет старт контейнера с Python, в который будет передан параметр duration. В случае если код отработал без ошибок, вы увидите надпись Выполнено на фоне цвета, HEX код которого вы указали в параметре Completed. Не обращайте внимание на надпись Error EverGIS API: No module named 'api.interfaces', эта ошибка возникает не в нашем коде и будет исправлена позднее.

Создание агрегационного слоя и вспомогательного слоя

В руководстве пользователя уже описан процесс создания изохрон при помощи солвера sproute2. В нем для построения использовалась таска netEngine. Этот метод оптимизирован для одновременного построения большого количества изохрон.

Другие методы

Есть и второй способ построения изохрон, основанный на REST-методе build_isochrone из evergis_tools.geo_tools.network. Он не требует создания вспомогательного слоя и возвращает геометрию напрямую в коде. Однако этот метод строит изохроны последовательно, из-за этого их построение происходит очень медленно

В этом примере изохроны будут перестраиваться автоматически, из-за чего нам необходимо организовать автоматическую очистку и перезапись данных. В первую очередь напишем функцию, которая создает пустой слой с полигональной геометрией:

def build_isochrone_layer():
	class IsochroneLayer(BaseModel):
		gid: int = Field(..., description="gid")
		object_id: int = Field(..., description="object_id")
		duration: int = Field(..., description="duration")
		route_center_x: float = Field(..., description="route_center_x")
		route_center_y: float = Field(..., description="route_center_y")
	
	client = Client() # создание объекта клиента
	username = client.account.get_user_info().username # имя пользователя, который запускает код
	layer_name = f"{username}.built_isochrones" # Задание имени пользователя и системного имени слоя
	create_layer_from_schema(
		client=client,
		schema=IsochroneLayer,
		layer_name=layer_name,
		layer_alias="Зоны доступности", # имя слоя, которое будет видно в каталоге
		overwrite=True, # возможность перезаписи данных в слое
		parent_path="eromakh/Данные для руководства пользователя/Тест символизации/Слои", # путь до родительской папки
		# Не забывайте указывать ваше имя пользователя в начале пути, иначе система создаст папки в корне каталога
		geometry_field="geometry",
		geometry_type="Polygon",
		srid=4326,
		log=True # логирование в случае возникновения ошибок создания слоя
	)
	
	print("Стаб слоя для изохрон создан")

Данные о числе зданий в зонах доступности будут поступать в агрегационный слой. Для его создания нам также потребуется код:

def build_aggregation_layer():
	class AggregationLayer(BaseModel):
		gid: int = Field(..., description="gid")
		building_category: str = Field(..., description="building_category")
		count: int = Field(..., description="count")
		color: str = Field(..., description="color") 
	
	client = Client() # создание объекта клиента
	username = client.account.get_user_info().username # имя пользователя, который запускает код
	layer_name = f"{username}.aggregation_buildings" # Задание имени пользователя и системного имени слоя
	create_layer_from_schema(
		client=client,
		schema=AggregationLayer,
		layer_name=layer_name,
		layer_alias="Данные агрегации", # имя слоя, которое будет видно в каталоге
		overwrite=True, # возможность перезаписи данных в слое
		parent_path="eromakh/Данные для руководства пользователя/Тест символизации/Слои", # путь до родительской папки
		# Не забывайте указывать ваше имя пользователя в начале пути, иначе система создаст папки в корне каталога
		log=True # логирование в случае возникновения ошибок создания слоя
	)
	print("Стаб слоя для данных агрегации создан")

Создание инструмента расчета

Инструмент расчета показателя будет принимать на вход данные из фильтра и передавать обратно обновляющий параметр. Также этот код будет обновлять слой, по которому будет строится диаграмма с результатом агрегации данных.

Python Data Sources

Диаграмма может получить данные напрямую из Python. Мы создадим подобную диаграмму на основе источника данных Python в следующем примере. Такой способ создания диаграммы очень удобен для быстрой обработки статистической информации

Время выполнения кода в данном примере слишком велико для того, чтобы создавать динамические источники данных. У такого метода построения диаграммы есть один существенный минус – он не позволяет показывать процесс выполнения кода на дашборде. Вы можете увидеть логи из кода в разделе Network инструментов разработчика браузера, но это не тот способ, который был бы предпочтителен для пользователей карты. В связи с этим может возникнуть ложное ощущение подвисания системы. По этой причине мы сделаем процесс расчета более интерактивным. Пользователь увидит обновление диаграммы только после того, как инструмент завершит свою работу.

Для запуска инструмента нам нужна функция – оркестратор, которая будет вызывать все остальные функции и передавать данные из/в конфигурацию. В данном примере код получается в пределе 150 строк, поэтому мы не будем делить его на разные файлы. Непосредственный расчет требует всего шести функций:

  1. Вспомогательная функция определения названия поля геометрии. Система поддерживает разные названия поля геометрии. При импорте данных из ESRI Shapefile или CSV, поле, содержащее геометрию, по умолчанию называется “geometry”. Если слой был загружен из geopackage, то поле называется “geom”. Если вы импортируете данные из внешней базы данных, то оно может иметь любое имя. Из-за этого необходимо написать вспомогательную функцию, которая нужна для определения колонки с геометрией
  2. Функция, которая бы создавала GeoDataFrame из слоя ЭверГИС со зданиями и оставляла только жилые дома
  3. Функция построения и последующего объединения изохрон
  4. Функция расчета числа зданий, попадающих или не попадающих в зону
  5. Функция, которая бы готовила выходные данные
  6. Функция-оркестратор

Обновление слоя

Не забывайте, что слой, в который вы записываете геометрию изохрон, необходимо очищать перед каждым запуском функции, это можно сделать при помощи функции client.layers.delete_by_condition

Функция-оркестратор будет возвращать один параметр, который мы будем использовать для обновления конфигурации. Он может быть любым, но он должен быть разным при каждом запуске кода. Идея в том, чтобы использовать "responseFilters" для обновления источника данных, по которому строится слой.

Полный код этих функций:

Показать фрагмент Python кода

from evergis_api import Client from evergis_tools.eql import eql_query_to_geodataframe from evergis_tools.features import add_df_features_to_layer from evergis_tools.geo_tools.network import build_isochrone from evergis_tools.geodataframes import df_to_feature_collection import shapely import pandas as pd import geopandas as gpd import datetime import random

layer_ = “eromakh.buildings_tver_instr” layer_result = “eromakh.aggregated_buildings_tver”

def check_geometry_field(client): geom_check = eql_query_to_geodataframe(f”SELECT * FROM {layer_} LIMIT 1”, client) data_columns = list(geom_check.columns) if (“geom” in data_columns): return “geom” else: return “geometry”

def get_residential(client: Client, geom_field: str) → gpd.GeoDataFrame: data_ = eql_query_to_geodataframe(f”SELECT * FROM {layer_} WHERE
type_1 IN (‘house’, ‘residential’, ‘detached’, ‘semidetached_house’, ‘apartments’)”, client=client, geometry_field=geom_field) data_.set_crs(4326, inplace=True) return data_

def make_accumulated_isochrone(client: Client, buildings_layer: str, duration: int, geom_field: str, target_layer_isochrone: str) → shapely.MultiPolygon: area_list: list[shapely.Polygon] = [] res = client.layers.delete_by_condition(name=target_layer_isochrone, condition=f”duration={duration}”) query = f”SELECT * FROM {buildings_layer} WHERE type_1 = ‘hospital’” eqp = eql_query_to_geodataframe(query, client) build_isochrones( client=client, # объект клиента provider_name=“sproute_isochrone_pedestrian”, # тип графа (sproute_isochrone_pedestrian — пешеходные зоны от точки) source_layer_eql=query, # SQL запрос к слою, от которого будут строиться зоны source_id_attribute=“gid”, # id объектов в слое, по умолчанию id имеют наименование gid source_geometry_attribute=geom_field, # название атрибута геометрии исходного слоя target_layer=target_layer_isochrone, # системное имя слоя, в который будут записываться полигоны изохрон duration_expression=f”{duration}”, # максимальное время перемещения для изохрон (минуты) id_attribute_name=“gid”, # id объектов в слое изохрон, по умолчанию id имеют наименование gid geometry_attribute_name=“geometry”, # название атрибута геометрии слоя с изохронами duration_attribute_name=“duration”, # время отсечки для изохрон base_object_id_attribute_name=“object_id”, # id объектов в слое изохрон route_center_x_attribute_name=“route_center_x”, # координата X (долгота) точки, из которой строится изохрона route_center_y_attribute_name=“route_center_y” # координата Y (широта) точки, из которой строится изохрона ) area_isochrones = eql_query_to_geodataframe(f”SELECT * FROM {target_layer_isochrone}”, client) return shapely.unary_union(area_isochrones[“geometry”].tolist())

def count_intersection(residentials: gpd.GeoDataFrame, isochrone_: shapely.MultiPolygon, duration: int) → dict[str, int]: counter_: dict[str, int] = {} intersection_result = residentials.clip(isochrone_) counter_[f”Здания в {duration} мин. зоне доступности”] = len(intersection_result) counter_[f”Здания за пределами {duration} мин. зоны доступности”] = len(residentials) - len(intersection_result) print(counter_) return counter_

def update_layer(client: Client, counted_data: dict): gids_ = [] categs_ = [] counters_ = [] colors_ = [] for i, (k, v) in enumerate(counted_data.items()): gids_.append(i) categs_.append(k) counters_.append(v) colors_.append(“#66CC33” if “зоне” in k else “#CC0000”) ready_df = pd.DataFrame({“gid”:gids_, “building_category”: categs_, “count”: counters_, “color”: colors_}) res = client.layers.delete_by_condition(name=layer_result, condition=“count>0”) add_df_features_to_layer(client, ready_df, layer_result)

def run(duration: int): start_execution = datetime.datetime.now() client = Client() geometry_field_name = check_geometry_field(client) residentials_ = get_residential(client, geometry_field_name) hospitals = get_hospital_centroid(client, geometry_field_name) acc_area = make_accumulated_isochrone(client, hospitals, duration) counted_data = count_intersection(residentials_, acc_area, duration) update_layer(client, counted_data) end_execution = datetime.datetime.now() print(f”Время выполнения скрипта: {end_execution - start_execution}”) df = pd.DataFrame({“target_gid”: [random.randint(0, 1000)]}) return df_to_feature_collection(df)

В результате выполнения мы видим словарь со значениями:

raw result

Однако такой вид не очень удобен для анализа. В связи с этим может потребоваться создание диаграммы. В примере создание простого дашборда мы уже рассмотрели создание круговой диаграммы из источника данных. Теперь мы рассмотрим процесс записи данных во вспомогательный слой и создания на его основе динамически обновляемого источника данных.

Python DS

В системе есть и иной способ создания диаграмм. Мы можем создавать их напрямую из кода на основе Python DataSources, мы рассмотрим этот метод в следующем примере

Обновление результирующего слоя

Отдельно рассмотрим блок с обновлением агрегационного слоя. Нам потребуется функция из API add_df_features_to_layer, она запишет данные в нужный нам слой.

Добавим в блок импорта кода инструмента pandas и add_df_features_to_layer, а также слой с агрегированными данными:

from evergis_tools.features import add_df_features_to_layer
import pandas as pd
 
layer_result = "eromakh.aggregated_buildings_tver"

Функция будет преобразовывать данные из словаря, который был получен на предыдущем этапе (counted_data = count_intersection(residentials_, acc_area, duration)):

def update_layer(client: Client, counted_data: dict):
 
	gids_ = []
	categs_ = []
	counters_ = []
	colors_ = []
	for i, (k, v) in enumerate(counted_data.items()):
		gids_.append(i)
		categs_.append(k)
		counters_.append(v)
		colors_.append("#66CC33" if "зоне" in k else "#CC0000")
		ready_df = pd.DataFrame({"gid":gids_, "building_category": categs_,
		"count": counters_, "color": colors_})
	
	res = client.layers.delete_by_condition(name=layer_result, condition="count>0")
	add_df_features_to_layer(client, ready_df, layer_result)

Обратите внимание на то, что мы не просто записываем данные в слой. Так как у инструмента есть динамический выбор параметра, то и значения, и названия категорий меняются. Из-за этого, перед тем как добавить данные в слой, мы очищаем его от предыдущих значений при помощи client.layers.delete_by_condition. Для использования этой функции нам не нужно изменять блок импорта.

update layer

Возвращаемый параметр

Если мы просто передадим данные в агрегационный слой, то диаграмма автоматически обновляться не будет. Для того, чтобы клиент ЭверГИС обновлял данные нам нужен дополнительный фильтр, в который будем передавать значения, которые получаются при выполнении Python кода.

Назовем возвращаемый фильтр base_object_task. Название может быть любым и включать в себя символы латиницы и нижние подчеркивания. Возвращаемый фильтр в конфигурации должен находится там же, где и входной. Изменим список фильтров dashboardConfiguration:

"filters": [
	{
		"name": "duration",
		"defaultValue": 5
	},
	{
		"name": "base_object_task"
	}
]

Далее убедитесь, что ваш фильтр есть в параметрах объекта конфигурации, отвечающего за код. В нем не забудьте указать название возвращаемого атрибута. Код может возвращать несколько атрибутов фильтра. Если вы хотите сделать множество атрибутов, то создайте несколько фильтров в dashboardConfiguration и перечислите их через запятую в блоке responseFilters.

В нашем примере responseFilters выглядят так:

"responseFilters": {
	"base_object_task": "target_gid"
}

Теперь посмотрим, как создается возвращаемый объект. Для этого обратимся к функции-оркестратору:

def run(duration: int):
	...
	df = pd.DataFrame({"target_gid": [random.randint(0, 1000)]})
	return df_to_feature_collection(df)

Многовариантность использования

Возвращаемые объекты можно использовать не только как флаг для обновления источника данных, но и как полноценный фильтр

В данном примере наш параметр нужен только для того, чтобы подать сигнал клиенту на обновление источника данных для конфигурации. В связи с этим нам не важно, что мы вернем в параметр. Важно только то, что возвращаемые значения должны быть уникальными.

Обратите внимание

Не забывайте, что название фильтра (в этом примере "base_object_task": "target_gid") должно совпадать с названием хотя бы одного столбца в DataFrame (“target_id”)

Однако изначально возвращаемые фильтры создавались немного для другой задачи. При помощи этих фильтров можно динамически фильтровать источники данных для диаграмм, а не просто отправлять клиенту флаг того, что что-то обновилось. Из-за этого этот элемент и находится в группе фильтров.

Создание диаграммы

Последним шагом мы создадим диаграмму на основе вспомогательного слоя. Однако нам нужно каким-то образом подать сигнал клиенту ЭверГИС о том, что что-то изменилось. Поэтому мы создадим динамически обновляемый источник данных на основе нашего агрегирующего слоя.

Перейдем в список dataSources страницы на которой мы размещаем слои. Нам нужно выбрать интересующие нас данные из агрегирующего слоя. Этот источник данных будет работать на основе EQL-запроса. Напишем простой запрос:

SELECT gid, building_category, count, color FROM eromakh.aggregated_buildings_tver

Он будет выбирать уникальный идентификатор, категорию зданий (она будет в легенде диаграммы), количество объектов, а также используемый цвет из слоя. Далее создадим объект источника данных в конфигурации:

"dataSources": [
	{
		"name": "chart_source",
		"query": "SELECT gid, building_category, count, color FROM eromakh.aggregated_buildings_tver",
		"parameters": {
			"@base_object_task": "%base_object_task"
		}
	}
],
"templateName": "ContainersGroup"

Видимых изменений не произошло, теперь нам надо создать сам объект диаграммы и добавить его в конфигурацию. Мы уже разбирали пример создания конфигурации для диаграммы в примере, посвященном дашбордам. Приведем только код конфигурации, подробнее о его создании в соответствующем разделе.

Показать фрагмент конфигурации

{
	"id": "python_chart",
	"style": {
		"marginBottom": 8
	},
	"options": {
		"twoColumns": true
	},
	"children": [
		{
			"id": "chart",
			"type": "chart",
			"style": {},
			"options": {
				"limit": 5,
				"height": 100,
				"radius": 0.7,
				"padding": 1,
				"chartType": "pie",
				"showTotal": true,
				"otherItems": 100,
				"shownItems": 5,
				"cornerRadius": 1,
				"orderByValue": false,
				"relatedDataSources": [
					{
						"hideAxis": true,
						"axisColor": "#CB94E5",
						"chartAxis": "y",
						"attributeName": "count",
						"attributeColor": "color",
						"attributeTitle": "building_category",
						"dataSourceName": "chart_source"
					}
				]
			}
		},
		{
			"id": "titleIcon",
			"type": "svg",
			"value": "38b84cc239164ca6973a6a31d88f30ab",
			"options": {
				"width": 16,
				"fontColor": "#00C2FF"
			}
		},
		{
			"id": "title",
			"type": "text",
			"value": "Доступность поликлиник"
		},
		{
			"id": "legend",
			"type": "legend",
			"options": {
				"chartId": "chart"
			}
		}
	],
	"templateName": "Chart"
}

Обратите внимание

Названия полей в конфигурации диаграммы и EQL запросе должны совпадать. Также не забудьте что должны совпадать значение параметра dataSourceName в конфигурации диаграммы и значение параметра name в списке источников данных

Теперь по нажатию кнопки Запустить система рассчитывает показатель и обновляет результат во вспомогательном слое. Перезагружать страницу или выполнять какие-либо дополнительные действия для обновления диаграммы не нужно.

pseudo py chart