How to change color of stroke in Parallel Coordinate Vega Chart? - vega

I'm working with vega charts (parallel coordinates). How do I change the color of the lines with respect to scheme colors (w.r.t 'name' field).
Here is my code
I tried changing the stroke property with color scale but there is no effect on line stroke.
Can anyone point out what am I doing wrong.
I'm using Vega Version 4
Thanks
vikky

Because the colors need to be by column "name", transform the input dataset to have repeated name rows. In other words, input dataset must be of 3 columns (name, quarter, value)
Then, change "group" type mark to use facet dataset grouped by column "name"
"name": "marks_group_lines",
"type": "group",
"from": {
"facet": {
"name": "cars_by_name",
"data": "cars",
"groupby": "name"
}
},
Use the cars_by_name as dataset to render "line" type mark.
tip: Instead of defining quarter dataset for 4 axes for each qarter and scales for these axes, "line" type mark which has point scale for "x" property can be used.
Full code for reference:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 700,
"height": 400,
"padding": 5,
"config": {
"axisY": {
"titleX": -2,
"titleY": 410,
"titleAngle": 0,
"titleAlign": "right",
"titleBaseline": "top"
}
},
"data": [
{
"name": "cars",
"values": [
{
"name": "A",
"quarter": "Q1",
"value": 51
},
{
"name": "A",
"quarter": "Q2",
"value": 47
},
{
"name": "A",
"quarter": "Q3",
"value": 45
},
{
"name": "A",
"quarter": "Q4",
"value": 30
},
{
"name": "B",
"quarter": "Q1",
"value": 42
},
{
"name": "B",
"quarter": "Q2",
"value": 57
},
{
"name": "B",
"quarter": "Q3",
"value": 72
},
{
"name": "B",
"quarter": "Q4",
"value": 41
},
{
"name": "C",
"quarter": "Q1",
"value": 25
},
{
"name": "C",
"quarter": "Q2",
"value": 37
},
{
"name": "C",
"quarter": "Q3",
"value": 60
},
{
"name": "C",
"quarter": "Q4",
"value": 25
},
{
"name": "D",
"quarter": "Q1",
"value": 22
},
{
"name": "D",
"quarter": "Q2",
"value": 25
},
{
"name": "D",
"quarter": "Q3",
"value": 51
},
{
"name": "D",
"quarter": "Q4",
"value": 42
}
]
},
{
"name": "fields",
"values": [
"Q1",
"Q2",
"Q3",
"Q4"
]
}
],
"scales": [
{
"name": "name_to_xaxis",
"type": "point",
"domain": {
"data": "cars",
"field": "quarter"
},
"range": "width"
},
{
"name": "values_to_height",
"type": "linear",
"domain": {
"data": "cars",
"field": "value"
},
"range": "height"
},
{
"name": "quarter_to_color",
"type": "ordinal",
"domain": {
"data": "cars",
"field": "name"
},
"range": "category"
},
{
"name": "ord",
"type": "point",
"range": "width",
"round": true,
"domain": {
"data": "fields",
"field": "data"
}
},
{
"name": "Q1",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q1"
}
},
{
"name": "Q2",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q2"
}
},
{
"name": "Q3",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q3"
}
},
{
"name": "Q4",
"type": "linear",
"range": "height",
"zero": false,
"nice": true,
"domain": {
"data": "cars",
"field": "Q4"
}
}
],
"axes": [
{
"orient": "left",
"zindex": 1,
"scale": "Q1",
"title": "Q1",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q1",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q2",
"title": "Q2",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q2",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q3",
"title": "Q3",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q3",
"mult": -1
}
},
{
"orient": "left",
"zindex": 1,
"scale": "Q4",
"title": "Q4",
"ticks": false,
"labels": false,
"offset": {
"scale": "ord",
"value": "Q4",
"mult": -1
}
}
],
"marks": [
{
"name": "marks_group_lines",
"type": "group",
"from": {
"facet": {
"name": "cars_by_name",
"data": "cars",
"groupby": "name"
}
},
"marks": [
{
"name": "marks_lines",
"type": "line",
"from": {
"data": "cars_by_name"
},
"encode": {
"update": {
"x": {
"scale": "name_to_xaxis",
"field": "quarter"
},
"y": {
"scale": "values_to_height",
"field": "value"
},
"stroke": {
"scale": "quarter_to_color",
"field": "name"
},
"strokeOpacity": {
"value": 1
}
},
"hover": {
"stroke": {
"value": "#7c7c7c"
},
"strokeOpacity": {
"value": 1
},
"zindex": 99
}
}
},
{
"name": "marks_symbols",
"type": "symbol",
"from": {
"data": "cars_by_name"
},
"encode": {
"enter": {
"stroke": {
"value": "#6D6D6D"
},
"strokeWidth": {
"value": 1
},
"shape": {
"value": "circle"
}
},
"update": {
"x": {
"scale": "name_to_xaxis",
"field": "quarter"
},
"y": {
"scale": "values_to_height",
"field": "value"
},
"fill": {
"scale": "quarter_to_color",
"field": "name"
},
"size": {
"value": 50
},
"stroke": {
"value": "#77AE80"
}
},
"hover": {
"fill": {
"value": "#AFD098"
}
}
}
}
]
}
]
}

