TMDL demo 2/3: Change Tracker

Disclaimer

This blog post is part of a three-part series based on my speaker session at the European Microsoft Fabric Community Conference 2025 (FabCon) in Vienna, which I had the pleasure of delivering together with my colleague Roger Unholz.

Our session, titled “TMDL Playoffs”, was a fast-paced showdown where we shared our favorite tips and tricks for working with TMDL. In this series, I’ll take a deeper dive into each topic we presented on stage and explore them in more detail.All source files referenced throughout the posts are available in my public GitHub repository.

Please note, that the scripts are not tested for every scenario, that they are only created for demonstration purposes and should never be applied on any running, productive enviroments.
Link: ivsch/TMDLPlayoffs.

Situation

For semantic models in Power BI, it is always recommended to maintain a proper version history. Now, I am not talking about version control—we can already achieve that using TMDL and a proper repository. This post is about tracking the semantic model from a business point of view. This means that customers can see the changes to a report in a manual table, which could also be displayed in a Power BI report using the semantic model.

Since I don’t want to spend time re-investigating every small change I’ve made to a semantic model, I still need a way for customers to clearly see what has changed in their semantic models.

For this demo, I already have a Power BI semantic model saved in TMDL format with a manual table for the semantic model version (file is in GitHub folder “Ivo” > “SM Change Tracker”). In the report view of the Power BI file, there is also a page showing the visual representation of the table.

Idea

As TMDL provides a proper definition of all objects within a semantic model, it is a solid basis for tracking changes from one version to another. What I’d like to do is compare all the changes I have made in my local model with the one published in a Power BI workspace.

For this comparison, I’d like to follow this process:

  1. Download the published semantic model via the Fabric REST API and store it locally.
  2. Compare the TMDL definitions and generate a difference report.
  3. Send the diff report to an LLM, which will summarize the differences in a clear, understandable way. The LLM should also classify each change as minor or major in order to properly increase the version number.
  4. Write the new version number and description back to the local semantic model. As the target table is a manual table, the data is stored within the TMDL definition and can easily be updated.
  5. Publish the updated report again to the destination (this step remains manual for now).

Prerequisites for using the REST API

Before you can call the Microsoft Fabric API with a service principal (like in this demo), a few prerequisites need to be set up. First, create an app registration in Entra ID (this is your service principal). Then, generate a client secret and keep both the ID and secret safe — these will be used for authentication.

Next, place the app registration into a security group that has access to Fabric/Power BI. In the Azure Portal, link this security group to the app registration (important: this step is done in the Azure Portal, not just inside Entra ID). You’ll also need the Tenant ID (and the ctid value mentioned in the setup) to include in your API calls.

Finally, check the Power BI Admin settings to ensure service principals are allowed to use APIs. Without this toggle enabled, the service principal won’t be able to access Fabric resources programmatically.

In short: register the app, generate a secret, put it into the right security group, grab the tenant details, and confirm admin permissions. Once those are in place, the service principal can authenticate directly to the Fabric API.

Solution

Because the process involves authentication, downloading model definitions, and file handling, a Jupyter notebook is used to orchestrate everything in one place. This could also run in any Jupyter environment, also directly inside Fabric to keep the workflow closer to the data and services.

The following text represantion just descibes some part of the notebook code. The notebook is called compare-sm.ipynb and also available in the GitHub repository.

Download the published semantic model

  • Authenticates against Fabric with the service principal (client ID, secret, tenant ID).
  • Calls the Fabric API getDefinition to export the current published semantic model in TMDL format.
  • Saves all model definition files into a definition_published/ folder locally.

Compare local vs. published versions

  • Loads your local semantic model (from the .pbip project).
  • Compares it line by line with the published TMDL version.
  • Produces a structured diff report (index.md) showing what was added, removed, or changed.

Summarize changes with an LLM

  • The diff report is sent to an Awan LLM (Meta-Llama-3.1).
  • The LLM generates a short, business-friendly summary of the changes (max 50 words).
  • It also labels the change as [MAJOR] (structural, new objects) or [MINOR] (renames, small tweaks).

Parse the LLM output

  • Extracts the summary text and the change tag (MAJOR/MINOR).

Update the version log inside the semantic model

  • Re-encodes and writes the updated version history back into the TMDL file (with a backup saved).
  • Opens the Semantic Model Version.tmdl file, which stores version history in a compressed payload.
  • Reads existing version numbers and finds the last version.
  • Bumps the version automatically:
    • MAJOR → increments the major version (1.3 → 2.0).
    • MINOR → increments the minor version (1.3 → 1.4).
  • Appends a new row with the new version number and the LLM-generated description.

