How to specify Rule Line with a single value in VegaLite? - vega

It's possible to specify Rule as encoding over the data. But sometimes it's too verbose. Is there a shorter way to specify it with just a single number?
In example below I want to draw a horizontal line with y=1 and it requires me to specify a calculate transform. Wonder if it's possible with something more compact, like:
"layer": [
...,
{ "mark": { "type": "rule", "y": 1 }, // Specify ruler with just a single line
...
]
Playground
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"transform":[
{ "calculate": "1", "as": "one" }
],
"layer": [
{
"mark": { "type": "bar" },
"encoding": {
"x": { "field": "diff", "type": "quantitative" },
"y": { "field": "diff", "type": "quantitative" }
}
},
{
"mark": { "type": "rule" },
"encoding": {
"y": { "field": "one", "type": "quantitative" }
}
}
],
"data": {
"values": [
{ "diff": 1 },
{ "diff": 2 },
{ "diff": 3 }
]
}
}

You can specify a single value using the "value" field in the encoding; e.g.
{
"mark": { "type": "rule" },
"encoding": {
"y": { "value": 133 }
}
}
(Playground)
But be aware this value is a value in the axis domain, rather than in the data domain; i.e. it represents pixels from the top-left of the chart.
If you want to specify a value in the data domain, there is no such shorthand. You have to either use a transform (as you did in your question) or define a new dataset for your layer. The most compact way of doing this, I think, is something like this:
{
"mark": { "type": "rule" },
"data": {"values": {"y": 1}},
"encoding": {
"y": { "field": "y" }
}
}

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

Json Schema Different required properties for first element in array?

Suppose I want to validate an array in json where only the first element has an optional property. The rest of the items in the array would required the property.
schema.json
{
"type": "object",
"properties": {
"x": {
"type": "array",
"items": {
"oneOf": [
{ "$ref": "./first.json" },
{ "$ref": "./rest.json" }
]
}
}
}
}
first.json
{
"type": "object",
"properties": {
"y": { "type": "number" },
"z": { "type": "boolean" }
},
"required": ["y"]
}
rest.json
{
"type": "object",
"properties": {
"y": { "type": "number" },
"z": { "type": "boolean" }
}
}
Valid json:
{
"x": [
{ "z": true },
{ "y": 4, "z": true },
{ "y": 5 }
]
}
Invalid json:
{
"x": [
{ "z": true },
{ "z": true }, // this line would be invalid
{ "y": 5 }
]
}
However, the above setup gives me "multiple schemas match" when I provide the y value. Another approach could be:
schema.json
{
"type": "object",
"properties": {
"x": {
"type": "array",
"items": [
{ "$ref": "./first.json" },
{ "$ref": "./rest.json" }
]
}
}
}
This schema does what I want for the first two elements in the array (not requiring y in the first but yes in the second), but does not apply any schema to the objects after the second.
The items keyword has two forms. The first is the schema-form that you are using. The second is the array-form. The array-form takes an array of schemas where each schema applies to it's corresponding item in the instance. For example, when given an array with two schema, it validates the first item in the instance against the first schema and the second item against the second schema.
There is also an additionalItems keyword that works with the array-form of items. Any item that doesn't correspond to a schema in items is validated against the additionalItems schema. Using the previous example with two schemas in items, an instance with three items would have it's third item evaluated against the additionalItems schema.
So, we can use the array-form of items to apply "./first.json" to the first items and use additionalItems to apply "./rest.json" to the rest of the array.
{
"type": "object",
"properties": {
"x": {
"type": "array",
"items": [{ "$ref": "./first.json" }],
"additionalItems": { "$ref": "./rest.json" }
}
}
}

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
},
...
]
}
}

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

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": "" }
}
}
}
]
}

Calculation in vega

I use vega in Kibana.
I select two values from two different index in section "data". But now I need to summarize this values and visualize it in the section "marks". Is anybody know, how can I do this? Now in the section "marks" I use only one value from first "data".
My code is the following:
{
"$schema": "https://vega.github.io/schema/vega/v3.0.json",
"title": {
"text": "Lead time, hr.",
"orient": "bottom"
},
"data": [
{
"name": "source_1",
"url": {
"index": "metrics-bitbucket-*",
"%context_query%": "#timestamp",
"body": {
"size": 0,
"aggs": {
"etb": {
"avg": {
"field": "elapsed_time",
"script": {"source": "_value/3600*10"}
}
}
}
}
},
"format": {"type": "json", "property": "aggregations.etb"}
},
{
"name": "source_2",
"url": {
"index": "metrics-jenkins-*",
"%context_query%": "#timestamp",
"body": {
"size": 0,
"aggs": {
"etj": {
"avg": {
"field": "elapsed_time",
"script": {"source": "_value/3600*10"}
}
}
}
}
},
"format": {"type": "json", "property": "aggregations.etj"}
}
],
"marks": {
"type": "text",
"from": {"data": "source_1"},
"encode": {
"update": {
"text": {"signal": "round(datum.value)/10"},
"fontSize": {"value": 60},
"fontStyle": {"value": "bold"},
"x": {"signal": "width/2-50"},
"y": {"signal": "height/2"}
}
}
}
}
You essentially have two lists of data objects: source1: [{}, {}, ...] and source2: [{}, {}, {}, ...]. When you draw items, you have to specify just one data source. That data source could be the concatenation of the first two, e.g. you create source3 with its source parameter set to ["source1", "source2"], which includes all elements from both, but I suspect this is not what you want here. Rather, you need to merge the data using lookup transform - iterate over the items in one data source, and pull the corresponding values from another data source. Afterwards, add a formula transform to sum the values. The mark would than use the result of the formula for drawing.