How to add legend for single or multi series chart in Vega Lite? - vega

How do I add a legend to a basic chart in Vega?
I'm using Vega in the web app where I want all my charts to include a legend even if its a single series.
i.e in Google Sheets it looks like

Since Datum hasn't been implemented yet I added an extra layer as a workaround (This also works for Multi Series Charts by adding additional values into data.values for the rule.)
{
"mark": {
"type": "rule"
},
"data": {
"values": [
{
"color": "Total Units"
}
]
},
"encoding": {
"color": {
"field": "color",
// If you want to update the color of the legend...
"scale": {"range": ["blue", "#000"]},
"sort": false,
"type": "nominal",
"legend": { "title": "" }
}
}
}
Also for those that want to view an example in VegaLite Editor https://vega.github.io/editor/#/
{
"layer": [
{
"mark": "bar",
"data": {
"values": [
{
"goal": 25,
"project": "a",
"score": 25
},
{
"goal": 47,
"project": "b",
"score": 57
},
{
"goal": 30,
"project": "c",
"score": 23
},
{
"goal": 27,
"project": "d",
"score": 19
}
]
},
"encoding": {
"x": {
"type": "nominal",
"field": "project"
},
"y": {
"type": "quantitative",
"field": "score"
}
},
"height": 300,
"width": 400
},
{
"mark": {
"type": "rule"
},
"data": {
"values": [
{
"color": "Goal"
}
]
},
"encoding": {
"color": {
"field": "color",
"sort": false,
"type": "nominal",
"legend": { "title": "" }
}
}
}
]
}

Related

How to follow make a dot and text follow a mouse?

