Is it possible to have columns of donut chart with gray arc indicating the missing part? - vega-lite

Currently, the donut chart assumed that the max value is 100%. What I would like is for the category Chinese to have a percentage of 50% with gray arc indicating the missing 50%. The two other donut charts will behave similarly in their respective column.
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "A simple donut chart with embedded data.",
"data": {
"values": [
{"category": "English", "value": 4},
{"category": "Malay", "value": 6},
{"category": "Chinese", "value": 10}
]
},
"mark": {"type": "arc", "innerRadius": 80},
"encoding": {
"column": {"field": "category"},
"theta": {"field": "value", "type": "quantitative"},
"color": {"field": "category", "type": "nominal"}
},
"view": {"stroke": null}
}

It's a bit more complex, but one way to do this is to use a transform to calculate the total, and then a layer chart to plot that total in the background.
Here is an example (open in editor):
{
"data": {
"values": [
{"category": "English", "value": 4},
{"category": "Malay", "value": 6},
{"category": "Chinese", "value": 10}
]
},
"transform": [
{"joinaggregate": [{"op": "sum", "field": "value", "as": "total"}]}
],
"facet": {"column": {"field": "category"}},
"spec": {
"layer": [
{
"mark": {"type": "arc", "innerRadius": 80, "color": "lightgray"},
"encoding": {"theta": {"field": "total", "type": "quantitative"}}
},
{
"mark": {"type": "arc", "innerRadius": 80},
"encoding": {
"theta": {"field": "value", "type": "quantitative"},
"color": {"field": "category"}
}
}
],
"view": {"stroke": null}
}
}

Related

How to position text at the top edge of a VegaLite chart?

I am trying to create a VegaLite chart with labelled highlighted areas which are specified in a separate dataset using [min_x, max_x] coordinates.
I've managed to highlight the area itself using a rect mark, but I'm struggling to properly position the label at the top edge of the chart.
This is the end result I'm trying to achieve. In this example I'm using the dy property of the text mark to position the label. Unfortunately this only works when the chart height is known in advance, which doesn't work for my use case.
If there is a better way to achieve the result I want, please let me know. This is the Vegalite specification for the chart above, without previously mentioned dy property:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text"},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}
You can reference height inside an expression to make it dynamic.
"dy": { "expr": "-height + (height/2) -10"}
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"datasets": {
"test_data": [
{"x": 0, "y": 1.5},
{"x": 5, "y": 2},
{"x": 9, "y": 4},
{"x": 14, "y": 0}
],
"highlight_data": [
{"from_x": 2.3, "to_x": 3, "label": "AAA"},
{"from_x": 6.3, "to_x": 8, "label": "BBB"}
]
},
"data": {"name": "test_data"},
"layer": [
{
"data": {"name": "highlight_data"},
"transform": [
{"calculate": "(datum.from_x + datum.to_x) / 2", "as": "mean_x"}
],
"layer": [
{
"mark": {"type": "rect", "opacity": 0.3},
"encoding": {
"x": {"field": "from_x", "type": "quantitative"},
"x2": {"field": "to_x"},
"color": {"value": "#fcfc00"}
}
},
{
"mark": {"type": "text", "dy": { "expr": "-height + (height/2) -10"}},
"encoding": {
"text": {"field": "label"},
"x": {"field": "mean_x", "type": "quantitative"}
}
}
]
},
{
"mark": {"type": "line"},
"encoding": {
"x": {"field": "x", "type": "quantitative", "title": "X Label"},
"y": {"field": "y", "type": "quantitative", "title": "Y Label"}
}
}
],
"title": "Title",
"width": 800,
"height": 500
}

How to Annotate a Line in line Chart in Vega-Lite?

How to annotate a line in line chart in vega-lite
For the below code https://vega.github.io/editor/#/
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"layer": [
{
"data": {"url": "data/stocks.csv"},
"mark": "line",
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {"field": "price", "type": "quantitative"},
"color": {"field": "symbol", "type": "nominal"}
}
},
{
"data": {"values": [{}]},
"mark": {"type": "rule", "strokeDash": [2, 2], "size": 2},
"encoding": {"x": {"datum": {"year": 2006}}}
}
]
}
We get plot
If I want to annotate the line at a specific position like (2004,400)
I tried this, it is working, but I don't want to pass hardcoded values like "a": 2004, "b": 400,
{
"data": {
"values": [
{"a": 2004, "b": 400}
]
},
"mark": {"type": "text", "fontSize" : 16, "fontWeight":"bold", "align" : "left"},
"encoding": {
"text": {"value": "Optimum"},
"x": {"field": "a", "type": "quantitative", "title":""},
"y": {"field": "b", "type": "quantitative", "title":""}
}
},
How to pass specific values from the data like average value of date (say:2004) and average value of price (say:400)?
or
just next to the line in the middle of y-axis
Transform and Aggregate Worked, I needed only for Y axis average position, so below code worked good. For another axis we can use same transform.
{
"mark": {"type": "text", "fontSize" : 16, "fontWeight":"bold", "align" : "left"},
"transform": [
{
"aggregate": [{
"op": "mean",
"field": "price",
"as": "mean_y_axis"
}],
"groupby": ["date"]
}
],
"encoding": {
"text": {"value": "Optimum"},
"x": {"field": "date",
"type": "quantitative"},
"y": {"field": "mean_y_axis",
"type": "quantitative"}
}
}

Vega-Lite: How do I include image marks in a doughnut chart?

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

Can I make it look more like a box plot

