---
name: Deneb Visuals
slug: deneb-visuals
category: Frontend
description: Deneb Visuals creates and tunes Deneb charts for Power BI using Vega and Vega-Lite specs. Use it when building custom visuals, handling cross-filtering or theme colors, or diagnosing rendering and field-name issues.
github: "https://github.com/data-goblin/power-bi-agentic-development/tree/main/plugins/custom-visuals/skills/deneb-visuals"
language: "C#"
stars: 872
forks: 129
install: "npx degit https://github.com/data-goblin/power-bi-agentic-development/tree/main/plugins/custom-visuals/skills/deneb-visuals ~/.claude/skills/deneb-visuals"
installs_to: ~/.claude/skills/deneb-visuals
source_path: plugins/custom-visuals/skills/deneb-visuals/SKILL.md
collection_size: 25
category_size: 567
collection_url: "https://dirskills.com/collections/data-goblin/power-bi-agentic-development"
added: 2026-08-22T05:21:23.629Z
last_synced: 2026-08-22T05:21:23.629Z
canonical_url: "https://dirskills.com/skills/deneb-visuals"
---

# Deneb Visuals

Deneb Visuals creates and tunes Deneb charts for Power BI using Vega and Vega-Lite specs. Use it when building custom visuals, handling cross-filtering or theme colors, or diagnosing rendering and field-name issues.

**Install:**

```bash
npx degit https://github.com/data-goblin/power-bi-agentic-development/tree/main/plugins/custom-visuals/skills/deneb-visuals ~/.claude/skills/deneb-visuals
```

## README

# Deneb Visuals in Power BI (PBIR)

> **Use `pbir` for every report mutation.** Read PBIR metadata only for diagnosis. If `pbir` is
> unavailable or lacks an operation, stop and report the gap; never edit report JSON directly.

Deneb is a certified custom visual for Power BI that enables Vega and Vega-Lite declarative visualization specs directly inside reports. Author specs using this skill.

## Provider Policy

