Легенда как элемент управления

Легенда в системах визуализации Vega и Vega-Lite выполняет не только декоративную функцию. Помимо расшифровки цветов, размеров, форм и других визуальных каналов, легенда способна выступать полноценным механизмом интерактивного управления графиком.

В интерактивных визуализациях легенда может:

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

Подход особенно полезен при работе с:

  • многосерийными графиками;
  • дашбордами;
  • аналитическими панелями;
  • большим количеством категорий;
  • визуализациями потоковых данных.

Легенда в Vega-Lite

В Vega-Lite легенда автоматически создаётся при использовании визуальных каналов:

  • color
  • shape
  • size
  • opacity
  • strokeDash

Простейший пример:

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

Допустимые значения:

  • left
  • right
  • top
  • bottom
  • top-left
  • none

Размеры символов

legend: {
  symbolSize: 200
}

Настройка шрифтов

legend: {
  labelFontSize: 14,
  titleFontSize: 16
}

Изменение формы символов

legend: {
  symbolType: "circle"
}

Также поддерживаются:

  • square
  • diamond
  • triangle
  • stroke

Интерактивная легенда

Главная особенность 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 автоматически:

  1. связывает элементы легенды с параметром;
  2. отслеживает клики;
  3. обновляет состояние выборки;
  4. изменяет отображение графика.

Фактически легенда становится контроллером состояния.


Подсветка вместо фильтрации

Наиболее распространённый сценарий — изменение прозрачности.

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
}

Ограничения Vega-Lite

Несмотря на удобство, механизм bind: "legend" имеет ограничения.

Поддерживаются только некоторые типы selection

Работает с:

  • point

Не работает напрямую с:

  • interval

Ограничение по каналам

Интерактивная легенда обычно применяется к:

  • color
  • shape
  • size

Ограниченная кастомизация поведения

Сложные сценарии требуют перехода к Vega.


Легенда в Vega

Vega предоставляет значительно более низкоуровневый контроль.

Здесь легенда может:

  • генерировать события;
  • управлять сигналами;
  • запускать трансформации;
  • изменять наборы данных;
  • синхронизировать представления;
  • работать как полноценный UI-компонент.

Архитектура интерактивной легенды в Vega

Основные элементы:

  • signals
  • legends
  • on
  • encode
  • обработчики событий

Простейшая интерактивная легенда в Vega

{
  "$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 позволяет отслеживать:

  • клики;
  • наведение;
  • уход курсора;
  • касания;
  • drag-события.

Пример:

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

Множественный выбор в Vega

Пример хранения массива выбранных категорий:

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

Далее сигнал используется:

  • в фильтрах;
  • в encode-блоках;
  • в трансформациях;
  • в анимациях.

Синхронизация дашбордов

Легенда может выступать центральным контроллером интерфейса.

Например:

  • выбор категории на одном графике;
  • обновление таблицы;
  • обновление карты;
  • изменение KPI-блоков;
  • фильтрация scatter plot.

Такой подход особенно распространён в аналитических системах.


Настройка внешнего вида легенды в Vega

Форматирование меток

{
  "labelFontSize": 14,
  "labelColor": "#333"
}

Размеры

{
  "symbolSize": 200
}

Отступы

{
  "padding": 10
}

Направление

{
  "orient": "bottom"
}

Пользовательские легенды

В Vega возможно полностью отказаться от стандартного блока legends и построить собственную легенду через marks.

Преимущества:

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

Построение кастомной легенды

Обычно используется:

{
  "marks": [
    {
      "type": "group"
    }
  ]
}

Внутри группы размещаются:

  • прямоугольники;
  • текст;
  • символы;
  • интерактивные области.

Когда использовать Vega вместо Vega-Lite

Vega-Lite подходит для:

  • простой интерактивности;
  • быстрого создания графиков;
  • стандартных легенд;
  • типовых dashboard-сценариев.

Vega необходима при:

  • сложной логике;
  • нестандартных UI-компонентах;
  • глубокой кастомизации;
  • сложных состояниях;
  • анимациях;
  • многоуровневом взаимодействии;
  • создании аналитических приложений.

Производительность

Интерактивная легенда влияет на производительность.

Особенно при:

  • десятках тысяч элементов;
  • большом числе категорий;
  • сложных transform-цепочках;
  • частом обновлении signals.

Оптимизация

Использование opacity вместо filter

Фильтрация приводит к перерасчёту сцены.

Изменение прозрачности обычно быстрее.


Ограничение количества категорий

Слишком длинные легенды ухудшают:

  • производительность;
  • читаемость;
  • UX.

Использование предварительной агрегации

Агрегированные данные уменьшают нагрузку.


Типичные ошибки

Использование bind: "legend" без legend

Если легенда отключена:

legend: null

то interactive binding работать не будет.


Несовпадение полей

fields: ["category"]

должно соответствовать полю, используемому в color.


Попытка использовать interval selection

type: "interval"

не поддерживается для legend binding.


Практические сценарии

Аналитические панели

Легенда управляет отображением:

  • метрик;
  • серий;
  • регионов;
  • временных интервалов.

Финансовые графики

Позволяет:

  • скрывать индикаторы;
  • включать линии;
  • выделять активы.

Географические визуализации

Легенда используется для:

  • выбора регионов;
  • управления слоями;
  • фильтрации данных.

Мониторинг систем

Интерактивная легенда помогает:

  • включать серверные группы;
  • скрывать шум;
  • анализировать аномалии.

Архитектурный подход

В современных визуализациях легенда перестаёт быть вспомогательным элементом.

Она становится:

  • контроллером состояния;
  • интерфейсом фильтрации;
  • системой навигации;
  • механизмом аналитического взаимодействия.

Именно поэтому Vega и Vega-Lite рассматривают легенду как часть интерактивной модели визуализации, а не просто подпись к цветам.