To get to know how events work in VEGA, I gave myself the simple exercice to render a dot and a text positioned on the cursors coordinates in a given view.
I managed to make a symbol follow the mouse coordinates, yet when I try to make two types of marks ( text and symbol) follow the mouse , it doesn't render them both but the first one appearing in the marks [ ] array.
Any ideas ?
Following specification is used in the exercice :
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 600,
"height": 600,
"signals": [
{
"name": "position",
"on": [
{
"events": {
"type": "mousemove"
},
"update": "xy()"
}
]
},
{
"name": "positionDot",
"on": [
{
"events": {
"type": "mousemove"
},
"update": "xy()"
}
]
}
],
"marks": [
{
"type": "text",
"encode": {
"enter": {
"fill": {
"value": "#000"
},
"text": {
"value": "Text Label"
}
},
"update": {
"opacity": {
"value": 1
},
"x": {
"signal": "position[0]+20"
},
"y": {
"signal": "position[1]+20"
},
"fontSize": {
"value": 50
}
}
}
},
{
"name": "dot",
"type": "symbol",
"encode": {
"enter": {
"fill": {
"value": "#939597"
},
"stroke": {
"value": "#652c90"
},
"x": {
"value": 0
},
"y": {
"value": 0
}
},
"update": {
"x": {
"signal": "positionDot[0]"
},
"y": {
"signal": "position[1]"
},
"size": {
"value": 550
},
"opacity": {
"value": 1
}
},
"hover": {
"opacity": {
"value": 0.5
}
}
}
}
]
}
https://vega.github.io/editor/#/gist/1dcd1034a1d8139b3de49f041ed1ed4b/spec.json
Your example works as expected if an initial value (using "init" or "value") is included in signal position:
"signals": [
{
"name": "position",
"init": [0, 0],
"on": [
{
"events": {
"type": "mousemove"
},
"update": "xy()"
}
]
},
View in Vega online editor

How to add vertical rules as new layer and same x-axis?

When add the strips as a new layer (in the 2-layers chart), stops to work: there are no visualization and a "WARN Cannot project a selection on encoding channel "y", which has no field".
The first two layer-definitions bellow was working fine when only two lines.
vglSpec.push(['#vis2a',{
$schema: vglVers,
data: {"url":"MyDataset1"},
// old "encoding": { x: {"field": "instant", "type": "temporal"} }
width:680,
layer: [
{
"mark": {"stroke": "#68C", "type": "line", "point": true},
"encoding": { x: {"field": "instant", "type": "temporal"}, "y": {
"field": "n_count",
"type": "quantitative"
}},
"selection": {"grid": {"type":"interval", "bind":"scales"}} //zoom
},
{
"mark": {"stroke": "red", "type": "line", "strokeOpacity": 0.4},
"encoding": { x: {"field": "instant", "type": "temporal"}, "y": {
"field": "instant_totmin",
"type": "quantitative"
}}
},
{
"mark": "rule",
"data": {"url":"MyDataset2"}, // little subset of instant of Dataset1
"encoding": {
"x": { "field": "instant", "type": "temporal"},
"color": {"value": "yellow"},
"size": {"value": 5}
},
//resolve:? x is same axis and the only visualization field
}
],
resolve: {"scale": {"y": "independent"}}
}]);
PS: only removed names and titles, all real script.
Emulating with dummy data: working fine!
Please click on the 3rd example of rule guide... And replace or adapt it for this VEGA-lite script:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/movies.json"},
"layer": [
{
"mark": "bar",
"encoding": {
"x": {"bin": true, "field": "IMDB_Rating", "type": "quantitative"},
"y": {"aggregate": "count", "type": "quantitative"}
}
},
{
"mark": "rule",
"data": {"values": [{"IMDB_Rating":3.5},{"IMDB_Rating":7.8}]},
"encoding": {
"x": { "field": "IMDB_Rating","type": "quantitative" },
"color": {"value": "yellow"},
"size": {"value": 4}
}
}
]
}
You're using an independent y-scale, and the y-scale of a rule mark with no y encoding is not well defined. The best way to address this is probably to combine the rule mark with one of the other layers, so it can use that y scale:
vglSpec.push(['#vis2a',{
$schema: vglVers,
data: {"url":"MyDataset1"},
// old "encoding": { x: {"field": "instant", "type": "temporal"} }
width:680,
layer: [
{
"mark": {"stroke": "#68C", "type": "line", "point": true},
"encoding": { x: {"field": "instant", "type": "temporal"}, "y": {
"field": "n_count",
"type": "quantitative"
}},
"selection": {"grid": {"type":"interval", "bind":"scales"}} //zoom
},
{
layer: [
{
"mark": {"stroke": "red", "type": "line", "strokeOpacity": 0.4},
"encoding": { x: {"field": "instant", "type": "temporal"}, "y": {
"field": "instant_totmin",
"type": "quantitative"
}}
},
{
"mark": "rule",
"data": {"url":"MyDataset2"}, // little subset of instant of Dataset1
"encoding": {
"x": { "field": "instant", "type": "temporal"},
"color": {"value": "yellow"},
"size": {"value": 5}
},
//resolve:? x is same axis and the only visualization field
}
]
}
],
resolve: {"scale": {"y": "independent"}}
}]);
(note, I've not actually tried this solution because you didn't include data in your question, but the approach should work).

Why column facet in Vega Lite not working properly with layer?

I'm trying to create 3 column plot and it works when there's no layer.
But when I add the layer - 3 columns get merged into one plot (open in editor).
How to make it to be separated into 3 columns by the duration field?
CODE
For the plot with the full data please use editor link above.
{
"encoding": {
"column": { "field": "duration", "type": "nominal" },
"x": { "field": "bin_i", "type": "ordinal" }
},
"layer": [
{
"mark": { "type": "bar", "size": 2 },
"encoding": {
"y": { "field": "min", "type": "quantitative" },
"y2": { "field": "max", "type": "quantitative" }
}
},
{
"mark": { "type": "tick" },
"encoding": {
"y": { "field": "mean", "type": "quantitative" }
}
}
],
"data": {
"values": [
{
"bin_i": 1,
"duration": 1,
"max": 1.9642835793718165,
"mean": 1.0781367168962268,
"min": 0.3111818864927448
},
...
]
}
}
A layered chart does not accept a faceted encoding. If you want to facet a layered chart, you should use the facet operator rather than a facet encoding.
For your example, it would look like this (Vega Editor):
{
"facet": {"column": {"field": "duration", "type": "nominal"}},
"spec": {
"encoding": {
"x": {"field": "bin_i", "type": "ordinal"}
},
"layer": [
{
"mark": {"type": "bar", "size": 2},
"encoding": {
"y": {"field": "min", "type": "quantitative"},
"y2": {"field": "max"}
}
},
{
"mark": {"type": "tick"},
"encoding": {
"y": {"field": "mean", "type": "quantitative"}
}
}
]
},
"data": {
"values": [
{
"bin_i": 1,
"duration": 1,
"max": 1.9642835793718165,
"mean": 1.0781367168962268,
"min": 0.3111818864927448
},
...
]
}
}

