Skip to content
Skills Library
Data & analytics · Building & coding

python-visuals

/python-visuals

Python visual creation and matplotlib/seaborn patterns for PBIR reports. Automatically invoke when the user mentions "Python visual", "matplotlib in Power BI", "seaborn in Power BI", "pythonVisual", or asks to "create a Python visual", "add a matplotlib chart", "write a Python visual script".

Licence
GPL-3.0
Last repository change
27.10.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
10
Scripts
2
HTML comments
0
URLs in SKILL.md
2
Deprecation

No signals detected. Repository changed on 27.10.2026, without references to retired models or APIs.

Licence

GPL-3.0, otwarta.

What to check before installing
  • 2 scripts in this package. Review them before installing, as Claude may execute them.

Scripts: examples/script/bar-chart.py, examples/script/trend-line.py

What it does and when to use it

Python visual creation and matplotlib/seaborn patterns for PBIR reports. Automatically invoke when the user mentions "Python visual", "matplotlib in Power BI", "seaborn in Power BI", "pythonVisual", or asks to "create a Python visual", "add a matplotlib chart", "write a Python visual script".

Triggers from the description

Python visualmatplotlib in Power BIseaborn in Power BIpythonVisualcreate a Python visualadd a matplotlib chartwrite a Python visual script
Original author description

Python visual creation and matplotlib/seaborn patterns for PBIR reports. Automatically invoke when the user mentions "Python visual", "matplotlib in Power BI", "seaborn in Power BI", "pythonVisual", or asks to "create a Python visual", "add a matplotlib chart", "write a Python visual script".

How it works

  1. Visual Identity
  2. Workflow: Creating a Python Visual
  3. PBIR Format
  4. Supported Libraries
  5. Best Practices
  6. Limitations
  7. Script Structure Template
  8. When to Use a Script Visual
  9. References
  10. Fetching Docs
Original SKILL.md headings · 196 lines, 1,288 words
SKILL.md preview
---
name: python-visuals
version: 26.40.3
description: Python visual creation and matplotlib/seaborn patterns for PBIR reports. Automatically invoke when the user mentions "Python visual", "matplotlib in Power BI", "seaborn in Power BI", "pythonVisual", or asks to "create a Python visual", "add a matplotlib chart", "write a Python visual script".
disable-model-invocation: true
---

# Python 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` on macOS or Windows; neither works on Linux, where path 2 is the only option. 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.

Python visuals execute matplotlib/seaborn scripts to render static PNG images on the Power BI canvas. **Prefer seaborn** over raw matplotlib for cleaner syntax and better defaults -- it handles most chart types with less code.

## Visual Identity

- **visualType:** `pythonVisual`
- **Data role:** `Values` (columns and measures, multiple allowed)
- **Data variable:** `dataset` (pandas DataFrame, auto-injected)
- **Row limit:** 150,000 rows
- **Output:** Static PNG at 72 DPI -- no interactivity

## Workflow: Creating a Python 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: pythonVisual`, 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

```python
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(dataset["Date"], dataset["Sales"], color="#5B8DBE")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.tight_layout()
plt.show()  # MANDATORY
```

Critical rules:
- `plt.show()` is **mandatory** as the final line -- nothing renders without it
- `dataset` is auto-injected as a pandas DataFrame; do not create it
- Column names match the projection's display label (`displayName` when set, otherwise `nativeQueryRef`) from field bindings
- Only the last `plt.show()` call renders; multiple figures not supported

### Step 2b: Review

Before presenting the script to the user, dispatch the `python-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: `'import matplotlib...\nplt.show()'`
- 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`:

```json
{
  "source": {"expr": {"Literal": {"Value": "'import matplotlib.pyplot as plt\\n...\\nplt.show()'"}}},
  "provider": {"expr": {"Literal": {"Value": "'Python'"}}}
}
```

The CLI handles all escaping automatically.

## Supported Libraries

### Power BI Service (Python 3.11)

| Package | Version | Purpose |
|---------|---------|---------|
| matplotlib | 3.8.4 | Primary plotting |
| seaborn | 0.13.2 | Statistical visualization |
| numpy | 2.0.0 | Numerical computing |
| pandas | 2.2.2 | Data manipulation |
| scipy | 1.13.1 | Scientific computing |
| scikit-learn | 1.5.0 | Machine learning |
| statsmodels | 0.14.2 | Statistical models |
| pillow | 10.4.0 | Image processing |

**Not supported:** plotly, bokeh, altair (networking blocked in Service).

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

### Desktop

Any locally installed package works without restriction.

## Best Practices

1. **Always call `plt.show()`** -- mandatory, must be the final line
2. **Use `figsize=(w, h)`** to match container aspect ratio (72 DPI output)
3. **Remove chart chrome** -- `ax.spines["top"].set_visible(False)` etc.
4. **Use hex colors** matching the report theme
5. **Keep scripts simple** -- 5-min timeout Desktop, 1-min Service
6. **Minimize transforms** -- do heavy computation in DAX/Power Query instead
7. **Use `try/except`** for robustness in production scripts
8. **Copy data first** -- `data = dataset.copy()` before manipulation

