Power BI Visuals Skill
Create and manage visuals on PBIR report pages. No Power BI Desktop connection
is needed -- these commands operate directly on JSON files.
Adding Visuals
# Add by alias (pbi-cli resolves to the PBIR type)
pbi visual add --page page_abc123 --type bar
pbi visual add --page page_abc123 --type card --name "Revenue Card"
# Custom position and size (pixels)
pbi visual add --page page_abc123 --type scatter \
--x 50 --y 400 --width 600 --height 350
# Named visual for easy reference
pbi visual add --page page_abc123 --type combo --name sales_combo
Each visual is created as a folder with a visual.json file inside the page's
visuals/ directory. The template includes the correct schema URL and queryState
roles for the chosen type.
Binding Data
Visuals start empty. Use visual bind with Table[Column] notation to connect
them to your semantic model. The bind options vary by visual type -- see the
type table below.
# Bar chart: category axis + value
pbi visual bind mybar --page p1 \
--category "Geography[Region]" --value "Sales[Revenue]"
# Card: single field
pbi visual bind mycard --page p1 --field "Sales[Total Revenue]"
# Matrix: rows + values + optional column
pbi visual bind mymatrix --page p1 \
--row "Product[Category]" --value "Sales[Amount]" --value "Sales[Quantity]"
# Scatter: X, Y, detail, optional size and legend
pbi visual bind myscatter --page p1 \
--x "Sales[Quantity]" --y "Sales[Revenue]" --detail "Product[Name]"
# Combo chart: category + column series + line series
pbi visual bind mycombo --page p1 \
--category "Calendar[Month]" --column "Sales[Revenue]" --line "Sales[Margin]"
# KPI: indicator + goal + trend axis
pbi visual bind mykpi --page p1 \
--indicator "Sales[Revenue]" --goal "Sales[Target]" --trend "Calendar[Date]"
# Gauge: value + max/target
pbi visual bind mygauge --page p1 \
--value "Sales[Revenue]" --max "Sales[Target]"
Binding uses ROLE_ALIASES to translate friendly names like --value into the PBIR
role name (e.g. Y, Values, Data). Measure vs Column is inferred from the role:
value/indicator/goal/max roles create Measure references, category/row/detail roles
create Column references. Override with --measure flag if needed.
Inspecting and Updating
# List all visuals on a page
pbi visual list --page page_abc123
# Get full details of one visual
pbi visual get visual_def456 --page page_abc123
# Move, resize, or toggle visibility
pbi visual update vis1 --page p1 --width 600 --height 400
pbi visual update vis1 --page p1 --x 100 --y 200
pbi visual update vis1 --page p1 --hidden
pbi visual update vis1 --page p1 --visible
# Delete a visual
pbi visual delete visual_def456 --page page_abc123
Container Properties
Set border, background, or title on the visual container itself:
pbi visual set-container vis1 --page p1 --background "#F0F0F0"
pbi visual set-container vis1 --page p1 --border-color "#CCCCCC" --border-width 2
pbi visual set-container vis1 --page p1 --title "Sales by Region"
Visual Calculations
Add DAX calculations that run inside the visual scope:
pbi visual calc-add vis1 --page p1 --role Values \
--name "RunningTotal" --expression "RUNNINGSUM([Revenue])"
pbi visual calc-list vis1 --page p1
pbi visual calc-delete vis1 --page p1 --name "RunningTotal"
Bulk Operations
Operate on many visuals at once by filtering with --type or --name-pattern:
# Find visuals matching criteria
pbi visual where --page overview --type barChart
pbi visual where --page overview --type kpi --y-min 300
# Bind the same field to ALL bar charts on a page
pbi visual bulk-bind --page overview --type barChart \
--category "Date[Month]" --value "Sales[Revenue]"
# Resize all KPI cards
pbi visual bulk-update --page overview --type kpi --width 250 --height 120
# Hide all visuals matching a pattern
pbi visual bulk-update --page overview --name-pattern "Temp_*" --hidden
# Delete all placeholders
pbi visual bulk-delete --page overview --name-pattern "Placeholder_*"
Filter options for where, bulk-bind, bulk-update, bulk-delete:
--type -- PBIR visual type or alias (e.g. barChart, bar)
--name-pattern -- fnmatch glob on visual name (e.g. Chart_*)
--x-min, --x-max, --y-min, --y-max -- position bounds (pixels)
All bulk commands require at least --type or --name-pattern to prevent
accidental mass operations.
Supported Visual Types (32)
Charts
| Alias |
PBIR Type |
Bind Options |
| bar |
barChart |
--category, --value, --legend |
| line |
lineChart |
--category, --value, --legend |
| column |
columnChart |
--category, --value, --legend |
| area |
areaChart |
--category, --value, --legend |
| ribbon |
ribbonChart |
--category, --value, --legend |
| waterfall |
waterfallChart |
--category, --value, --breakdown |
| stacked_bar |
stackedBarChart |
--category, --value, --legend |
| clustered_bar |
clusteredBarChart |
--category, --value, --legend |
| clustered_column |
clusteredColumnChart |
--category, --value, --legend |
| scatter |
scatterChart |
--x, --y, --detail, --size, --legend |
| funnel |
funnelChart |
--category, --value |
| combo |
lineStackedColumnComboChart |
--category, --column, --line, --legend |
| donut / pie |
donutChart |
--category, --value, --legend |
| treemap |
treemap |
--category, --value |
Cards and KPIs
| Alias |
PBIR Type |
Bind Options |
| card |
card |
--field |
| card_visual |
cardVisual |
--field (modern card) |
| card_new |
cardNew |
--field |
| multi_row_card |
multiRowCard |
--field |
| kpi |
kpi |
--indicator, --goal, --trend |
| gauge |
gauge |
--value, --max / --target |
Tables
| Alias |
PBIR Type |
Bind Options |
| table |
tableEx |
--value |
| matrix |
pivotTable |
--row, --value, --column |
Slicers
| Alias |
PBIR Type |
Bind Options |
| slicer |
slicer |
--field |
| text_slicer |
textSlicer |
--field |
| list_slicer |
listSlicer |
--field |
| advanced_slicer |
advancedSlicerVisual |
--field (tile/image slicer) |
Maps
| Alias |
PBIR Type |
Bind Options |
| azure_map / map |
azureMap |
--category, --size |
Decorative and Navigation
| Alias |
PBIR Type |
Bind Options |
| action_button |
actionButton |
(no data binding) |
| image |
image |
(no data binding) |
| shape |
shape |
(no data binding) |
| textbox |
textbox |
(no data binding) |
| page_navigator |
pageNavigator |
(no data binding) |
Suppressing Auto-Sync (--no-sync)
By default, every write command automatically syncs Power BI Desktop. When
adding or binding many visuals in sequence, Desktop reloads after each one.
Use --no-sync on the visual command group to batch all changes, then call
pbi report reload once at the end:
# Suppress sync while building visuals
pbi visual --no-sync add --page overview --type card --name rev_card
pbi visual --no-sync bind rev_card --page overview --field "Sales[Total Revenue]"
pbi visual --no-sync add --page overview --type bar --name sales_bar
pbi visual --no-sync bind sales_bar --page overview --category "Product[Category]" --value "Sales[Revenue]"
# Single reload when all visuals are done
pbi report reload
JSON Output
All commands support --json for agent consumption:
pbi --json visual list --page overview
pbi --json visual get vis1 --page overview
pbi --json visual where --page overview --type barChart
Gotchas
visual bind infers Measure vs Column from the role, not the underlying TMDL object: A role like --value always creates a Measure reference. If Sales[Revenue] is actually a column (not a measure), the visual renders BLANK with no error. Use --measure or rename to a real measure.
bulk-bind without --type or --name-pattern is blocked, but with a too-loose pattern it can rebind unrelated visuals: --name-pattern "Chart_*" matches Chart_Revenue, Chart_Margin, AND Chart_Drillthrough_Hidden. Always preview with pbi visual where first.
- Visual position
--x/--y is in report-design pixels, not screen pixels: A --x 1280 on a 1280-wide canvas places the visual at the right edge regardless of viewer screen size. Visuals positioned past canvas bounds render off-screen with no warning.
- Visual calculations via
calc-add run AFTER measures in the visual scope: Referencing a measure inside a visual calculation captures the post-filter value. Iterating over the calc as if it were a measure (e.g. inside SUMX) produces unexpected results because the calc only exists within the visual's query scope.
- PBIR visual
name is the folder slug — renaming requires file system move, not a CLI flag: The --name flag only applies at creation. Subsequent visual update does not rename. To rename, delete + re-add (losing the visual ID) or edit the file system directly.
bulk-delete --name-pattern "Placeholder_*" is irreversible and skips no confirmation: Each delete is a folder removal; combined with --no-sync you can wipe dozens of visuals before noticing. Always run pbi visual where with the same pattern first.
1---
2name: power-bi-visuals
3description: >
4 Add, configure, bind data to, and bulk-manage visuals on Power BI PBIR report
5 pages using pbi-cli. Invoke this skill whenever the user mentions "add a chart",
6 "bar chart", "line chart", "card", "KPI", "gauge", "scatter", "table visual",
7 "matrix", "slicer", "combo chart", "bind data", "visual type", "visual layout",
8 "resize visuals", "bulk update visuals", "bulk delete", "visual calculations",
9 or wants to place, move, bind, or remove any visual on a report page. Also invoke
10 when the user asks what visual types are supported or how to connect a visual to
11 their data model.
12tools: pbi-cli
13---
14
15# Power BI Visuals Skill
16
17Create and manage visuals on PBIR report pages. No Power BI Desktop connection
18is needed -- these commands operate directly on JSON files.
19
20## Adding Visuals
21
22```bash
23# Add by alias (pbi-cli resolves to the PBIR type)
24pbi visual add --page page_abc123 --type bar
25pbi visual add --page page_abc123 --type card --name "Revenue Card"
26
27# Custom position and size (pixels)
28pbi visual add --page page_abc123 --type scatter \
29 --x 50 --y 400 --width 600 --height 350
30
31# Named visual for easy reference
32pbi visual add --page page_abc123 --type combo --name sales_combo
33```
34
35Each visual is created as a folder with a `visual.json` file inside the page's
36`visuals/` directory. The template includes the correct schema URL and queryState
37roles for the chosen type.
38
39## Binding Data
40
41Visuals start empty. Use `visual bind` with `Table[Column]` notation to connect
42them to your semantic model. The bind options vary by visual type -- see the
43type table below.
44
45```bash
46# Bar chart: category axis + value
47pbi visual bind mybar --page p1 \
48 --category "Geography[Region]" --value "Sales[Revenue]"
49
50# Card: single field
51pbi visual bind mycard --page p1 --field "Sales[Total Revenue]"
52
53# Matrix: rows + values + optional column
54pbi visual bind mymatrix --page p1 \
55 --row "Product[Category]" --value "Sales[Amount]" --value "Sales[Quantity]"
56
57# Scatter: X, Y, detail, optional size and legend
58pbi visual bind myscatter --page p1 \
59 --x "Sales[Quantity]" --y "Sales[Revenue]" --detail "Product[Name]"
60
61# Combo chart: category + column series + line series
62pbi visual bind mycombo --page p1 \
63 --category "Calendar[Month]" --column "Sales[Revenue]" --line "Sales[Margin]"
64
65# KPI: indicator + goal + trend axis
66pbi visual bind mykpi --page p1 \
67 --indicator "Sales[Revenue]" --goal "Sales[Target]" --trend "Calendar[Date]"
68
69# Gauge: value + max/target
70pbi visual bind mygauge --page p1 \
71 --value "Sales[Revenue]" --max "Sales[Target]"
72```
73
74Binding uses ROLE_ALIASES to translate friendly names like `--value` into the PBIR
75role name (e.g. `Y`, `Values`, `Data`). Measure vs Column is inferred from the role:
76value/indicator/goal/max roles create Measure references, category/row/detail roles
77create Column references. Override with `--measure` flag if needed.
78
79## Inspecting and Updating
80
81```bash
82# List all visuals on a page
83pbi visual list --page page_abc123
84
85# Get full details of one visual
86pbi visual get visual_def456 --page page_abc123
87
88# Move, resize, or toggle visibility
89pbi visual update vis1 --page p1 --width 600 --height 400
90pbi visual update vis1 --page p1 --x 100 --y 200
91pbi visual update vis1 --page p1 --hidden
92pbi visual update vis1 --page p1 --visible
93
94# Delete a visual
95pbi visual delete visual_def456 --page page_abc123
96```
97
98## Container Properties
99
100Set border, background, or title on the visual container itself:
101
102```bash
103pbi visual set-container vis1 --page p1 --background "#F0F0F0"
104pbi visual set-container vis1 --page p1 --border-color "#CCCCCC" --border-width 2
105pbi visual set-container vis1 --page p1 --title "Sales by Region"
106```
107
108## Visual Calculations
109
110Add DAX calculations that run inside the visual scope:
111
112```bash
113pbi visual calc-add vis1 --page p1 --role Values \
114 --name "RunningTotal" --expression "RUNNINGSUM([Revenue])"
115
116pbi visual calc-list vis1 --page p1
117pbi visual calc-delete vis1 --page p1 --name "RunningTotal"
118```
119
120## Bulk Operations
121
122Operate on many visuals at once by filtering with `--type` or `--name-pattern`:
123
124```bash
125# Find visuals matching criteria
126pbi visual where --page overview --type barChart
127pbi visual where --page overview --type kpi --y-min 300
128
129# Bind the same field to ALL bar charts on a page
130pbi visual bulk-bind --page overview --type barChart \
131 --category "Date[Month]" --value "Sales[Revenue]"
132
133# Resize all KPI cards
134pbi visual bulk-update --page overview --type kpi --width 250 --height 120
135
136# Hide all visuals matching a pattern
137pbi visual bulk-update --page overview --name-pattern "Temp_*" --hidden
138
139# Delete all placeholders
140pbi visual bulk-delete --page overview --name-pattern "Placeholder_*"
141```
142
143Filter options for `where`, `bulk-bind`, `bulk-update`, `bulk-delete`:
144- `--type` -- PBIR visual type or alias (e.g. `barChart`, `bar`)
145- `--name-pattern` -- fnmatch glob on visual name (e.g. `Chart_*`)
146- `--x-min`, `--x-max`, `--y-min`, `--y-max` -- position bounds (pixels)
147
148All bulk commands require at least `--type` or `--name-pattern` to prevent
149accidental mass operations.
150
151## Supported Visual Types (32)
152
153### Charts
154
155| Alias | PBIR Type | Bind Options |
156|--------------------|------------------------------|-----------------------------------------------|
157| bar | barChart | --category, --value, --legend |
158| line | lineChart | --category, --value, --legend |
159| column | columnChart | --category, --value, --legend |
160| area | areaChart | --category, --value, --legend |
161| ribbon | ribbonChart | --category, --value, --legend |
162| waterfall | waterfallChart | --category, --value, --breakdown |
163| stacked_bar | stackedBarChart | --category, --value, --legend |
164| clustered_bar | clusteredBarChart | --category, --value, --legend |
165| clustered_column | clusteredColumnChart | --category, --value, --legend |
166| scatter | scatterChart | --x, --y, --detail, --size, --legend |
167| funnel | funnelChart | --category, --value |
168| combo | lineStackedColumnComboChart | --category, --column, --line, --legend |
169| donut / pie | donutChart | --category, --value, --legend |
170| treemap | treemap | --category, --value |
171
172### Cards and KPIs
173
174| Alias | PBIR Type | Bind Options |
175|--------------------|------------------------------|-----------------------------------------------|
176| card | card | --field |
177| card_visual | cardVisual | --field (modern card) |
178| card_new | cardNew | --field |
179| multi_row_card | multiRowCard | --field |
180| kpi | kpi | --indicator, --goal, --trend |
181| gauge | gauge | --value, --max / --target |
182
183### Tables
184
185| Alias | PBIR Type | Bind Options |
186|--------------------|------------------------------|-----------------------------------------------|
187| table | tableEx | --value |
188| matrix | pivotTable | --row, --value, --column |
189
190### Slicers
191
192| Alias | PBIR Type | Bind Options |
193|--------------------|------------------------------|-----------------------------------------------|
194| slicer | slicer | --field |
195| text_slicer | textSlicer | --field |
196| list_slicer | listSlicer | --field |
197| advanced_slicer | advancedSlicerVisual | --field (tile/image slicer) |
198
199### Maps
200
201| Alias | PBIR Type | Bind Options |
202|--------------------|------------------------------|-----------------------------------------------|
203| azure_map / map | azureMap | --category, --size |
204
205### Decorative and Navigation
206
207| Alias | PBIR Type | Bind Options |
208|--------------------|------------------------------|-----------------------------------------------|
209| action_button | actionButton | (no data binding) |
210| image | image | (no data binding) |
211| shape | shape | (no data binding) |
212| textbox | textbox | (no data binding) |
213| page_navigator | pageNavigator | (no data binding) |
214
215## Suppressing Auto-Sync (--no-sync)
216
217By default, every write command automatically syncs Power BI Desktop. When
218adding or binding many visuals in sequence, Desktop reloads after each one.
219
220Use `--no-sync` on the `visual` command group to batch all changes, then call
221`pbi report reload` once at the end:
222
223```bash
224# Suppress sync while building visuals
225pbi visual --no-sync add --page overview --type card --name rev_card
226pbi visual --no-sync bind rev_card --page overview --field "Sales[Total Revenue]"
227pbi visual --no-sync add --page overview --type bar --name sales_bar
228pbi visual --no-sync bind sales_bar --page overview --category "Product[Category]" --value "Sales[Revenue]"
229
230# Single reload when all visuals are done
231pbi report reload
232```
233
234## JSON Output
235
236All commands support `--json` for agent consumption:
237
238```bash
239pbi --json visual list --page overview
240pbi --json visual get vis1 --page overview
241pbi --json visual where --page overview --type barChart
242```
243
244---
245
246## Gotchas
247
248- **`visual bind` infers Measure vs Column from the role, not the underlying TMDL object:** A role like `--value` always creates a Measure reference. If `Sales[Revenue]` is actually a column (not a measure), the visual renders BLANK with no error. Use `--measure` or rename to a real measure.
249- **`bulk-bind` without `--type` or `--name-pattern` is blocked, but with a too-loose pattern it can rebind unrelated visuals:** `--name-pattern "Chart_*"` matches `Chart_Revenue`, `Chart_Margin`, AND `Chart_Drillthrough_Hidden`. Always preview with `pbi visual where` first.
250- **Visual position `--x`/`--y` is in report-design pixels, not screen pixels:** A `--x 1280` on a 1280-wide canvas places the visual at the right edge regardless of viewer screen size. Visuals positioned past canvas bounds render off-screen with no warning.
251- **Visual calculations via `calc-add` run AFTER measures in the visual scope:** Referencing a measure inside a visual calculation captures the post-filter value. Iterating over the calc as if it were a measure (e.g. inside `SUMX`) produces unexpected results because the calc only exists within the visual's query scope.
252- **PBIR visual `name` is the folder slug — renaming requires file system move, not a CLI flag:** The `--name` flag only applies at creation. Subsequent `visual update` does not rename. To rename, delete + re-add (losing the visual ID) or edit the file system directly.
253- **`bulk-delete --name-pattern "Placeholder_*"` is irreversible and skips no confirmation:** Each delete is a folder removal; combined with `--no-sync` you can wipe dozens of visuals before noticing. Always run `pbi visual where` with the same pattern first.
254