vega-litevegavega-lite-apivega-embed

How to show the full legend label as a tooltip on hovering over the legend symbol in vega lite


I am working on a use case where I want to display the full legend label as a tooltip when hovering over the legend symbol in Vega-Lite. The reason is that the legend labels are being truncated, so I want to show the full label name on hover as a workaround.

enter image description here Here’s what I’ve tried so far:

I attempted to add a title attribute to the target HTML element using the following code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vega Legend Tooltip Example</title>
  <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
</head>
<body>
  <div id="vis"></div>
  <script>
    const vegaLiteSpec = {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "data": {
        "values": [
          {"category": "Long Category Name 1", "value": 10},
          {"category": "Long Category Name 2", "value": 15},
          {"category": "Long Category Name 3", "value": 20}
        ]
      },
      "mark": "bar",
      "encoding": {
        "x": {"field": "category", "type": "nominal"},
        "y": {"field": "value", "type": "quantitative"},
        "color": {
          "field": "category",
          "type": "nominal",
          "legend": {"title": "Categories"}
        }
      }
    };

    vegaEmbed('#vis', vegaLiteSpec).then(result => {
      const view = result.view;

      // Wait for the Vega view to fully render
      view.runAsync().then(() => {
        // Select all legend symbol groups and add `title` attributes for tooltips
        const legendSymbols = document.querySelectorAll('.role-legend-symbol');
        
        // Array of category names for the legend symbols
        const categories = ["Long Category Name 1", "Long Category Name 2", "Long Category Name 3"];
        
        legendSymbols.forEach((symbol, index) => {
          // Set the full category name as the title tooltip
          symbol.setAttribute('title', categories[index]);
        });
      });
    });
  </script>
</body>
</html>

The code successfully adds the title attribute to the desired HTML elements, but I’m still not seeing the tooltip when hovering over the legend symbols.

Could anyone suggest a way to achieve this in Vega-Lite or Vega? I’ve read about using signals in Vega for user interactions but am not sure how to apply them here. Vega-Lite is preferred, but since I’m using JavaScript to render the chart, I can also manipulate the underlying Vega if necessary.

Thanks in advance!


Solution

  • Like this?

    enter image description here

    {
          "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
          "data": {
            "values": [
              {"category": "Long Category Name 1", "value": 10},
              {"category": "Long Category Name 2", "value": 15},
              {"category": "Long Category Name 3", "value": 20}
            ]
          },
          "mark": "bar",
          "encoding": {
            "x": {"field": "category", "type": "nominal"},
            "y": {"field": "value", "type": "quantitative"},
            "color": {
              "field": "category",
              "type": "nominal",
              "legend": {"title": "Categories"}
            },
            "tooltip": {"field": "category", "type": "ordinal"}
          }
        }
    

    UPDATE

    {
      "$schema": "https://vega.github.io/schema/vega/v5.json",
      "background": "white",
      "padding": 5,
      "height": 200,
      "style": "cell",
      "data": [
        {
          "name": "source_0",
          "values": [
            {"category": "Long Category Name 1", "value": 10},
            {"category": "Long Category Name 2", "value": 15},
            {"category": "Long Category Name 3", "value": 20}
          ]
        },
        {
          "name": "data_0",
          "source": "source_0",
          "transform": [
            {
              "type": "stack",
              "groupby": ["category"],
              "field": "value",
              "sort": {"field": [], "order": []},
              "as": ["value_start", "value_end"],
              "offset": "zero"
            },
            {
              "type": "filter",
              "expr": "isValid(datum[\"value\"]) && isFinite(+datum[\"value\"])"
            }
          ]
        }
      ],
      "signals": [
        {"name": "x_step", "value": 20},
        {
          "name": "width",
          "update": "bandspace(domain('x').length, 0.1, 0.05) * x_step"
        }
      ],
      "marks": [
        {
          "name": "marks",
          "type": "rect",
          "style": ["bar"],
          "from": {"data": "data_0"},
          "encode": {
            "update": {
              "fill": {"scale": "color", "field": "category"},
              "x": {"scale": "x", "field": "category"},
              "width": {"signal": "max(0.25, bandwidth('x'))"},
              "y": {"scale": "y", "field": "value_end"},
              "y2": {"scale": "y", "field": "value_start"}
            }
          }
        }
      ],
      "scales": [
        {
          "name": "x",
          "type": "band",
          "domain": {"data": "data_0", "field": "category", "sort": true},
          "range": {"step": {"signal": "x_step"}},
          "paddingInner": 0.1,
          "paddingOuter": 0.05
        },
        {
          "name": "y",
          "type": "linear",
          "domain": {"data": "data_0", "fields": ["value_start", "value_end"]},
          "range": [{"signal": "height"}, 0],
          "nice": true,
          "zero": true
        },
        {
          "name": "color",
          "type": "ordinal",
          "domain": {"data": "data_0", "field": "category", "sort": true},
          "range": "category"
        }
      ],
      "axes": [
        {
          "scale": "x",
          "orient": "bottom",
          "grid": false,
          "title": "category",
          "labelAlign": "right",
          "labelAngle": 270,
          "labelBaseline": "middle",
          "zindex": 0
        },
        {
          "scale": "y",
          "orient": "left",
          "grid": false,
          "title": "value",
          "labelOverlap": true,
          "tickCount": {"signal": "ceil(height/40)"},
          "zindex": 0
        }
      ],
      "legends": [{"title": "Categories", "fill": "color", "symbolType": "square",
      
      
       "encode": {
    
          "labels": {
            "interactive": true,
    
            "hover": {
           "tooltip":{"signal": "datum.value"}
            }
          }
        }
      
      }]
    }