Search code examples
vega-lite

Vega-lite Multiple Measures + Normalized Stacked Bar Chart + Overlay percentages as text


Trying to extend the solution to Vega Lite: Normalized Stacked Bar Chart + Overlay percentages as text but for a multi-measure repeat layer chart. I'm unable to get the text values to appear, with each attempt at "plugging in" "field": {"repeat": "layer"} where I think it should go throwing error: unsupported object: {"repeat":"layer"}.

What I have working now is the chart, without the labels. What I want is to add the percentage labels as I was able to do in the second chart: open in editor enter image description here

I have the same data but in a single measure layout with labels working fine open in editor enter image description here

What I tried was to joinaggregate and calculate in totalSales, totalQty, fractionSales and fractionQty. Then, instead of "repeat": {"layer": ["Sales", "Qty"]} I thought to "repeat": {"layer": ["totalSales", "totalQty"]}


Solution

  • Using the code from David Bacci, the solution here was to fold the data first, then add two joinaggregates, one for the total per measure (totalKey) and a second for the per-province per measure total (totalProvince). This allowed for the single column fraction to hold what was needed for the text, without having to repeat layers.

    view in editor enter image description here

    {
      "width": 200,
      "height": 200,
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "data": {
        "values": [
          {"Province": "ON", "Date": "Jan 2020", "Sales": "7", "Qty": "15"},
          {"Province": "ON", "Date": "Feb 2020", "Sales": "2", "Qty": "2"},
          {"Province": "BC", "Date": "Jan 2020", "Sales": "3", "Qty": "5"},
          {"Province": "BC", "Date": "Feb 2020", "Sales": "8", "Qty": "18"}
        ]
      },
      "transform": [
        {"fold": ["Sales", "Qty"]},
        {
          "joinaggregate": [{"op": "sum", "field": "value", "as": "totalKey"}],
          "groupby": ["key"]
        },
        {
          "joinaggregate": [{"op": "sum", "field": "value", "as": "totalProvince"}],
          "groupby": ["key", "Province"]
        },
        {"calculate": "(datum['totalProvince'] / datum.totalKey)", "as": "fraction"}
      ],
      "encoding": {
        "x": {
          "field": "key",
          "type": "ordinal",
          "title": ""
        },
        "y": {
          "field": "fraction",
          "type": "quantitative",
          "aggregate": "sum",
          "stack": "normalize"
        },
        "order": {"field": "fraction", "sort": "descending"}
      },
      "layer": [
        {
          "mark": "bar",
          "encoding": {"color": {"field": "Province", "type": "nominal"}}
        },
        {
          "mark": {"type": "text", "color": "white"},
          "encoding": {
            "text": {"field": "fraction", "format": "~p"},
            "yOffset": {"datum": 10}
          }
        }
      ]
    }