Enhancing Power BI Visuals for Color Accessibility: Balancing Color and Clarity

In the quest to make data visualizations more inclusive, it’s crucial to address the needs of color-blind people, while still preserving the effective storytelling that colors provide. In this post, we’ll explore some practical adjustments made to Power BI built-in visuals, that not only enhance accessibility but also retain the meaningful use of color.

Understanding Color Blindness

Color blindness affects approximately 8% of men and 0.5% of women globally. It occurs when the eye’s color-detecting cells fail to respond to certain wavelengths of light. This condition can make it difficult to distinguish between colors, particularly reds and greens, or blues and yellows.

For many color-blind individuals, visuals that rely solely on color for differentiation can be challenging to interpret. To address this, we need to implement design strategies that enhance clarity. Often, a color-blind friendly palette of colors is used. But this may come with some disadvantages to the real meaning of the colors.

The Importance of Color in Storytelling

Colors in data visualization do more than just decorate—they convey meaning and context. Lets look at the following example of three visuals displaying the age categories of Switzerland’s population:

Note: While there are many ways to enhance visuals further, this post focuses on color-related adjustments to improve accessibility.

  • Yellow signifies the “golden age” of seniors (65+), symbolizing experience and wisdom.
  • Green represents vitality and growth for individuals aged 19-64, reflecting an active and productive life stage.
  • Light blue (symbolizing youth under 20) conveys freshness, new beginnings, and potential. Light blue often evokes a sense of calm and clarity, making it ideal for representing the younger demographic.

These colors help users quickly understand and remember the context of the data. However, when viewed by individuals with color blindness, distinguishing these colors becomes problematic if used alone. As someone with “normal” color vision, I could only imagine how such visuals would look like. In monochrome, differentiating between categories becomes difficult without color cues, underscoring the need for enhanced visual clarity.

Addressing Color Accessibility

To ensure that our visuals are accessible to everyone, including those with color blindness, I have implemented several key adjustments:
Legends make it much easier to interpret individual visuals. For the line and bar charts, legends were added to clearly identify categories, while the pie chart now uses data labels instead of a legend, providing direct category information. To further enhance accessibility, different line styles—dotted, dashed, and solid—were applied to the line chart for each category. In the stacked column chart, borders were introduced:

  • The youth category remains default
  • The age group 20-64 has a grayscale border
  • The senior category features a solid black border

These adjustments collectively improve the clarity and readability of the visuals, even for those viewing them in grayscale.

Before Adjustments: In grayscale, it’s difficult to distinguish between categories due to the lack of color cues.

After Adjustments: With the addition of distinct line styles and borders, the grayscale visuals become much clearer, showing how these changes enhance readability.

Final Visuals

The final updated visuals incorporate color and additional design elements to improve accessibility while preserving the storytelling aspect. These adjustments not only help those with color blindness but also streamline the user experience for all viewers.

In summary, while these adjustments involve a minor increase in visual space for the additional legends, they significantly enhance both accessibility and overall clarity. By retaining the original color storytelling and incorporating complementary visual aids like borders and line styles, we ensure that our Power BI reports are both inclusive and effective.

Swiss federal elections 2023: Displaying results [demo report in German]

Data visualization has revolutionized the way we understand and interpret election results. In this context, I created a Power BI report to showcase the results of the Swiss National Council elections held in 2015 and 2019. With data directly ingested from open platforms provided by the Swiss Government, this report gives a comprehensive view of election results down to each municipality.

I recommend to display the report on a desktop-sized screen. Many of the visuals are interactive, detailed results from single municipalities can be displayed by hovering over map of Switzerland (image 1).

The second page will display results on the election day (coming 22th October 2023). Display the report in full-screen to get the best experience. In upcoming posts, I will explain the technical background and add new content.

Live report (select in the bottom right corner for full screen)

Hello world!

“was there” selfie

I just returned home after an intense week fully booked with speaker sessions about data. I was attending the SQLbits 2023 in Wales, which is basically the largest data platform conference.

Now I got a backpack full of new ideas, new connections and new knowledge. I was impressed about the whole data community actively sharing their knowledge with free videos, blogs or sessions. In one session called “keynote to the community”, all attendees gathered in the big auditorium. Some key persons of the community invited all attendees to actively share knowledge with others as well.

As I thought about this, I remembered the numerous times I was glad that someone wrote about a specific topic, explaining it and providing solutions. Especially in our very specialized area of data engineering, it is crucial to be able to access this knowledge.

Even if this blog may not be read by a hundred persons, it could help the one or the other in daily business. Maybe I just want to give something back, for all the thousands of blog posts helping me during my journey on data platforms.

Have fun!