What type of Vega marks to show a point along a scale? (see image) - vega

I am attempting to create a visualization where we are showing a score along a scale, something like this:
The scale is based on quartiles of a large dataset (these are pre-calculated and don’t need to be calculated within Vega). In this particular example, the scale looks like this:
Break
Value
Min
0
Low
26.3
Mid
42.9
High
54.8
Max
70.7
So in the example image above, the score we are reporting is something like 56 (I will display the score with a tooltip).
At this point, I’m not even sure what type of marks I should be using in Vega to attempt to create this display. Any help getting started is greatly appreciated!

Here is a complete example in Vega.
Open in Vega on-line editor
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 100,
"padding": 5,
"data": [
{
"name": "data_segments",
"values": [
{"segmentLabel": "min", "segmentStart": 0, "segmentEnd": 26.3},
{"segmentLabel": "low", "segmentStart": 26.3, "segmentEnd": 42.9},
{"segmentLabel": "mid", "segmentStart": 42.9, "segmentEnd": 54.8},
{"segmentLabel": "high", "segmentStart": 54.8, "segmentEnd": 70.7}
]
}
],
"signals": [
{
"name": "signal_score",
"value": "56",
"bind": {"input": "range", "min": 0, "max": 70.7, "step": 0.01, "name": "Score: "}
},
{
"name": "signal_score_mid",
"value": "42.9"
}
],
"scales": [
{
"name": "scale_x",
"type": "linear",
"domain": {"data": "data_segments", "fields": ["segmentStart", "segmentEnd"]},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "scale_y",
"domain": [0, 1],
"range": "height"
},
{
"name": "scale_segment_color",
"type": "ordinal",
"domain": ["min", "low", "mid", "high"],
"range": ["grey", "green", "orange", "red"]
},
{
"name": "scale_segment_opacity",
"type": "ordinal",
"domain": ["min", "low", "mid", "high"],
"range": [0.5, 0.5, 0.5, 0.5]
}
],
"axes": [
{ "orient": "bottom", "scale": "scale_x" },
{ "orient": "left", "scale": "scale_y", "domainOpacity": 0, "tickOpacity": 0, "labelOpacity": 0}
],
"marks": [
{
"type": "rect",
"from": {"data":"data_segments"},
"encode": {
"enter": {
"x": {"scale": "scale_x", "field": "segmentStart"},
"x2": {"scale": "scale_x", "field": "segmentEnd"},
"y": {"scale": "scale_y", "value": 0.5},
"y2": {"scale": "scale_y", "value": 0.7},
"fill": {"scale": "scale_segment_color", "field": "segmentLabel"},
"fillOpacity":{"scale": "scale_segment_opacity", "field": "segmentLabel"},
"stroke": {"value": "white"}
}
}
},
{
"type": "text",
"from": {"data":"data_segments"},
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "top"},
"fill": {"value": "black"},
"fillOpacity": {"signal": "datum['segmentLabel'] == 'min' ? 0 : 1 "},
"x": {"scale": "scale_x", "field": "segmentStart"},
"y": {"scale": "scale_y", "value": 0.4},
"text": {"field": "segmentLabel"}
}
}
},
{
"type": "rect",
"from": {"data":"data_segments"},
"encode": {
"update": {
"x": {"signal": "scale('scale_x', signal_score) - 5"},
"x2": {"signal": "scale('scale_x', signal_score) + 5"},
"y": {"scale": "scale_y", "value": 0.45},
"y2": {"scale": "scale_y", "value": 0.75},
"fill": {"value": "red"},
"fillOpacity":{"value": 0.7},
"stroke": {"value": "grey"},
"tooltip": {"signal": "signal_score"}
}
}
},
{
"type": "rule",
"from": {"data":"data_segments"},
"encode": {
"update": {
"x": {"signal": "scale('scale_x', signal_score_mid)"},
"x2": {"signal": "scale('scale_x', signal_score) + ((signal_score > signal_score_mid) ? -15 : 15)"},
"y": {"scale": "scale_y", "value": 0.6},
"stroke": {"value": "blue"},
"strokeWidth": {"value": 2},
"opacity": {"value": 1}
}
}
},
{
"type": "symbol",
"from": {"data":"data_segments"},
"encode": {
"update": {
"x": {"signal": "scale('scale_x', signal_score) + ((signal_score > signal_score_mid) ? -15 : 15)"},
"y": {"scale": "scale_y", "value": 0.6},
"angle": {"signal": "signal_score > signal_score_mid ? 90 : -90"},
"size": {"value": 100},
"shape": {"value": "triangle"},
"opacity": {"value": 1},
"fill": {"value": "blue"}
}
}
}
]
}

