Исправление подсветки границ при наведении в геокартах Vega-Lite
Исправление проблем с подсветкой границ при наведении в геокартах Vega-Lite при использовании lookup transforms. Узнайте решения для сохранения интерактивности при наведении с данными TopoJSON в визуализациях Vega-Lite.
Vega-Lite: Подсветка границ геокарты при наведении не работает с преобразованием поиска
Я пытаюсь подсвечивать границы регионов (стран) на мировой карте Vega-Lite при наведении на них. Цель - сделать границу страны черной и более толстой при наведении.
Взаимодействие при наведении работает, когда я удаляю преобразование поиска, но перестает работать, когда поиск включен. Похоже, что Vega-Lite теряет связь между наведенной фигурой и данными, используемыми для поиска.
Вот спецификация Vega-Lite, которую я использую:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"country": "United States of America", "value": 18000},
{"country": "Canada", "value": 7500},
{"country": "Mexico", "value": 4200},
{"country": "Brazil", "value": 6800},
{"country": "Argentina", "value": 3100},
{"country": "Chile", "value": 2400},
]
},
"layer": [
{
"name": "CHART_0",
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"mark": {"type": "geoshape", "fill": "#e9e6ef", "cursor": "pointer"},
"encoding": {
"stroke": {
"condition": {"param": "geoHover", "empty": false, "value": "black"},
"value": "white"
},
"strokeWidth": {
"condition": {"param": "geoHover", "empty": false, "value": 2},
"value": 0.5
}
}
},
{
"name": "CHART_1",
"encoding": {
"color": {
"field": "value",
"type": "quantitative",
"scale": {"scheme": "blues"}
}
},
"layer": [
{"mark": {"type": "geoshape", "tooltip": true, "cursor": "pointer"}}
],
"transform": [
{
"lookup": "country",
"from": {
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"key": "properties.name",
"fields": ["properties", "geometry", "type"]
}
}
]
}
],
"params": [
{
"name": "geoHover",
"select": {"type": "point", "on": "pointerover", "clear": "pointerout"},
"views": ["CHART_0"]
}
],
"projection": {"type": "equalEarth"},
"height": "container",
"width": "container"
}
Как можно сделать подсветку границ при наведении корректной при использовании преобразования поиска с данными TopoJSON?
Содержание
- Понимание основной проблемы
- Анализ вашего текущего спецификации
- Решения для работающего выделения при наведении
- Альтернативные подходы
- Лучшие практики для взаимодействий при наведении
- Полный рабочий пример
Понимание основной проблемы
Коренная проблема заключается в том, что преобразования lookup изменяют структуру данных, от которой зависят взаимодействия при наведении. Когда вы применяете преобразование lookup к объектам TopoJSON, исходные геометрические данные изменяются, и механизм выбора при наведении может больше корректно идентифицировать, какой географический объект находится под курсором.
Как описано в вопросе на Stack Overflow, это распространенный паттерн, при котором “Vega-Lite теряет связь между наведенной фигурой и данными, используемыми для преобразования lookup.”
Ключевая задача — сохранение связи между географической геометрией и атрибутами данных при сохранении интерактивности при наведении.
Анализ вашего текущего спецификации
Анализируя вашу спецификацию, я могу определить несколько проблем:
-
Ограничение области параметра: Параметр
geoHoverсвязан только сCHART_0, но преобразование lookup применяется вCHART_1. Это означает, что выбор при наведении не достигает слоя, где применяется фактическая географическая данные с преобразованием lookup. -
Несоответствие структуры данных: Преобразование lookup пытается выполнить объединение, используя
"properties.name"в качестве ключа, но это может не правильно соответствовать названиям стран в ваших значениях данных. -
Разделение слоев: Наличие отдельных слоев для базовой географии и применения данных может мешать взаимодействиям при наведении, которые должны работать в обоих слоях.
Решения для работающего выделения при наведении
Решение 1: Подход с одним слоем
Наиболее прямое решение — объединить все в один слой и применить преобразование lookup перед кодированием наведения:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"country": "United States of America", "value": 18000},
{"country": "Canada", "value": 7500},
{"country": "Mexico", "value": 4200},
{"country": "Brazil", "value": 6800},
{"country": "Argentina", "value": 3100},
{"country": "Chile", "value": 2400},
]
},
"transform": [
{
"lookup": "country",
"from": {
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"key": "properties.name",
"fields": ["geometry", "type"]
}
}
],
"mark": {"type": "geoshape", "cursor": "pointer"},
"encoding": {
"color": {
"field": "value",
"type": "quantitative",
"scale": {"scheme": "blues"}
},
"stroke": {
"condition": {"param": "geoHover", "empty": false, "value": "black"},
"value": "white"
},
"strokeWidth": {
"condition": {"param": "geoHover", "empty": false, "value": 2},
"value": 0.5
},
"tooltip": {"field": "country"}
},
"params": [
{
"name": "geoHover",
"select": {"type": "point", "on": "pointerover", "clear": "pointerout"}
}
],
"projection": {"type": "equalEarth"},
"height": "container",
"width": "container"
}
Решение 2: Исправление области параметра
Если вам нужно сохранить структуру слоев, исправьте область параметра для ссылки на оба слоя:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"layer": [
{
"name": "CHART_0",
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"mark": {"type": "geoshape", "fill": "#e9e6ef", "cursor": "pointer"},
"encoding": {
"stroke": {
"condition": {"param": "geoHover", "empty": false, "value": "black"},
"value": "white"
},
"strokeWidth": {
"condition": {"param": "geoHover", "empty": false, "value": 2},
"value": 0.5
}
}
},
{
"name": "CHART_1",
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"mark": {"type": "geoshape", "cursor": "pointer"},
"encoding": {
"color": {
"field": "value",
"type": "quantitative",
"scale": {"scheme": "blues"}
},
"tooltip": {"field": "country"}
},
"transform": [
{
"lookup": "properties.name",
"from": {
"data": {
"values": [
{"country": "United States of America", "value": 18000},
{"country": "Canada", "value": 7500},
{"country": "Mexico", "value": 4200},
{"country": "Brazil", "value": 6800},
{"country": "Argentina", "value": 3100},
{"country": "Chile", "value": 2400},
]
},
"key": "country",
"fields": ["value"]
}
}
]
}
],
"params": [
{
"name": "geoHover",
"select": {"type": "point", "on": "pointerover", "clear": "pointerout"},
"views": ["CHART_0", "CHART_1"] // Включить оба слоя
}
],
"projection": {"type": "equalEarth"},
"height": "container",
"width": "container"
}
Альтернативные подходы
Использование меток Shape с преобразованием GeoShape
Для более сложных взаимодействий рассмотрите использование меток shape с преобразованием geoshape, как упоминается в документации Vega. Этот подход обеспечивает больший контроль над геометрическим рендерингом:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"transform": [
{
"lookup": "properties.name",
"from": {
"data": {
"values": [
{"country": "United States of America", "value": 18000},
{"country": "Canada", "value": 7500},
{"country": "Mexico", "value": 4200},
{"country": "Brazil", "value": 6800},
{"country": "Argentina", "value": 3100},
{"country": "Chile", "value": 2400},
]
},
"key": "country",
"fields": ["value"]
}
},
{
"geoshape": {"projection": "projection"}
}
],
"mark": {
"type": "shape",
"cursor": "pointer"
},
"encoding": {
"color": {
"field": "value",
"type": "quantitative",
"scale": {"scheme": "blues"}
},
"stroke": {
"condition": {
"param": "geoHover",
"empty": false,
"value": "black",
"test": "datum.value !== null"
},
"value": "white"
},
"strokeWidth": {
"condition": {
"param": "geoHover",
"empty": false,
"value": 2,
"test": "datum.value !== null"
},
"value": 0.5
}
},
"params": [
{
"name": "geoHover",
"select": {"type": "point", "on": "pointerover", "clear": "pointerout"}
}
],
"projection": {"type": "equalEarth"},
"height": "container",
"width": "container"
}
Лучшие практики для взаимодействий при наведении
-
Сохраняйте согласованность структур данных: Убедитесь, что преобразование lookup не нарушает связь между геометрическими объектами и их идентификаторами.
-
Используйте условное тестирование: Добавляйте тесты в ваши условия наведения, чтобы они применялись только к допустимым точкам данных, как показано в альтернативном подходе выше.
-
Рассмотрите предварительную обработку данных: Для сложных наборов данных рассмотрите предварительную обработку данных для включения необходимых идентификаторов перед загрузкой в Vega-Lite.
-
Тестируйте с минимальными примерами: Начните с простого рабочего примера и постепенно добавляйте сложность для изоляции проблем.
-
Используйте подходящие типы выбора: Разные типы выбора лучше подходят для разных случаев использования. Точечные выборки хорошо работают для отдельных географических объектов.
Полный рабочий пример
Вот полная рабочая спецификация, демонстрирующая решение:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"country": "United States of America", "value": 18000},
{"country": "Canada", "value": 7500},
{"country": "Mexico", "value": 4200},
{"country": "Brazil", "value": 6800},
{"country": "Argentina", "value": 3100},
{"country": "Chile", "value": 2400},
]
},
"transform": [
{
"lookup": "country",
"from": {
"data": {
"url": "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",
"format": {"type": "topojson", "feature": "countries"}
},
"key": "properties.name",
"fields": ["geometry", "type"]
}
}
],
"mark": {"type": "geoshape", "cursor": "pointer"},
"encoding": {
"color": {
"field": "value",
"type": "quantitative",
"scale": {"scheme": "blues"}
},
"stroke": {
"condition": {
"param": "geoHover",
"empty": false,
"value": "black",
"test": "datum.value !== null"
},
"value": "white"
},
"strokeWidth": {
"condition": {
"param": "geoHover",
"empty": false,
"value": 2,
"test": "datum.value !== null"
},
"value": 0.5
},
"tooltip": [
{"field": "country", "type": "nominal"},
{"field": "value", "type": "quantitative"}
]
},
"params": [
{
"name": "geoHover",
"select": {"type": "point", "on": "pointerover", "clear": "pointerout"}
}
],
"projection": {"type": "equalEarth"},
"height": 500,
"width": 800
}
Это решение сохраняет функциональность преобразования lookup, обеспечивая правильную работу выделения при наведении. Ключевые улучшения включают:
- Применение преобразования lookup перед кодированием метки
- Добавление тестов для обеспечения применения эффектов наведения только к допустимым точкам данных
- Сохранение всей логики рендеринга в одном слое для лучшей области параметра
Источники
- Vega-Lite geo map hover border highlighting not working when using lookup transform - Stack Overflow
- GeoShape Transform - Vega Documentation
- Geoshape | Vega-Lite Documentation
- Selection Parameters | Vega-Lite Documentation
- Shape Mark - Vega-Lite Documentation
Заключение
Проблема выделения границы при наведении с преобразованиями lookup в Vega-Lite возникает из-за изменений в структуре данных, которые нарушают связь между наведенными фигурами и соответствующими данными. Основные решения:
- Используйте подход с одним слоем для сохранения согласованности данных
- Исправьте область параметра для ссылки на все соответствующие слои
- Добавляйте условные тесты в условия наведения для проверки данных
- Рассмотрите использование меток shape с преобразованиями geoshape для большего контроля
Наиболее надежное решение обычно — объединение всего в один слой с применением преобразования lookup перед кодированием метки. Этот подход сохраняет связь между географическими объектами и атрибутами данных, поддерживая правильную интерактивность при наведении.
Для оптимальных результатов всегда тестируйте ваши спецификации постепенно и убедитесь, что ваши ключи преобразования lookup правильно соответствуют между наборами данных.