1

I am able to implement vega-lite chart which renders as follows:

enter image description here

The code for it looks something like this:

{
  "width": 400,
  "config": {"view": {"continuousWidth": 600, "continuousHeight": 300}},
  "data": {"name": "data-eb6aa7311f370dcc2f64d37c32c9e387"},
  "usermeta": {"embedOptions": {"renderer": "svg"}},
  "layer":[
    {
      "mark": {"type": "bar", "width": {"band": 0.2}},
      "encoding": {
        "x": {"field": "title", 
              "type": "nominal",
              "axis": { "title": "Quizzes"}
             },
        "y": {"field": "my-score", 
              "type": "quantitative",
              "axis": { "title": "Percentage Score"}
             }
      }
    },
    {
      "mark": {"type": "line", "color": "red"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "max", "type": "quantitative"}
      }
    },
    {
      "mark": {"type": "circle", "color": "red", "size":100, "opacity": "100"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "max", "type": "quantitative"},
      }
    },
    {
      "mark": {"type": "line", "color": "#02c754"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "avg", "type": "quantitative"}
      }
    },
    {
      "mark": {"type": "circle", "color": "#02c754", "size":100, "opacity": "100"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "avg", "type": "quantitative"}
      }
    },
    {
      "mark": {"type": "line", "color": "#02b6de"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "min", "type": "quantitative"}
      }
    },
    {
      "mark": {"type": "circle", "color": "#02b6de", "size":100, "opacity": "100"},
      "encoding": {
        "x": {"field": "title", "type": "nominal"},
        "y": {"field": "min", "type": "quantitative"}
      }
    }
    
  ],
  "title": "Quiz Scores",
  "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json",
  "datasets": {
    "data-eb6aa7311f370dcc2f64d37c32c9e387": [ 
      {
        "title": "Quiz-1",
        "my-score": 62,
        "max": 80,
        "avg": 45,
        "min": 15
      },
      {
        "title": "Quiz-2",
        "my-score": 48,
        "max": 48,
        "avg": 30,
        "min": 10
      },
      {
        "title": "Quiz-3",
        "my-score": 54,
        "max": 62,
        "avg": 36,
        "min": 12
      },
      {
        "title": "Quiz-4",
        "my-score": 27,
        "max": 69,
        "avg": 50,
        "min": 9
      },
      {
        "title": "Quiz-5",
        "my-score": 40,
        "max": 48,
        "avg": 30,
        "min": 11
      },
      {
        "title": "Quiz-6",
        "my-score": 50,
        "max": 55,
        "avg": 28,
        "min": 5
      },
    ]
  }
}

I want to render legends for the same something like this:

enter image description here

I am not able to figure out how I can do this. I checked the example given here or precisely this example. But the stock data used by this example has different schema: {symbol, date, price} and it renders different colors for different values in symbol. And vega-lite seem to auto generate legends from this schema. But, in my case, the schema is of the form {title, my-score, max, avg, min}. How do I implement legends as shown in the picture above (also note that legend for bar chart is somewhat wide)? I am fine to have somewhat different legends as long as they are sensible. But do I have to transform data to match the schema to what vega-lite stocks example schema?

PS: You can try out my visualization at this URL.

Davide Bacci
  • 16,647
  • 3
  • 10
  • 36
MsA
  • 2,599
  • 3
  • 22
  • 47

1 Answers1

1

Here you go.

enter image description here

