vega grouping difference for vertical and horizontal bar chart? - vega

thanks in advance! I am trying to make a grouped bar chart with Vega. So I took the "stacked bar chart example" data (removed the stacking transform), and made a vertical one and horizontal one. The strange thing is, the horizontal one worked as I expected, but the vertical one has duplicated overlapping bars on each individual groups. I made them exactly the same way, only switching the properties. I will post my json file below.
Vertical bar chart:
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic stacked bar chart example.",
"width": 500,
"height": 200,
"padding": 5,
"data": [
{
"name": "table",
"values": [
{"x": 0, "y": 28, "c": 0}, {"x": 0, "y": 55, "c": 1},
{"x": 1, "y": 43, "c": 0}, {"x": 1, "y": 91, "c": 1},
{"x": 2, "y": 81, "c": 0}, {"x": 2, "y": 53, "c": 1},
{"x": 3, "y": 19, "c": 0}, {"x": 3, "y": 87, "c": 1},
{"x": 4, "y": 52, "c": 0}, {"x": 4, "y": 48, "c": 1},
{"x": 5, "y": 24, "c": 0}, {"x": 5, "y": 49, "c": 1},
{"x": 6, "y": 87, "c": 0}, {"x": 6, "y": 66, "c": 1},
{"x": 7, "y": 17, "c": 0}, {"x": 7, "y": 27, "c": 1},
{"x": 8, "y": 68, "c": 0}, {"x": 8, "y": 16, "c": 1},
{"x": 9, "y": 49, "c": 0}, {"x": 9, "y": 15, "c": 1}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"range": "width",
"domain": {"data": "table", "field": "c"}
},
{
"name": "yscale",
"type": "linear",
"range": "height",
"domain": {"data": "table", "field": "y"}
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "table", "field": "c"}
}
],
"axes": [
{"orient": "bottom", "scale": "xscale", "zindex": 1},
{"orient": "left", "scale": "yscale", "zindex": 1}
],
"marks": [
{
"type": "group",
"from": {
"facet": {
"name": "facet",
"data": "table",
"groupby": "c"
}
},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "c"}
}
},
"signals": [
{"name": "width", "update": "bandwidth('xscale')"}
],
"scales": [
{
"name": "inner",
"type": "band",
"range": "width",
"domain": {"data": "facet", "field": "x"}
}
],
"axes": [
{"orient": "top", "scale": "inner", "tickSize": 0, "labelPadding": 10, "zindex": 2, "title": "x"}
],
"marks": [
{
"type": "rect",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"scale": "inner", "field": "x"},
"width": {"scale": "inner", "band": 1, "offset": -1},
"y": {"scale": "yscale", "field": "y"},
"y2": {"scale": "yscale", "value": 0},
"fill": {"scale": "color", "field": "c"}
},
"update": {
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
}
]
}]
}
Horizontal bar chart:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic stacked bar chart example.",
"width": 500,
"height": 200,
"padding": 5,
"data": [
{
"name": "table",
"values": [
{"x": 0, "y": 28, "c": 0}, {"x": 0, "y": 55, "c": 1},
{"x": 1, "y": 43, "c": 0}, {"x": 1, "y": 91, "c": 1},
{"x": 2, "y": 81, "c": 0}, {"x": 2, "y": 53, "c": 1},
{"x": 3, "y": 19, "c": 0}, {"x": 3, "y": 87, "c": 1},
{"x": 4, "y": 52, "c": 0}, {"x": 4, "y": 48, "c": 1},
{"x": 5, "y": 24, "c": 0}, {"x": 5, "y": 49, "c": 1},
{"x": 6, "y": 87, "c": 0}, {"x": 6, "y": 66, "c": 1},
{"x": 7, "y": 17, "c": 0}, {"x": 7, "y": 27, "c": 1},
{"x": 8, "y": 68, "c": 0}, {"x": 8, "y": 16, "c": 1},
{"x": 9, "y": 49, "c": 0}, {"x": 9, "y": 15, "c": 1}
]
}
],
"scales": [
{
"name": "y",
"type": "band",
"range": "height",
"domain": {"data": "table", "field": "c"}
},
{
"name": "x",
"type": "linear",
"range": "width",
"domain": {"data": "table", "field": "y"}
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "table", "field": "c"}
}
],
"axes": [
{"orient": "bottom", "scale": "x", "zindex": 1},
{"orient": "left", "scale": "y", "zindex": 1}
],
"marks": [
{"type": "group",
"from": {
"facet": {
"name": "facet",
"data": "table",
"groupby": "c"
}
},
"encode": {
"enter": {
"y": {"scale": "y", "field": "c"}
}
},
"signals": [
{"name": "height", "update": "bandwidth('y')"}
],
"scales": [
{
"name": "pos",
"type": "band",
"range": "height",
"domain": {"data": "facet", "field": "x"}
}
],
"axes": [
{"orient": "right", "scale": "pos", "tickSize": 0, "labelPadding": 10, "zindex": 3}
],
"marks": [{
"type": "rect",
"from": {"data": "facet"},
"encode": {
"enter": {
"y": {"scale": "pos", "field": "x"},
"height": {"scale": "pos", "band": 1, "offset":-1},
"x": {"scale": "x", "field": "y"},
"x2": {"scale": "x", "value": 0},
"fill": {"scale": "color", "field": "c"}
}
}
}]
}]
}
Images:
Is this something I didn't setup correctly in the specs? Thanks.