Related

Labels on Rects in Vega Stacked Bar Chart

In the old vega-label documentation there is reference to a labeled stacked bar chart example. The example spec doesn’t work in the online Vega editor, throwing an error that a.map is not a function.
I am trying to do almost exactly what is referenced in the above example: create a vertically-stacked bar chart where each segment is labeled with its value. I have seen a few examples of this in Vega-Lite with layers, but how can it be achieved in Vega?
I’ve attempted to recreate the above spec using a group containing the rect mark and the text mark, but I’m not getting it right. I also see how to display the value as a tooltip on hover, but I’d like it displayed in the rectangle of each segment of the bar itself.
Ideally I would end up with a chart like this:
Here’s the spec I’ve been working with:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic stacked bar chart example.",
"width": 294,
"height": 200,
"padding": 5,
"autosize": {"type": "fit-x", "contains": "padding"},
"data": [
{
"name": "categories",
"values": [
{"y": 5, "c": 0, "name": "other"},
{"y": 7, "c": 1, "name": "corn"},
{"y": 22, "c": 2, "name": "pasture/hay"},
{"y": 31, "c": 3, "name": "developed"},
{"y": 35, "c": 4, "name": "forest"}
],
"transform": [
{
"type": "stack",
"field": "y"
}
]
}
],
"scales": [
{
"name": "y",
"type": "linear",
"range": "height",
"nice": true, "zero": true,
"domain": {"data": "categories", "field": "y1"}
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "categories", "field": "c"}
}
],
"axes": [
],
"marks": [
{
"name": "categoriesBars",
"type": "group",
"from": {"data": "categories"},
"zindex": 1,
"marks": [
{
"type": "rect",
"from": {"data": "categories"},
"encode": {
"enter": {
"x": {"value": 0},
"width": {"value": 294},
"y": {"scale": "y", "field": "y0"},
"y2": {"scale": "y", "field": "y1"},
"fill": {"scale": "color", "field": "c"}
},
"update": {
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"y": {"field": {"parent": "y"}},
"x": {"value": 130},
"fill": [
{"test": "contrast('white', datum.fill) > contrast('black', datum.fill)", "value": "white"},
{"value": "black"}
],
"align": {"value": "center"},
"baseline": {"value": "middle"},
"text": {"field": {"parent": "name"}}
}
}
}
]
}
]
}
Is this what you're after?
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic stacked bar chart example.",
"width": 294,
"height": 200,
"padding": 5,
"autosize": {"type": "fit-x", "contains": "padding"},
"data": [
{
"name": "categories",
"values": [
{"y": 5, "c": 0, "name": "other"},
{"y": 7, "c": 1, "name": "corn"},
{"y": 22, "c": 2, "name": "pasture/hay"},
{"y": 31, "c": 3, "name": "developed"},
{"y": 35, "c": 4, "name": "forest"}
],
"transform": [{"type": "stack", "field": "y"}]
}
],
"scales": [
{
"name": "y",
"type": "linear",
"range": "height",
"nice": true,
"zero": true,
"domain": {"data": "categories", "field": "y1"}
},
{
"name": "color",
"type": "ordinal",
"range": {"scheme": "pastel2"},
"domain": {"data": "categories", "field": "c"}
}
],
"axes": [],
"marks": [
{
"name": "i",
"type": "rect",
"from": {"data": "categories"},
"encode": {
"enter": {
"x": {"value": 0},
"width": {"value": 294},
"y": {"scale": "y", "field": "y0"},
"y2": {"scale": "y", "field": "y1"},
"fill": {"scale": "color", "field": "c"}
},
"update": {"fillOpacity": {"value": 1}},
"hover": {"fillOpacity": {"value": 0.5}}
}
},
{
"type": "text",
"from": {"data": "i"},
"encode": {
"update": {
"y": {"field": "y"},
"dy": {"signal": "(datum.y2 - datum.y)/2"},
"x": {"signal": "width/2"},
"fill": [
{
"test": "contrast('white', datum.fill) > contrast('black', datum.fill)",
"value": "white"
},
{"value": "black"}
],
"align": {"value": "center"},
"baseline": {"value": "middle"},
"text": {"field": "datum.name"}
}
}
}
]
}

