Условное кодирование через выделения

Условное кодирование (conditional encoding) в Vega-Lite позволяет изменять визуальные свойства элементов графика в зависимости от состояния данных, взаимодействий пользователя или логических выражений. Наиболее распространённый сценарий — выделение объектов при наведении курсора, клике, выборе диапазона или активации фильтра.

Механизм основан на конструкции condition, которая определяет:

  • условие применения;
  • значение при выполнении условия;
  • значение по умолчанию.

Благодаря этому диаграмма становится интерактивной без ручного управления DOM-элементами.


Базовая структура condition

Простейший пример изменения цвета точки при выделении:

{
  mark: "point",
  encoding: {
    color: {
      condition: {
        param: "hover",
        value: "red"
      },
      value: "gray"
    }
  }
}

Здесь:

  • если параметр hover активен — точка окрашивается в красный;
  • иначе используется серый цвет.

Выделения через params

Современный подход в Vega-Lite строится вокруг params. Параметры позволяют хранить состояние взаимодействия.

Пример определения выделения:

params: [
  {
    name: "hover",
    select: {
      type: "point",
      on: "mouseover",
      clear: "mouseout"
    }
  }
]

Разбор параметров

Свойство Назначение
name имя выделения
select.type тип выделения
on событие активации
clear событие сброса

Типы выделений

Point Selection

Выделение отдельных элементов.

select: {
  type: "point"
}

Используется для:

  • выбора точек;
  • кликов по столбцам;
  • активации категорий.

Interval Selection

Выделение диапазона.

select: {
  type: "interval"
}

Подходит для:

  • zoom-областей;
  • brush selection;
  • фильтрации диапазонов.

Выделение при наведении

Один из самых популярных сценариев.

const spec = {
  data: {
    values: [
      {x: 10, y: 20},
      {x: 20, y: 40},
      {x: 30, y: 10}
    ]
  },

  params: [
    {
      name: "hover",
      select: {
        type: "point",
        on: "mouseover",
        clear: "mouseout"
      }
    }
  ],

  mark: "point",

  encoding: {
    x: {field: "x", type: "quantitative"},
    y: {field: "y", type: "quantitative"},

    size: {
      condition: {
        param: "hover",
        value: 300
      },
      value: 100
    },

    color: {
      condition: {
        param: "hover",
        value: "orange"
      },
      value: "steelblue"
    }
  }
};

Что происходит

При наведении:

  • точка увеличивается;
  • цвет меняется;
  • после ухода курсора состояние очищается.

Выделение по клику

Клик позволяет сохранять состояние выбора.

params: [
  {
    name: "selectPoint",
    select: "point"
  }
]

Использование:

opacity: {
  condition: {
    param: "selectPoint",
    value: 1
  },
  value: 0.2
}

Эффект

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

Такой подход часто применяется в dashboard-интерфейсах.


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

По умолчанию point selection поддерживает множественный выбор через Shift.

Явная настройка:

select: {
  type: "point",
  toggle: true
}

Отключение множественного выбора

select: {
  type: "point",
  toggle: false
}

Настройка событий

Использование click

on: "click"

Двойной клик

on: "dblclick"

Комбинированные события

on: "mouseover[event.shiftKey]"

Выделение активируется только при зажатом Shift.


Условное изменение прозрачности

Наиболее распространённый паттерн.

opacity: {
  condition: {
    param: "highlight",
    value: 1
  },
  value: 0.15
}

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

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

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

shape: {
  condition: {
    param: "selected",
    value: "diamond"
  },
  value: "circle"
}

Условное изменение толщины линии

strokeWidth: {
  condition: {
    param: "selected",
    value: 4
  },
  value: 1
}

Особенно полезно в line chart.


Использование выражений (test)

Условие может основываться не только на selection, но и на логическом выражении.

color: {
  condition: {
    test: "datum.value > 100",
    value: "red"
  },
  value: "green"
}

Объект datum

datum представляет текущую строку данных.


Сложные условия

Несколько проверок

test: "datum.value > 100 && datum.category === 'A'"

Тернарные конструкции

test: "datum.score >= 80 ? true : false"

Комбинирование selection и test

color: {
  condition: [
    {
      param: "hover",
      value: "orange"
    },
    {
      test: "datum.value > 50",
      value: "red"
    }
  ],
  value: "gray"
}

Приоритет

Условия проверяются сверху вниз.


Выделение категорий

Пример для bar chart:

const spec = {
  data: {
    values: [
      {category: "A", value: 28},
      {category: "B", value: 55},
      {category: "C", value: 43}
    ]
  },

  params: [
    {
      name: "selectBar",
      select: "point"
    }
  ],

  mark: "bar",

  encoding: {
    x: {field: "category", type: "nominal"},
    y: {field: "value", type: "quantitative"},

    color: {
      condition: {
        param: "selectBar",
        value: "crimson"
      },
      value: "lightgray"
    }
  }
};

Interval Selection

Создание brush selection

params: [
  {
    name: "brush",
    select: "interval"
  }
]

Выделение области

color: {
  condition: {
    param: "brush",
    value: "steelblue"
  },
  value: "lightgray"
}

Связанные визуализации

Одно из сильнейших применений conditional encoding — coordinated views.

Пример фильтрации

transform: [
  {
    filter: {
      param: "brush"
    }
  }
]

Сценарий

  • верхний график задаёт диапазон;
  • нижний отображает только выбранные данные.

Использование выделений в layered charts

Выделение может применяться между слоями.

layer: [
  {
    mark: "line"
  },
  {
    mark: "point",
    encoding: {
      opacity: {
        condition: {
          param: "hover",
          value: 1
        },
        value: 0
      }
    }
  }
]

