Vega-lite interactive legend and bar chart

1.7k views Asked by At

I'm fairly new to vega-lite. I'd really like to get the following interactive bar chart working:

  • Legend for the bar chart that can be clicked on to highlight one or more bars
  • Click on one or more bars to highlight and reflect that it legend
  • When highlighed, show text value above the bar.

My strategy for building this is to have two layers, one layer for the bars, and one for the text. Then one selection that is in 'multi' mode on mousedown, and also bound to the legend.

My question is two-fold:

  1. Is it possible to have a selection bound to the legend but also utilize mousedown?
  2. I'm having a hard time understanding how selections work in layered graphs/charts. If I define the selection outside of the layers I get a warning saying selection can't be found, and the selection only works as expected if I put it in the definition of the first layer. Additionally, the legend binding seems to work if I don't have layers, but stops working when I do have layers. Is this a limitation of the library or am I doing something wrong.

Here is my schema, thanks for any help in advance!

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "description": "A simple bar chart with embedded data.",
  "title": "test",
  "data": {
    "values": [
      ["Lateral", 630.666127],
      ["Basal", 413.211154],
      ["Accessory", 257.842981],
      ["Anterior", 48.735523],
      ["Central", 45.797799],
      ["Medial", 30.314856],
      ["Cortical", 27.697457],
      ["Corticoamygdaloid", 169.707268],
      ["Paralaminar", 46.216784],
      ["Whole_amygdala", 1670.189948]
    ],
    "name": "data"
  },
  "width": "600",
  "height": "400",
  "encoding": {
    "x": {"field": "0", "type": "nominal", "sort": "-y"},
    "y": {"field": "1", "type": "quantitative"}
  },
  "layer": [
    {
      "mark": "bar",
      "encoding": {
        "color": {
          "field": "0"
        },
        "opacity": {
          "condition": {"selection": "series", "value": 1},
          "value": 0.2
        }
      },
      "selection": {
        "series": {"type": "multi", "bind": "legend"}
      }
    },
    {
      "transform": [{"filter": {"selection":"series"}}],
      "mark": {"type": "text", "dy": -5},
      "encoding": {"text": {"field": "1"}}
    }
  ]
}
1

There are 1 answers

2
jakevdp On BEST ANSWER

You were quite close. When you bind a selection to a legend, by default it deactivates other ways of interacting. But as mentioned briefly in the Legend Binding docs, you can re-enable this by specifying the "on" attribute. Here is the result (Open in editor):

{
  "title": "test",
  "data": {
    "values": [
      ["Lateral", 630.666127],
      ["Basal", 413.211154],
      ["Accessory", 257.842981],
      ["Anterior", 48.735523],
      ["Central", 45.797799],
      ["Medial", 30.314856],
      ["Cortical", 27.697457],
      ["Corticoamygdaloid", 169.707268],
      ["Paralaminar", 46.216784],
      ["Whole_amygdala", 1670.189948]
    ],
    "name": "data"
  },
  "width": "600",
  "height": "400",
  "encoding": {
    "x": {"field": "0", "type": "nominal", "sort": "-y"},
    "y": {"field": "1", "type": "quantitative"}
  },
  "layer": [
    {
      "mark": "bar",
      "encoding": {
        "color": {"field": "0"},
        "opacity": {
          "condition": {"selection": "series", "value": 1},
          "value": 0.2
        }
      },
      "selection": {
        "series": {
          "type": "multi",
          "encodings": ["color"],
          "on": "click",
          "bind": "legend"
        }
      }
    },
    {
      "transform": [{"filter": {"selection": "series"}}],
      "mark": {"type": "text", "dy": -5},
      "encoding": {"text": {"field": "1"}}
    }
  ]
}

enter image description here

Regarding your second question: currently selections must be defined within the layers they are bound to, but this will likely change in future Vega-Lite versions; see https://github.com/vega/vega-lite/pull/6919.