{
  "width": 400,
  "config": {"view": {"continuousWidth": 600, "continuousHeight": 300}},
  "data": {
    "values": [
      {"title": "Quiz-1", "my-score": 62, "max": 80, "avg": 45, "min": 15},
      {"title": "Quiz-2", "my-score": 48, "max": 48, "avg": 30, "min": 10},
      {"title": "Quiz-3", "my-score": 54, "max": 62, "avg": 36, "min": 12},
      {"title": "Quiz-4", "my-score": 27, "max": 69, "avg": 50, "min": 9},
      {"title": "Quiz-5", "my-score": 40, "max": 48, "avg": 30, "min": 11},
      {"title": "Quiz-6", "my-score": 50, "max": 55, "avg": 28, "min": 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"]}}
      }
    },
    {
      "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": ["green", "red", "#3aa1ff"]},
          "legend": {"title": ""}
        }
      }
    },
    {
      "mark": {"type": "circle"},
      "transform": [
        {
          "filter": "datum.key == 'max' || datum.key == 'min' ||datum.key == 'avg'  "
        }
      ],
      "encoding": {
        "y": {"field": "value", "type": "quantitative"},
        "fill": {
          "field": "key",
          "scale": {"range": ["green", "red", "#3aa1ff"]},
          "legend": null
        }
      }
    }
  ],
  "title": "Quiz Scores",
  "$schema": "https://vega.github.io/schema/vega-lite/v5.6.json"
}
Davide Bacci
  • 16,647
  • 3
  • 10
  • 36
  • Am not as proficient as you in vega-lite. Please help me understand what you did: **Q1.** filtering three `key`s for line mark and specifying `value` as field is enough for vega-lite to plot three lines? Till now I was explicitly specifying field to be used for specific line. But this approach seem different. Is there any article in vega lite doc that exaplains this approach? **Q2.** Why it still show `my-score` legend even when there is no legend specified for bar? Also what does it mean by `"legend": {"title": ""}` and `"legend": null`? – MsA Mar 17 '23 at 09:01
  • Your original had lots of repeated encodings which are not necessary. Your data was also in the wrong shape which is what the fold transform takes care of - have a look in the editor at the table it generates. That is the answer to question 1 and question 2. If you put a title in the title, you can see what happens and if you remove legend null, you'll end up with 2 legends. Have a play with the spec to see what changes. Plotting in Vega usually comes down to how your data is shaped and the key to both questions is the fold transform. – Davide Bacci Mar 17 '23 at 09:10
  • Ohh I see, so `color` encoding by default creates a legend. To remove redundant legends, you set `"legend": null` & to remove redundant title `key`, u set `"legend": {"title": ""}`. Also, I had some redundant encoding because thats how I found some examples in docs: creating encodings and then layering them up. Is there any book / course from which you got grip of vega-lite? Or examples, tutorial and doc at [vega-lite](https://vega.github.io/vega-lite/) & [this course](https://observablehq.com/@uwdata/data-visualization-curriculum) are the only sources? Is there any better source you referred? – MsA Mar 17 '23 at 10:18
  • 1
    Sorry, I don't know of any courses - I just learnt by going through all the examples. If you get stuck, just post here. You can see my LinkedIn for some advanced dataviz examples and I post all the code in my Github for others to learn from. – Davide Bacci Mar 17 '23 at 11:02
  • Btw, it seems that this approach makes it impossible to apply on-hover animation to just one circle (say just max). Instead of animating just one hovered-circle, it animates all three circles. Also specifying `"tooltip": [{"field": "value", "type": "quantitative"}]`, just shows `value: N` for all circles, but not `Avg: N`, `Max: N`and `Min: N`. Is there any way to fix it. [Here is my viz](https://pastebin.com/Jinrncwq). (I have shared URL on pastebin as vega URL is huge for comments and stckoverflow comments does not allow shortened URLs.) Should I create new question for doubt? – MsA Mar 17 '23 at 11:32
  • (continued from last comment...) I noticed a weird behavior, when we open the bitly link shared in pastebin, the circles in visualisation are not rendered in edge browser, but are present in chrome and brave browser. – MsA Mar 17 '23 at 11:37
  • I'd add a new question describing your desired behaviour. – Davide Bacci Mar 17 '23 at 12:02
  • Asked new one [here](https://stackoverflow.com/questions/75767964/achieving-custom-tooltip-containing-multiple-columns-in-vega-lite). – MsA Mar 17 '23 at 13:08