Skip to content
Back to Blog
1 min read

Power BI April 2024 Updates: AI-Powered Analytics

Power BI continues to evolve with AI-driven features that make data analysis more accessible. Here’s what’s new in April 2024.

Key Updates Overview

POWER_BI_APRIL_2024 = {
    "copilot_features": [
        "Report page generation from prompts",
        "Visual recommendations",
        "DAX suggestions",
        "Narrative generation"
    ],
    "visualization": [
        "New chart types",
        "Enhanced formatting options",
        "Improved mobile experience"
    ],
    "modeling": [
        "Enhanced calculation groups",
        "Improved relationships",
        "Better DirectQuery performance"
    ],
    "collaboration": [
        "Improved sharing",
        "Better embedding options",
        "Enhanced security"
    ]
}

Copilot in Power BI

Power BI Copilot now supports more sophisticated interactions:

# Example: Using Copilot APIs (when available)
# These demonstrate the types of interactions possible

COPILOT_PROMPTS = {
    "create_visual": "Create a bar chart showing sales by region for 2024",
    "add_filter": "Add a slicer for product category",
    "create_measure": "Create a measure for year-over-year growth",
    "explain_data": "Why did sales drop in March?",
    "suggest_visuals": "What visualizations would help analyze customer churn?"
}

# Copilot generates visuals based on data model understanding
# Example response for "Create a bar chart showing sales by region":
visual_config = {
    "type": "clusteredBarChart",
    "data": {
        "categories": "Geography[Region]",
        "values": "[Total Sales]"
    },
    "format": {
        "title": "Sales by Region - 2024",
        "dataLabels": True,
        "legend": False
    }
}

Working with Power BI REST API

import requests
from azure.identity import DefaultAzureCredential

class PowerBIClient:
    """Client for Power BI REST API"""

    def __init__(self):
        self.credential = DefaultAzureCredential()
        self.base_url = "https://api.powerbi.com/v1.0/myorg"

    def _get_headers(self):
        token = self.credential.get_token(
            "https://analysis.windows.net/powerbi/api/.default"
        )
        return {
            "Authorization": f"Bearer {token.token}",
            "Content-Type": "application/json"
        }

    def list_workspaces(self):
        """List all workspaces"""
        response = requests.get(
            f"{self.base_url}/groups",
            headers=self._get_headers()
        )
        return response.json().get("value", [])

    def list_reports(self, workspace_id: str):
        """List reports in workspace"""
        response = requests.get(
            f"{self.base_url}/groups/{workspace_id}/reports",
            headers=self._get_headers()
        )
        return response.json().get("value", [])

    def list_datasets(self, workspace_id: str):
        """List datasets in workspace"""
        response = requests.get(
            f"{self.base_url}/groups/{workspace_id}/datasets",
            headers=self._get_headers()
        )
        return response.json().get("value", [])

    def refresh_dataset(self, workspace_id: str, dataset_id: str):
        """Trigger dataset refresh"""
        response = requests.post(
            f"{self.base_url}/groups/{workspace_id}/datasets/{dataset_id}/refreshes",
            headers=self._get_headers()
        )
        return response.status_code == 202

    def execute_queries(self, workspace_id: str, dataset_id: str, query: str):
        """Execute DAX query"""
        response = requests.post(
            f"{self.base_url}/groups/{workspace_id}/datasets/{dataset_id}/executeQueries",
            headers=self._get_headers(),
            json={
                "queries": [{"query": query}],
                "serializerSettings": {"includeNulls": True}
            }
        )
        return response.json()

# Usage
client = PowerBIClient()

# List workspaces
workspaces = client.list_workspaces()
for ws in workspaces:
    print(f"Workspace: {ws['name']}")

# Execute DAX query
result = client.execute_queries(
    workspace_id="workspace-id",
    dataset_id="dataset-id",
    query="EVALUATE SUMMARIZE(Sales, 'Product'[Category], \"Total\", SUM(Sales[Amount]))"
)

New Visualization Features

# New chart configurations available in April 2024

NEW_VISUAL_FEATURES = {
    "small_multiples": {
        "description": "Create grid of charts by category",
        "config": {
            "rows": "Category",
            "columns": "Year",
            "visual": "lineChart"
        }
    },
    "anomaly_detection": {
        "description": "Automatic anomaly highlighting in line charts",
        "config": {
            "enabled": True,
            "sensitivity": 90,
            "explainBy": ["Category", "Region"]
        }
    },
    "dynamic_format_strings": {
        "description": "Conditional formatting based on values",
        "config": {
            "positive": "#00FF00",
            "negative": "#FF0000",
            "neutral": "#808080"
        }
    }
}

