Power-bi-agentic-development r-visuals

R visual creation and ggplot2 patterns for PBIR reports. Automatically invoke when the user mentions "R visual", "ggplot2", "ggplot in Power BI", or asks to "create an R visual", "add an R chart", "write an R visual script", "inject an R script into Power BI".

install
source · Clone the upstream repo
git clone https://github.com/data-goblin/power-bi-agentic-development
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/data-goblin/power-bi-agentic-development "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/reports/skills/r-visuals" ~/.claude/skills/data-goblin-power-bi-agentic-development-r-visuals && rm -rf "$T"
manifest: plugins/reports/skills/r-visuals/SKILL.md
source content

R Visuals in Power BI (PBIR)

Report modification requires tooling. Two paths exist:

  1. pbir
    CLI (preferred)
    -- use the
    pbir
    command and the
    pbir-cli
    skill. Install with
    uv tool install pbir-cli
    or
    pip install pbir-cli
    . Check availability with
    pbir --version
    .
  2. Direct JSON modification -- if
    pbir
    is not available, use the
    pbir-format
    skill (pbip plugin) for PBIR JSON structure and patterns. Validate every change with
    jq empty <file.json>
    .

If neither the

pbir-cli
skill nor the
pbir-format
skill is loaded, ask the user to install the appropriate plugin before proceeding with report modifications.

R visuals execute R scripts (primarily ggplot2) to render static PNG images on the Power BI canvas. ggplot2 is the preferred library -- its grammar of graphics approach produces clean, publication-quality statistical visualizations with less code. R is particularly strong for statistical visualizations.

Visual Identity

  • visualType:
    scriptVisual
  • Data role:
    Values
    (columns and measures, multiple allowed)
  • Data variable:
    dataset
    (data.frame, auto-injected)
  • Row limit: 150,000 rows
  • Output: Static PNG at 72 DPI -- no interactivity

Workflow: Creating an R Visual

Step 1: Add the Visual

Create the visual.json file manually (see

pbir-format
skill in the pbip plugin for JSON structure) with
visualType: scriptVisual
, field bindings for the columns and measures you need (use
Values:Table.Column
or
Values:Table.Measure
format), and position/size as required.

Step 2: Write the Script

library(ggplot2)

p <- ggplot(dataset, aes(x=Date, y=Sales)) +
  geom_col(fill="#5B8DBE") +
  theme_minimal(base_size=12) +
  theme(panel.grid.major.x=element_blank())

print(p)  # MANDATORY for ggplot2

Critical rules:

  • print(p)
    is mandatory for ggplot2 objects -- they do not auto-display in Power BI
  • dataset
    is auto-injected as a data.frame; do not create it
  • Access columns by index (
    dataset[,1]
    ) to avoid name escaping issues
  • Use backticks for column names with spaces:
    dataset$`Order Lines`

Step 2b: Review

Before presenting the script to the user, dispatch the

r-reviewer
agent to validate correctness and provide design feedback.

Step 3: Inject the Script

Set the script content in the visual's

objects.script[0].properties.source
literal value (see PBIR Format section below).

Escaping rules for visual.json injection:

The script must be encoded as a single-quoted DAX literal string inside

expr.Literal.Value
:

  • Newlines in the script become
    \n
    in the JSON string
  • Double quotes inside the script (e.g.,
    "#5B8DBE"
    ) become
    \"
    in the JSON string
  • The entire script is wrapped in single quotes:
    'library(ggplot2)\n...\nprint(p)'
  • See
    examples/visual/
    for a complete real-world visual.json showing this encoding

Step 4: Validate

Validate JSON syntax with

jq empty <visual.json>
and inspect the visual.json to confirm script content and field bindings.

PBIR Format

Scripts are stored in

visual.objects.script[0].properties
:

{
  "source": {"expr": {"Literal": {"Value": "'library(ggplot2)\\n...\\nprint(p)'"}}},
  "provider": {"expr": {"Literal": {"Value": "'R'"}}}
}

Identical structure to Python visuals except

visualType
is
scriptVisual
and
provider
is
'R'
.

Supported Packages

Power BI Service (R 4.3.3)

PackageVersionPurpose
ggplot23.5.1Grammar of graphics
dplyr1.1.4Data manipulation
tidyr1.3.1Data tidying
ggrepel0.9.5Non-overlapping labels
patchwork1.2.0Compose multiple plots
cowplot1.1.3Publication-quality plots
corrplot0.94Correlation matrices
viridis0.6.5Color scales
RColorBrewer1.1-3Color palettes
forecast8.23.0Time series forecasting
pheatmap1.0.12Heatmaps
treemap2.4-4Treemaps
lattice0.22-6Trellis graphics

