I'm having trouble using the rule mark in vega to create lines that span the entire width or height of a plot.
The documentation for rule is a bit sparse. I'm basing my example below on this google groups post.
{
"width": 250,
"height": 250,
"padding": "auto",
"scales": [
{"name": "xscale", "type": "linear", "range": "width", "domain": [0, 10]},
{"name": "yscale", "type": "linear", "range": "height", "domain": [0, 10]}
],
"axes": [
{"type": "x", "scale": "xscale"},
{"type": "y", "scale": "yscale"}
],
"marks": [
{
"type": "rule",
"properties": {
"enter": {
"x": {"scale": "xscale", "value": 0},
"x2": {"scale": "xscale", "group": "width"},
"y": {"scale": "yscale", "value": 5.5},
"stroke": {"value": "green"}
}
}
}
]
}
Seems straight-forward enough, but I'm getting an empty plot in the vega editor
The problem is width the specification of x2.
In this case it should be either:
"x2": {"scale": "xscale", "value": 10},
or
"x2": {"signal": "width"},
Making the full specification:
{
"width": 250,
"height": 250,
"padding": "auto",
"scales": [
{"name": "xscale", "type": "linear", "range": "width", "domain": [0, 10]},
{"name": "yscale", "type": "linear", "range": "height", "domain": [0, 10]}
],
"axes": [
{"type": "x", "scale": "xscale"},
{"type": "y", "scale": "yscale"}
],
"marks": [
{
"type": "rule",
"properties": {
"enter": {
"x": {"scale": "xscale", "value": 0},
"x2": {"signal": "width"},
"y": {"scale": "yscale", "value": 5.5},
"stroke": {"value": "green"}
}
}
}
]
}
Related
I have a line graph.
I wanted the lines to start from the y-axis only. Currently the line is starting after a break.
This is the original graph:
https://vega.github.io/editor/#/gist/dcc9afece4dc6a5e89835650ec607280/og_chart.json
This is the chart in which I tried to get the change:
https://vega.github.io/editor/#/gist/e99bd5bd778e63af42bbbe6757301523/change_og_chart.json
This is the current chart
I would like to change this so the lines start from the y-axis only.
How could I shift the grid lines to the right to start with the y-axis domain line or is there a better way to start the line from the domain line.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 800,
"height": 200,
"data": {
"values": [
{
"60": 100,
"90": 150,
"120": 200,
"-120": 10,
"-90": 15,
"-60": 30,
"type": "Mango"
},
{
"-120": 50,
"-90": 30,
"-60": 45,
"60": 90,
"90": 140,
"120": 190,
"type": "Apple"
}
]
},
"transform": [{"fold": ["-120", "-90", "-60", "60", "90", "120"]}],
"layer": [
{
"mark": "line",
"encoding": {
"x": {
"field": "key",
"type": "quantitative",
"sort": null,
"axis": {"tickCount": 10, "values": [-120,-90,-60,0,60,90,120],
"labelExpr": "abs(datum.value)"}
},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "type", "type": "nominal"}
}
},
{
"mark": {
"type": "rule",
"color": "maroon",
"size": 3,
"strokeDash": [6, 4]
},
"encoding": {"x": {"datum": 0, "bandPosition": 0}}
}
]
}
You are using discrete x-axis (bands) rather than continuous. I would do something like this.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 800,
"height": 200,
"data": {
"values": [
{
"pre_120": 10,
"pre_90": 15,
"pre_60": 30,
"post_60": 100,
"post_90": 150,
"post_120": 200,
"type": "Mango"
},
{
"pre_120": 50,
"pre_90": 30,
"pre_60": 45,
"post_60": 90,
"post_90": 140,
"post_120": 190,
"type": "Apple"
}
]
},
"transform": [
{"fold": ["pre_120", "pre_90", "pre_60", "post_60", "post_90", "post_120"]}
],
"layer": [
{
"mark": "line",
"encoding": {
"x": {
"field": "key",
"bandPosition": 0,
"axis":{ "bandPosition":0, "labelOffset":-55},
"sort": [
"pre_120",
"pre_90",
"pre_60",
"0",
"post_60",
"post_90",
"post_120"
],
"scale": {
"domain": [
"pre_120",
"pre_90",
"pre_60",
"0",
"post_60",
"post_90",
"post_120"
]
}
},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "type", "type": "nominal"}
}
},
{
"mark": {
"type": "rule",
"color": "maroon",
"size": 3,
"strokeDash": [6, 4]
},
"encoding": {"x": {"datum": "0", "bandPosition": 0}}
}
]
}
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 800,
"height": 200,
"data": {
"values": [
{
"60": 100,
"90": 150,
"120": 200,
"-120": 10,
"-90": 15,
"-60": 30,
"type": "Mango"
},
{
"-120": 50,
"-90": 30,
"-60": 45,
"60": 90,
"90": 140,
"120": 190,
"type": "Apple"
}
]
},
"transform": [{"fold": ["-120", "-90", "-60", "60", "90", "120"]}],
"layer": [
{
"mark": "line",
"encoding": {
"x": {
"field": "key",
"type": "quantitative",
"sort": null,
"axis": {"tickCount": 10, "values": [-120,-90,-60,0,60,90,120]}
},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "type", "type": "nominal"}
}
},
{
"mark": {
"type": "rule",
"color": "maroon",
"size": 3,
"strokeDash": [6, 4]
},
"encoding": {"x": {"datum": 0, "bandPosition": 0}}
}
]
}
This is the chart I am trying to follow for my work
Vega editor
How could I change the order of the 'Measure' to keep 'Measure 1' at the top only by ignoring that it is a negative value? I still want to show the '-' sign in the text but I want the bar to go to the top.
For David: One of the bars are in such a way where the top blue bar can be negative but should always be on the top
:
Like this? If so, you need a sort.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"Value": 0.321, "Date": "09/30/2021", "Measure": "Measure 4"},
{"Value": 0.031, "Date": "09/30/2021", "Measure": "Measure 3"},
{"Value": 0.123, "Date": "09/30/2021", "Measure": "Measure 2"},
{"Value": -0.475, "Date": "09/30/2021", "Measure": "Measure 1"}
]
},
"width": 500,
"height": 250,
"resolve": {"scale": {"color": "independent"}},
"layer": [
{
"mark": "bar",
"encoding": {
"y": {
"field": "Value",
"type": "quantitative",
"axis": {"format": ".1%"},
"sort": "descending"
},
"x": {"field": "Date", "type": "nominal", "axis": {"labelAngle": -45}},
"color": {"field": "Measure", "type": "nominal"}
}
},
{
"transform": [
{
"stack": "Value",
"groupby": ["Date"],
"as": ["lower", "upper"],
"sort": [{"field": "Measure", "order": "descending"}]
},
{"calculate": "(datum.lower + datum.upper) / 2", "as": "midpoint"}
],
"mark": {"type": "text"},
"encoding": {
"y": {"field": "midpoint", "type": "quantitative"},
"x": {"field": "Date", "type": "nominal"},
"color": {
"field": "Measure",
"type": "nominal",
"scale": {"range": ["white"]},
"legend": null
},
"text": {"aggregate": "sum", "field": "Value"}
}
}
]
}
am trying to figure out how to use vega in a web app.
From what I am seeing it looks like it is possible to resize the chart size but I am not entirely sure how to go about it? Would I have to manually change the json object that vega is working off or is there an easier way?
Also, I am having a bad time trying to customize the x-axis. I have date that ranges from 0-potentially thousands. Would like to be able to dynamically set the tick data for the x-axis (by tick data I mean how the x axis increments.. part of my confusion I'm sure is that I don't know what vega means by tick, etc.).
BTW, I'm using angular for the front-end with ng-vega to put the "spec" for vega onto the scope.
{
"signals":[
{
"name":"width",
"init":"isFinite(containerSize()[0]) ? containerSize()[0] : 200",
"on":[
{
"update":"isFinite(containerSize()[0]) ? containerSize()[0] : 200",
"events":"window:resize"
}
]
}
]
}
Please have a look in sample
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"autosize": {"type": "fit", "contains": "padding"},
"background": "white",
"padding": 5,
"height": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"url": "data/seattle-weather.csv",
"format": {"type": "csv", "parse": {"date": "date"}, "delimiter": ","},
"transform": [
{
"type": "formula",
"as": "month_date",
"expr": "datetime(0, month(datum[\"date\"]), 1, 0, 0, 0, 0)"
},
{
"type": "formula",
"as": "month_date_end",
"expr": "datetime(0, month(datum[\"date\"])+1, 1, 0, 0, 0, 0)"
},
{
"type": "aggregate",
"groupby": ["month_date", "month_date_end"],
"ops": ["mean"],
"fields": ["precipitation"],
"as": ["mean_precipitation"]
},
{
"type": "filter",
"expr": "(isDate(datum[\"month_date\"]) || (isValid(datum[\"month_date\"]) && isFinite(+datum[\"month_date\"])))"
}
]
}
],
"signals": [
{
"name": "width",
"init": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
"on": [
{
"update": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
"events": "window:resize"
}
]
}
],
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "source_0"},
"encode": {
"update": {
"fill": {"value": "#4c78a8"},
"x2": [
{
"test": "!isValid(datum[\"month_date\"]) || !isFinite(+datum[\"month_date\"])",
"value": 0
},
{"scale": "x", "field": "month_date", "offset": 1}
],
"x": [
{
"test": "!isValid(datum[\"month_date\"]) || !isFinite(+datum[\"month_date\"])",
"value": 0
},
{"scale": "x", "field": "month_date_end"}
],
"y": {"scale": "y", "field": "mean_precipitation"},
"y2": {"scale": "y", "value": 0}
}
}
}
],
"scales": [
{
"name": "x",
"type": "time",
"domain": {
"data": "source_0",
"fields": ["month_date", "month_date_end"]
},
"range": [0, {"signal": "width"}]
},
{
"name": "y",
"type": "linear",
"domain": {"data": "source_0", "field": "mean_precipitation"},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"gridScale": "y",
"grid": true,
"domain": false,
"labels": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"gridScale": "x",
"grid": true,
"tickCount": {"signal": "ceil(height/40)"},
"domain": false,
"labels": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "date (month)",
"labelFlush": true,
"labelOverlap": true,
"encode": {
"labels": {
"update": {"text": {"signal": "timeFormat(datum.value, '%b')"}}
}
},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Mean of precipitation",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"zindex": 0
}
],
"config": {"background": "white"}
}
I've been playing around with Vega, but I can't get my head around how to turn a vertical bar chart into an horizontal bar chart.
A similar question was posted a while ago here: vega horizontal bar charts but the provided answer isn't very clear on what exactly is being done to the code to produce the desired result. I also haven't been able to get the solution to run!
My understanding for now is that you need to switch the X and Y axis and scales, but where I get lost is in getting the mark to be flipped as well? I've tried setting the "x" and "y" attributes but I just get a blank chart in return... It really feels like I'm only missing one thing as my axes are right, but can't figure what it is!
EDIT: made some progress! My columns are now appearing, but their position is weirdly shifted vs the actual ticks. I've looked into adjusting the "points" parameter of the ordinal scale, but as a result the last column
The plot I obtain right now.
And with the "points" parameter set to true for the y scale.
Here's the code I have so far below
{
"width": 400,
"height": 400,
"padding": {
"top": 30,
"left": 40,
"bottom": 30,
"right": 10
},
"data": [
{
"name": "table",
"values": [
{
"x": "Mon",
"y": 2
},
{
"x": "Tue",
"y": 3
},
{
"x": "Wed",
"y": 10
}
]
}
],
"scales": [
{
"name": "x",
"type": "ordinal",
"points": true
"range": "height",
"zero": false,
"domain": {
"data": "table",
"field": "x"
}
},
{
"name": "y",
"type": "linear",
"range": "width",
"domain": {
"data": "table",
"field": "y"
},
"nice": true
}
],
"axes": [
{
"type": "x",
"scale": "y"
},
{
"type": "y",
"scale": "x"
}
],
"marks": [
{
"type": "rect",
"from": {
"data": "table"
},
"properties": {
"enter": {
"x": {
"scale": "y",
"field": "y"
},
"x2": {
"value": 0
},
"yc": {
"scale": "x",
"field": "x"
},
"height": {
"value": 40
},
"fill": {
"r": {
"value": 66
},
"g": {
"value": 190
},
"b": {
"value": 244
}
}
}
}
}
]
}
Victory!
Here's a working spec!
I used the "padding" property of the ordinal scale to get the desired result.
{
"width": 400,
"height": 400,
"padding": {
"top": 30,
"left": 40,
"bottom": 30,
"right": 10
},
"data": [
{
"name": "table",
"values": [
{
"x": "Mon",
"y": 2
},
{
"x": "Tue",
"y": 3
},
{
"x": "Wed",
"y": 10
}
]
}
],
"scales": [
{
"name": "x",
"type": "ordinal",
"range": "height",
"points": true,
"padding": 1,
"zero": false,
"domain": {
"data": "table",
"field": "x"
}
},
{
"name": "y",
"type": "linear",
"range": "width",
"domain": {
"data": "table",
"field": "y"
},
"nice": true
}
],
"axes": [
{
"type": "x",
"scale": "y"
},
{
"type": "y",
"scale": "x"
}
],
"marks": [
{
"type": "rect",
"from": {
"data": "table"
},
"properties": {
"enter": {
"x": {
"scale": "y",
"field": "y"
},
"x2": {
"value": 0
},
"yc": {
"scale": "x",
"field": "x"
},
"height": {
"value": 40
},
"fill": [
66,
190,
244
]
}
}
}
]
}
I am referring VEGA chart following code which is available in the preview. There "domain": [0, 3] is used set range in x and y axis. Here if i set [-0.5, 3], x axis will start from -0.5 but if i want to have positive number such as 0.5 it, x-axis will not start from that value instead it starts from 0. Is there any alternative way to sort this matter?
{
"name": "image",
"width": 200,
"height": 200,
"padding": {"left":30, "top":10, "bottom":30, "right":10},
"data": [
{
"name": "data",
"values": [
{"x":0.5, "y":0.5, "img":"data/ffox.png"},
{"x":1.5, "y":1.5, "img":"data/gimp.png"},
{"x":2.5, "y":2.5, "img":"data/7zip.png"}
]
}
],
"scales": [
{"name": "x", "domain": [0, 3], "range": "width"},
{"name": "y", "domain": [0, 3], "range": "height"}
],
"axes": [
{"type": "x", "scale": "x"},
{"type": "y", "scale": "y"}
],
"marks": [
{
"type": "image",
"from": {"data": "data"},
"properties": {
"enter": {
"url": {"field": "data.img"},
"width": {"value": 50},
"height": {"value": 50},
"x": {"scale": "x", "field": "data.x"},
"y": {"scale": "y", "field": "data.y"},
"align": {"value": "center"},
"baseline": {"value": "middle"}
},
"update": {
"opacity": {"value": 1.0}
},
"hover": {
"opacity": {"value": 0.5}
}
}
}
]
}
Add attribute "zero": false in scales
"scales": [
{"name": "x", "domain": [0, 3], "range": "width", "zero": false},
{"name": "y", "domain": [0, 3], "range": "height"}
]