Search code examples
powerbivisualizationpowerbi-desktopvega-litedeneb

VEGA LITE : stacked bar spacing between categories with fixed order


I got stuck with developing my stacked bar chart in Vega-Lite when attempting to create a space between categories and set a fixed order of categories.

So I don't want the categories ("Funding Income", "Other", "Expenses", "Earned Income") to be blended together but to have a little space between each of them.

Also, the order in the bar should be fixed as follows: "Funding Income", "Other", "Expenses", "Earned Income"; however, I couldn't make it work properly.

Could anyone help out, please? Thanks"

Here is a sample :

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {
        "Year": 2022,
        "Group": "Funding Income",
        "Value": 7000,
        "Type": "plan"
      },
      {
        "Year": 2022,
        "Group": "Earned Income",
        "Value": 3000,
        "Type": "plan"
      },
      {
        "Year": 2022,
        "Group": "Other",
        "Value": 500,
        "Type": "plan"
      },
      {
        "Year": 2022,
        "Group": "Expenses",
        "Value": 8000,
        "Type": "reality"
      },
      {
        "Year": 2022,
        "Group": "Other",
        "Value": 1000,
        "Type": "reality"
      },
      {
        "Year": 2022,
        "Group": "Funding Income",
        "Value": 8000,
        "Type": "reality"
      },
      {
        "Year": 2021,
        "Group": "Funding Income",
        "Value": 6000,
        "Type": "reality"
      },
      {
        "Year": 2021,
        "Group": "Other",
        "Value": 700,
        "Type": "reality"
      },
      {
        "Year": 2021,
        "Group": "Earned Income",
        "Value": 3000,
        "Type": "plan"
      },
      {
        "Year": 2021,
        "Group": "Other",
        "Value": 1100,
        "Type": "plan"
      },
      {
        "Year": 2021,
        "Group": "Funding Income",
        "Value": 4000,
        "Type": "plan"
      },
      {
        "Year": 2021,
        "Group": "Expenses",
        "Value": 5000,
        "Type": "reality"
      }
    ]
  },
  "facet": {
    "column": {
      "field": "Year",
      "type": "nominal",
      "header": {
        "labelOrient": "bottom",
        "labelFont": "Arial black",
        "labelColor": "black",
        "title": null
      }
    }
  },
  "spec": {
    "height": 164,
    "layer": [
      {
        "mark": {
          "type": "bar",
          "cornerRadius": 1,
          "stroke": "#363636",
          "strokeWidth": 1.5
        },
        "encoding": {
          "x": {
            "field": "Type",
            "axis": {
              "labelAngle": 0,
              "labelOffset": 0
            },
            "title": null
          },
          "y": {
            "field": "Value",
            "type": "quantitative",
            "title": null
          },
          "xOffset": {"field": "Type"},
          "color": {
            "field": "Group",
            "sort": [
              "Funding Income",
              "Other",
              "Expenses",
              "Earned Income"
            ],
            "scale": {
              "domain": [
                "Funding Income",
                "Other",
                "Expenses",
                "Earned Income"
              ],
              "range": [
                "gray",
                "white",
                "lightgray",
                "black"
              ]
            }
          }
        }
      }
    ]
  }
}

Solution

  • Do you mean a sort order like this?

    enter image description here

    If so, add an order:

    "order":{"sort": "descending", "field":"Group"},
    

    Regarding the space between stacks, this is a bit nuanced. You can either:

    1. Explode
    2. Erode

    If you explode, then you can no longer have a Y axis as it wouldn't make sense. If you erode, then the smaller values may disappear. Either way, there is no built in functionality to do this but if you want to go the explosion route, then you can copy the technique from my sankey example here which involves introducing dummy values for the spaces:

    https://github.com/PBI-David/Deneb-Showcase?tab=readme-ov-file#sankey-chart

    UPDATE enter image description here This sorts the stacks using a calculate transform and order encoding. To sort the legend, just change the order of your domain/range as desired.

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "data": {
        "values": [
          {"Year": 2022, "Group": "Funding Income", "Value": 7000, "Type": "plan"},
          {"Year": 2022, "Group": "Earned Income", "Value": 3000, "Type": "plan"},
          {"Year": 2022, "Group": "Other", "Value": 500, "Type": "plan"},
          {"Year": 2022, "Group": "Expenses", "Value": 8000, "Type": "reality"},
          {"Year": 2022, "Group": "Other", "Value": 1000, "Type": "reality"},
          {
            "Year": 2022,
            "Group": "Funding Income",
            "Value": 8000,
            "Type": "reality"
          },
          {
            "Year": 2021,
            "Group": "Funding Income",
            "Value": 6000,
            "Type": "reality"
          },
          {"Year": 2021, "Group": "Other", "Value": 700, "Type": "reality"},
          {"Year": 2021, "Group": "Earned Income", "Value": 3000, "Type": "plan"},
          {"Year": 2021, "Group": "Other", "Value": 1100, "Type": "plan"},
          {"Year": 2021, "Group": "Funding Income", "Value": 4000, "Type": "plan"},
          {"Year": 2021, "Group": "Expenses", "Value": 5000, "Type": "reality"}
        ]
      },
      "transform": [
        {
          "calculate": "indexof(['Funding Income','Other','Expenses','Earned Income'], datum.Group)",
          "as": "sort"
        }
      ],
      "facet": {
        "column": {
          "field": "Year",
          "type": "nominal",
          "header": {
            "labelOrient": "bottom",
            "labelFont": "Arial black",
            "labelColor": "black",
            "title": null
          }
        }
      },
      "spec": {
        "height": 164,
        "layer": [
          {
            "mark": {
              "type": "bar",
              "cornerRadius": 1,
              "stroke": "#363636",
              "strokeWidth": 1.5
            },
            "encoding": {
              "x": {
                "field": "Type",
                "axis": {"labelAngle": 0, "labelOffset": 0},
                "title": null
              },
              "order": {"sort": "ascending", "field": "sort"},
              "y": {"field": "Value", "type": "quantitative", "title": null},
              "xOffset": {"field": "Type"},
              "color": {
                "field": "Group", 
                "scale": {
                  "domain": [
                    "Funding Income",
                    "Other",
                    "Expenses",
                    "Earned Income"
                  ],
                  "range": ["gray", "white", "lightgray", "black"]
                }
              }
            }
          }
        ]
      }
    }