Vega и Vega-Lite используют декларативный подход к описанию визуализаций, в котором внешний вид отделён от структуры данных и логики построения графиков. Темы выступают как слой конфигурации, задающий единые визуальные правила оформления: цвета, шрифты, сетки, толщины линий, стили подписей и поведение интерактивных элементов.
Ключевая особенность системы тем заключается в том, что она не изменяет спецификацию графика, а накладывается поверх неё через механизм конфигурационного слияния (configuration merging). Это позволяет переиспользовать одну и ту же визуализацию в разных стилях без модификации описания данных.
Тема в Vega/Vega-Lite представляет собой JavaScript-объект (или JSON-структуру), который переопределяет значения в конфигурации визуализации.
Основные секции:
background — фон всей визуализацииtitle — стили заголовковaxis — оформление осейlegend — стили легендыrange — цветовые и шкальные диапазоныmark — стили графических примитивовview — параметры контейнера визуализацииПример минимальной темы:
const theme = {
background: "#ffffff",
title: {
font: "Inter",
fontSize: 16,
color: "#222"
},
axis: {
labelFont: "Inter",
titleFont: "Inter",
labelColor: "#555",
domainColor: "#ccc",
gridColor: "#eee"
},
mark: {
color: "#4c78a8"
}
};
В Vega тема применяется через конфигурацию runtime или через регистрацию темы в глобальном реестре.
import { register } from "vega-themes";
register("customTheme", theme);
После регистрации тема становится доступной для использования в визуализациях:
const runtime = vega.parse(spec);
const view = new vega.View(runtime).renderer("canvas");
view.runAsync();
Или с явным указанием конфигурации:
const view = new vega.View(runtime, {
config: theme
});
В Vega-Lite тема задаётся через поле config в
спецификации:
const spec = {
data: { url: "data.csv" },
mark: "line",
encoding: {
x: { field: "date", type: "temporal" },
y: { field: "value", type: "quantitative" }
},
config: theme
};
При компиляции Vega-Lite преобразует спецификацию в Vega и переносит конфигурацию на уровень Vega runtime.
Система тем работает по принципу многоуровневого переопределения:
При конфликте значений более высокий уровень перекрывает нижний.
Пример приоритетов:
default < theme < spec.config < mark encoding style
Оси являются одной из наиболее часто настраиваемых частей темы.
const axisTheme = {
axis: {
domain: true,
domainColor: "#333",
domainWidth: 1,
grid: true,
gridColor: "#f0f0f0",
gridDash: [4, 2],
tickColor: "#333",
tickSize: 5,
labelFont: "Roboto",
labelFontSize: 11,
labelColor: "#444",
titleFont: "Roboto",
titleFontSize: 12,
titleColor: "#111"
}
};
Оси в Vega делятся на типы:
xyxOffsetyOffsetКаждый тип может быть переопределён отдельно:
axisX: {
labelAngle: 0,
labelPadding: 8
}
Mark-элементы определяют визуальные примитивы: линии, точки, прямоугольники, текст.
const markTheme = {
mark: {
color: "#1f77b4",
opacity: 0.9
},
area: {
fill: "#aec7e8",
opacity: 0.6
},
line: {
strokeWidth: 2,
strokeJoin: "round"
},
point: {
size: 60,
filled: true
}
};
Особенность Vega заключается в том, что каждый тип mark имеет отдельную секцию конфигурации, что позволяет создавать сложные визуальные системы без изменения спецификации данных.
Темы управляют палитрами через range:
const colorTheme = {
range: {
category: [
"#4e79a7",
"#f28e2b",
"#e15759",
"#76b7b2",
"#59a14f"
],
diverging: [
"#d73027",
"#fdae61",
"#ffffbf",
"#a6d96a",
"#1a9850"
]
}
};
Для количественных шкал используются интерполяции:
range: {
heatmap: ["#f7fbff", "#08306b"]
}
Типографика определяет читаемость визуализаций и обычно выносится в отдельный слой конфигурации:
const typographyTheme = {
title: {
font: "Helvetica Neue",
fontWeight: "bold",
fontSize: 18
},
text: {
font: "Helvetica Neue",
fontSize: 12
},
legend: {
labelFont: "Helvetica Neue",
labelFontSize: 11,
titleFont: "Helvetica Neue"
}
};
Vega не ограничивает выбор шрифтов, но их поддержка зависит от рендерера (canvas или SVG).
Темы могут быть композиционными. Базовая тема расширяется специализированными слоями.
const baseTheme = {
background: "#fff",
axis: { domainColor: "#ccc" }
};
const darkTheme = {
...baseTheme,
background: "#1e1e1e",
axis: {
...baseTheme.axis,
labelColor: "#ddd",
domainColor: "#666"
}
};
Композиция позволяет строить:
В Vega возможно использование signals для динамической смены темы:
signals: [
{
name: "themeMode",
value: "light"
}
]
И далее привязка к стилям:
config: {
background: { signal: "themeMode === 'dark' ? '#000' : '#fff'" }
}
Такой подход позволяет переключать темы без пересборки спецификации.
Процесс применения темы в Vega проходит несколько стадий:
В Vega-Lite добавляется дополнительный этап:
Финансовые графики:
const financeTheme = {
axis: {
grid: true,
gridColor: "#e6e6e6"
},
mark: {
line: {
strokeWidth: 1.5
}
},
range: {
category: ["#2c3e50", "#e74c3c", "#27ae60"]
}
};
Научные визуализации:
const scienceTheme = {
axis: {
labelFontSize: 10,
tickCount: 5
},
mark: {
point: {
size: 40
}
}
};
Рендерер Vega интерпретирует тему как часть runtime-конфигурации. Это означает, что:
При обновлении темы возможен частичный rerender без пересборки всей спецификации.
Типичная структура набора тем:
themes/
light.js
dark.js
corporate.js
scientific.js
index.js
Центральный реестр:
export const themes = {
light,
dark,
corporate,
scientific
};
Использование тем позволяет:
Темы становятся фундаментальным слоем, который отделяет семантику данных от их визуального представления.