Related

Vega Zoomable USA Map

I want to use this map https://vega.github.io/vega/examples/zoomable-world-map/ but only for USA.
I used this spec.
private specVega = {
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "An interactive world map supporting pan and zoom.",
"width": 900,
"height": 500,
"autosize": "none",
"signals": [
{ "name": "tx", "update": "width / 2" },
{ "name": "ty", "update": "height / 2" },
{
"name": "scale",
"value": 150,
"on": [{
"events": {"type": "wheel", "consume": true},
"update": "clamp(scale * pow(1.0005, -event.deltaY * pow(16, event.deltaMode)), 150, 3000)"
}]
},
{
"name": "angles",
"value": [0, 0],
"on": [{
"events": "mousedown",
"update": "[rotateX, centerY]"
}]
},
{
"name": "cloned",
"value": null,
"on": [{
"events": "mousedown",
"update": "copy('projection')"
}]
},
{
"name": "start",
"value": null,
"on": [{
"events": "mousedown",
"update": "invert(cloned, xy())"
}]
},
{
"name": "drag", "value": null,
"on": [{
"events": "[mousedown, window:mouseup] > window:mousemove",
"update": "invert(cloned, xy())"
}]
},
{
"name": "delta", "value": null,
"on": [{
"events": {"signal": "drag"},
"update": "[drag[0] - start[0], start[1] - drag[1]]"
}]
},
{
"name": "rotateX", "value": 0,
"on": [{
"events": {"signal": "delta"},
"update": "angles[0] + delta[0]"
}]
},
{
"name": "centerY", "value": 0,
"on": [{
"events": {"signal": "delta"},
"update": "clamp(angles[1] + delta[1], -60, 60)"
}]
}
],
"projections": [
{
"name": "projection",
"type": "mercator",
"scale": {"signal": "scale"},
"rotate": [{"signal": "rotateX"}, 0, 0],
"center": [0, {"signal": "centerY"}],
"translate": [{"signal": "tx"}, {"signal": "ty"}]
}
],
"data": [
{
"name": "counties",
values: null,
"format": {"type": "topojson", "feature": "states"},
},
{
"name": "graticule",
"transform": [
{ "type": "graticule", "step": [15, 15] }
]
}
],
"marks": [
{
"type": "shape",
"from": {"data": "graticule"},
"encode": {
"enter": {
"strokeWidth": {"value": 1},
"stroke": {"value": "#ddd"},
"fill": {"value": null}
}
},
"transform": [
{ "type": "geoshape", "projection": "projection" }
]
},
{
"type": "shape",
"from": {"data": "states"},
"encode": {
"enter": {
"strokeWidth": {"value": 0.5},
"stroke": {"value": "#bbb"},
"fill": {"value": "#e5e8d3"}
}
},
"transform": [
{ "type": "geoshape", "projection": "projection" }
]
}
]
}
this.specVega["data"][0]["values"] = "data/us-10m.json" (this is just for understanding which data i used)
So i put data for only US here, but it didn't work. Got an error in console:
Undefined data set name: "states"
In general i just need a zoomable map for USA only, which i am going to use as a bubble map.
If this map has a zoom i would definitely use it https://vega.github.io/vega-lite/examples/geo_layer.html
Here is an working example of USA map by states or counties in "albersUsa" projection. Zooming is by mouse wheel and panning by mouse click-drag. For better performance, zooming and panning are best done with states instead of counties.
View in Vega online editor
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "An interactive USA map supporting pan and zoom.",
"width": 900,
"height": 500,
"autosize": "none",
"signals": [
{
"name": "signal_show_map_graticule",
"value": true,
"bind": {
"input": "checkbox",
"name": "Map graticule: "}
},
{
"name": "signal_states_or_counties",
"value": "states",
"bind": { "input": "select",
"options": ["states", "counties"],
"name": "Map areas: "
}
},
{
"name": "signal_map_scale",
"value": 1000,
"bind": {"input": "range", "min": 1000, "max": 4000, "step": 50, "name": "Map scale: "},
"on": [{
"events": {"type": "wheel", "consume": true},
"update": "round(clamp(signal_map_scale * pow(1.0005, -event.deltaY * pow(16, event.deltaMode)), 1000, 4000))"
}]
},
{ "name": "signal_translate_xy",
"value": [450, 250],
"update": "[clamp(signal_translate_last_xy[0] + signal_mouse_delta_xy[0], -300, 1200), clamp(signal_translate_last_xy[1] + signal_mouse_delta_xy[1], -200, 800)]"
},
{ "name": "signal_translate_last_xy",
"value": [450, 250],
"on": [{
"events": [
{"type": "mousedown"}
],
"update": "signal_translate_xy"
}]
},
{
"name": "signal_mouse_start_xy",
"value": [0, 0],
"on": [{
"events": [
{"type": "mousedown"}
],
"update": "xy()"
}]
},
{
"name": "signal_mouse_drag_xy",
"value": [0, 0],
"on": [{
"events": [
{
"type": "mousemove",
"between": [
{"type": "mousedown"},
{"type": "mouseup"}
]
}
],
"update": "xy()"
}]
},
{
"name": "signal_mouse_delta_xy",
"value": [0, 0],
"update": "[signal_mouse_drag_xy[0] - signal_mouse_start_xy[0], signal_mouse_drag_xy[1] - signal_mouse_start_xy[1]]"
}
],
"projections": [
{
"name": "map_projection",
"type": "albersUsa",
"scale": {"signal": "signal_map_scale"},
"translate": {"signal": "signal_translate_xy"}
}
],
"data": [
{
"name": "data_geo_usa",
"url": "data/us-10m.json",
"format": {
"type": "topojson",
"feature": {"signal": "signal_states_or_counties"}
}
},
{
"name": "data_geo_graticule",
"transform": [
{ "type": "graticule", "step": [5, 5] }
]
}
],
"marks": [
{
"type": "shape",
"from": {"data": "data_geo_graticule"},
"encode": {
"enter": {
"strokeWidth": {"value": 1},
"stroke": {"value": "#ddd"}
},
"update": {
"strokeOpacity": {"signal": "signal_show_map_graticule ? 1 : 0"}
}
},
"transform": [
{ "type": "geoshape", "projection": "map_projection" }
]
},
{
"type": "shape",
"from": {"data": "data_geo_usa"},
"encode": {
"enter": {
"strokeWidth": {"value": 0.5},
"stroke": {"value": "#bbb"},
"fill": {"value": "#e5e8d3"}
}
},
"transform": [
{ "type": "geoshape", "projection": "map_projection" }
]
}
]
}
Change "data" to:
"data": [
{
"name": "states",
"url": "data/us-10m.json",
"format": {"type": "topojson", "feature": "states"}
},
View in Vega online editor
Apologies but I'm not a mapping expert. I have the following where zoom works fine but the drag is a little janky but definitely useable. It would probably take me quite a while to get this any better.
Roy's answer is another option for you.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"autosize": "none",
"background": "white",
"padding": 5,
"width": 500,
"height": 300,
"signals": [
{"name": "tx", "update": "width / 2"},
{"name": "ty", "update": "height / 2"},
{
"name": "scale",
"value": 685,
"on": [
{
"events": {"type": "wheel", "consume": true},
"update": "clamp(scale * pow(1.0005, -event.deltaY * pow(16, event.deltaMode)), 150, 3000)"
}
]
},
{
"name": "angles",
"value": [222, 146],
"on": [{"events": "mousedown", "update": "[rotateX, centerY]"}]
},
{
"name": "cloned",
"value": null,
"on": [{"events": "mousedown", "update": "copy('projection')"}]
},
{
"name": "start",
"value": null,
"on": [{"events": "mousedown", "update": "invert(cloned, xy())"}]
},
{
"name": "drag",
"value": null,
"on": [
{
"events": "[mousedown, window:mouseup] > window:mousemove",
"update": "invert(cloned, xy())"
}
]
},
{
"name": "delta",
"value": null,
"on": [
{
"events": {"signal": "drag"},
"update": "[(drag[0] - start[0])*4, (start[1] - drag[1])*4]"
}
]
},
{
"name": "rotateX",
"value": 250,
"on": [{"events": {"signal": "delta"}, "update": "angles[0] + delta[0]"}]
},
{
"name": "centerY",
"value": 140,
"on": [{"events": {"signal": "delta"}, "update": "angles[1] + delta[1]"}]
}
],
"data": [
{
"name": "source_0",
"url": "data/us-10m.json",
"format": {"type": "topojson", "feature": "states"}
}
],
"projections": [
{
"name": "projection",
"scale": {"signal": "scale"},
"translate": [{"signal": "rotateX"}, {"signal": "centerY"}],
"type": "albersUsa"
}
],
"marks": [
{
"name": "marks",
"type": "shape",
"style": ["geoshape"],
"from": {"data": "source_0"},
"encode": {
"update": {"fill": {"value": "lightgray"}, "stroke": {"value": "white"}}
},
"transform": [{"type": "geoshape", "projection": "projection"}]
}
]
}

