Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
data-goblin avatar

R Visuals

  • 33 installs
  • 836 repo stars
  • Updated July 29, 2026
  • data-goblin/power-bi-agentic-development

Create R visuals in Power BI PBIR reports using ggplot2 patterns, injecting R scripts into the report.

About

Guidance for creating R visuals in PBIR reports with ggplot2 patterns. A developer uses it to add an R-scripted chart to a Power BI report via the pbir CLI or direct JSON editing.

  • Creates R visuals with ggplot2 in PBIR reports
  • Applies via pbir CLI or direct PBIR JSON edits

R Visuals by the numbers

  • 33 all-time installs (skills.sh)
  • Ranked #1,088 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/data-goblin/power-bi-agentic-development --skill r-visuals

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs33
repo stars836
Last updatedJuly 29, 2026
Repositorydata-goblin/power-bi-agentic-development

What it does

Create R visuals in Power BI PBIR reports using ggplot2 patterns, injecting R scripts into the report.

Files

SKILL.mdMarkdownGitHub ↗

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)Not supportedNot supported

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 Syntax Reference

For the language-choice decision, see the "When to Use a Script Visual" section above. This table covers only mechanical syntax differences for scripts already committed to R:

AspectR (scriptVisual)Python (pythonVisual)
Render callprint(p)plt.show()
Column accessdataset[,1] or dataset$coldataset.iloc[:,0] or dataset["col"]
Empty guardif (nrow(dataset) == 0)if len(dataset) == 0:
Factor/category orderfactor(x, levels=...)pd.Categorical(x, categories=...)
Runtime (Service)R 4.3.3Python 3.11

When to Use a Script Visual

Reach for an R visual only when all of the following hold:

  • The chart has no native equivalent and no reasonable Deneb spec
  • The value is in a statistical computation that must run at render time (model fit, kernel density, forecast band), not just a shape Vega could draw
  • The visual does not need to be a cross-filter source, hover tooltips, publish-to-web, or app-owns-data embed
  • The report is served in a Pro/PPU or higher capacity with a Fabric-enabled region

If interactivity or cross-filtering matters, use Deneb (a static PNG cannot be a selection source). If the need is a small inline mark (sparkline, bar, status pill), use an SVG measure (no row cap, no timeout, no licensing/region gate, renders under publish-to-web). The script visual's niche is narrow: compute-at-render statistical plots for internal or org consumption.

R vs Python once a script visual is the right call: use R for publication-quality statistical defaults and packages with no Python peer (forecast, corrplot, pheatmap, ridgeline/violin). Use Python when the computation leans on scikit-learn, statsmodels, or scipy, or when surrounding report logic is already Python. Where equal, default to whichever language the report's other scripts use; mixing doubles the publish-time package surface to validate.

Do not default to a script visual because a chart type "looks statistical." A box plot, lollipop, or dumbbell is an SVG-measure or Deneb job; reserve scripts for charts that genuinely compute.

References

  • `references/data-model.md` -- dataset grouping mechanic, row/byte caps, forcing per-row input, and R-specific traps (Time type, text rendering flags, CJK fonts)
  • `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

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.