Modifying the Width of a Symbol Mark in Vega

I want to label the symbols in my Vega graph. Some of the labels are long, extending beyond the boundaries of my symbols. How do I extend the width of a symbol to handle long labels?
Update: Is there a way of increasing the width of a symbol mark?
This is a link to my code.
N.B: I tried using rect marks, whose widths are easier to modify. But the aesthetics of the rect mark do not work for my use case. My use case is a Force Transform force-directed graph.
Here is a working example using your Vega spec with Force transform and text box using reactive geometry as suggested by David.
View in Vega online editor
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A node-link diagram with force-directed layout, depicting character co-occurrence in the novel Les Misérables.",
"width": 500,
"height": 200,
"autosize": "pad",
"signals": [
{
"name": "nodeRadius",
"value": 50,
"bind": {"input": "range", "min": 1, "max": 100, "step": 1}
},
{
"name": "nodeCharge",
"value": -100,
"bind": {"input": "range", "min": -100, "max": 10, "step": 1}
},
{
"name": "linkDistance",
"value": 66,
"bind": {"input": "range", "min": 5, "max": 100, "step": 1}
},
{
"name": "textPadding",
"value": 5,
"bind": {"input": "range", "min": 0, "max": 20, "step": 1}
},
{
"name": "cornerRadius",
"value": 10,
"bind": {"input": "range", "min": 0, "max": 20, "step": 1}
},
{ "name": "showSymbol", "value": false, "bind": {"input": "checkbox"} },
],
"data": [
{
"name": "node_data",
"values": [
{"name": "A Name", "type": "node", "1d": 0},
{"name": "A Very Long Name", "type": "node", "1d": 1}
]
},
{"name": "edge_data", "values": [{"source": 0, "target": 1}]}
],
"marks": [
{
"type": "symbol",
"name": "nodes",
"from": {"data": "node_data"},
"encode": {
"update": {
"fill": {"value": "grey"},
"opacity": {"signal": "showSymbol ? 0.5 : 0"},
"size": {"signal": "PI * nodeRadius * nodeRadius"},
"shape": {"value": "circle"}
}
},
"transform": [
{
"type": "force",
"iterations": 300,
"static": {"signal": "false"},
"signal": "force",
"forces": [
{
"force": "center",
"x": {"signal": "width/2"},
"y": {"signal": "height/2"}
},
{"force": "collide", "radius": {"signal": "nodeRadius"}},
{"force": "nbody", "strength": {"signal": "nodeCharge * 10"}},
{
"force": "link",
"links": "edge_data",
"distance": {"signal": "linkDistance"}
}
]
}
]
},
{
"type": "path",
"from": {"data": "edge_data"},
"interactive": false,
"encode": {
"update": {"stroke": {"value": "#ccc"}, "strokeWidth": {"value": 0.5}}
},
"transform": [
{
"type": "linkpath",
"require": {"signal": "force"},
"shape": "line",
"sourceX": "datum.source.x",
"sourceY": "datum.source.y",
"targetX": "datum.target.x",
"targetY": "datum.target.y"
}
]
},
{
"type": "text",
"name": "textmark",
"from": {"data": "nodes"},
"interactive": false,
"encode": {
"enter": {"fill": {"value": "black"}, "fontSize": {"value": 16}},
"update": {
"y": {"field": "y", "offset": {"signal": "nodeRadius * -0.1"}},
"x": {"field": "x"},
"text": {"field": "datum.name"},
"align": {"value": "center"},
"baseline": {"value": "middle"}
}
},
"zindex": 1
},
{
"name": "rectmark",
"type": "rect",
"from": {"data": "textmark"},
"encode": {
"update": {
"x": {"field": "bounds.x1", "round": true, "offset": {"signal": "-textPadding"}},
"x2": {"field": "bounds.x2", "round": true, "offset": {"signal": "textPadding"}},
"y": {"field": "bounds.y1", "round": true, "offset": {"signal": "-textPadding"}},
"y2": {"field": "bounds.y2", "round": true, "offset": {"signal": "textPadding"}},
"cornerRadius": {"signal": "cornerRadius"},
"fill": {"value": "aliceblue"},
"stroke": {"value": "steelblue"}
}
}
}
]
}
It isn't clear what you're asking. Do you mean just increase the size of the symbol statically like this?
If so, just put a value in the size property.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A node-link diagram with force-directed layout, depicting character co-occurrence in the novel Les Misérables.",
"width": 700,
"height": 500,
"autosize": "pad",
"signals": [
{
"name": "nodeRadius",
"value": 50,
"bind": {"input": "range", "min": 1, "max": 50, "step": 1}
},
{
"name": "nodeCharge",
"value": -100,
"bind": {"input": "range", "min": -100, "max": 10, "step": 1}
},
{
"name": "linkDistance",
"value": 66,
"bind": {"input": "range", "min": 5, "max": 100, "step": 1}
}
],
"data": [
{
"name": "node_data",
"values": [
{"name": "A Name", "type": "node", "1d": 0},
{"name": "A Very Long Name", "type": "node", "1d": 1}
]
},
{"name": "edge_data", "values": [{"source": 0, "target": 1}]}
],
"marks": [
{
"type": "symbol",
"name": "nodes",
"from": {"data": "node_data"},
"encode": {
"enter": {
"fill": {"value": "steelblue"},
"size": {"value": 10000},
"tooltip": {"field": "name"}
}
},
"transform": [
{
"type": "force",
"iterations": 300,
"static": {"signal": "false"},
"signal": "force",
"forces": [
{
"force": "center",
"x": {"signal": "width/2"},
"y": {"signal": "height/2"}
},
{"force": "collide", "radius": {"signal": "nodeRadius"}},
{"force": "nbody", "strength": {"signal": "nodeCharge * 10"}},
{
"force": "link",
"links": "edge_data",
"distance": {"signal": "linkDistance"}
}
]
}
]
},
{
"type": "path",
"from": {"data": "edge_data"},
"interactive": false,
"encode": {
"update": {"stroke": {"value": "#ccc"}, "strokeWidth": {"value": 0.5}}
},
"transform": [
{
"type": "linkpath",
"require": {"signal": "force"},
"shape": "line",
"sourceX": "datum.source.x",
"sourceY": "datum.source.y",
"targetX": "datum.target.x",
"targetY": "datum.target.y"
}
]
},
{
"type": "text",
"from": {"data": "nodes"},
"interactive": false,
"enter": {"fill": {"value": "black"}, "fontSize": {"value": 10}},
"encode": {
"update": {
"y": {"field": "y", "offset": {"signal": "nodeRadius * -0.1"}},
"x": {"field": "x"},
"text": {"field": "datum.name"},
"align": {"value": "center"}
}
}
}
]
}
Or you can split the word like this.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A node-link diagram with force-directed layout, depicting character co-occurrence in the novel Les Misérables.",
"width": 700,
"height": 500,
"autosize": "pad",
"signals": [
{
"name": "nodeRadius",
"value": 50,
"bind": {"input": "range", "min": 1, "max": 50, "step": 1}
},
{
"name": "nodeCharge",
"value": -100,
"bind": {"input": "range", "min": -100, "max": 10, "step": 1}
},
{
"name": "linkDistance",
"value": 66,
"bind": {"input": "range", "min": 5, "max": 100, "step": 1}
}
],
"data": [
{
"name": "node_data",
"values": [
{"name": "A Name", "type": "node", "1d": 0},
{"name": ["A Very", "Long Name"], "type": "node", "1d": 1}
]
},
{"name": "edge_data", "values": [{"source": 0, "target": 1}]}
],
"marks": [
{
"type": "symbol",
"name": "nodes",
"from": {"data": "node_data"},
"encode": {
"enter": {
"fill": {"value": "steelblue"},
"size": {"value": 10000},
"tooltip": {"field": "name"}
}
},
"transform": [
{
"type": "force",
"iterations": 300,
"static": {"signal": "false"},
"signal": "force",
"forces": [
{
"force": "center",
"x": {"signal": "width/2"},
"y": {"signal": "height/2"}
},
{"force": "collide", "radius": {"signal": "nodeRadius"}},
{"force": "nbody", "strength": {"signal": "nodeCharge * 10"}},
{
"force": "link",
"links": "edge_data",
"distance": {"signal": "linkDistance"}
}
]
}
]
},
{
"type": "path",
"from": {"data": "edge_data"},
"interactive": false,
"encode": {
"update": {"stroke": {"value": "#ccc"}, "strokeWidth": {"value": 0.5}}
},
"transform": [
{
"type": "linkpath",
"require": {"signal": "force"},
"shape": "line",
"sourceX": "datum.source.x",
"sourceY": "datum.source.y",
"targetX": "datum.target.x",
"targetY": "datum.target.y"
}
]
},
{
"type": "text",
"from": {"data": "nodes"},
"interactive": false,
"enter": {"fill": {"value": "black"}, "fontSize": {"value": 10}},
"encode": {
"update": {
"y": {"field": "y", "offset": {"signal": "nodeRadius * -0.1"}},
"x": {"field": "x"},
"text": {"field": "datum.name"},
"align": {"value": "center"}
}
}
}
]
}
If you want something dynamic to size the node to the label extent, you have to use reactive geometry.
Using reactive geometry for you. This example is from jheer on GitHub.
This sets the rectangles width and height according to the text mark.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 100,
"height": 100,
"data": [
{"name": "labels", "values": [{"label": "Text"}]}
],
"marks": [
{
"type": "group",
"signals": [
{"name": "bgoffset", "value": 3}
],
"marks": [
{
"name": "textmark",
"type": "text",
"from": {"data": "labels"},
"encode": {
"enter": {
"text": {"field": "label"},
"x": {"value": 50},
"y": {"value": 50},
"fontSize": {"value": 14},
"align": {"value": "center"},
"baseline": {"value": "middle"}
}
},
"zindex": 1
},
{
"name": "rectmark",
"type": "rect",
"from": {"data": "textmark"},
"encode": {
"enter": {
"x": {"field": "bounds.x1", "round": true, "offset": {"signal": "-bgoffset"}},
"x2": {"field": "bounds.x2", "round": true, "offset": {"signal": "bgoffset"}},
"y": {"field": "bounds.y1", "round": true, "offset": {"signal": "-bgoffset"}},
"y2": {"field": "bounds.y2", "round": true, "offset": {"signal": "bgoffset"}},
"fill": {"value": "aliceblue"},
"stroke": {"value": "steelblue"}
}
}
}
]
}
]
}