Vega How to SUM all descendants value of every node on a treemap

I am trying to access the sum of values for a node in VEGA. In other words, I want to display sum of "percentage" values of all leaves for each parent node.
Got the following Vega specs (https://gist.github.com/omerakko/655674f9f37e9361fe5378b6d440e411)
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "An example of treemap layout for hierarchical data.",
"width": 960,
"height": 500,
"padding": 2.5,
"autosize": "none",
"data": [
{
"name": "tree",
"url": "https://raw.githubusercontent.com/omerakko/VEGA/main/vegaTreemapData.json",
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "treemap",
"field": "percentage",
"sort": {"field": "value", "order":"descending"},
"round": true,
"method": "resquarify",
"ratio": 1,
"size": [{"signal": "width"}, {"signal": "height"}],
"paddingOuter": 2,
"paddingInner":2
}
]
},
{
"name": "nodes",
"source": "tree",
"transform": [{ "type": "filter", "expr": "datum.children" }]
},
{
"name": "leaves",
"source": "tree",
"transform": [{ "type": "filter", "expr": "!datum.children" },
{"type": "filter", "expr": "datum.percentage > 0"}]
}
],
"scales": [
{
"name": "color",
"type": "ordinal",
"domain": {"data": "nodes", "field": "name"},
"range": [
"transparent", "#dd96ba", "#dea84e", "#c83836", "#dfde9b",
"#5eafb9", "#adc35d"]
},
{
"name": "size",
"type": "ordinal",
"domain": [0, 1, 2, 3],
"range": [256, 28, 20, 14]
},
{
"name": "opacity",
"type": "ordinal",
"domain": [0, 1, 2, 3],
"range": [0.15, 0.5, 0.8, 1.0]
}
],
"marks": [
{
"type": "rect",
"from": {"data": "nodes"},
"interactive": false,
"encode": {
"enter": {
"fill": {"value":"#333238"},
"stroke": {"scale": "color", "field": "name"},
"strokeWidth":{"value": 5}
},
"update": {
"x": {"field": "x0"},
"y": {"field": "y0"},
"x2": {"field": "x1"},
"y2": {"field": "y1"},
"stroke": {"scale": "color", "field": "name"}
}
}
},
{
"type": "rect",
"from": {"data": "leaves"},
"encode": {
"enter": {
"stroke": {"value": "#fff"}
},
"update": {
"x": {"field": "x0"},
"y": {"field": "y0"},
"x2": {"field": "x1"},
"y2": {"field": "y1"},
"fill": {"value": "transparent"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"from": {"data": "nodes"},
"interactive": false,
"encode": {
"enter": {
"font": {"value": "Helvetica Neue, Arial"},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"fill": {"scale": "color", "field": "name"},
"text": {"field": "name"},
"fontSize": {"scale": "size", "field": "depth"}
},
"update": {
"x": {"signal": "0.5 * (datum.x0 + datum.x1)"},
"y": {"signal": "0.5 * (datum.y0 + datum.y1)"}
}
}
}
]
}
There is doc available https://vega.github.io/vega/docs/transforms/treemap/ here saying that I can access to what I want, but I couldnt manage to apply it to the specs.
It seems like it's not currently possible in Vega. There's this PR that hasn't been merged yet.
But you can work around that by manually aggregating the values and then looking them up. Here a gist in which there's now a total field for each node, the relevant part being:
{
"name": "leaves",
"source": "tree",
"transform": [
{"type": "filter", "expr": "!datum.children"},
{"type": "filter", "expr": "datum.percentage > 0.3"}
]
},
{
"name": "totals",
"source": "leaves",
"transform": [
{
"type": "aggregate",
"groupby": ["parent"],
"fields": ["percentage"],
"as": ["total"],
"ops": ["sum"]
}
]
},
{
"name": "nodes",
"source": "tree",
"transform": [
{"type": "filter", "expr": "datum.children"},
{
"type": "lookup",
"from": "totals",
"key": "parent",
"fields": ["id"],
"values": ["total"],
"as": ["total"]
}
]
},
Basically you just get sums of all the leaves by parent in totals and then, after constructing the base nodes dataset, look the total up in totals.
Note that this will only work for this particular example, where there are exactly two levels in the hierarchy.

Brushing/linking in vega (not vega-lite)

I'm trying to brush/link two plots in vega, more specifically a node-link diagram and a couple of scatterplots. Based on how dragging works with signals in the node-link diagram I did get quite far, but not far enough...
For the sake of simplicity, I'll provide a little test code here using just two scatterplots:
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"padding": 0,
"autosize": "none",
"width": 800,
"height": 400,
"signals": [
{ "description": "Any datapoint is activated",
"name": "datapoint_is_activated", "value": false,
"on": [
{
"events": "symbol:mouseover",
"update": "true"
},
{
"events": "symbol:mouseout",
"update": "false"
}
]
},
{ "description": "Active datapoint",
"name": "activated_datapoint", "value": null,
"on": [
{
"events": "symbol:mouseover",
"update": "item()"
},
{
"events": "symbol:mouseout",
"update": "null"
}
]
}
],
"data": [
{
"name": "table",
"values": [
{"name": "point A", "a": 1, "b": 2, "c": 3},
{"name": "point B", "a": 4, "b": 5, "c": 6},
{"name": "point C", "a": 9, "b": 8, "c": 7}
]
}
],
"scales": [
{ "name": "xscale",
"type": "linear",
"domain": [0,10],
"range": [0,200]
},
{ "name": "yscale",
"type": "linear",
"domain": [0,10],
"range": [0,200]
}
],
"layout": {"padding": 20},
"marks": [
{ "name": "plot1",
"type": "group",
"axes": [
{"orient": "bottom", "scale": "xscale"},
{"orient": "right", "scale": "yscale"}
],
"marks": [
{
"type": "symbol",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"field": "a", "scale": "xscale"},
"y": {"field": "b", "scale": "yscale"},
"tooltip": {"field": "name"}
},
"update": {
"size": {"value": 100},
"fill": {"value": "grey"}
}
}
}
]
},
{ "name": "plot2",
"type": "group",
"axes": [
{"orient": "bottom", "scale": "xscale"},
{"orient": "right", "scale": "yscale"}
],
"marks": [
{
"type": "symbol",
"from": {"data": "table"},
"on": [
{
"trigger": "datapoint_is_activated",
"modify": "activated_datapoint",
"values": "{fill: \"red\"}"
},
{
"trigger": "!datapoint_is_activated",
"modify": "activated_datapoint",
"values": "{fill: \"grey\"}"
}
],
"encode": {
"enter": {
"x": {"field": "a", "scale": "xscale"},
"y": {"field": "c", "scale": "yscale"},
"size": {"value": 100},
"tooltip": {"field": "name"}
},
"update": {
"fill": {"value": "grey"}
}
}
}
]
}
]
}
The resulting image looks like this:
The idea is that hovering over a datapoint in the left plot will highlight the corresponding datapoint in the right plot. I know this is straightforward in vega-lite, but that does not (yet) support node-link diagrams. Hence: vega.
My approach in the code is to:
create a signal in the outer scope that tracks (a) if there is a point activated, and (b) which point this is
in plot 2 to have a trigger that takes the activated datapoint and changes its colour to 'red'.
I have an inkling feeling that it has to do with my definition of the modify and values part, but I can't figure it out.
Any help very much appreciated!
Thank you,
jan.
After a lot of trial and error, I did find a way to do this. Instead of using a trigger (which I believe would be the canonical way of doing this), I merely use a test in the fill section: datapoint_is_activated && datum === activated_datapoint.datum. See code and image below.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"padding": 0,
"autosize": "none",
"width": 800,
"height": 400,
"signals": [
{ "description": "Any datapoint is activated",
"name": "datapoint_is_activated", "value": false,
"on": [
{
"events": "symbol:mouseover",
"update": "true"
},
{
"events": "symbol:mouseout",
"update": "false"
}
]
},
{ "description": "Active datapoint",
"name": "activated_datapoint", "value": null,
"on": [
{
"events": "symbol:mouseover",
"update": "item()"
},
{
"events": "symbol:mouseout",
"update": "null"
}
]
}
],
"data": [
{
"name": "table",
"values": [
{"name": "point A", "a": 2, "b": 2, "c": 4},
{"name": "point B", "a": 4, "b": 5, "c": 6},
{"name": "point C", "a": 5, "b": 3, "c": 5}
]
}
],
"scales": [
{ "name": "xscale",
"type": "linear",
"domain": [0,10],
"range": [0,200]
},
{ "name": "yscale",
"type": "linear",
"domain": [0,10],
"range": [0,200]
}
],
"layout": {"padding": 20},
"marks": [
{ "name": "plot1",
"type": "group",
"axes": [
{"orient": "bottom", "scale": "xscale"},
{"orient": "right", "scale": "yscale"}
],
"marks": [
{
"type": "symbol",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"field": "a", "scale": "xscale"},
"y": {"field": "b", "scale": "yscale"},
"tooltip": {"field": "name"},
"size": {"value": 200}
},
"update": {
"fill": [
{"test": "datapoint_is_activated && datum === activated_datapoint.datum",
"value": "red"},
{"value": "lightgrey"}
]
}
}
}
]
},
{ "name": "plot2",
"type": "group",
"axes": [
{"orient": "bottom", "scale": "xscale"},
{"orient": "right", "scale": "yscale"}
],
"marks": [
{
"type": "symbol",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"field": "a", "scale": "xscale"},
"y": {"field": "c", "scale": "yscale"},
"size": {"value": 200},
"tooltip": {"field": "name"}
},
"update": {
"fill": [
{"test": "datapoint_is_activated && datum === activated_datapoint.datum",
"value": "red"},
{"value": "lightgrey"}
]
}
}
}
]
}
]
}