I figured it out. The inner chart marks needs to be sourced from facet instead of the original table
"from": {"data": "facet"}
That fixed it.

Related

Ordering of a faceted Bar-chart in Vega

I have a question about facet visualizations in vega.
I have a pretty similar problem as the nested bar char example.
Here I changed the order of the tuple values. as intended, the order in the visualization is changing to.
But I want the 3 facets ordered ascending for value "a".
I don't really understand, if there is a "scale" for the facets, or where to order them.
Second part would be to have an axes for the value "a" shown below/above the bar chart.
Hope someone can help me.
Greetings
Christian
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A nested bar chart example, with bars grouped by category.",
"width": 300,
"padding": 5,
"autosize": "pad",
"signals": [
{
"name": "rangeStep", "value": 20,
"bind": {"input": "range", "min": 5, "max": 50, "step": 1}
},
{
"name": "innerPadding", "value": 0.1,
"bind": {"input": "range", "min": 0, "max": 0.7, "step": 0.01}
},
{
"name": "outerPadding", "value": 0.2,
"bind": {"input": "range", "min": 0, "max": 0.4, "step": 0.01}
},
{
"name": "height",
"update": "trellisExtent[1]"
}
],
"data": [
{
"name": "tuples",
"values": [
{"a": 1, "b": "b", "c": 4.4},
{"a": 0, "b": "c", "c": 5.1},
{"a": 0, "b": "a", "c": 6.3},
{"a": 0, "b": "a", "c": 4.2},
{"a": 0, "b": "b", "c": 6.8},
{"a": 2, "b": "b", "c": 3.5},
{"a": 2, "b": "c", "c": 6.2}
],
"transform": [
{
"type": "aggregate",
"groupby": ["a", "b"],
"fields": ["c"],
"ops": ["average"],
"as": ["c"]
}
]
},
{
"name": "trellis",
"source": "tuples",
"transform": [
{
"type": "aggregate",
"groupby": ["a"]
},
{
"type": "formula", "as": "span",
"expr": "rangeStep * bandspace(datum.count, innerPadding, outerPadding)"
},
{
"type": "stack",
"field": "span"
},
{
"type": "extent",
"field": "y1",
"signal": "trellisExtent"
}
]
}
],
"scales": [
{
"name": "xscale",
"domain": {"data": "tuples", "field": "c"},
"nice": true,
"zero": true,
"round": true,
"range": "width"
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "trellis", "field": "a"}
}
],
"axes": [
{ "orient": "bottom", "scale": "xscale", "domain": true }
],
"marks": [
{
"type": "group",
"from": {
"data": "trellis",
"facet": {
"name": "faceted_tuples",
"data": "tuples",
"groupby": "a"
}
},
"encode": {
"enter": {
"x": {"value": 0},
"width": {"signal": "width"}
},
"update": {
"y": {"field": "y0"},
"y2": {"field": "y1"}
}
},
"scales": [
{
"name": "yscale",
"type": "band",
"paddingInner": {"signal": "innerPadding"},
"paddingOuter": {"signal": "outerPadding"},
"round": true,
"domain": {"data": "faceted_tuples", "field": "b"},
"range": {"step": {"signal": "rangeStep"}}
}
],
"axes": [
{ "orient": "left", "scale": "yscale",
"ticks": false, "domain": false, "labelPadding": 4 }
],
"marks": [
{
"type": "rect",
"from": {"data": "faceted_tuples"},
"encode": {
"enter": {
"x": {"value": 0},
"x2": {"scale": "xscale", "field": "c"},
"fill": {"scale": "color", "field": "a"},
"strokeWidth": {"value": 2}
},
"update": {
"y": {"scale": "yscale", "field": "b"},
"height": {"scale": "yscale", "band": 1},
"stroke": {"value": null},
"zindex": {"value": 0}
},
"hover": {
"stroke": {"value": "firebrick"},
"zindex": {"value": 1}
}
}
}
]
}
]
}

