vega-lite

Sort bars (columns) inside a group


How can I sort the groups inside a category by value?

See the below sample data, from this data I'm looking for that shows (in descending order): for category A: z,y,x for category B: z,x,y for category C: x,y,z

My final question would be the ordering of the categories: B,A,C

{
  "data": {
    "values": [
      {"category":"A", "group": "x", "value":0.1},
      {"category":"A", "group": "y", "value":0.6},
      {"category":"A", "group": "z", "value":0.9},
      {"category":"B", "group": "x", "value":0.7},
      {"category":"B", "group": "y", "value":0.2},
      {"category":"B", "group": "z", "value":1.1},
      {"category":"C", "group": "x", "value":0.6},
      {"category":"C", "group": "y", "value":0.1},
      {"category":"C", "group": "z", "value":0.2}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "category"},
    "y": {"field": "value", "type": "quantitative"},
    "xOffset": {"field": "group"},
    "color": {"field": "group"}
  }
}

Solution

  • While I believe the Vega-Lite grammar believes the order of a series should be consistent across categories by its xOffset, if you want to do this, you can use a window transform to calculate the row number (or rank) in descending order of value within each group and apply this to your xOffset channel, e.g.:

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
      "data": {
        "values": [
          {"category": "A", "group": "x", "value": 0.1},
          {"category": "A", "group": "y", "value": 0.6},
          {"category": "A", "group": "z", "value": 0.9},
          {"category": "B", "group": "x", "value": 0.7},
          {"category": "B", "group": "y", "value": 0.2},
          {"category": "B", "group": "z", "value": 1.1},
          {"category": "C", "group": "x", "value": 0.6},
          {"category": "C", "group": "y", "value": 0.1},
          {"category": "C", "group": "z", "value": 0.2}
        ]
      },
      "transform": [
        {
          "window": [{"op": "row_number", "as": "offset_order"}],
          "groupby": ["category"],
          "sort": [{"field": "value", "order": "descending"}]
        }
      ],
      "mark": "bar",
      "encoding": {
        "x": {"field": "category"},
        "y": {"field": "value", "type": "quantitative"},
        "xOffset": {"field": "offset_order"},
        "color": {"field": "group"}
      }
    }
    

    enter image description here

    Here it is in the Vega Editor for you to explore/remix.


    For your second question, which I presume relates to the sorting of the categories by descending total value, you could use a joinaggregate to sum the total for each category and then using that as your sort predicate on the x encoding channel, e.g.:

    {
      ...
      "transform": [
        ...
        {
          "joinaggregate": [
            {"op": "sum", "field": "value", "as": "category_value"}
          ],
          "groupby": ["category"]
        }
      ],
      "mark": "bar",
      "encoding": {
        "x": {
          "field": "category",
          "sort": {"field": "category_value", "order": "descending"}
        },
        ...
      }
    }
    

    enter image description here

    Again, here's a Vega Editor link.