Incorrect axis position for grouped marks

I'd like to group axes and marks together within a group mark, as I'd like a bar chart to be one of several onto the data. However, when I do so the x axis moved from the bottom to the top of the bar chart. Here's an example:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "cars",
"format": {
"type": "json",
"parse": {
"year": "date"
}
},
"url": "https://vega.github.io/vega-datasets/data/cars.json",
"transform": [
{
"type": "aggregate",
"groupby": [
"Origin"
],
"as": [
"num_records"
]
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {
"data": "cars",
"field": "Origin"
},
"range": "width",
"padding": 0.05
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "cars",
"field": "num_records"
},
"range": "height",
"nice": true
}
],
"marks": [
{
"type": "group",
"axes": [
{
"orient": "bottom",
"scale": "x"
},
{
"orient": "left",
"scale": "y"
}
],
"marks": [
{
"type": "rect",
"from": {
"data": "cars"
},
"encode": {
"enter": {
"x": {
"scale": "x",
"field": "Origin"
},
"width": {
"scale": "x",
"band": 1
},
"y": {
"scale": "y",
"field": "num_records"
},
"y2": {
"scale": "y",
"value": 0
}
}
}
}
]
}
]
}
The Group Mark documentation suggests that groups support such nested visualisation specifications. What am I doing wrong?
What I was doing wrong was not encoding the width and height of the group mark. Here's my revised example:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "cars",
"format": {
"type": "json",
"parse": {
"year": "date"
}
},
"url": "https://vega.github.io/vega-datasets/data/cars.json",
"transform": [
{
"type": "aggregate",
"groupby": [
"Origin"
],
"as": [
"num_records"
]
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {
"data": "cars",
"field": "Origin"
},
"range": "width",
"padding": 0.05
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "cars",
"field": "num_records"
},
"range": "height",
"nice": true
}
],
"marks": [
{
"type": "group",
"axes": [
{
"orient": "bottom",
"scale": "x"
},
{
"orient": "left",
"scale": "y"
}
],
"encode": {
"enter": {
"width": {
"signal": "width"
},
"height": {
"signal": "height"
}
}
},
"marks": [
{
"type": "rect",
"from": {
"data": "cars"
},
"encode": {
"enter": {
"x": {
"scale": "x",
"field": "Origin"
},
"width": {
"scale": "x",
"band": 1
},
"y": {
"scale": "y",
"field": "num_records"
},
"y2": {
"scale": "y",
"value": 0
}
}
}
}
]
}
]
}

How to change color of stroke in Parallel Coordinate Vega Chart?

