Arquitectura de Señales en Vega: El Estándar Profesional
Por qué escribí esto
Después de +2 años desarrollando visuales custom con Vega y Vega-Lite en Deneb para Power BI, aprendí una lección por las malas: el código que escribes hoy lo mantendrás mañana.
No existe un curso de Arquitectura Vega 101. Lo que vas a leer es el resultado de abrir archivos JSON que yo mismo escribí hace meses y no entender nada, de refactorizar el mismo visual 5 veces, y de finalmente encontrar patrones que realmente funcionan.
Si eres nuevo en Vega, esto te ahorrará meses de frustración.
Si ya tienes experiencia, encontrarás al menos una técnica que aplicarás en tu próximo proyecto.
💡 La idea clave: Sistema de prefijos (UI_, DATA_, LAYOUT_, STATE_) + agrupación en objetos = visuales mantenibles, escalables y profesionales.
📌 Nota: Vega vs Vega-Lite
Este artículo usa sintaxis de Vega (signals), pero el sistema de arquitectura aplica igual para Vega-Lite.
| Vega | Vega-Lite |
|---|---|
| ”signals”: […] | “params”: […] |
| {“signal”: “UI_Colors.primary”} | {“expr”: “UI_Colors.primary”} |
Ejemplo de conversión:
// Vega
"signals": [
{"name": "UI_Colors", "value": {"primary": "#3B82F6"}}
]
// Vega-Lite
"params": [
{"name": "UI_Colors", "value": {"primary": "#3B82F6"}}
]
La arquitectura es idéntica — solo cambia el nombre del contenedor.
El Problema
Abres un JSON de Vega que creaste hace 3 meses:
"signals": [
{"name": "c1", "value": "#3B82F6"},
{"name": "fs", "value": 14},
{"name": "w", "value": 400}
]
¿Qué es c1? ¿fs es font-size? ¿De qué elemento?
Este artículo resuelve exactamente ese problema.
La Solución: 4 Prefijos que Recomiendo
| Prefijo | Propósito | Ejemplo |
|---|---|---|
| UI_ | Estilos y colores | UI_Colors, UI_Typography |
| DATA_ | Valores del dataset | DATA_MaxValue, DATA_Categories |
| LAYOUT_ | Geometría responsive | LAYOUT_ChartWidth, LAYOUT_Columns |
| STATE_ | Interacción del usuario | STATE_HoveredItem, STATE_Selected |
UI_ — Estilos Visuales
Todo lo que el usuario puede personalizar: colores, fuentes, geometría.
Ejemplo: Paleta de Colores
{
"name": "UI_Colors",
"description": "Paleta de colores del visual",
"value": {
"primary": "#3B82F6",
"background": "#FFFFFF",
"positive": "#10B981",
"negative": "#EF4444"
}
}
Ejemplo: Tipografía
{
"name": "UI_Typography",
"description": "Configuración de fuentes",
"value": {
"fontFamily": "Segoe UI",
"titleSize": 18,
"bodySize": 12
}
}
DATA_ — Datos Derivados
Valores extraídos o calculados del dataset.
Ejemplo: Valor Máximo
{
"name": "DATA_MaxValue",
"description": "Valor máximo para escalar el eje Y",
"update": "data('dataset')[0]['__max__']"
}
Ejemplo: Lista de Categorías
{
"name": "DATA_Categories",
"description": "Lista única de categorías",
"update": "pluck(data('dataset'), 'category')"
}
LAYOUT_ — Geometría Reactiva
Cálculos de posicionamiento que reaccionan al contenedor.
Ejemplo: Ancho Responsive
{
"name": "LAYOUT_ChartWidth",
"description": "Ancho del gráfico (responsive)",
"update": "containerSize()[0] - 80"
}
Ejemplo: Columnas Dinámicas
{
"name": "LAYOUT_Columns",
"description": "Columnas según ancho",
"update": "containerSize()[0] < 600 ? 2 : containerSize()[0] < 900 ? 3 : 4"
}
STATE_ — Interacción
Variables que cambian con acciones del usuario.
Ejemplo: Hover State
{
"name": "STATE_HoveredItem",
"description": "ID del elemento bajo el mouse",
"value": null,
"on": [
{"events": "rect:mouseover", "update": "datum.id"},
{"events": "rect:mouseout", "update": "null"}
]
}
Agrupación en Objetos
❌ Sopa de Variables
"signals": [
{"name": "ColorFondo", "value": "#FFFFFF"},
{"name": "ColorBorde", "value": "#E5E7EB"},
{"name": "TamanoTitulo", "value": 18},
{"name": "TamanoSubtitulo", "value": 14}
// ... 50 variables más
]
✅ Objetos Semánticos
"signals": [
{
"name": "UI_Colors",
"value": {"background": "#FFFFFF", "border": "#E5E7EB"}
},
{
"name": "UI_Typography",
"value": {"titleSize": 18, "subtitleSize": 14}
}
]
De 50+ variables a 4-5 objetos organizados.
Reglas de Oro
- Máximo 1 nivel de profundidad en objetos
- Máximo 10 propiedades por objeto
- Siempre description en cada señal
- Un objeto = una responsabilidad
value vs update
| Propiedad | Cuándo Usar | Ejemplo |
|---|---|---|
| value | Valores estáticos | UI_Colors |
| update | Valores dinámicos | LAYOUT_ChartWidth |
| on | Eventos de usuario | STATE_HoveredItem |
Ejemplo Completo
"signals": [
{
"name": "UI_Colors",
"description": "Paleta de colores",
"value": {
"barFill": "#3B82F6",
"barHover": "#2563EB",
"background": "#FFFFFF"
}
},
{
"name": "LAYOUT_ChartWidth",
"description": "Ancho responsive del gráfico",
"update": "containerSize()[0] - 80"
},
{
"name": "DATA_MaxValue",
"description": "Máximo para escala Y",
"update": "data('dataset')[0]['__max__']"
},
{
"name": "STATE_HoveredBar",
"description": "Barra bajo el mouse",
"value": null,
"on": [
{"events": "rect:mouseover", "update": "datum.id"},
{"events": "rect:mouseout", "update": "null"}
]
}
]
Uso en Marks:
"fill": [
{"test": "datum.id === STATE_HoveredBar", "signal": "UI_Colors.barHover"},
{"signal": "UI_Colors.barFill"}
]
🎯 Caso Real: Universal KPI Trend Matrix
La teoría está bien, pero ¿cómo se ve esto en un visual real de producción?
Este es el Universal KPI Trend Matrix, un visual que desarrollé aplicando exactamente esta arquitectura. Veamos cómo se implementan las señales:
UI_FontSizes y UI_FontWeights — Tipografía Centralizada