I am working with Elasticsearch which provides the min, max, Q1, Q2 and Q3 data. All I have to do is to plot it in form of a box plot. Kibana as of now only supports vega-lite version 2.6.0 and vega 4.3.0.
Here is a complete sample I have made.
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"width": 100,
"height": 200,
"padding": 10,
"data": {
"name": "sample",
"values": [
{
"task": "A",
"min" : 72.66500091552734,
"max" : 139.54299926757812,
"q1" : 98.68599700927734,
"q2" : 120.12850189208984,
"q3" : 121.82099914550781
},
{
"task": "B",
"min" : 71.66500091552734,
"max" : 159.54299926757812,
"q1" : 88.68599700927734,
"q2" : 110.12850189208984,
"q3" : 141.82099914550781
},
{
"task": "c",
"min" : 45.66500091552734,
"max" : 169.54299926757812,
"q1" : 88.68599700927734,
"q2" : 110.12850189208984,
"q3" : 141.82099914550781
}
]
},
"layer": [
{
"width": 5,
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "min"},
"y2": {"type": "quantitative","field": "max"},
"color": {"value": "#2CB5E8"}
},
"mark": {
"type": "bar"
}
},
{
"width": 20,
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "q1"},
"y2": {"type": "quantitative","field": "q3"},
"color": {"value": "#EB985E"}
},
"mark": "bar"
},
{
"encoding": {
"x": {"type": "ordinal","field": "task"},
"y": {"type": "quantitative","field": "q2"},
"color": {"value": "#090502"}
},
"mark": "point"
}
]
}
This is what the plot looks like:
But box plot look something like this
The current version of vega-lite does support the boxplot. But I am stuck with older version.
I am trying to reduce the width of the bar plot for min and max. And keep it thick for Q1 and Q3. Somehow it is not working.
Also is it possible to plot Q2 as a flat line instead of a point?
You can construct a boxplot manually using a layer chart with a bar, tick, and rule mark. For example (view in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"width": 100,
"height": 200,
"data": {
"name": "sample",
"values": [
{
"task": "A",
"min": 72.66500091552734,
"max": 139.54299926757812,
"q1": 98.68599700927734,
"q2": 120.12850189208984,
"q3": 121.82099914550781
},
{
"task": "B",
"min": 71.66500091552734,
"max": 159.54299926757812,
"q1": 88.68599700927734,
"q2": 110.12850189208984,
"q3": 141.8209991455078
},
{
"task": "c",
"min": 45.66500091552734,
"max": 169.54299926757812,
"q1": 88.68599700927734,
"q2": 110.12850189208984,
"q3": 141.8209991455078
}
]
},
"layer": [
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "min"},
"y2": {"type": "quantitative", "field": "max"}
},
"mark": {"type": "rule", "color": "black"}
},
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "q1"},
"y2": {"type": "quantitative", "field": "q3"}
},
"mark": {"type": "bar", "color": "#EB985E", "size": 20}
},
{
"encoding": {
"x": {"type": "ordinal", "field": "task"},
"y": {"type": "quantitative", "field": "q2"}
},
"mark": {"type": "tick", "color": "gray", "size": 20}
}
]
}

Filter by selection from referenced table

I have a single data source within datasets that I use in two concatenated charts. Now when I click on a bar in the left chart I would like to filter the right chart. See animated gif:
But is doesn't.
Click here to open in the vega-editor.
Or check the spec here::
{
"config": {"view": {"width": 400, "height": 300}},
"hconcat": [
{
"width": 100,
"selection": {"SELECT": {"type": "single", "resolve": "global"}},
"data": {"name": "table_data"},
"mark": "bar",
"encoding": {
"x": {"type": "nominal", "field": "Major_Genre"},
"y": {"aggregate": "count", "type": "quantitative"},
"color": {"type": "nominal", "field": "Major_Genre"},
"fillOpacity": {
"condition": {"selection": "SELECT", "value": 1},
"value": 0.3
}
}
},
{
"width": 100,
"data": {"name": "table_data"},
"transform": [{"filter": {"selection": "SELECT"}}],
"mark": "bar",
"encoding": {
"x": {"type": "nominal", "field": "Major_Genre"},
"y": {"aggregate": "count", "type": "quantitative"},
"color": {"type": "nominal", "field": "Major_Genre"}
}
}
],
"datasets": {
"table_data": [
{
"Title": "Cidade de Deus",
"Major_Genre": "Drama",
"Country_Origin": "Brazil"
},
{
"Title": "Chocolate: Deep Dark Secrets",
"Major_Genre": "Thriller/Suspense",
"Country_Origin": "India"
},
{"Title": "Fiza", "Major_Genre": "Drama", "Country_Origin": "India"},
{
"Title": "First Love, Last Rites",
"Major_Genre": "Drama",
"Country_Origin": "United States"
},
{
"Title": "Foolish",
"Major_Genre": "Comedy",
"Country_Origin": "United States"
},
{
"Title": "I Married a Strange Person",
"Major_Genre": "Comedy",
"Country_Origin": "United States"
}
]
}
}
When your selections refer to groups of points rather than single points, you need to provide an explicit fields or encodings argument to specify what points are included in the selection.
In this case, the chart will behave as expected if you specify your selection in one of the following ways:
"selection": {"SELECT": {"type": "single", "fields": ["Major_Genre"], "resolve": "global"}}
"selection": {"SELECT": {"type": "single", "encodings": ["color"], "resolve": "global"}}
"selection": {"SELECT": {"type": "single", "encodings": ["x"], "resolve": "global"}}
Here's the working chart in action: (vega editor link).