How to put x-axis labels in Vega using "datum"?

In Vega, I want to put in the x-axis labels an expression with the data from the "reference" column. I have only been able to put a fixed label for all the values (commented line 67), but when I try to put the expression "datum.reference" in the text, I can't do it (line 68). Could you help me? Thank you very much in advance
The code is the following:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"padding": 5,
"autosize": "pad",
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28, "reference": "ref1"},
{"category": "B", "amount": 55, "reference": "ref2"},
{"category": "C", "amount": 43, "reference": "ref3"},
{"category": "D", "amount": 91, "reference": "ref1"},
{"category": "E", "amount": 81, "reference": "ref4"},
{"category": "F", "amount": 53, "reference": "ref5"},
{"category": "G", "amount": 19, "reference": "ref6"},
{"category": "H", "amount": 87, "reference": "ref7"}
]
}
],
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale",
"title": "X-Axis",
"encode": {
"ticks": {
"update": {
"stroke": {"value": "steelblue"}
}
},
"labels": {
"interactive": true,
"update": {
//"text": {"value": "x_label"}, // Line 67: This is fine
"text": {"expr": "datum.reference"}, // Line 68: Here, I have the problem
"fill": {"value": "steelblue"},
"angle": {"value": 50},
"fontSize": {"value": 14},
"align": {"value": "left"},
"baseline": {"value": "middle"},
"dx": {"value": 3}
},
"hover": {
"fill": {"value": "firebrick"}
}
},
"title": {
"update": {
"fontSize": {"value": 16}
}
},
"domain": {
"update": {
"stroke": {"value": "#333"},
"strokeWidth": {"value": 1.5}
}
}
}
},
{ "orient": "left",
"scale": "yscale",
"title": "Y-Axis",
"tickCount": 4,"offset": 6 }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "isNaN(tooltip.amount)", "value": 0},
{"value": 1}
]
}
}
}
]
}
```
First of all, "datum" in Vega axis does not refer to any item in the dataset "table". Instead, Vega axis uses an internally generated dataset based on the scale defined for that axis.
See Vega documentation for "axis". The documentation also states that (without giving an example):
Custom text can be defined using the "text" property for labels. For example, one could define an ordinal scale that serves as a lookup table from axis values to axis label text.
Here is an example of how to use a lookup dataset and scale for this purpose. Note that all values of "category" must be unique and all values for "reference" must be unique.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"padding": 5,
"autosize": "pad",
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28},
{"category": "B", "amount": 55},
{"category": "C", "amount": 43},
{"category": "D", "amount": 91},
{"category": "E", "amount": 81},
{"category": "F", "amount": 53},
{"category": "G", "amount": 19},
{"category": "H", "amount": 87}
]
},
{
"name": "data_lookup",
"values": [
{"category": "A", "reference": "ref1"},
{"category": "B", "reference": "ref2"},
{"category": "C", "reference": "ref3"},
{"category": "D", "reference": "ref10"},
{"category": "E", "reference": "ref4"},
{"category": "F", "reference": "ref5"},
{"category": "G", "reference": "ref6"},
{"category": "H", "reference": "ref7"}
]
}
],
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "scale_lookup",
"type": "ordinal",
"domain": {"data": "data_lookup", "field": "category"},
"range": {"data": "data_lookup", "field": "reference"}
},
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale",
"title": "X-Axis",
"encode": {
"ticks": {
"update": {
"stroke": {"value": "steelblue"}
}
},
"labels": {
"interactive": true,
"update": {
"text": {"signal": "scale('scale_lookup', datum.value)"},
"fill": {"value": "steelblue"},
"angle": {"value": 50},
"fontSize": {"value": 14},
"align": {"value": "left"},
"baseline": {"value": "middle"},
"dx": {"value": 3}
},
"hover": {
"fill": {"value": "firebrick"}
}
},
"title": {
"update": {
"fontSize": {"value": 16}
}
},
"domain": {
"update": {
"stroke": {"value": "#333"},
"strokeWidth": {"value": 1.5}
}
}
}
},
{ "orient": "left",
"scale": "yscale",
"title": "Y-Axis",
"tickCount": 4,"offset": 6 }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "isNaN(tooltip.amount)", "value": 0},
{"value": 1}
]
}
}
}
]
}
View in Vega online editor.
I have solved the problem in a very simple way. Just creating a transform that concatenates the two fields and then using that new column to represent the data. Anyway thank you very much for the other solution that I find very interesting and useful.
Here I provide the code of what I wanted to achieve
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"padding": 5,
"autosize": "pad",
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28, "reference": "ref1"},
{"category": "B", "amount": 55, "reference": "ref2"},
{"category": "C", "amount": 43, "reference": "ref3"},
{"category": "D", "amount": 91, "reference": "ref1"},
{"category": "E", "amount": 81, "reference": "ref4"},
{"category": "F", "amount": 53, "reference": "ref5"},
{"category": "G", "amount": 19, "reference": "ref6"},
{"category": "H", "amount": 87, "reference": "ref7"}
],
"transform":[
{"type": "formula",
"expr": "datum.category + ' (' + datum.reference + ')' ",
"as": "category(ref)"}
]
},
],
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category(ref)"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale",
"title": "X-Axis",
"encode": {
"ticks": {
"update": {
"stroke": {"value": "steelblue"}
}
},
"labels": {
"interactive": true,
"update": {
"fill": {"value": "steelblue"},
"angle": {"value": 50},
"fontSize": {"value": 14},
"align": {"value": "left"},
"baseline": {"value": "middle"},
"dx": {"value": 3}
},
"hover": {
"fill": {"value": "firebrick"}
}
},
"title": {
"update": {
"fontSize": {"value": 16}
}
},
"domain": {
"update": {
"stroke": {"value": "#333"},
"strokeWidth": {"value": 1.5}
}
}
}
},
{ "orient": "left",
"scale": "yscale",
"title": "Y-Axis",
"tickCount": 4,"offset": 6 }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category(ref)"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "isNaN(tooltip.amount)", "value": 0},
{"value": 1}
]
}
}
}
]
}

Vertical Violin Plot in Vega

I'm trying to swap the axes on the violin plot example provided by the Vega documentation here. When attempting this myself (link here) I seem successful in swapping the axes, and the rectangles seem to render fine. However the area chart (the actual violin) is completely absent. I'm completely at a loss on this. Any help would be much appriciated.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A violin plot example showing distributions for pengiun body mass.",
"width": 800,
"height": 600,
"padding": 5,
"config": {
"axisBand": {"bandPosition": 1, "tickExtra": true, "tickOffset": 0}
},
"signals": [
{"name": "plotWidth", "update": "(width - 30)/3"},
{"name": "height", "update": "height * 1"},
{"name": "trim", "value": true, "bind": {"input": "checkbox"}},
{
"name": "bandwidth",
"value": 0,
"bind": {"input": "range", "min": 0, "max": 200, "step": 1}
}
],
"data": [
{
"name": "penguins",
"url": "data/penguins.json",
"transform": [
{
"type": "filter",
"expr": "datum.Species != null && datum['Body Mass (g)'] != null"
}
]
},
{
"name": "density",
"source": "penguins",
"transform": [
{
"type": "kde",
"field": "Body Mass (g)",
"groupby": ["Species"],
"bandwidth": {"signal": "bandwidth"},
"extent": {"signal": "trim ? null : [2000, 6500]"}
}
]
},
{
"name": "stats",
"source": "penguins",
"transform": [
{
"type": "aggregate",
"groupby": ["Species"],
"fields": ["Body Mass (g)", "Body Mass (g)", "Body Mass (g)"],
"ops": ["q1", "median", "q3"],
"as": ["q1", "median", "q3"]
}
]
}
],
"scales": [
{
"name": "layout",
"type": "band",
"range": "width",
"domain": {"data": "penguins", "field": "Species"}
},
{
"name": "yscale",
"type": "linear",
"range": "height",
"round": true,
"domain": {"data": "penguins", "field": "Body Mass (g)"},
"domainMin": 0,
"zero": false,
"nice": true
},
{
"name": "hscale",
"type": "linear",
"range": [0, {"signal": "plotWidth"}],
"domain": {"data": "density", "field": "density"}
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "penguins", "field": "Species"},
"range": "category"
}
],
"axes": [
{"orient": "bottom", "scale": "layout", "zindex": 1},
{"orient": "left", "scale": "yscale", "zindex": 1}
],
"marks": [
{
"type": "group",
"from": {
"facet": {"data": "density", "name": "violin", "groupby": "Species"}
},
"encode": {
"enter": {
"xc": {"scale": "layout", "field": "Species", "band": 0.5},
"width": {"signal": "plotWidth"},
"height": {"signal": "height"}
}
},
"data": [
{
"name": "summary",
"source": "stats",
"transform": [
{"type": "filter", "expr": "datum.Species === parent.Species"}
]
}
],
"marks": [
{
"type": "area",
"from": {"data": "violin"},
"encode": {
"enter": {
"fill": {"scale": "color", "field": {"parent": "Species"}}
},
"update": {
"y": {"scale": "yscale", "field": "value"},
"xc": {"signal": "plotWidth / 2"},
"width": {"scale": "hscale", "field": "density"}
}
}
},
{
"type": "rect",
"from": {"data": "summary"},
"encode": {
"enter": {"fill": {"value": "black"}, "width": {"value": 2}},
"update": {
"y": {"scale": "yscale", "field": "q1"},
"y2": {"scale": "yscale", "field": "q3"},
"xc": {"signal": "plotWidth / 2"}
}
}
},
{
"type": "rect",
"from": {"data": "summary"},
"encode": {
"enter": {
"fill": {"value": "black"},
"height": {"value": 2},
"width": {"value": 8}
},
"update": {
"y": {"scale": "yscale", "field": "median"},
"xc": {"signal": "plotWidth / 2"}
}
}
}
]
}
]
}
Chart Image
Was able to figure this out, required an "orient" parameter in the encoding of the area mark.
"marks": [
{
"type": "area",
"from": {"data": "violin"},
"encode": {
"enter": {
"orient": {"value":"horizontal"},
"fill": {"scale": "color", "field": {"parent": "Species"}}
},
"update": {
"y": {"field":"value", "scale":"yscale"},
"xc": {"signal": "plotWidth / 2"},
"width": {"scale": "hscale", "field": "density"}
}
}
},
Example Here

How to include a range slider to transform Data in Vega?

What I have tried:
I included a range slider. This range slider is meant to change the way the data is filtered (see transform). (Almost like in this example https://vega.github.io/vega/examples/population-pyramid/)
The Issue:
When I change the slider's position on the graph, there is no change in the graph's input.
Question:
How could I change the code, so that my input parameters are changed through the user's interaction with the range slider?
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"padding": 20,
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
},
{
"name": "Y_Value",
"bind":{"input": "range", "min": 0, "max": 100, "step": 1},
"value": 100
}
],
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28},
{"category": "B", "amount": 55},
{"category": "C", "amount": 43},
{"category": "D", "amount": 91},
{"category": "E", "amount": 81},
{"category": "F", "amount": 53},
{"category": "G", "amount": 19},
{"category": "H", "amount": 87}
]
},
{
"name": "range",
"source": "table",
"transform": [
{"type": "filter", "expr": "datum.amount <= Y_Value"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale",
"encode": {
"labels": {
"interactive": true,
"update": {
"tooltip": {"signal": "datum.label"}
}
}
}
},
{ "orient": "left", "scale": "yscale" }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "datum === tooltip", "value": 0},
{"value": 1}
]
}
}
}
]
}
After some time I have figured this:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 400,
"height": 200,
"padding": 20,
"title": {"text":"A title", "anchor":"middle"},
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
},
{
"name": "Threshold",
"bind":{"input": "range", "min": 0, "max": 100, "step": 1},
"value": 0
}
],
"data": [
{
"name": "table",
"values": [
{"category": "Mon", "amount": 28},
{"category": "Tue", "amount": 55},
{"category": "wed", "amount": 43},
{"category": "Thu", "amount": 91},
{"category": "Fri", "amount": 81},
{"category": "Sat", "amount": 53},
{"category": "Sun", "amount": 19}
]
},
{
"name": "range",
"source": "table",
"transform": [
{"type": "filter", "expr": "datum.amount >= Threshold"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
}
],
"axes": [
{
"orient": "bottom",
"scale": "xscale",
"encode": {
"labels": {
"interactive": true,
"update": {
"tooltip": {"signal": "datum.label"}
}
}
}
},
{ "orient": "left", "scale": "yscale", "title": "Y Title" }
],
"marks": [
{
"type": "rect",
"from": {"data":"range"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "datum === tooltip", "value": 0},
{"value": 1}
],
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"value": "#333"}
}
}
}
]
}