# DAX for dynamic formatting
dynamic_format_dax = """
VAR SalesGrowth = [Sales YoY %]
RETURN
    IF(
        SalesGrowth >= 0,
        FORMAT(SalesGrowth, "+0.0%"),
        FORMAT(SalesGrowth, "0.0%")
    )
"""

Enhanced DAX Capabilities

# New DAX patterns and functions

# Calculation Groups (enhanced in April 2024)
calculation_group_dax = """
-- Time Intelligence Calculation Group
CALCULATIONGROUP 'Time Intelligence'

CALCULATIONITEM "Current Period" = SELECTEDMEASURE()

CALCULATIONITEM "Prior Period" =
    CALCULATE(
        SELECTEDMEASURE(),
        DATEADD('Calendar'[Date], -1, YEAR)
    )

CALCULATIONITEM "YoY Change" =
    VAR CurrentValue = SELECTEDMEASURE()
    VAR PriorValue = CALCULATE(
        SELECTEDMEASURE(),
        DATEADD('Calendar'[Date], -1, YEAR)
    )
    RETURN
        DIVIDE(CurrentValue - PriorValue, PriorValue)

CALCULATIONITEM "Rolling 12M" =
    CALCULATE(
        SELECTEDMEASURE(),
        DATESINPERIOD('Calendar'[Date], MAX('Calendar'[Date]), -12, MONTH)
    )
"""

# Field Parameters (for dynamic axis/legend)
field_parameter_dax = """
Metric Selection = {
    ("Sales", NAMEOF([Total Sales]), 0),
    ("Quantity", NAMEOF([Total Quantity]), 1),
    ("Profit", NAMEOF([Total Profit]), 2),
    ("Margin %", NAMEOF([Profit Margin %]), 3)
}
"""

Embedding Power BI

from typing import Optional
import requests

class PowerBIEmbed:
    """Generate embed tokens for Power BI content"""

    def __init__(self, client: PowerBIClient):
        self.client = client
        self.base_url = "https://api.powerbi.com/v1.0/myorg"

    def get_embed_token(
        self,
        workspace_id: str,
        report_id: str,
        dataset_ids: list = None,
        access_level: str = "View"
    ) -> dict:
        """Generate embed token for report"""

        payload = {
            "accessLevel": access_level,
            "allowSaveAs": access_level == "Edit"
        }

        if dataset_ids:
            payload["datasetIds"] = dataset_ids

        response = requests.post(
            f"{self.base_url}/groups/{workspace_id}/reports/{report_id}/GenerateToken",
            headers=self.client._get_headers(),
            json=payload
        )

        return response.json()

    def get_embed_url(self, workspace_id: str, report_id: str) -> str:
        """Get embed URL for report"""
        report = requests.get(
            f"{self.base_url}/groups/{workspace_id}/reports/{report_id}",
            headers=self.client._get_headers()
        ).json()

        return report.get("embedUrl")

# Embed configuration for frontend
embed_config = {
    "type": "report",
    "tokenType": "Embed",
    "accessToken": "embed-token-here",
    "embedUrl": "https://app.powerbi.com/reportEmbed...",
    "id": "report-id",
    "settings": {
        "filterPaneEnabled": True,
        "navContentPaneEnabled": True,
        "layoutType": "custom",
        "customLayout": {
            "displayOption": "fitToWidth"
        }
    }
}

Performance Optimization

# Best practices for Power BI performance

PERFORMANCE_TIPS = {
    "data_model": [
        "Use star schema design",
        "Remove unnecessary columns",
        "Use appropriate data types",
        "Create relationships properly"
    ],
    "dax": [
        "Use variables to avoid recalculation",
        "Prefer CALCULATE over FILTER",
        "Use TREATAS for virtual relationships",
        "Avoid DISTINCTCOUNT on high cardinality"
    ],
    "visuals": [
        "Limit visuals per page to 8-10",
        "Use bookmarks for complex filters",
        "Enable query reduction settings",
        "Use aggregations for large datasets"
    ]
}

# Example: Optimized DAX measure
optimized_measure = """
Sales with Discount =
VAR DiscountRate = 0.1
VAR BaseSales = SUM(Sales[Amount])
VAR DiscountedItems =
    CALCULATE(
        SUM(Sales[Amount]),
        Sales[HasDiscount] = TRUE()
    )
RETURN
    BaseSales - (DiscountedItems * DiscountRate)
"""

Conclusion

Power BI’s April 2024 updates enhance AI-assisted analytics with Copilot improvements, new visualization capabilities, and better performance features. Take advantage of these updates to build more insightful reports.

Michael John Peña

Michael John Peña

Data & AI Director and Microsoft MVP based in Sydney. Writing about Microsoft Fabric, Azure, data engineering, and AI.