Incorrect axis position for grouped marks

I'd like to group axes and marks together within a group mark, as I'd like a bar chart to be one of several onto the data. However, when I do so the x axis moved from the bottom to the top of the bar chart. Here's an example:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "cars",
"format": {
"type": "json",
"parse": {
"year": "date"
}
},
"url": "https://vega.github.io/vega-datasets/data/cars.json",
"transform": [
{
"type": "aggregate",
"groupby": [
"Origin"
],
"as": [
"num_records"
]
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {
"data": "cars",
"field": "Origin"
},
"range": "width",
"padding": 0.05
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "cars",
"field": "num_records"
},
"range": "height",
"nice": true
}
],
"marks": [
{
"type": "group",
"axes": [
{
"orient": "bottom",
"scale": "x"
},
{
"orient": "left",
"scale": "y"
}
],
"marks": [
{
"type": "rect",
"from": {
"data": "cars"
},
"encode": {
"enter": {
"x": {
"scale": "x",
"field": "Origin"
},
"width": {
"scale": "x",
"band": 1
},
"y": {
"scale": "y",
"field": "num_records"
},
"y2": {
"scale": "y",
"value": 0
}
}
}
}
]
}
]
}
The Group Mark documentation suggests that groups support such nested visualisation specifications. What am I doing wrong?
What I was doing wrong was not encoding the width and height of the group mark. Here's my revised example:
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "cars",
"format": {
"type": "json",
"parse": {
"year": "date"
}
},
"url": "https://vega.github.io/vega-datasets/data/cars.json",
"transform": [
{
"type": "aggregate",
"groupby": [
"Origin"
],
"as": [
"num_records"
]
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {
"data": "cars",
"field": "Origin"
},
"range": "width",
"padding": 0.05
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "cars",
"field": "num_records"
},
"range": "height",
"nice": true
}
],
"marks": [
{
"type": "group",
"axes": [
{
"orient": "bottom",
"scale": "x"
},
{
"orient": "left",
"scale": "y"
}
],
"encode": {
"enter": {
"width": {
"signal": "width"
},
"height": {
"signal": "height"
}
}
},
"marks": [
{
"type": "rect",
"from": {
"data": "cars"
},
"encode": {
"enter": {
"x": {
"scale": "x",
"field": "Origin"
},
"width": {
"scale": "x",
"band": 1
},
"y": {
"scale": "y",
"field": "num_records"
},
"y2": {
"scale": "y",
"value": 0
}
}
}
}
]
}
]
}

