Канал color: fill и stroke

В Vega и Vega-Lite визуальные свойства графических примитивов управляются через систему каналов кодирования (encoding channels), среди которых цвет занимает особое место. Два базовых канала, определяющих цветовую заливку и обводку геометрии, — fill и stroke — используются для управления внешним видом маркеров, областей, линий и сложных графических элементов.


Семантическое различие fill и stroke

fill — заливка внутренней области

Канал fill задаёт цвет внутреннего пространства графического объекта. Он применяется к фигурам, обладающим площадью:

  • круги (circle)
  • прямоугольники (rect)
  • области (area)
  • географические полигоны (geoshape)
  • символы (symbol, в зависимости от режима)

Основная характеристика fill — заполнение замкнутой области:

{
  "mark": "rect",
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"},
    "color": {"field": "category", "type": "nominal"}
  }
}

В Vega-Lite канал color по умолчанию маппится в fill для большинства заливочных марок.


stroke — обводка контура

Канал stroke управляет цветом линии контура объекта. Он применяется к:

  • линиям (line)
  • границам фигур (rect, circle, geoshape)
  • точечным маркерам (point, symbol)
  • путям (path)
{
  "mark": {
    "type": "line",
    "strokeWidth": 2
  },
  "encoding": {
    "x": {"field": "date", "type": "temporal"},
    "y": {"field": "value", "type": "quantitative"},
    "color": {"field": "series", "type": "nominal"}
  }
}

В линейных графиках stroke является основным визуальным носителем цвета.


Поведение color в Vega-Lite

В Vega-Lite канал color является абстрактным уровнем, который автоматически транслируется в:

  • fill — для заливочных марок
  • stroke — для линейных и контурных марок

Автоматическое сопоставление

Тип марки Используемый канал
rect fill
area fill
bar fill
circle fill
point fill + stroke (в зависимости от config)
line stroke

Явное разделение fill и stroke

Vega позволяет задавать fill и stroke независимо, что критично при построении сложных визуализаций.

{
  "mark": {
    "type": "circle",
    "fill": "steelblue",
    "stroke": "black",
    "strokeWidth": 1
  },
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"}
  }
}

Такое разделение позволяет:

  • выделять контуры без изменения заливки
  • создавать визуальную иерархию
  • комбинировать несколько слоёв восприятия

Приоритет encoding над mark свойствами

Если одновременно заданы:

  • mark.fill
  • encoding.color

приоритет зависит от типа маппинга:

  • если encoding.color → применяется динамическое значение
  • если отсутствует encoding → используется фиксированное значение mark

Пример конфликта:

{
  "mark": {
    "type": "bar",
    "fill": "red"
  },
  "encoding": {
    "color": {"field": "group", "type": "nominal"}
  }
}

Здесь fill: red игнорируется, так как color переопределяет визуальное свойство.


Механика трансляции color → fill/stroke

Внутренне Vega-Lite компилирует color в Vega-spec:

  • для fill-ориентированных марок:
"fill": {"scale": ..., "field": ...}
  • для stroke-ориентированных:
"stroke": {"scale": ..., "field": ...}

Это разделение особенно важно при кастомизации Vega напрямую.


Работа с масштабами цвета

Каналы fill и stroke почти всегда связаны с цветовой шкалой (scale).

Номинальные данные

"color": {
  "field": "category",
  "type": "nominal",
  "scale": {
    "scheme": "category10"
  }
}
  • применяются дискретные палитры
  • каждому значению соответствует отдельный цвет

Количественные данные

"color": {
  "field": "value",
  "type": "quantitative",
  "scale": {
    "scheme": "blues"
  }
}
  • используется градиент
  • stroke часто требует дополнительной настройки контраста

Временные данные

"color": {
  "field": "date",
  "type": "temporal"
}
  • применяется непрерывная шкала
  • часто комбинируется с opacity для уменьшения визуального шума

fill и stroke в слоях (layered charts)

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

{
  "layer": [
    {
      "mark": {"type": "area", "opacity": 0.3},
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y1"},
        "y2": {"field": "y2"},
        "color": {"value": "lightblue"}
      }
    },
    {
      "mark": {
        "type": "line",
        "strokeWidth": 2
      },
      "encoding": {
        "x": {"field": "x"},
        "y": {"field": "y1"},
        "color": {"value": "blue"}
      }
    }
  ]
}

Здесь:

  • fill формирует подложку (area)
  • stroke выделяет границу тренда (line)

Управление прозрачностью и взаимодействием с цветом

Каналы fill и stroke часто комбинируются с:

  • opacity
  • fillOpacity
  • strokeOpacity

Пример различного поведения

"mark": {
  "type": "point",
  "fillOpacity": 0.7,
  "strokeOpacity": 1,
  "strokeWidth": 2
}
  • fill становится полупрозрачным
  • stroke остаётся визуально чётким

Особенности для symbol и point

Марки point и symbol могут использовать одновременно fill и stroke:

  • fill — основная заливка точки
  • stroke — обводка, усиливающая читаемость
{
  "mark": "point",
  "encoding": {
    "color": {"field": "group"}
  },
  "config": {
    "point": {
      "filled": true,
      "strokeWidth": 1
    }
  }
}

При filled: false fill отключается полностью, остаётся только stroke.


Поведение при null и отсутствующих значениях

Если значение цвета отсутствует:

  • применяется null → default color
  • либо fallback из config
"config": {
  "mark": {
    "color": "#999"
  }
}

fill/stroke ведут себя независимо:

  • отсутствие fill не влияет на stroke
  • отсутствие stroke не влияет на fill

Различия реализации Vega и Vega-Lite

Vega-Lite

  • декларативное описание
  • автоматическое определение fill/stroke
  • упрощённая модель color

Vega

  • явное указание fill/stroke в encoding signal
  • полная свобода управления графикой
  • требуется ручная компоновка шкал

Практика комбинирования fill и stroke

Визуальное выделение категорий

  • fill — кодирует категорию
  • stroke — подчёркивает границы групп

Структурная иерархия

  • слабый fill → фоновые элементы
  • сильный stroke → активные элементы

Избежание визуальной перегрузки

  • уменьшение fill opacity
  • усиление stroke width для ключевых объектов

Типичные ошибки при работе с fill и stroke

  • одновременное использование color и ручных fill/stroke без понимания приоритета
  • применение fill к линейным графикам (неэффективно и игнорируется)
  • отсутствие stroke в точках малого размера (потеря читаемости)
  • перегруженные палитры без разделения ролей fill и stroke

Роль конфигурации (config)

Глобальные настройки влияют на fill/stroke:

"config": {
  "mark": {
    "fill": "steelblue",
    "stroke": "black"
  }
}

Это позволяет задавать базовый стиль для всех визуализаций без дублирования encoding.