Back to Blog
5 min read

Power BI April 2024 Updates: AI-Powered Analytics

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

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.