En la imagen puedes ver:
- UI_FontSizes: Un objeto que agrupa TODOS los tamaños de fuente del visual (encabezados, KPIs, subtítulos, ejes)
- UI_FontWeights: Controla el grosor de cada elemento textual (normal, bold, bolder)
¿El beneficio? Cambiar la tipografía de todo el visual = modificar 2 objetos. No 20 variables dispersas.
UI_FontWeights — Control de Estilos de Texto

Aquí vemos cómo las señales UI_ controlan el estilo visual del texto:
- UI_FontWeights: Define el grosor de cada elemento textual
- Valores: normal, bold, bolder para diferentes jerarquías
Esto permite que todos los estilos de texto se configuren desde un solo lugar.
LAYOUT_CardDimensions, GridConfig y Spacing — El Sistema de Grid

El corazón del layout responsive:
- LAYOUT_CardDimensions: Define
widthyheightde cada tarjeta KPI - LAYOUT_GridConfig: Especifica número de columnas (calculado automáticamente según ancho)
- LAYOUT_Spacing: Controla el espaciado horizontal y vertical entre tarjetas
Resultado: Un grid que se reorganiza automáticamente según el espacio disponible.
¿Por qué funciona?
Observa cómo cada imagen muestra:
- Prefijos claros → UI_, LAYOUT_ — sabes inmediatamente qué hace cada señal
- Descripciones detalladas → Cada señal explica su propósito
- Objetos agrupados → Propiedades relacionadas están juntas
- Valores semánticos → headerTitle, kpiName, no h1, t1
Este es el resultado de aplicar la arquitectura profesional de señales desde el día 1.
💡 ¿Quieres usar este visual? El Universal KPI Trend Matrix está disponible como plantilla lista para usar en Power BI. Obtener Plantilla Premium
Beneficios Cuantificados
| Sin Arquitectura | Con Arquitectura |
|---|---|
| Cambiar tema = 50+ ediciones | Cambiar tema = 3 ediciones |
| 2-3 horas de trabajo | 2 minutos |
| Alto riesgo de errores | 0 errores |
| Código incomprensible | Auto-documentado |
Checklist Rápido
Antes de publicar tu próximo visual, verifica:
- Prefijos en todas las señales (UI_, DATA_, LAYOUT_, STATE_)
- Variables agrupadas en objetos semánticos
- description en cada señal
- update para valores dinámicos, value para estáticos
- Sin valores hardcodeados de ancho/alto
Conclusión
La diferencia entre un gráfico que funciona y un visual profesional está en la arquitectura:
- Prefijos → Revelan propósito instantáneamente
- Objetos → Organizan variables relacionadas
- Descripciones → Auto-documentan el código
- Reactividad → Visuales responsive automáticos
El Universal KPI Trend Matrix que viste en este artículo es prueba de que esta arquitectura funciona en producción. Cada señal tiene su lugar, cada cambio es predecible, y el código es mantenible después de meses.
Tu yo del futuro te lo agradecerá.
Recursos Relacionados
Si este artículo te resultó útil, también te recomiendo:
-
Función pbiFormat - Opciones Avanzadas - Aprende a formatear valores dinámicamente en Deneb
-
Gráfico de Barras Apiladas - Template completo con arquitectura de señales
-
Gantt Chart en Vega-Lite - Ejemplo avanzado de layout responsive
-
Universal KPI Trend Matrix - La plantilla premium que usa esta arquitectura
¿Preguntas o comentarios? Déjalos abajo en la sección de comentarios. Me encantaría saber cómo implementas estos patrones en tus propios visuales.
Por Cristobal Salcedo Beltran — Desarrollador de visuales custom con Vega y Vega-Lite en Deneb para Power BI
Fecha de publicación: 28 de enero de 2026
¿Te resultó útil este artículo?
Si este contenido te ha ayudado, considera apoyarme con un café. Tu apoyo me permite seguir creando contenido de calidad.