I know how to control the spacing of elements within a visualization, and I know how to control the width and height of the visualization. However, is it possible to control the spacing between the visualization and other elements, such as the title or legend?
To customize titles, you can use an object instead of a string. You can learn more about the available options in the docs at https://vega.github.io/vega-lite/docs/title.html.
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"description": "A simple bar chart with embedded data.",
"title": {
"text": "This is an awesome Chart!",
"offset": 20
},
"data": {
"values": [
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
]
},
"mark": "bar",
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"}
}
}
If you want to make your chart more compact, you can also use a negative offset.
You can customize legends similarly.
{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"data": {
"url": "data/cars.json"
},
"mark": "point",
"encoding": {
"x": {
"field": "Horsepower",
"type": "quantitative"
},
"y": {
"field": "Miles_per_Gallon",
"type": "quantitative"
},
"color": {
"field": "Origin",
"type": "nominal",
"legend": {
"labelOffset": 30,
"titleAnchor": "end",
"offset": 30
}
}
}
}
Related
I would like to have image marks surrounding my doughnut chart instead of texts. The example for image marks use x and y for its coordinate. How should I adjust that for a doughnut chart where we work with radius and theta?
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple pie chart with labels.",
"data": {
"values": [
{"category": "a", "value": 4, "image": url},
{"category": "b", "value": 6, "image": url},
{"category": "c", "value": 10, "image": url},
{"category": "d", "value": 3, "image": url},
{"category": "e", "value": 7, "image": url},
{"category": "f", "value": 8, "image": url}
]
},
"encoding": {
"theta": {"field": "value", "type": "quantitative", "stack": true},
"color": {"field": "category", "type": "nominal", "legend": null}
},
"layer": [{
"mark": {"type": "arc", "outerRadius": 80}
}, {
"mark": {"type": "text", "radius": 90},
"encoding": {
"text": {"field": "category", "type": "nominal"}
}
}],
"view": {"stroke": null}
}
New vega version:
Open the Chart in the Vega Editor
After some trials and reading through the doc, it seems Image Mark cannot be positioned by theta encoding, but the example shows that x and y encodings are supported.
Therefore, I worked out this positioning via simple trigonometry and an extra layer to place the images in the doughnut:
{
"transform": [
{"joinaggregate": [{"op":"sum", "field": "value", "as": "total"}]},
{
"window": [{"op": "sum", "field": "value", "as": "cum"}],
"frame": [null, 0]
},
{"calculate": "cos(2*PI*(datum.cum-datum.value/2)/datum.total)", "as": "y"},
{"calculate": "sin(2*PI*(datum.cum-datum.value/2)/datum.total)", "as": "x"}
],
"mark": {"type": "image", "width": 20, "height": 20},
"encoding": {
"url": {"field": "image"},
"x": {"field": "x", "type": "quantitative", "scale": {"domain": [-2, 2]}, "axis": null},
"y": {"field": "y", "type": "quantitative", "scale": {"domain": [-2, 2]}, "axis": null}
}
}
Yet another Vega Editor
As the order is messed up by the color encoding mentioned in comments below, a new window transform is added to generate an extra ordering field which is provided to color field
Renewed Vega Editor
3 changes were made: (2021-07-16)
Using cos in the calculate of y
Using sin in the calculate of x
Messing up the data value to check if working
Old & Wrong Vega Editor
I have a concatenated graph with two sets of data being displayed. By selecting bars on the left graph you can change the data shown on the right graph. I would like to prevent the user from being able to clear the selection and am trying to set {"select": {"clear": false}} to achieve this, however it is not working. Whenever I click outside of the graph or if I double click on the bars, the selection clears.
I have tried this using an example bar graph in the vega-lite examples page and that is also not working. So I am just wondering if this is not possible for certain types of graphs or if there is a specific way of doing it. I have attached the code for the bar graph that does not work with the clear: false property and for a heatmap that does work.
Not working bar graph:
Vega-lite link to graph: https://vega.github.io/editor/#/url/vega-lite/N4IgJAzgxgFgpgWwIYgFwhgF0wBwqgegIDc4BzJAOjIEtMYBXAI0poHsDp5kTykBaADZ04JAKyUAVhDYA7EABoQAEzjQATjRyZ289AEEABEyTrDsU5kMB3OjEMwaZGMOc7ZZQ3IdtSZpLLKhhBwgnBQ7p7eUMJQANaUhgAUAJKyEDg06nBBTACehgAqSExhSAwA5BCGNLKYcOpIEbrBmHlhlACUiipImCiooMRIggxqaADaoAMg+j1MaABMABwAvgrTaCAAQvNoYmLrm+gAwnuoACwAzEcgMwAi5wCcAIy3MwCi58tvG3dbADFzmIbn8ZgBxc4vJ7vLYACW+AHZYegUsDFqsALrrEA4UxIBAQSagWQEuBbRzOVxYHohMIRNCgNo4cnoHBsWqYHoxOCmLYAMxGIRAq1upIQrJAdPCXKU0oZbI5dRFmKUyHUcUZIGZkpM6h6-JogkEWwAxBcTojlvplrTMOo2HFdYImpqlFAGOoZPrFZyGiKlHBZFA2MpamQtQAPLWG0LKLYoJQ6rZsdRh0kmnF5GM0ONbBZJvIsrYARwYAR0-R0pADIENxoA8nioHRs4MQCHAnRdFq8Y0EFt5bKQMNRqzfiORmM0AAGSigqX2x1wADqNGU9C1nbDOjkxNx+IH6EpLicNKUo+nqAxfz7BIpZ+pw8v46xF6nrJnovdckNEfb0AjKyoAmIEAAKSDKOmZBpLI-qoHOGKikAA
Code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A bar chart with highlighting on hover and selecting on click. (Inspired by Tableau's interaction style.)",
"data": {
"values": [
{"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
{"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
{"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
]
},
"params": [
{
"name": "highlight",
"select": {"type": "point", "clear": "false"}
},
{"name": "select", "select": "point"}
],
"mark": {
"type": "bar",
"fill": "#4C78A8",
"stroke": "black",
"cursor": "pointer"
},
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"},
"fillOpacity": {
"condition": {"param": "select", "value": 1},
"value": 0.3
},
"strokeWidth": {
"condition": [
{
"param": "highlight",
"value": 2
},
{
"param": "highlight",
"value": 1
}
],
"value": 0
}
},
"config": {
"scale": {
"bandPaddingInner": 0.2
}
}
}
Working heatmap graph:
Vega-lite link:https://vega.github.io/editor/#/url/vega-lite/N4IgJAzgxgFgpgWwIYgFwhgF0wBwqgegIDc4BzJAOjIEtMYBXAI0poHsDp5kTykBaADZ04JAKyUAVhDYA7EABoQAEySYUqUMSSCGcCGgDaoJFEwMdaEAEFFIHACc4ymmedXbSqGwazMaAEYAZgBfBRMzC0EPO0dnV0x3dAAhO29ff1QABjCI80t0T3snFzdlKwBhNJ8-NBzwkFN86JTYkoSkm2qMutzGyIKQVKU40sTy1q8azID6vKirYeL4ssru2tQANj6mhfQqkfbVwvXMuf7mtcOV8cXT3obdwYPlsc6X9I2AThCAXTD7EgHEgEAZUMYQLIQXArDAaGQYMIEf4lBA4II4GY0KBMABPHAw9A4Ng0WpeDFAtAAMx0aJCfyUyAcAGtsSA8QSrE4sajMA42My4AB1GjKehoABMALgsm8LlkZDZuLZVJo6ImFwWSg5hMhbAQpMsAIAHiq1YINaMOuVtfjdbJ9YbogDVYIWqBVeqrJ8Uey7VYAI4WPx0NQ0UggAEQPkCwmgbyyFyYdjyTSA4EIWHwxHZ32IHB46m0uBKbS6XVMQSmVkAst6NCyBhugFsHCmOjKtMJpMptltjNZhFIrB2OuEgK1nT17KUMQthzKOAONndui9tP9kGDnPI0dT8eT8u9AEJ1WKtPQHRxkBMJCJgAKSGU8rIAElZLIl3UlLeH0+XwA8gwiTLtktZqgA7my0ZwDgaAACz1CAwIKteGZwResCILquLooIbAQWQTgypW9b0koSDGjQYKgMo+pIKSRaCHS9JAA
Code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"actual": "A", "predicted": "A", "count": 13},
{"actual": "A", "predicted": "B", "count": 0},
{"actual": "A", "predicted": "C", "count": 0},
{"actual": "B", "predicted": "A", "count": 0},
{"actual": "B", "predicted": "B", "count": 10},
{"actual": "B", "predicted": "C", "count": 6},
{"actual": "C", "predicted": "A", "count": 0},
{"actual": "C", "predicted": "B", "count": 0},
{"actual": "C", "predicted": "C", "count": 9}
]
},
"params": [
{"name": "highlight", "select": {"type": "point", "clear": false}}
],
"mark": {"type": "rect", "strokeWidth": 2},
"encoding": {
"y": {"field": "actual", "type": "nominal"},
"x": {"field": "predicted", "type": "nominal"},
"fill": {"field": "count", "type": "quantitative"},
"stroke": {
"condition": {"param": "highlight", "empty": false, "value": "black"},
"value": null
},
"opacity": {"condition": {"param": "highlight", "value": 1}, "value": 0.5},
"order": {"condition": {"param": "highlight", "value": 1}, "value": 0}
},
"config": {
"scale": {"bandPaddingInner": 0, "bandPaddingOuter": 0},
"view": {"step": 40},
"range": {"ramp": {"scheme": "yellowgreenblue"}},
"axis": {"domain": false}
}
}
The difference between heatmap and bar chart seems a bit different from your understanding:
heatmap rects fill up all area on the grid
bar chart leaves some area on the grid outside the bars
As a result, upon clicks outside the grid, both won't clear the selection as you desire. However, clicks on the empty area inside the grid of bar chart emit an event with nothing selected, thus clearing the original selection.
I'm not sure if you know there is a toggle property for select. When it is true, any newly clicked point is inserted to the selection, thus clicking on the empty area adds nothing and preserves your previous selection. BUT, a side effect is that multi selection will be allowed...
"params": [
{"name": "highlight", "select": {"type": "point", "toggle": "true"}},
{"name": "select", "select": {"type": "point", "toggle": "true"}}
],
Last but not least, according to the Doc, clear property specifies an event to clear the selection. Yet, I'm not sure what happens when it is set as false.
clear property identifies which events must fire to empty a selection of all selected value
I have a pie chart with width & height set to "container". I would like to label each slice of the pie. Therefore I included a layer and it creates the correct text. However, I don't know how to implement a relative radius size. How would you go about it?
With an absolute radius (e.g. 30) it works, but I need a relative position.
`"layer": [{"mark": {"type": "arc"}},
{"mark": {"type": "text", "radius":30},
"encoding": {"text": {"field": "*", "type": "nominal"}}
}]`
You can create relative radii using an Expression Reference for the radius value.
For example, here is a chart where the radius of the pie chart is set to 40% of the chart size, and the text is set at 45% of the chart size (here I chose to measure the chart size as the minimum of the width and height, which seems reasonable for a circular chart):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "A simple pie chart with labels.",
"data": {
"values": [
{"category": "a", "value": 4},
{"category": "b", "value": 6},
{"category": "c", "value": 10},
{"category": "d", "value": 3},
{"category": "e", "value": 7},
{"category": "f", "value": 8}
]
},
"encoding": {
"theta": {"field": "value", "type": "quantitative", "stack": true}
},
"layer": [
{
"mark": {"type": "arc", "radius": {"expr": "0.4 * min(width, height)"}},
"encoding": {"color": {"field": "category", "type": "nominal", "legend": null}}
},
{
"mark": {"type": "text", "radius": {"expr": "0.45 * min(width, height)"}},
"encoding": {"text": {"field": "category", "type": "nominal"}}
}
],
"view": {"stroke": null}
}
(open in editor)
I am wondering how Vega-lite works with respect to tying Marks to associated Encodings.
In the below example, both the encoding and the mark are at the "top-level" of the spec:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "A simple bar chart with embedded data.",
"data": {
"values": [
{"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
{"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
{"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
]
},
"mark": "bar",
"encoding": {
"x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
"y": {"field": "b", "type": "quantitative"}
}
}
And with the simplest layer example, both the bar mark and the text mark are nested in the Layer property
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Bar chart with text labels. Apply scale padding to make the frame cover the labels.",
"data": {
"values": [
{"a": "A", "b": 28},
{"a": "B", "b": 55},
{"a": "C", "b": 43}
]
},
"encoding": {
"y": {"field": "a", "type": "nominal"},
"x": {"field": "b", "type": "quantitative", "scale": {"padding": 10}}
},
"layer": [{
"mark": "bar"
}, {
"mark": {
"type": "text",
"align": "left",
"baseline": "middle",
"dx": 3
},
"encoding": {
"text": {"field": "b", "type": "quantitative"}
}
}]
}
In this case, am I correct to assume that any Mark in the Layer property automatically inherits the encodings at the top-level?
Further, I notice that I cannot move the bar Mark outside of the Layer property (Vega Editor prompts that this is not an allowed property and bars fail to render if placed in top-level).
Finally, in more complicated example still (see: https://vega.github.io/vega-lite/examples/layer_line_mean_point_raw.html), the encodings are repeated in the layer (despite having a redundant x encoding) -> so in this case, when is it appropriate to place encoding at the top level versus in the layer?
The Vega-lite docs go into a fair bit of detail about the configuration of these properties but I have not been able to find a conceptual answer to these 3 questions.
Thank you
Vega-Lite provides a hierarchical chart model, where each level in the hierarchy can override various properties declared in the parent level. In terms of layer specifications, the relevant concepts are this:
a UnitSpec is what you think of as a single chart: it it, you can specify data, mark, encodings, transforms, and other properties.
a LayerSpec, is a container that can hold a number of UnitSpec or LayerSpec specifications in the layers property. Additionally, you can specify data, encodings transforms, and other properties (but not mark).
A UnitSpec that is within a LayerSpec or other top-level object will inherit any properties specified there (such as data, encodings, transforms, etc.), and is also able to override them by specifying its own data, encodings, or transforms.
Similar hierarchical concepts apply to other compound chart types, such as ConcatSpec, VConcatSpec, HConcatSpec, FacetSpec, etc.
More concretely, in your example, the data and some encodings are defined in the top-level layer:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Bar chart with text labels. Apply scale padding to make the frame cover the labels.",
"data": {
"values": [
{"a": "A", "b": 28},
{"a": "B", "b": 55},
{"a": "C", "b": 43}
]
},
"encoding": {
"y": {"field": "a", "type": "nominal"},
"x": {"field": "b", "type": "quantitative", "scale": {"padding": 10}}
},
"layer": [{
"mark": "bar"
}, {
"mark": {
"type": "text",
"align": "left",
"baseline": "middle",
"dx": 3
},
"encoding": {
"text": {"field": "b", "type": "quantitative"}
}
}]
}
In terms of the inheritance from parent, this is functionally equivalent to the following, where I have moved data and encodings from the top-level into each contained UnitSpec:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Bar chart with text labels. Apply scale padding to make the frame cover the labels.",
"layer": [{
"data": {
"values": [
{"a": "A", "b": 28},
{"a": "B", "b": 55},
{"a": "C", "b": 43}
]
},
"mark": "bar"
"encoding": {
"y": {"field": "a", "type": "nominal"},
"x": {"field": "b", "type": "quantitative", "scale": {"padding": 10}}
},
}, {
"data": {
"values": [
{"a": "A", "b": 28},
{"a": "B", "b": 55},
{"a": "C", "b": 43}
]
},
"mark": {
"type": "text",
"align": "left",
"baseline": "middle",
"dx": 3
},
"encoding": {
"y": {"field": "a", "type": "nominal"},
"x": {"field": "b", "type": "quantitative", "scale": {"padding": 10}}
"text": {"field": "b", "type": "quantitative"}
}
}]
}
Specifying shared properties at the top level is a way to make chart specifications more concise and understandable.
I am trying to figure out how to not have my y-axis start at zero? It works in general for me, but if I add the color encoding (see below) it is not working anymore and instead I get to see the zero.
{
"data": {"name": "d"},
"mark": {"type": "bar"},
"encoding": {
"color": {"type": "nominal", "field": "group"},
"x": {"type": "nominal", "field": "model"},
"y": {
"type": "quantitative",
"field": "inf_f1",
"scale": {"zero": false}
}
},
"$schema": "https://vega.github.io/schema/vega-lite/v4.0.2.json",
"datasets": {
"d": [
{
"model": "lr-bow",
"inf_f1": 0.7991841662090597,
"group" : "A"
},
{
"model": "fcn-bow",
"inf_f1": 0.8220151833558302,
"group" : "B"
}
]
}
}
The reason the scale includes zero is that bars are stacked by default, and each bar has an implicit stacked zero-height bar for the group that does not appear, but does affect the automatically chosen axis limits. You can address this by setting stack to "none" in the y encoding (view in editor):
{
"data": {"name": "d"},
"mark": {"type": "bar"},
"encoding": {
"color": {"type": "nominal", "field": "group"},
"x": {"type": "nominal", "field": "model"},
"y": {
"type": "quantitative",
"field": "inf_f1",
"stack": "none",
"scale": {"zero": false}
}
},
"datasets": {
"d": [
{"model": "lr-bow", "inf_f1": 0.7991841662090597, "group": "A"},
{"model": "fcn-bow", "inf_f1": 0.8220151833558302, "group": "B"}
]
}
}