javascriptvega-litevegavega-lite-api

Achieving custom tooltip containing multiple columns in vega-lite


I am able to prepare following visualization with vegalite:

enter image description here

The code for this visualization looks like following:

{
  "width": 400,
  "config": {"view": {"continuousWidth": 600, "continuousHeight": 300}},
  "data": {
    "values": [
      {"title": "Quiz-1", "my-score": 62, "max": 80, "avg": 45, "min": 15, "my-actual-score": 124, "max-score": 160, "avg-score": 90, "min-score": 30  },
      {"title": "Quiz-2", "my-score": 48, "max": 48, "avg": 30, "min": 10, "my-actual-score": 24, "max-score": 24, "avg-score": 15, "min-score": 5  },
      {"title": "Quiz-3", "my-score": 54, "max": 62, "avg": 36, "min": 12, "my-actual-score": 54, "max-score": 62, "avg-score": 36, "min-score": 12  },
      {"title": "Quiz-4", "my-score": 27, "max": 69, "avg": 50, "min": 9 , "my-actual-score": 27, "max-score": 69, "avg-score": 50, "min-score": 9  },
      {"title": "Quiz-5", "my-score": 40, "max": 48, "avg": 30, "min": 11, "my-actual-score": 80, "max-score": 96, "avg-score": 60, "min-score": 22  },
      {"title": "Quiz-6", "my-score": 50, "max": 55, "avg": 28, "min": 5 , "my-actual-score": 50, "max-score": 55, "avg-score": 28, "min-score": 5  }
    ]
  },
  "transform": [{"fold": ["max", "avg", "min", "my-score"]}],
  "usermeta": {"embedOptions": {"renderer": "svg"}},
  "encoding": {
    "x": {"field": "title", "type": "nominal", "axis": {"title": "Quizzes"}}
  },
  "layer": [
    {
      "mark": {"type": "bar", "width": {"band": 0.2}},
      "transform": [{"filter": "datum.key == 'my-score' "}],
      "encoding": {
        "y": {
          "field": "value",
          "type": "quantitative",
          "axis": {"title": "Percentage Score"}
        },
        "color": {"field": "key", "scale": {"range": ["#312eaa"]}, "legend": {"title": ""}},
        "tooltip": [{"field": "value", "type": "quantitative"}]
      }
    },
    {
      "mark": {"type": "line"},
      "transform": [
        {
          "filter": "datum.key == 'max' || datum.key == 'min' ||datum.key == 'avg'  "
        }
      ],
      "encoding": {
        "y": {"field": "value", "type": "quantitative"},
        "stroke": {
          "field": "key",
          "scale": {"range": ["#02c754", "red", "#02b6de"]},
          "legend": {"title": ""}
        }
      }
    },
    {
      "mark": {"type": "circle", "size":100, "opacity": "100%"},
      "params": [
                    {
                        "name": "highlight-max",
                        "select": { "type": "point", "on": "mouseover" }
                    }
                ],
      "transform": [
        {
          "filter": "datum.key == 'max' || datum.key == 'min' ||datum.key == 'avg'"
        }
      ],
      "encoding": {
        "y": {"field": "value", "type": "quantitative"},
        "fill": {
          "field": "key",
          "scale": {"range": ["#02c754", "red", "#02b6de"]},
          "legend": null
        },
        "size": {
                  "condition": { "param": "highlight-max", "empty": false, "value": 250}
        },
        "tooltip": [{"field": "value", "type": "quantitative"}]
      }
    }
  ],
  "title": "Quiz Scores",
  "$schema": "https://vega.github.io/schema/vega-lite/v5.6.json"
}

There are some discrepancies in this visualization:

enter image description here

First issue is that when hovered on any one circle, all circles in that quiz / column gets animated (increases their size as can be seen in figure above).

Second issue is that the tooltip simply says value: V (where V is corresponding value) when hovered on anything: bar, max/red circle, green/avg circle and blue/min circle. Note that there are two set of values in each record. For example, if we consider this record:

{"title": "Quiz-3", "my-score": 54, "max": 62, "avg": 36, "min": 12, "my-actual-score": 54, "max-score": 62, "avg-score": 36, "min-score": 12  }

then, we have first set:

"my-score": 54, "max": 62, "avg": 36, "min": 12

and second set:

"my-actual-score": 54, "max-score": 62, "avg-score": 36, "min-score": 12

First set is some what normalization (say percentage) of actual score given in second set. I want to show both when hovered on. For example when someone hovers on red circle, I want to show tooltip containing: Avg: 36%, 62, instead of just value: 36 as shown in above image. How can I achieve this?

PS: You can try out this visualization here.


Solution

  • Try the following - it should give you what you need as a template to fill in the rest of the tooltip values.

    {
      "width": 400,
      "config": {"view": {"continuousWidth": 600, "continuousHeight": 300}},
      "data": {
        "values": [
          {
            "title": "Quiz-1",
            "my-score": 62,
            "max": 80,
            "avg": 45,
            "min": 15,
            "my-actual-score": 124,
            "max-score": 160,
            "avg-score": 90,
            "min-score": 30
          },
          {
            "title": "Quiz-2",
            "my-score": 48,
            "max": 48,
            "avg": 30,
            "min": 10,
            "my-actual-score": 24,
            "max-score": 24,
            "avg-score": 15,
            "min-score": 5
          },
          {
            "title": "Quiz-3",
            "my-score": 54,
            "max": 62,
            "avg": 36,
            "min": 12,
            "my-actual-score": 54,
            "max-score": 62,
            "avg-score": 36,
            "min-score": 12
          },
          {
            "title": "Quiz-4",
            "my-score": 27,
            "max": 69,
            "avg": 50,
            "min": 9,
            "my-actual-score": 27,
            "max-score": 69,
            "avg-score": 50,
            "min-score": 9
          },
          {
            "title": "Quiz-5",
            "my-score": 40,
            "max": 48,
            "avg": 30,
            "min": 11,
            "my-actual-score": 80,
            "max-score": 96,
            "avg-score": 60,
            "min-score": 22
          },
          {
            "title": "Quiz-6",
            "my-score": 50,
            "max": 55,
            "avg": 28,
            "min": 5,
            "my-actual-score": 50,
            "max-score": 55,
            "avg-score": 28,
            "min-score": 5
          }
        ]
      },
      "transform": [{"fold": ["max", "avg", "min", "my-score"]}],
      "usermeta": {"embedOptions": {"renderer": "svg"}},
      "encoding": {
        "x": {"field": "title", "type": "nominal", "axis": {"title": "Quizzes"}}
      },
      "layer": [
        {
          "mark": {"type": "bar", "width": {"band": 0.2}},
          "transform": [{"filter": "datum.key == 'my-score' "}],
          "encoding": {
            "y": {
              "field": "value",
              "type": "quantitative",
              "axis": {"title": "Percentage Score"}
            },
            "color": {
              "field": "key",
              "scale": {"range": ["#312eaa"]},
              "legend": {"title": ""}
            },
            
            "tooltip": [{"field": "key", "title":"Attribute"},{"field": "value", "type": "quantitative", "title":"Score"}]
          }
        },
        {
          "mark": {"type": "line"},
          "transform": [
            {
              "filter": "datum.key == 'max' || datum.key == 'min' ||datum.key == 'avg'  "
            }
          ],
          "encoding": {
            "y": {"field": "value", "type": "quantitative"},
            "stroke": {
              "field": "key",
              "scale": {"range": ["#02c754", "red", "#02b6de"]},
              "legend": {"title": ""}
            }
          }
        },
        {
          "mark": {"type": "circle", "size": 100, "opacity": "100%"},
          "params": [
            {
              "name": "highlight-max",
              "select": {"type": "point", "on": "mouseover", "encodings": ["x","y", "fill"]}
            }
          ],
          "transform": [
            {
              "filter": "datum.key == 'max' || datum.key == 'min' ||datum.key == 'avg'"
            }
          ],
          "encoding": {
            "y": {"field": "value", "type": "quantitative"},
            "fill": {
              "field": "key",
              "scale": {"range": ["#02c754", "red", "#02b6de"]},
              "legend": null
            },
            "size": {
              "condition": {"param": "highlight-max", "empty": false,  "value": 250}
            },
            "tooltip": [{"field": "key", "title":"Attribute"},{"field": "value", "type": "quantitative", "title":"Score"}]
          }
        }
      ],
      "title": "Quiz Scores",
      "$schema": "https://vega.github.io/schema/vega-lite/v5.6.json"
    }