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.
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!
Like this?
{
"$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"}
}
}
}
}]
}