Highlight ближайшей точки

Частый паттерн для line chart.

params: [
  {
    name: "hover",
    select: {
      type: "point",
      nearest: true,
      on: "mouseover",
      clear: "mouseout"
    }
  }
]

nearest: true

Позволяет автоматически выбирать ближайшую точку к курсору.


Tooltip и conditional encoding

Интерактивность часто комбинируется с tooltip.

tooltip: [
  {field: "x"},
  {field: "y"}
]

Совместно с hover selection создаётся полноценное интерактивное исследование данных.


Условное отображение текста

text: {
  condition: {
    param: "hover",
    field: "value"
  },
  value: ""
}

Поведение

Текст отображается только при наведении.


Управление z-index

Для акцентирования элементов:

order: {
  condition: {
    param: "selected",
    value: 1
  },
  value: 0
}

Выделение линий по категории

params: [
  {
    name: "legendSelect",
    select: {
      type: "point",
      fields: ["category"]
    },
    bind: "legend"
  }
]

Что даёт bind: "legend"

Легенда становится интерактивной:

  • клик по категории;
  • выделение соответствующей линии;
  • скрытие остальных.

Условное кодирование в legend-driven interaction

opacity: {
  condition: {
    param: "legendSelect",
    value: 1
  },
  value: 0.1
}

Использование вычисляемых полей

Иногда условие проще вынести в transform.

transform: [
  {
    calculate: "datum.value > 50",
    as: "isHigh"
  }
]

После этого:

color: {
  condition: {
    test: "datum.isHigh",
    value: "red"
  },
  value: "blue"
}

Условное кодирование в heatmap

color: {
  condition: {
    test: "datum.value > 80",
    value: "darkred"
  },
  value: "lightyellow"
}

Выделение через keyboard events

on: "keydown"

Можно использовать:

  • стрелки;
  • Enter;
  • Escape;
  • сочетания клавиш.

Очистка выделения

Автоматическая

clear: "mouseout"

По двойному клику

clear: "dblclick"

Отключение очистки

clear: false

Состояние будет сохраняться до следующего выбора.


Использование empty

Контроль поведения при отсутствии selection.

condition: {
  param: "brush",
  empty: false,
  value: "red"
}

Значение

Если выделение пустое — условие не применяется.


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

При работе с большими наборами данных важно учитывать:

Количество условий

Сложные цепочки condition увеличивают стоимость рендеринга.


Частота событий

mousemove значительно тяжелее click.


Layered Charts

Много слоёв с condition могут приводить к заметным задержкам.


Практический паттерн: dimming

Один из самых популярных UX-приёмов.

opacity: {
  condition: {
    param: "hover",
    value: 1
  },
  value: 0.05
}

Эффект

  • активный объект подчёркивается;
  • остальные уходят на второй план.

Практический паттерн: focus + context

Комбинация interval selection и linked views.

params: [
  {
    name: "brush",
    select: "interval"
  }
]

Используется для:

  • временных рядов;
  • финансовых графиков;
  • аналитических dashboard.

Практический паттерн: interactive legend

bind: "legend"

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


Отличие Vega-Lite от Vega

Vega-Lite

  • декларативный уровень;
  • простые selection API;
  • автоматическая генерация сигналов.

Vega

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

Эквивалент на Vega

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

fill: [
  {
    test: "hover",
    value: "red"
  },
  {
    value: "gray"
  }
]

Когда использовать conditional encoding

Наиболее эффективные сценарии:

  • аналитические панели;
  • исследование данных;
  • визуальная фильтрация;
  • linked charts;
  • hover-highlight;
  • interactive legends;
  • drill-down интерфейсы;
  • exploratory visualization.

Частые ошибки

Отсутствие clear

clear: "mouseout"

Без очистки выделение может «залипать».


Неправильный порядок условий

condition: [
  {...},
  {...}
]

Первое совпавшее условие имеет приоритет.


Смешивание типов selection

Нежелательно использовать одинаковые имена параметров для разных типов выделения.


Избыточная интерактивность

Слишком большое количество hover-эффектов ухудшает UX и производительность.


Архитектурные рекомендации

Выделения должны быть предсказуемыми

Пользователь должен понимать:

  • что выделено;
  • почему выделено;
  • как снять выделение.

Использование opacity предпочтительнее изменения цвета

Изменение прозрачности:

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

Hover — временное состояние, click — постоянное

Это важный UX-принцип при проектировании интерактивных визуализаций.


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

const spec = {
  data: {
    values: [
      {x: 1, y: 28, category: "A"},
      {x: 2, y: 55, category: "B"},
      {x: 3, y: 43, category: "A"},
      {x: 4, y: 91, category: "C"},
      {x: 5, y: 81, category: "B"}
    ]
  },

  params: [
    {
      name: "hover",
      select: {
        type: "point",
        on: "mouseover",
        clear: "mouseout",
        nearest: true
      }
    },

    {
      name: "selected",
      select: {
        type: "point",
        on: "click"
      }
    }
  ],

  mark: "point",

  encoding: {
    x: {
      field: "x",
      type: "quantitative"
    },

    y: {
      field: "y",
      type: "quantitative"
    },

    color: {
      condition: [
        {
          param: "selected",
          value: "crimson"
        },
        {
          param: "hover",
          value: "orange"
        }
      ],
      field: "category",
      type: "nominal"
    },

    size: {
      condition: {
        param: "hover",
        value: 300
      },
      value: 100
    },

    opacity: {
      condition: {
        param: "selected",
        value: 1
      },
      value: 0.3
    },

    tooltip: [
      {field: "x"},
      {field: "y"},
      {field: "category"}
    ]
  }
};