Легенда в системах визуализации Vega и Vega-Lite выполняет не только декоративную функцию. Помимо расшифровки цветов, размеров, форм и других визуальных каналов, легенда способна выступать полноценным механизмом интерактивного управления графиком.
В интерактивных визуализациях легенда может:
Подход особенно полезен при работе с:
В Vega-Lite легенда автоматически создаётся при использовании визуальных каналов:
colorshapesizeopacitystrokeDashПростейший пример:
{
data: {
values: [
{category: "A", value: 28},
{category: "B", value: 55},
{category: "C", value: 43}
]
},
mark: "bar",
encoding: {
x: {field: "category", type: "nominal"},
y: {field: "value", type: "quantitative"},
color: {field: "category", type: "nominal"}
}
}
Легенда будет построена автоматически на основе поля
category.
Иногда легенда мешает восприятию или дублирует подписи.
color: {
field: "category",
type: "nominal",
legend: null
}
color: {
field: "category",
type: "nominal",
legend: {
title: "Тип данных"
}
}
legend: {
orient: "right"
}
Допустимые значения:
leftrighttopbottomtop-leftnonelegend: {
symbolSize: 200
}
legend: {
labelFontSize: 14,
titleFontSize: 16
}
legend: {
symbolType: "circle"
}
Также поддерживаются:
squarediamondtrianglestrokeГлавная особенность Vega-Lite — возможность связать легенду с
параметрами (params) и механизмом выборки
(selection).
Легенда превращается в интерфейс управления данными.
{
data: {
values: [
{type: "A", value: 10},
{type: "B", value: 30},
{type: "C", value: 50}
]
},
params: [
{
name: "legendSelection",
select: {
type: "point",
fields: ["type"]
},
bind: "legend"
}
],
mark: "bar",
encoding: {
x: {field: "type", type: "nominal"},
y: {field: "value", type: "quantitative"},
color: {
field: "type",
type: "nominal"
},
opacity: {
condition: {
param: "legendSelection",
value: 1
},
value: 0.2
}
}
}
bind: "legend"При использовании:
bind: "legend"
Vega-Lite автоматически:
Фактически легенда становится контроллером состояния.
Наиболее распространённый сценарий — изменение прозрачности.
opacity: {
condition: {
param: "legendSelection",
value: 1
},
value: 0.1
}
Активные элементы становятся яркими, остальные — полупрозрачными.
Вместо прозрачности можно использовать фильтрацию.
transform: [
{
filter: {
param: "legendSelection"
}
}
]
Теперь будут отображаться только выбранные категории.
По умолчанию выборка позволяет выбирать несколько элементов.
Поведение можно изменить:
select: {
type: "point",
fields: ["category"],
toggle: false
}
toggle: false отключает множественный выбор.
По умолчанию двойной клик очищает состояние выборки.
Настройка:
select: {
type: "point",
clear: "dblclick"
}
Полное отключение очистки:
clear: false
Один из самых полезных сценариев.
{
data: {
values: [
{x: 1, y: 10, group: "A"},
{x: 2, y: 15, group: "A"},
{x: 1, y: 20, group: "B"},
{x: 2, y: 25, group: "B"}
]
},
params: [
{
name: "series",
select: {
type: "point",
fields: ["group"]
},
bind: "legend"
}
],
mark: "line",
encoding: {
x: {field: "x", type: "quantitative"},
y: {field: "y", type: "quantitative"},
color: {
field: "group",
type: "nominal"
},
strokeWidth: {
condition: {
param: "series",
value: 4
},
value: 1
},
opacity: {
condition: {
param: "series",
value: 1
},
value: 0.15
}
}
}
Интерактивность может воздействовать не только на прозрачность.
size: {
condition: {
param: "legendSelection",
value: 300
},
value: 50
}
color: {
condition: {
param: "legendSelection",
field: "category",
type: "nominal"
},
value: "lightgray"
}
Неактивные элементы становятся серыми.
opacity: {
condition: [
{
param: "legendSelection",
value: 1
},
{
test: "datum.value > 50",
value: 0.8
}
],
value: 0.2
}
Несмотря на удобство, механизм bind: "legend" имеет
ограничения.
Работает с:
pointНе работает напрямую с:
intervalИнтерактивная легенда обычно применяется к:
colorshapesizeСложные сценарии требуют перехода к Vega.
Vega предоставляет значительно более низкоуровневый контроль.
Здесь легенда может:
Основные элементы:
signalslegendsonencode{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"signals": [
{
"name": "activeCategory",
"value": null,
"on": [
{
"events": "@legendSymbol:click",
"update": "datum.value"
}
]
}
],
"data": [
{
"name": "table",
"values": [
{"category": "A", "value": 10},
{"category": "B", "value": 20}
]
}
],
"scales": [
{
"name": "color",
"type": "ordinal",
"domain": {"data": "table", "field": "category"},
"range": ["red", "blue"]
}
],
"legends": [
{
"fill": "color"
}
]
}
Vega позволяет отслеживать:
Пример:
{
"events": "@legendSymbol:mouseover",
"update": "datum.value"
}
Можно обращаться к конкретным частям:
@legendSymbol@legendLabel@legendEntryЭто позволяет создавать сложное поведение.
{
"name": "hovered",
"value": null,
"on": [
{
"events": "@legendSymbol:mouseover",
"update": "datum.value"
},
{
"events": "@legendSymbol:mouseout",
"update": "null"
}
]
}
{
"fillOpacity": [
{
"test": "hovered === datum.category",
"value": 1
},
{
"value": 0.15
}
]
}
Vega позволяет изменять набор данных.
{
"type": "filter",
"expr": "activeCategory == null || datum.category === activeCategory"
}
Сигналы позволяют создавать полноценные toggle-механизмы.
{
"events": "@legendSymbol:click",
"update": "
activeCategory === datum.value
? null
: datum.value
"
}
Пример хранения массива выбранных категорий:
{
"name": "selected",
"value": [],
"on": [
{
"events": "@legendSymbol:click",
"update": "
indexof(selected, datum.value) >= 0
? filter(selected, x => x !== datum.value)
: selected.concat([datum.value])
"
}
]
}
Одно из крупнейших преимуществ Vega.
Один сигнал может управлять несколькими представлениями одновременно.
{
"signals": [
{
"name": "selectedCategory"
}
]
}
Далее сигнал используется:
Легенда может выступать центральным контроллером интерфейса.
Например:
Такой подход особенно распространён в аналитических системах.
{
"labelFontSize": 14,
"labelColor": "#333"
}
{
"symbolSize": 200
}
{
"padding": 10
}
{
"orient": "bottom"
}
В Vega возможно полностью отказаться от стандартного блока
legends и построить собственную легенду через marks.
Преимущества:
Обычно используется:
{
"marks": [
{
"type": "group"
}
]
}
Внутри группы размещаются:
Интерактивная легенда влияет на производительность.
Особенно при:
Фильтрация приводит к перерасчёту сцены.
Изменение прозрачности обычно быстрее.
Слишком длинные легенды ухудшают:
Агрегированные данные уменьшают нагрузку.
bind: "legend" без legendЕсли легенда отключена:
legend: null
то interactive binding работать не будет.
fields: ["category"]
должно соответствовать полю, используемому в color.
type: "interval"
не поддерживается для legend binding.
Легенда управляет отображением:
Позволяет:
Легенда используется для:
Интерактивная легенда помогает:
В современных визуализациях легенда перестаёт быть вспомогательным элементом.
Она становится:
Именно поэтому Vega и Vega-Lite рассматривают легенду как часть интерактивной модели визуализации, а не просто подпись к цветам.