**Prefer Vega-Lite** for new Deneb visuals unless specific Vega-only features are required (signals, event streams, custom projections, force/voronoi layouts). Vega-Lite is more concise, easier to maintain, and covers most chart types. For advanced Vega features, see `references/vega-patterns.md` and the [Vega documentation](https://vega.github.io/vega/docs/).

## Visual Identity

- **visualType:** `deneb7E15AEF80B9E4D4F8E12924291ECE89A`
- **Bundled runtime:** Vega 6.2.0 / Vega-Lite 6.4.1 (since Deneb 1.8; use `v6.json` schema URLs)
- **Data role:** Single `dataset` role (all fields go into one "Values" well)
- **Default row limit:** 10,000 rows (override via `dataLimit.override`)
- **Provider:** `vegaLite` (default) or `vega` (when Vega-specific features needed)
- **Render modes:** `svg` (default, sharp text) or `canvas` (better for large datasets)

## Custom Visual Registration (Required)

Copying a working Deneb visual with `pbir cp` carries its registration. For a new visual, inspect
`publicCustomVisuals` with `pbir get` and update the complete list through `pbir set --json`,
preserving any existing ids. Never edit `report.json` directly.

## Workflow: Creating a Deneb Visual

### Step 1: Add the Visual

Create the visual and bindings through `pbir`:

```bash
pbir add visual deneb7E15AEF80B9E4D4F8E12924291ECE89A \
  "Report.Report/Page.Page" --name RevenueByCategoryDeneb
pbir visuals bind "Report.Report/Page.Page/RevenueByCategoryDeneb.Visual" \
  --add "dataset:Sales.Category" --type Column
pbir visuals bind "Report.Report/Page.Page/RevenueByCategoryDeneb.Visual" \
  --add "dataset:Sales.Revenue" --type Measure
```

All fields bind to the single `dataset` role. Use `Table.Column` for columns and `Table.Measure` for measures. Field names in bindings must match those used in the Vega/Vega-Lite spec.

### Step 2: Write the Spec

Create a Vega-Lite (or Vega) JSON spec file. Key difference:

- **Vega-Lite:** `"data": {"name": "dataset"}` (object)
- **Vega:** `"data": [{"name": "dataset"}]` (array)

```json
{
  "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
  "data": {"name": "dataset"},
  "mark": {"type": "bar", "tooltip": true},
  "encoding": {
    "y": {"field": "Category", "type": "nominal"},
    "x": {"field": "Value", "type": "quantitative"}
  }
}
```

See `examples/spec/` for complete spec files (Vega and Vega-Lite) and `examples/visual/` for full PBIR visual.json files. Field names in the spec must match the `nativeQueryRef` (display name) from the field bindings.

### Step 3: Inject the Spec

```bash
pbir visuals deneb "Report.Report/Page.Page/RevenueByCategoryDeneb.Visual" \
  --spec-file chart.vl.json --provider vegaLite
```

The CLI handles PBIR encoding. Keep ordinary Vega or Vega-Lite JSON in the spec file.

### Step 3b: Review

Before presenting the spec to the user, dispatch the `deneb-reviewer` agent to validate syntax and provide design feedback.

### Step 4: Validate

```bash
pbir visuals bind "Report.Report/Page.Page/RevenueByCategoryDeneb.Visual" --show
pbir validate "Report.Report" --all
```

## Spec Authoring Rules

### Data Binding

- Vega: `"data": [{"name": "dataset"}]` (array form)
- Vega-Lite: `"data": {"name": "dataset"}` (object form)
- Fields reference display names. Special characters (`.`, `[`, `]`, `\`, `"`) become `_`
- Spaces are NOT replaced -- field names keep their spaces (e.g., `"Order Lines"`)

### Field Name Escaping in Expressions (Critical)

Escaping depends on whether the spec is standalone or injected into a PBIR visual.json:

**Standalone spec files** (in `examples/spec/`): use double quotes with JSON escaping:

```json
{"calculate": "datum[\"Order Lines\"] - datum[\"Order Lines (PY)\"]", "as": "diff"}
```

**Inside PBIR visual.json** (in `examples/visual/`): the entire spec is a single-quoted DAX literal string. Field names with spaces use doubled single quotes (`''`):

```
datum[''Order Lines''] - datum[''Order Lines (PY)'']
```

Single quotes that are NOT part of field name escaping (e.g., string literals in filter expressions like `datum.Series == 'Actuals'`) work as-is because they don't conflict with the outer single-quote wrapper.

### Responsive Sizing (Vega)

Use Deneb's built-in signals for responsive container sizing:

```json
"width": {"signal": "pbiContainerWidth - 25"},
"height": {"signal": "pbiContainerHeight - 27"}
```

The offsets account for padding. For absolute positioning of text marks, use `{"signal": "width"}` instead of hardcoded pixel values.

### Config (Separate from Spec)

Always provide a config file for consistent styling. See the Standard Config section in `references/vega-patterns.md`. Key settings: `autosize: fit`, `view.stroke: transparent`, `font: Segoe UI`.

## Theme Integration

Use Power BI theme colors instead of hardcoded hex values:

| Function/Scheme | Purpose | Usage in Vega |
|-----------------|---------|---------------|
| `pbiColor(index)` | Theme color by index (0-based) | `{"signal": "pbiColor(0)"}` |
| `pbiColor(0, -0.3)` | Darken theme color by 30% | Shade: -1 (dark) to 1 (light) |
| `pbiColor("negative")` | Sentiment colors | `"min"`, `"middle"`, `"max"`, `"negative"`, `"positive"` |
| `pbiColor("bad")` | Aliases for sentiment | `"bad"` = `"negative"`, `"good"` = `"positive"`, `"neutral"` = `"middle"` |
| `pbiColorNominal` | Categorical palette (distinct) | `"range": {"scheme": "pbiColorNominal"}` |
| `pbiColorOrdinal` | Ordinal palette (ordered categories) | `"range": {"scheme": "pbiColorOrdinal"}` |
| `pbiColorLinear` | Continuous gradient | `"range": {"scheme": "pbiColorLinear"}` |
| `pbiColorDivergent` | Divergent gradient | `"range": {"scheme": "pbiColorDivergent"}` |

## Interactivity

Enable interactivity via the `vega` objects in visual.json:

| Feature | Property | Default | Notes |
|---------|----------|---------|-------|
| Tooltips | `enableTooltips` | `true` | Use `"tooltip": {"signal": "datum"}` in encode |
| Context menu | `enableContextMenu` | `true` | Right-click drill-through |
| Cross-filtering | `enableSelection` | `false` | Requires `__selected__` handling |
| Cross-highlighting | `enableHighlight` | `false` | Creates `<field>__highlight` fields |

### Cross-Filtering

When `enableSelection` is true, handle `__selected__` (`"on"`, `"off"`, `"neutral"`) in encode blocks. Selection modes: `simple` (auto-resolves, up to 250 data points) or `advanced` (Vega only; required for brush/lasso/region selection, supports up to 2500 via `options.limit`, exposes `pbiCrossFilterApply` and `pbiCrossFilterClear` signals). See `references/vega-patterns.md` for the simple pattern and `references/advanced-patterns.md` for the advanced signal API.

### Cross-Highlighting

Use layered marks -- background at reduced opacity, foreground shows `<field>__highlight` values. See `references/vega-patterns.md` for details.

### Special Runtime Fields

Deneb injects runtime fields into each dataset row. See `references/capabilities.md` for the full table.

Key fields: `__row__` (zero-based row index, replaces removed `__identity__`), `__selected__` (selection state), `<field>__highlight` + `<field>__highlightStatus` + `<field>__highlightComparator` (cross-highlighting), `<field>__formatted` (pre-formatted value string), `<field>__format` (Power BI format string).

> **Breaking change in 1.9:** `__identity__` and `__key__` were removed. Replace any `datum.__identity__` with `datum.__row__`.

## Best Practices

1. **Use Vega-Lite** for new visuals unless Vega-specific features are needed (signals, events, force layouts)
2. **Always use `autosize: fit`** in config for responsive Power BI sizing
3. **Use `pbiContainerWidth`/`pbiContainerHeight`** signals for responsive Vega specs
4. **Use theme colors** (`pbiColor`, `pbiColorNominal`) instead of hex values
5. **Use `enter`/`update`/`hover`** encode blocks for clean state management (Vega only)
6. **Enable tooltips** with `"tooltip": {"signal": "datum"}` on marks
7. **Performance** -- aggregate in DAX first, prefer `renderMode: canvas` for many marks, and only then raise `dataLimit.override`. See `references/advanced-patterns.md` for the full lever order
8. **Test field names** -- verify `nativeQueryRef` matches spec field references
9. **Avoid external data** -- AppSource certification prevents loading external URLs
10. **Escaping depends on context** -- double quotes in standalone specs, doubled single quotes in PBIR visual.json (see escaping rules above)

## When to Use Deneb

Deneb is the preferred choice for **advanced custom visuals** that need interactivity (cross-filtering, tooltips, hover effects) and go beyond what native Power BI visuals offer. Use Deneb when you need:

- Custom chart types not available natively (bullet charts, beeswarms, sankeys, etc.)
- Fine-grained control over visual encoding, animation, and interactivity
- Vector-based rendering (crisp at any size)

**Use SVG measures instead** for simple inline graphics in tables/cards (sparklines, data bars, progress bars) where interactivity is not needed. **Use Python/R instead** for statistical visualizations (distribution analysis, regression, correlation) where the focus is analytical rigor over interactivity.

## References

- **`references/community-examples.md`** -- 170+ community templates organized by chart type, with author citations and direct links
- **`references/vega-patterns.md`** -- Vega chart patterns (bar, line, scatter, donut, stacked, heatmap, area, lollipop, bullet, KPI card), standard config, transforms and scales reference
- **`references/vega-lite-patterns.md`** -- Vega-Lite chart patterns (for editing existing Vega-Lite visuals only)
- **`references/pbir-structure.md`** -- PBIR JSON structure (literal encoding, query state, interactivity example)
- **`references/capabilities.md`** -- Full Deneb object properties reference and template format (`usermeta` schema)
- **`references/advanced-patterns.md`** -- Advanced cross-filtering signals (Vega `pbiCrossFilterApply`/`pbiCrossFilterClear`), performance engineering lever order, and community template round-trip from the terminal
- **`examples/visual/bullet-chart.json`** -- PBIR visual.json: faceted bullet chart with conditional indicators and cross-filtering (Vega-Lite)
- **`examples/visual/kpi-card.json`** -- PBIR visual.json: KPI card with layered text and conditional % change coloring (Vega-Lite)
- **`examples/visual/trend-line.json`** -- PBIR visual.json: dual-series line chart with fold transform and color/legend mapping (Vega-Lite)
- **`examples/visual/ytd-comparison.json`** -- PBIR visual.json: YTD vs target with dashed lines, endpoint labels, number formatting, and rank-based filtering (Vega-Lite)
- **`examples/spec/vega/`** -- Standalone Vega spec files (bar-chart, line-chart) -- ready to inject into visual.json after escaping
- **`examples/spec/vega-lite/`** -- Standalone Vega-Lite spec files (bullet-chart, kpi-card) -- ready to inject after escaping
- **`examples/standard-config.json`** -- Standard config for all Deneb specs

## Fetching Docs

To retrieve current Power BI custom visual docs, use `microsoft_docs_search` + `microsoft_docs_fetch` (MCP) if available, otherwise `mslearn search` + `mslearn fetch` (CLI). Search based on the user's request and run multiple searches as needed to ensure sufficient context before proceeding. Note: Vega/Vega-Lite docs live at vega.github.io (not MS Learn) -- use `WebFetch` for those.

## Related Skills

- **`pbir-format`** (pbip plugin) -- PBIR JSON format reference
- **`pbi-report-design`** -- Layout and design best practices
- **`r-visuals`** -- R Script visuals (ggplot2)
- **`python-visuals`** -- Python Script visuals (matplotlib)
- **`svg-visuals`** -- SVG via DAX measures (lightweight inline graphics)
