Search code examples
vega-lite

vega lite expr reference mark column width


I have vertical column chart like this one

vertical column bar chart

The chart is set to fit into the container with 100% width. Column with in the chart is calculated responsively by vega to fit into the container.

In additional layer I'm rendering text value labels above the columns. And I need the label to be exactly above its corresponding column. To calculate the position of a label I'm using expression:

 "mark": {
        "dx": {"expr": "((datum.maxGroupCount-1)*-10)+(datum.index-1)*20"},
        "dy": -5,
        "fontSize": 9,
        "type": "text"
      }

Instead of the defined constant 20 in the dx expr I need to reference the actual column width so that the labels are rendered properly when size of the chart changes.

In the vega lite editor https://vega.github.io/editor/ you can see the actual column width in Data viewer tab when you select layer_0_marks.

Is it possible to reference the column width?


Solution

  • You could setup the text marks in a dynamic way like this:

    {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.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}
        ]
      },
      "encoding": {
        "x": {"field": "category", "title": null},
        "y": {"field": "value", "type": "quantitative", "title": null},
        "xOffset": {"field": "group"},
        "color": {"field": "group"}
      },
      "layer": [
        {"mark": {"type": "bar"}},
        {
          "mark": {"type": "text", "dy": -7},
          "encoding": {
            "text": {"field": "value", "type": "quantitative"},
            "color": {"value": "black"}
          }
        },
        {
          "transform": [
            {
              "joinaggregate": [{"op": "max", "field": "value", "as": "total"}],
              "groupby": []
            },
            {"calculate": "datum.total * 1.1", "as": "max"}
          ],
          "mark": {"type": "point", "dy": -10},
          "encoding": {
            "y": {"field": "max", "type": "quantitative"},
            "color": {"value": "transparent"}
          }
        }
      ],
      "config": {}
    }
    

    I also added an additional point layer to extend the top of the chart for the largest value. I added 10% but you can change this.

    Let me know if this was useful.

    enter image description here