Search code examples
vega-lite

How can I rename legend labels in Vega Lite?


I've been trying for the last few days to rename the legend labels on my vega-lite chart.

Normally these labels match their respective data field names. I have a case where I'd like to give them a more descriptive name, but without renaming the original data names.

A simplified example:

example chart

vl.markLine()
  .data([
    { t:1, v:5, c:'a' }, { t:2, v:3, c:'a' }, { t:3, v:7, c:'a' },
    { t:1, v:6, c:'b' }, { t:2, v:8, c:'b' }, { t:3, v:2, c:'b' }
   ])
  .encode(
    vl.x().fieldQ('t'),
    vl.y().fieldQ('v'),
    vl.color().fieldN('c')
  )
  .render()

How can I rename 'a' and 'b' in the legend, without changing the original data?

(I'm using the javascript API but will be happy with a JSON solution too).

I'd like to find a way that doesn't involve just copying and mapping all the data to another variable name just for the sake of the legend labels.

I've yet to find a way of manually entering the legend labels as something like "labels": ['long name for a', 'long name for b'].


Solution

  • There are two possible approaches to this. You can either use a calculate transform to modify the values within the data stream (open in editor):

    {
      "data": {
        "values": [
          {"t": 1, "v": 5, "c": "a"},
          {"t": 2, "v": 3, "c": "a"},
          {"t": 3, "v": 7, "c": "a"},
          {"t": 1, "v": 6, "c": "b"},
          {"t": 2, "v": 8, "c": "b"},
          {"t": 3, "v": 2, "c": "b"}
        ]
      },
      "transform": [
        {"calculate": "{'a': 'Label A', 'b': 'Label B'}[datum.c]", "as": "c"}
      ],
      "mark": "line",
      "encoding": {
        "x": {"field": "t", "type": "quantitative"},
        "y": {"field": "v", "type": "quantitative"},
        "color": {"field": "c", "type": "nominal"}
      }
    }
    

    or you can use a labelExpr to define new labels, referencing the original label as datum.label (open in editor):

    {
      "data": {
        "values": [
          {"t": 1, "v": 5, "c": "a"},
          {"t": 2, "v": 3, "c": "a"},
          {"t": 3, "v": 7, "c": "a"},
          {"t": 1, "v": 6, "c": "b"},
          {"t": 2, "v": 8, "c": "b"},
          {"t": 3, "v": 2, "c": "b"}
        ]
      },
      "mark": "line",
      "encoding": {
        "x": {"field": "t", "type": "quantitative"},
        "y": {"field": "v", "type": "quantitative"},
        "color": {
          "field": "c",
          "type": "nominal",
          "legend": {"labelExpr": "{'a': 'Label A', 'b': 'Label B'}[datum.label]"}
        }
      }
    }
    

    The benefit of the former approach is that it changes the values everywhere (including in, e.g. tooltips). The benefit of the latter approach is that it's more efficient, because it only does the transform once per unique label.