~1000 CRAN packages available. Not supported: packages requiring networking (RgoogleMaps, mailR).

Full package list: https://learn.microsoft.com/power-bi/connect-data/service-r-packages-support

Desktop

Any locally installed R package works without restriction. R must be installed separately.

Best Practices

  1. Always call
    print(p)
    -- ggplot2 objects require explicit printing
  2. Guard against empty data --
    if (nrow(dataset) == 0) { plot.new(); text(0.5, 0.5, "No data") }
  3. Use index-based column access --
    dataset[,1]
    avoids name escaping issues
  4. Use
    theme_minimal()
    -- clean aesthetic that works well with Power BI
  5. Factor categorical variables -- control sort order explicitly with
    factor()
  6. Use hex colors matching the report theme
  7. Set margins --
    plot.margin=margin(t, r, b, l)
    to prevent clipping
  8. Keep scripts concise -- 5-min timeout Desktop, 1-min Service

Limitations

ConstraintDesktopService
OutputStatic PNG, 72 DPIStatic PNG, 72 DPI
Timeout5 minutes1 minute
Row limit150,000150,000
Output size2 MB30 MB
NetworkingUnrestrictedBlocked
GatewayPersonal onlyPersonal only
Cross-filter FROMNot supportedNot supported
Receive cross-filterYesYes
Publish to webNot supportedNot supported
Embed (app-owns-data)Ending May 2026Ending May 2026

Script Structure Template

library(ggplot2)

# 1. Guard against empty data
if (nrow(dataset) == 0) {
  plot.new()
  text(0.5, 0.5, "No data available", cex=1.5)
} else {
  # 2. Data preparation (index-based access)
  df <- data.frame(
    category = dataset[,1],
    value = dataset[,2]
  )

  # 3. Create visualization
  p <- ggplot(df, aes(x=reorder(category, -value), y=value)) +
    geom_col(fill="#5B8DBE", width=0.7) +
    theme_minimal(base_size=12) +
    theme(
      panel.grid.major.x = element_blank(),
      axis.title = element_blank()
    )

  # 4. Render
  print(p)
}

R vs Python Comparison

AspectR (
scriptVisual
)
Python (
pythonVisual
)
Primary libraryggplot2matplotlib
Render call
print(p)
plt.show()
Column access
dataset[,1]
or
dataset$col
dataset.iloc[:,0]
or
dataset["col"]
Empty guard
if (nrow(dataset) == 0)
if len(dataset) == 0:
Factor control
factor(x, levels=...)
pd.Categorical(x, categories=...)
Runtime (Service)R 4.3.3Python 3.11

When to Use R Visuals

R visuals are the preferred choice for statistical and analytical visualizations, particularly where R's statistical ecosystem excels. Use R visuals when you need:

  • Distribution analysis (violin, ridgeline, density, boxplot)
  • Statistical modeling (regression, correlation, ANOVA)
  • Publication-quality analytical charts with ggplot2
  • Packages like forecast, corrplot, pheatmap that have no Python equivalent of equal quality

Output is static PNG -- no cross-filtering FROM the visual, no hover/tooltip interactivity. Use Deneb instead for interactive custom visuals. Use SVG measures for simple inline graphics in tables/cards.

References

  • references/community-examples.md
    -- R Graph Gallery examples organized by chart type (distribution, correlation, ranking, evolution, flow)
  • references/ggplot2-patterns.md
    -- Common ggplot2 chart patterns (bar, donut, line, heatmap, bullet)
  • examples/script/
    -- Standalone R scripts (bar-chart, trend-line) -- ready to inject into visual.json after escaping
  • examples/visual/bullet-chart.json
    -- PBIR visual.json: bullet chart with conditional coloring, error handling, and extensive escaping
  • examples/visual/bar-chart.json
    -- PBIR visual.json: horizontal bar with PY comparison lines and colored account labels
  • examples/visual/trend-line.json
    -- PBIR visual.json: area chart with ribbon plot and month factor handling

Fetching Docs

To retrieve current R visual / package support 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.

Related Skills

  • pbi-report-design
    -- Layout and design best practices
  • python-visuals
    -- Python Script visuals (same concept, different language)
  • deneb-visuals
    -- Vega/Vega-Lite visuals (interactive, vector-based alternative)
  • svg-visuals
    -- SVG via DAX measures (lightweight inline graphics)
  • pbir-format
    (pbip plugin) -- PBIR JSON format reference