## Limitations

| Constraint | Desktop | Service |
|------------|---------|---------|
| Output | Static PNG, 72 DPI | Static PNG, 72 DPI |
| Timeout | 5 minutes | 1 minute |
| Row limit | 150,000 | 150,000 |
| Payload | -- | 30 MB |
| Networking | Unrestricted | Blocked |
| Gateway | Personal only | Personal only |
| Cross-filter FROM | Not supported | Not supported |
| Receive cross-filter | Yes | Yes |
| Publish to web | Not supported | Not supported |
| Embed (app-owns-data) | Not supported | Not supported |

## Script Structure Template

```python
import matplotlib.pyplot as plt
import numpy as np

# 1. Guard against empty data
if dataset.empty:
    fig, ax = plt.subplots(1, 1, figsize=(6, 4))
    ax.text(0.5, 0.5, "No data available", ha='center', va='center', fontsize=14, color='#888888')
    ax.axis('off')
    plt.show()
else:
    # 2. Data preparation (dataset is auto-injected)
    data = dataset.copy()

    # 3. Create figure with explicit size
    fig, ax = plt.subplots(figsize=(8, 4))

    # 4. Plot
    ax.plot(data["X"], data["Y"], color="#5B8DBE", linewidth=2)

    # 5. Style
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.grid(axis="y", alpha=0.3)

    # 6. Layout and render
    plt.tight_layout()
    plt.show()
```

## When to Use a Script Visual

Reach for a Python 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.

**Python vs R once a script visual is the right call:** use Python when the computation leans on scikit-learn, statsmodels, or scipy, or when surrounding report logic is already Python. Use R for publication-quality statistical defaults and packages with no Python peer (`forecast`, `corrplot`, `pheatmap`, ridgeline/violin). 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, the row/byte caps, and how to force per-row input
- **`references/community-examples.md`** -- seaborn gallery examples organized by chart type, plus matplotlib and Python Graph Gallery links
- **`references/chart-patterns.md`** -- Common matplotlib/seaborn chart patterns (bar, heatmap, donut, KPI, area)
- **`examples/script/`** -- Standalone Python scripts (bar-chart, trend-line) -- ready to inject into visual.json after escaping
- **`examples/visual/bar-chart.json`** -- PBIR visual.json: horizontal stacked bar with PY comparison lines and % change labels
- **`examples/visual/kpi-card.json`** -- PBIR visual.json: text-based KPI with value, % change indicator, and PY comparison
- **`examples/visual/trend-line.json`** -- PBIR visual.json: area chart with line plot and monthly x-axis

## Fetching Docs

To retrieve current Python visual / package support docs, use `microsoft_docs_search` + `microsoft_docs_fetch` (MCP) if available, otherwise search https://learn.microsoft.com and fetch the relevant pages. 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
- **`r-visuals`** -- R 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
Files in this package (10)
  • SKILL.md 9 KB
  • examples/script/bar-chart.py 1 KB
  • examples/script/trend-line.py 1 KB
  • examples/visual/bar-chart.json 6 KB
  • examples/visual/kpi-card.json 5 KB
  • examples/visual/trend-line.json 4 KB
  • examples/visual/ytd-line-chart.json 6 KB
  • references/chart-patterns.md 4 KB
  • references/community-examples.md 4 KB
  • references/data-model.md 2 KB

Versions

RepositoryScoreLicence
This page · insightfulanalytics/pbi_agentic_dev100GPL-3.0
data-goblin/power-bi-agentic-development100GPL-3.0

Database snapshot: 13.11.2026 · package version 0fabfc2f07b0 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100r-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".
  • 100r-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".
  • 90Power BI Visuals
    Add, configure, bind data to, and bulk-manage visuals on Power BI PBIR report pages using pbi-cli. Invoke this skill whenever the user mentions "add a chart", "bar chart", "line chart", "card", "KPI", "gauge", "scatter", "table visual", "matrix", "slicer", "combo chart", "bind…
  • 100power-bi-visuals
    Add, configure, bind data to, and bulk-manage visuals on Power BI PBIR report pages using pbi-cli. Invoke this skill whenever the user mentions "add a chart", "bar chart", "line chart", "card", "KPI", "gauge", "scatter", "table visual", "matrix", "slicer", "combo chart", "bind…
  • 100pbir-format
    Format reference for Power BI Enhanced Report (PBIR) JSON schemas and patterns. Automatically invoke when the user asks about PBIR JSON structure, visual.json properties, PBIR expressions, objects vs visualContainerObjects, theme inheritance, conditional formatting patterns,…
  • 100python-matplotlib-config
    Creates and reviews Matplotlib/Seaborn global style, CJK font fallback, reusable .mplstyle files, and Figure/Axes calling style. Use when creating/editing a style sheet or configuring plotting appearance/API behavior; applies one theme mechanism before fonts and prefers Axes…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.