How to start bar from 1 instead of 0 in Vega Lite?

I'm plotting the diff time series [1.1, 0.9, 1.2, ...].
And as the values are relative multipliers, the middle is 1 and not 0.
Is there a way to tell Vega Lite to start bar with 1?
So for the value 1.1 the bar will be start: 1, end: 1.1 and for 0.9 it will be start: 1, end: 0.9?
You can use a y2 encoding with datum set to 1. For example (vega editor):
{
"data": {
"values": [
{"x": "A", "y": 0.9},
{"x": "B", "y": 0.8},
{"x": "C", "y": 1.1},
{"x": "D", "y": 1.2},
{"x": "E", "y": 0.9},
{"x": "F", "y": 1.3}
]
},
"mark": "bar",
"encoding": {
"x": {"type": "nominal", "field": "x"},
"y": {
"type": "quantitative",
"field": "y",
"scale": {"domain": [0.6, 1.4]}
},
"y2": {"datum": 1}
}
}

Filled area graph vertical orientation

I am attempting to get a vertical filled area graph, where the area on the left between the y axis and the data line is filled. Essentially, take the normal area graph and rotate it 90 degrees clockwise.
I've basically just taken the example from the vega examples and tried to convert everything to vertical, changed the names of the scales to something more related to the data, and added a line width and colour.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 500,
"height": 500,
"padding": 5,
"signals": [
{
"name": "interpolate",
"value": "linear",
"bind": {
"input": "select",
"options": [
"basis",
"cardinal",
"catmull-rom",
"linear",
"monotone",
"natural",
"step",
"step-after",
"step-before"
]
}
}
],
"data": [
{
"name": "table",
"values": [
{"u": 1, "v": 28}, {"u": 2, "v": 55},
{"u": 3, "v": 43}, {"u": 4, "v": 91},
{"u": 5, "v": 81}, {"u": 6, "v": 53},
{"u": 7, "v": 19}, {"u": 8, "v": 87},
{"u": 9, "v": 52}, {"u": 10, "v": 48},
{"u": 11, "v": 24}, {"u": 12, "v": 49},
{"u": 13, "v": 87}, {"u": 14, "v": 66},
{"u": 15, "v": 17}, {"u": 16, "v": 27},
{"u": 17, "v": 68}, {"u": 18, "v": 16},
{"u": 19, "v": 49}, {"u": 20, "v": 15}
]
}
],
"scales": [
{
"name": "uscale",
"type": "linear",
"range": "height",
"zero": false,
"domain": {"data": "table", "field": "u"}
},
{
"name": "vscale",
"type": "linear",
"range": "width",
"nice": true,
"zero": true,
"domain": {"data": "table", "field": "v"}
}
],
"axes": [
{"orient": "bottom", "scale": "vscale", "tickCount": 25},
{"orient": "left", "scale": "uscale"}
],
"marks": [
{
"type": "area",
"orient": "horizontal",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"scale": "vscale", "field": "v"},
"y": {"scale": "uscale", "field": "u"},
"x2": {"scale": "vscale", "value": 0},
"stroke": {"value": "#000000"},
"fill": {"value": "steelblue"}
},
"update": {
"interpolate": {"signal": "interpolate"},
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
}
]
}
Pretty sure I'm doing something wrong here. According to the docs "vertical" orientation is the default, and I've tried this with x2 and y2, and orient "vertical" and "horizontal" for both - I've also tried to set the scale as vscale and uscale for x2 and y2.
I get no errors in the vega online editor - The line is correct but I would expect the graph to be filled to the left of the line between the y axis and the graph line. The actual output right now is just a solid line.
The orient property has to go into the encode block.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 500,
"height": 500,
"padding": 5,
"signals": [
{
"name": "interpolate",
"value": "linear",
"bind": {
"input": "select",
"options": [
"basis",
"cardinal",
"catmull-rom",
"linear",
"monotone",
"natural",
"step",
"step-after",
"step-before"
]
}
}
],
"data": [
{
"name": "table",
"values": [
{"u": 1, "v": 28}, {"u": 2, "v": 55},
{"u": 3, "v": 43}, {"u": 4, "v": 91},
{"u": 5, "v": 81}, {"u": 6, "v": 53},
{"u": 7, "v": 19}, {"u": 8, "v": 87},
{"u": 9, "v": 52}, {"u": 10, "v": 48},
{"u": 11, "v": 24}, {"u": 12, "v": 49},
{"u": 13, "v": 87}, {"u": 14, "v": 66},
{"u": 15, "v": 17}, {"u": 16, "v": 27},
{"u": 17, "v": 68}, {"u": 18, "v": 16},
{"u": 19, "v": 49}, {"u": 20, "v": 15}
]
}
],
"scales": [
{
"name": "uscale",
"type": "linear",
"range": "height",
"zero": false,
"domain": {"data": "table", "field": "u"}
},
{
"name": "vscale",
"type": "linear",
"range": "width",
"nice": true,
"zero": true,
"domain": {"data": "table", "field": "v"}
}
],
"axes": [
{"orient": "bottom", "scale": "vscale", "tickCount": 25},
{"orient": "left", "scale": "uscale"}
],
"marks": [
{
"type": "area",
"from": {"data": "table"},
"encode": {
"enter": {
"orient": {"value": "horizontal"},
"x": {"scale": "vscale", "field": "v"},
"y": {"scale": "uscale", "field": "u"},
"x2": {"scale": "vscale", "value": 0},
"stroke": {"value": "#000000"},
"fill": {"value": "steelblue"}
},
"update": {
"interpolate": {"signal": "interpolate"},
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
}
]
}

Only show ticks at integer values in Vega Lite

In a graph I'm making using Vega Lite, I'm seeing ticks at 0.5 steps, even though the data will only include integer values. Is there a way to set this in Vega Lite? I tried looking for something like "minimum tick step", or something similar in the docs, but I couldn't find anything like that.
There are a couple ways to do this, depending on what your situation is. For example, consider this chart:
{
"data": {
"values": [
{"x": 1, "y": 1},
{"x": 2, "y": 3},
{"x": 3, "y": 4},
{"x": 4, "y": 2}
]
},
"mark": "point",
"encoding": {
"x": {"type": "quantitative", "field": "x"},
"y": {"type": "quantitative", "field": "y"}
},
"width": 400
}
If all of your values are integers and you only care about integers, it might be that your data are better represented by ordinal values (i.e. ordered categorical data). If so, you can remove the ticks by specifying an ordinal type:
{
"data": {
"values": [
{"x": 1, "y": 1},
{"x": 2, "y": 3},
{"x": 3, "y": 4},
{"x": 4, "y": 2}
]
},
"mark": "point",
"encoding": {
"x": {"type": "ordinal", "field": "x"},
"y": {"type": "quantitative", "field": "y"}
},
"width": 400
}
If you want your data to be represented as quantitative, but just want to adjust the tick spacing, you can use the axis.tickMinStep property:
{
"data": {
"values": [
{"x": 1, "y": 1},
{"x": 2, "y": 3},
{"x": 3, "y": 4},
{"x": 4, "y": 2}
]
},
"mark": "point",
"encoding": {
"x": {"type": "quantitative", "field": "x", "axis": {"tickMinStep": 1}},
"y": {"type": "quantitative", "field": "y"}
},
"width": 400
}

Vega Visualization Custom Axis orientation

I am making the following graph of temperature over time using Vega Visualization Grammar. I am currently using area plot.
X-axis - time
y-axis - temperature (Starting from -40 to 80)
I need the x-axis to start from 0 instead of -40.
Following is the vega Json:
var tempdata = {
"width": 250,
"height": 150,
"background": "#FFF",
"padding": {"top": 10, "left": 30, "bottom": 30, "right": 10},
"data": [
{
"name": "table",
"values": [
{"x": 1, "y": -40}, {"x": 2, "y": -30},
{"x": 3, "y": -10}, {"x": 4, "y": -4},
{"x": 5, "y": -1}, {"x": 6, "y": 0},
{"x": 7, "y": -5}, {"x": 8, "y": -2},
{"x": 9, "y": 20}, {"x": 10, "y": 20},
{"x": 11, "y": 24}, {"x": 12, "y": 12},
{"x": 13, "y": 50}, {"x": 14, "y": 30},
{"x": 15, "y": 15}, {"x": 16, "y": 60},
{"x": 17, "y": 60}, {"x": 18, "y": 80},
{"x": 19, "y": 70}, {"x": 20, "y": 70},
{"x": 21, "y": 72}, {"x": 22, "y": 75},
{"x": 23, "y": 60}, {"x": 24, "y": 60}
]
}
],
"scales": [
{
"name": "x",
"type": "linear",
"range": "width",
"zero": false,
"domain": {"data": "table", "field": "x"}
},
{
"name": "y",
"type": "linear",
"range": "height",
"nice": true,
"domain": {"data": "table", "field": "y"}
}
],
"axes": [
{
"type": "x",
"scale": "x",
"properties": {
"ticks": {
"stroke": {"value": "#000"}
},
"labels": {
"fill": {"value": "#000"}
},
"axis": {
"stroke": {"value": "#000"},
"strokeWidth": {"value": 1.5}
}
}
},
{
"type": "y",
"scale": "y",
"properties": {
"ticks": {
"stroke": {"value": "#000"}
},
"labels": {
"fill": {"value": "#000"}
},
"axis": {
"stroke": {"value": "#000"},
"strokeWidth": {"value": 1.5}
}
}
}
],
"marks": [
{
"type": "area",
"from": {"data": "table"},
"properties": {
"enter": {
"interpolate": {"value": "monotone"},
"x": {"scale": "x", "field": "x"},
"y": {"scale": "y", "field": "y"},
"y2": {"scale": "y", "value": 0},
"fill": {"value": "#A41600"},
"stroke": {"value": "#FFF"}
},
"update": {
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
}
]
};
From what you've written I suppose you want the y-Axis to start from 0 to 80, not the x-Axis, as you have stated (because the x-Axis does not include -40).
A possible approach would be to remove the data which violates your condition, so in other words: Removing every datum which has a y-Value smaller than 0.
You can achieve this by adding a data transform of type filter to the toplevel data-property in the following way:
"transform":
[
{
"type": "filter",
"test": "datum.y >= 0"
}
]
This will remove every datum which has a y-Value smaller than 0 and then you can proceed normally.
Make sure to enter above code in the toplevel-property data.
P.S. Feel free to edit by highlighting/ underlining anything as this is my first post and eventually will contain flaws :).