How to align line chart with bar chart

I'd like to align the line vertices (and bullets) of the following chart to the center of the corresponding bars:
{
"data": [
{
"name": "table",
"transform": [
{
"type": "formula",
"field": "predicate0",
"expr": "d.data.x"
}
],
"values": [
{
"x": 1,
"series": 0,
"y": 9
},
{
"x": 1,
"series": 1,
"y": 9
},
{
"x": 3,
"series": 0,
"y": 7
},
{
"x": 3,
"series": 1,
"y": 7
},
{
"x": 5,
"series": 0,
"y": 1
},
{
"x": 5,
"series": 1,
"y": 3
},
{
"x": 2,
"series": 0,
"y": 9
},
{
"x": 2,
"series": 1,
"y": 9
},
{
"x": 4,
"series": 0,
"y": 2
},
{
"x": 4,
"series": 1,
"y": 3
}
]
}
],
"scales": [
{
"name": "x-axis",
"range": "width",
"type": "ordinal",
"padding": 0.2,
"domain": {
"data": "table",
"field": "predicate0"
}
},
{
"name": "y-axis",
"round": true,
"nice": true,
"range": "height",
"domain": {
"data": "table",
"field": "data.y"
}
},
{
"name": "color",
"type": "ordinal",
"domain": [
0,
1
],
"range": [
"#4682b4",
"#8a8f99"
]
},
{
"name": "shortLabels",
"type": "ordinal",
"domain": {
"data": "table",
"field": "data.x"
}
}
],
"axes": [
{
"properties": {
"axis": {
"stroke": {
"value": "#55606e"
}
},
"labels": {
"fill": {
"value": "#55606e"
},
"font": {
"value": "Open Sans"
},
"fontSize": {
"value": 12
}
},
"ticks": {
"stroke": {
"value": "#55606e"
}
},
"title": {
"fill": {
"value": "#55606e"
},
"font": {
"value": "Open Sans"
},
"fontSize": {
"value": 14
},
"fontWeight": {
"value": "normal"
}
}
},
"scale": "x-axis",
"tickPadding": 8,
"tickSize": 0,
"title": "Series",
"type": "x"
},
{
"grid": "true",
"layer": "back",
"scale": "y-axis",
"ticks": 5,
"title": "Count",
"type": "y",
"properties": {
"grid": {
"strokeDash": {
"value": [
2,
2
]
}
},
"ticks": {
"stroke": {
"scale": "color",
"value": 0
}
},
"axis": {
"stroke": {
"scale": "color",
"value": 0
}
},
"title": {
"font": {
"value": "Open Sans"
},
"fontSize": {
"value": 14
},
"fontWeight": {
"value": "normal"
},
"fill": {
"scale": "color",
"value": 0
}
},
"labels": {
"font": {
"value": "Open Sans"
},
"fontSize": {
"value": 12
},
"fill": {
"scale": "color",
"value": 0
}
}
}
}
],
"marks": [
{
"type": "rect",
"properties": {
"enter": {
"x": {
"scale": "x-axis",
"field": "predicate0"
},
"width": {
"scale": "x-axis",
"band": true
},
"y": {
"scale": "y-axis",
"field": "data.y"
},
"y2": {
"scale": "y-axis",
"value": 0
},
"fill": {
"scale": "color",
"field": "data.series"
}
}
},
"from": {
"transform": [
{
"type": "filter",
"test": "d.data.series === 0"
}
],
"data": "table"
}
},
{
"type": "line",
"properties": {
"enter": {
"x": {
"scale": "x-axis",
"field": "data.x"
},
"y": {
"scale": "y-axis",
"field": "data.y"
},
"stroke": {
"scale": "color",
"field": "data.series"
},
"strokeWidth": {
"value": 2
}
}
},
"from": {
"transform": [
{
"type": "filter",
"test": "d.data.series === 1"
}
],
"data": "table"
}
},
{
"type": "symbol",
"properties": {
"update": {
"fill": {
"scale": "color",
"field": "data.series"
}
},
"enter": {
"strokeWidth": {
"value": 3
},
"fill": {
"scale": "color",
"field": "data.series"
},
"x": {
"scale": "x-axis",
"field": "data.x"
},
"y": {
"scale": "y-axis",
"field": "data.y"
}
}
},
"from": {
"transform": [
{
"type": "filter",
"test": "d.data.series === 1"
}
],
"data": "table"
}
}
]
}
Unfortunately, the line marks doesn't support the dx property. I tried using a group but wasn't able to get it to work.