I'm working with vega charts (parallel coordinates). How do I change the color of the lines with respect to scheme colors (w.r.t 'name' field).
Here is my code
I tried changing the stroke property with color scale but there is no effect on line stroke.
Can anyone point out what am I doing wrong.
I'm using Vega Version 4
Thanks
vikky
Because the colors need to be by column "name", transform the input dataset to have repeated name rows. In other words, input dataset must be of 3 columns (name, quarter, value)
Then, change "group" type mark to use facet dataset grouped by column "name"
"name": "marks_group_lines",
"type": "group",
"from": {
"facet": {
"name": "cars_by_name",
"data": "cars",
"groupby": "name"
}
},
Use the cars_by_name as dataset to render "line" type mark.
tip: Instead of defining quarter dataset for 4 axes for each qarter and scales for these axes, "line" type mark which has point scale for "x" property can be used.
Full code for reference:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 700,
"height": 400,
"padding": 5,
"config": {
"axisY": {
"titleX": -2,
"titleY": 410,
"titleAngle": 0,
"titleAlign": "right",
"titleBaseline": "top"
}
},
"data": [
{
"name": "cars",
"values": [
{
"name": "A",
"quarter": "Q1",
"value": 51
},
{
"name": "A",
"quarter": "Q2",
"value": 47
},
{
"name": "A",
"quarter": "Q3",
"value": 45
},
{
"name": "A",
"quarter": "Q4",
"value": 30
},
{
"name": "B",
"quarter": "Q1",
"value": 42
},
{
"name": "B",
"quarter": "Q2",
"value": 57
},
{
"name": "B",
"quarter": "Q3",
"value": 72
},
{
"name": "B",
"quarter": "Q4",
"value": 41
},
{
"name": "C",
"quarter": "Q1",
"value": 25
},
{
"name": "C",
"quarter": "Q2",
"value": 37
},
{
"name": "C",
"quarter": "Q3",
"value": 60
},
{
"name": "C",
"quarter": "Q4",
"value": 25
},
{
"name": "D",
"quarter": "Q1",
"value": 22
},
{
"name": "D",
"quarter": "Q2",
"value": 25
},
{
"name": "D",
"quarter": "Q3",
"value": 51
},
{
"name": "D",
"quarter": "Q4",
"value": 42
}
]
},
{
"name": "fields",
"values": [
"Q1",
"Q2",
"Q3",
"Q4"
]
}
],
"scales": [
{
"name": "name_to_xaxis",
"type": "point",
"domain": {
"data": "cars",
"field": "quarter"
},
"range": "width"
},
{
"name": "values_to_height",
"type": "linear",
"domain": {
"data": "cars",
"field": "value"
},
"range": "height"
},
{
"name": "quarter_to_color",
"type": "ordinal",
"domain": {
"data": "cars",
"field": "name"
},
"range": "category"
},
{
"name": "ord",
"type": "point",
"range": "width",
"round": true,
"domain": {
"data": "fields",
"field": "data"
}
},
{
"name": "Q1",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q1"
}
},
{
"name": "Q2",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q2"
}
},
{
"name": "Q3",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q3"
}
},
{
"name": "Q4",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q4"
}
}
],
"axes": [
{
"orient": "left",
"zindex": 1,
"scale": "Q1",
"title": "Q1",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q1",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q2",
"title": "Q2",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q2",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q3",
"title": "Q3",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q3",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q4",
"title": "Q4",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q4",
"mult": -1
}
}
],
"marks": [
{
"name": "marks_group_lines",
"type": "group",
"from": {
"facet": {
"name": "cars_by_name",
"data": "cars",
"groupby": "name"
}
},
"marks": [
{
"name": "marks_lines",
"type": "line",
"from": {
"data": "cars_by_name"
},
"encode": {
"update": {
"x": {
"scale": "name_to_xaxis",
"field": "quarter"
},
"y": {
"scale": "values_to_height",
"field": "value"
},
"stroke": {
"scale": "quarter_to_color",
"field": "name"
},
"strokeOpacity": {
"value": 1
}
},
"hover": {
"stroke": {
"value": "#7c7c7c"
},
"strokeOpacity": {
"value": 1
},
"zindex": 99
}
}
},
{
"name": "marks_symbols",
"type": "symbol",
"from": {
"data": "cars_by_name"
},
"encode": {
"enter": {
"stroke": {
"value": "#6D6D6D"
},
"strokeWidth": {
"value": 1
},
"shape": {
"value": "circle"
}
},
"update": {
"x": {
"scale": "name_to_xaxis",
"field": "quarter"
},
"y": {
"scale": "values_to_height",
"field": "value"
},
"fill": {
"scale": "quarter_to_color",
"field": "name"
},
"size": {
"value": 50
},
"stroke": {
"value": "#77AE80"
}
},
"hover": {
"fill": {
"value": "#AFD098"
}
}
}
}
]
}
]
}