powerbivega-litevegadeneb

How to dynamically provide colour hex codes (from a dataset) to Deneb (Power BI) Visualizations Using Vega/Vega-Lite?


For reference, we have been using the following template as a starting point: https://github.com/PBI-David/Deneb-Showcase/tree/main/Gantt%20Chart

I have these rows of data within my visualization that have colour assigned to them: Visualization Example

This seems to be handled by a JSONObject:

    {
      "name": "cDark",
      "type": "ordinal",
      "range": ["#ff2d00"],
      "domain": {
        "data": "input",
        "field": "phase"
      }
    },
    {
      "name": "cLight",
      "type": "ordinal",
      "range": ["#ff2d00"],
      "domain": {
        "data": "input",
        "field": "phase"
      }
    }

If I hardcode the values (e.g. #ff2d00) it works perfectly fine and displays red as shown in the example. Now I am interested in dynamically assigning this hex code from the dataset (that is already providing other things such as the Some text).

I have added a column of data to my dataset defined as Colour: Colour Dataset

This dataset is simply a hex code for the colour I wish to have for that row; e.g: Hexcode Example

But when I try to read this value with "range": ["datum.Colour"],, it doesn't throw any error but it does not read it (the colour is just transparent, aka no colour assigned).

Other columns in the dataset are accessed via this weird datum object, aka datum.id for example accesses the id column of the data "expr": "length(data('input'))+datum.id+'^^^^^^^'" . How come this is not working with the new Colour column that I added?

I am very new to Power BI, Deneb, Vega and all these tools and am just quickly modifying some files for a stakeholder on the side thus have very little knowledge about the insides of how this works.


Solution

  • Credit to dm-p

    After reading and applying this solution to my JSON file I was able to solve this issue.


    If you're trying to bind a field value to a scale in either tool, you need to have a 1:1 mapping of scale domain (e.g., your semantic value) to your range (your color value). If these don't match (e.g. if you want to set a bunch of category values to the same color), then this isn't going to create the right results. In these cases, you would need to dynamically assign the value as part of the mark properties.

    For Vega-Lite, you would use an ExprRef in the mark property channel. Something like:

    "mark": {  
     "type": "bar",  
     "color": { "expr": "datum\['Color'\]" },  
     ...  
    }  
    

    Note that if you have the same property in your encoding channels, then encoding has the highest order of precedence, which won't take effect. You would need to remove the encoding so that Vega-Lite doesn't assign a scale and takes over. Note that if you want a legend in conjunction with this approach, you will need to find a way for the overlapping values and scales to co-exist. The easiest way would be to use close (but distinctly different) values against a category.

    For Vega, you'd use the approach in the mark properties to assign the value, without a corresponding scale. As a psuedo-example:

    {  
        "type": "rect",  
        "from": {"data": "dataset"},  
        "encode": {  
            "update": {  
            "color": {"field": "datum\['Color'\]"},  
                 ...  
                      }  
                  }  
     }