how to align rule on x axis with line chart data in vega-lite - vega-lite

I am getting this chart where rule is not correctly aligned on x axis.
group a has value 3.2 and it is not between 2 and 4 on x axis as supposed to. same for b group and c group.
I tried resolve, scale separately line chart and rule without success
Result should be that rule for group a, group b and group c lie on axis x aligned the value they have.
Here is my code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 606,
"height":384,
"data": {
"values": [
{
"datapoints": {
"division": [
{
"participation_duration": {
"total": {
"mean": 384,
"a": 190,
"b": 365,
"c": 495,
"distribution": {
"min": 0,
"max": 10,
"step": 2,
"data": [0,0.3,0.1,0.2,0.2, 0]
}
}
}
}
]
}
}
]
},
"transform": [
{ "calculate": "datum.datapoints.division", "as": "D" },
{ "flatten": ["D"] },
{"calculate": "datum.D.participation_duration.total.distribution.data", "as": "y"},
{"flatten": ["y"]},
{
"window": [{ "op": "count", "field": "y", "as": "i" }],
"frame": [null, 0]
},
{ "calculate": "(datum.i-1)*2", "as": "x" }
],
"layer": [
{
"mark": {"type":"line",
"point": false,
"interpolate": "cardinal",
"color":"blueviolet"
},
"encoding": {
"x": {
"field": "x",
"type": "quantitative",
"title": "",
"axis":{
"tickCount": 5,
"grid": true
}
},
"y": {
"scale":{"domain":[0,0.3]},
"field": "y",
"type": "quantitative",
"title": "",
"axis": {
"orient": "right",
"tickCount": 3,
"format": "%"
}
}
}
},
{
"transform": [
{"calculate": "datum.D.participation_duration.total", "as": "total"},
{"calculate": "datum.total.a/60", "as": "a group"},
{"calculate": "datum.total.b/60", "as": "b group"},
{"calculate": "datum.total.c/60", "as": "c group"},
{"fold": ["a group", "b group", "c group"]}
],
"encoding": {
"x":{
"field": "value",
"title":null,
"axis":{
"format":".2",
"grid": false,
"domain": false,
"labels":true,
"ticks": false,
"labelAlign":"center",
"labelAngle":0,
"labelPadding": 15
}
},
"color":{
"field": "key",
"legend":null
},
"text": {"field":"key"}
},
"layer": [
{
"mark":{"type":"rule",
"strokeWidth": 5,
"strokeDash":[3,16]
}},
{
"mark":{"type": "text", "align": "center", "dy":-220}
}
]
}
]
}````
Please advise which part is missing.
Thank you

You mean like this?
You need to explicitly set the type.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 606,
"height": 384,
"data": {
"values": [
{
"datapoints": {
"division": [
{
"participation_duration": {
"total": {
"mean": 384,
"a": 190,
"b": 365,
"c": 495,
"distribution": {
"min": 0,
"max": 10,
"step": 2,
"data": [0, 0.3, 0.1, 0.2, 0.2, 0]
}
}
}
}
]
}
}
]
},
"transform": [
{"calculate": "datum.datapoints.division", "as": "D"},
{"flatten": ["D"]},
{
"calculate": "datum.D.participation_duration.total.distribution.data",
"as": "y"
},
{"flatten": ["y"]},
{"window": [{"op": "count", "field": "y", "as": "i"}], "frame": [null, 0]},
{"calculate": "(datum.i-1)*2", "as": "x"}
],
"layer": [
{
"mark": {
"type": "line",
"point": false,
"interpolate": "cardinal",
"color": "blueviolet"
},
"encoding": {
"x": {
"field": "x",
"type": "quantitative",
"title": "",
"axis": {"tickCount": 5, "grid": true}
},
"y": {
"scale": {"domain": [0, 0.3]},
"field": "y",
"type": "quantitative",
"title": "",
"axis": {"orient": "right", "tickCount": 3, "format": "%"}
}
}
},
{
"transform": [
{"calculate": "datum.D.participation_duration.total", "as": "total"},
{"calculate": "datum.total.a/60", "as": "a group"},
{"calculate": "datum.total.b/60", "as": "b group"},
{"calculate": "datum.total.c/60", "as": "c group"},
{"fold": ["a group", "b group", "c group"]}
],
"encoding": {
"x": {
"field": "value",
"title": null,
"type": "quantitative",
"axis": {
"format": ".2",
"grid": false,
"domain": false,
"labels": true,
"ticks": false,
"labelAlign": "center",
"labelAngle": 0,
"labelPadding": 15
}
},
"color": {"field": "key", "legend": null},
"text": {"field": "key"}
},
"layer": [
{"mark": {"type": "rule", "strokeWidth": 5, "strokeDash": [3, 16]}},
{"mark": {"type": "text", "align": "center", "dy": -220}}
]
}
]
}

Related

my picked_store on Vega-lite is not functioning. I'm wanting to select filter datapoints by year

This element of my Vega-lite does not pick up on the desired data. Im wanting the selector to filter data, depending upon the net-zero year
Are my options in the wrong format? Is having a mix of integers and "No Target Selected" invalidating my picked_store?
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "Equal earth map depicting CO2 emissions per capita. Some countries did not produce any estimates.",
"title": {
"text": "Greenhouse Gas Emissions Against CCS Readiness",
"subtitle": "CO₂ emissions (metric tonne per capita). Source: Our World in Data",
"subtitleFontStyle": "italic",
"subtitleFontSize": 10,
"anchor": "start",
"color": "rgba(58, 59, 60)"
},
"height": 500,
"width": 545,
"background": null,
"data": {
"url": "https://raw.githubusercontent.com/jameseconnolly/jameseconnolly.github.io/main/Carbon_Capture_Requirement.csv",
"format": {"type": "csv"}
},
"layer": [
{
"selection": {
"picked": {
"empty": "none",
"bind": {
"Net-zero Target": {
"input": "select",
"options": [
"No Target Selected",
0,
2000,
2030,
2035,
2040,
2045,
2050,
2053,
2060,
2065,
2070
],
"name": "Net-zero Target:"
}
},
"type": "single",
"fields": ["Net-zero Target"]
},
"grid": {
"type": "interval",
"bind": "scales",
"on": "[mousedown, window:mouseup] > window:mousemove!",
"translate": "[mousedown, window:mouseup] > window:mousemove!",
"zoom": "wheel!",
"resolve": "global"
}
},
"mark": {"type": "point", "filled": true},
"encoding": {
"color": {
"value": "grey",
"condition": {
"field": "Cluster",
"selection": "picked",
"type": "nominal",
"legend": null
}
},
"size": {
"value": 60,
"condition": {"value": 120, "selection": "picked"}
},
"opacity": {
"value": 0.4,
"condition": {"value": 1, "selection": "picked"}
},
"x": {
"field": "Carbon Capture Requirement",
"scale": {"zero": false},
"type": "quantitative",
"title": null,
"axis": {
"grid": false,
"title": "Carbon Capture and Storage Readiness"
}
},
"y": {
"field": "log_GHG",
"scale": {"zero": false},
"type": "quantitative",
"axis": {
"grid": false,
"title": "Log Greenhouse Gas Emissions (MT CO2e)"
}
}
}
},
{
"data": {"values": [{"y": "17", "x": "0"}, {"y": "23", "x": "90"}]},
"mark": {"type": "line", "strokeDash": [9, 1], "color": "#ff0101"},
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative"}
}
},
{
"mark": {"type": "text", "x": 540, "align": "right", "y": 20, "size": 25},
"transform": [{"calculate": "0.1", "as": "R2"}],
"encoding": {"text": {"type": "nominal", "field": "R2"}}
}
]
}
Is the following what you want?
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "Equal earth map depicting CO2 emissions per capita. Some countries did not produce any estimates.",
"title": {
"text": "Greenhouse Gas Emissions Against CCS Readiness",
"subtitle": "CO₂ emissions (metric tonne per capita). Source: Our World in Data",
"subtitleFontStyle": "italic",
"subtitleFontSize": 10,
"anchor": "start",
"color": "rgba(58, 59, 60)"
},
"height": 500,
"width": 545,
"data": {
"url": "https://raw.githubusercontent.com/jameseconnolly/jameseconnolly.github.io/main/Carbon_Capture_Requirement.csv",
"format": {"type": "csv"}
},
"layer": [
{
"params": [
{
"name": "year",
"select": {"type": "point", "fields": ["Net-zero Target"]},
"bind": {
"input": "select",
"options": [
"",
"2000.0",
"2030.0",
"2050.0"
]
}
}
],
"mark": {"type": "point", "filled": true},
"encoding": {
"color": {
"condition": {
"param": "year",
"field": "Net-zero Target",
"type": "nominal"
},
"value": "grey"
},
"size": {"value": 60},
"opacity": {"value": 0.4},
"x": {
"field": "Carbon Capture Requirement",
"scale": {"zero": false},
"type": "quantitative",
"title": null,
"axis": {
"grid": false,
"title": "Carbon Capture and Storage Readiness"
}
},
"y": {
"field": "log_GHG",
"scale": {"zero": false},
"type": "quantitative",
"axis": {
"grid": false,
"title": "Log Greenhouse Gas Emissions (MT CO2e)"
}
}
}
},
{
"data": {"values": [{"y": "17", "x": "0"}, {"y": "23", "x": "90"}]},
"mark": {"type": "line", "strokeDash": [9, 1], "color": "#ff0101"},
"encoding": {
"x": {"field": "x", "type": "quantitative"},
"y": {"field": "y", "type": "quantitative"}
}
},
{
"mark": {"type": "text", "x": 540, "align": "right", "y": 20, "size": 25},
"transform": [{"calculate": "0.1", "as": "R2"}],
"encoding": {"text": {"type": "nominal", "field": "R2"}}
}
]
}

How to add text on bar chart in vega lite

I am trying to add text label to bar chart, but it not showing it. Here is a example i want to achieve
Here is code
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "background": "#EFF1EF", "width": 500, "height": 26, "autosize":"pad", "data": { "values": [ { "standarts": { "divisions": [ { "a": { "mean": 135, "part1": 10, "part2": 60, "part5": 130,
"part7": 198, "part9": 255, "goal": { "value": 150 } } } ] } } ] }, "transform": [ {"calculate": "datum.standarts.divisions", "as": "D"}, {"flatten": ["D"]}, {"calculate": "datum.D.a", "as": "x"} ], "encoding": { "x": {"field": "x", "type": "quantitative","scale":{"domain":[0,300]},
"stack": null}, "opacity": {"value": 1} }, "layer": [ { "mark":{"type":"bar", "color" : "#b2b7b4", "cornerRadius": 40}, "encoding": {"x": {}} }, { "mark": {"type": "bar", "color": "#0ef9e5", "height": 25}, "encoding": {"x": {"field": "x.mean"}} }, { "mark":{"type":
"text", "align":"center"}, "encoding": {"text": {"field": "x.mean"}} }, { "mark":{"type": "rule"}, "encoding": {"x": {"field":"x.goal.value", "title":["Target"],"axis":{ "titleFont": "Google Sans", "titleFontSize": 16, "titleFontWeight":700, "titleY":
8} }}} ], "config": { "axis": {"ticks": false, "labels": false, "domain": false}, "rule": { "strokeWidth": 4, "strokeDash": [ 0.2, 8 ], "strokeCap": "round", "align":"center" } } }
this is code
And link to editor
vega-lite editor
text part is still not working.
I used documentation on vega-lite website and example codes, but still no success.
Thanks for the help.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"background": "#EFF1EF",
"width": 500,
"height": 26,
"autosize": "pad",
"data": {
"values": [
{
"standarts": {
"divisions": [
{
"a": {
"mean": 135,
"part1": 10,
"part2": 60,
"part5": 130,
"part7": 198,
"part9": 255,
"goal": {"value": 150}
}
}
]
}
}
]
},
"transform": [
{"calculate": "datum.standarts.divisions", "as": "D"},
{"flatten": ["D"]},
{"calculate": "datum.D.a", "as": "x"}
],
"encoding": {
"x": {
"field": "x",
"type": "quantitative",
"scale": {"domain": [0, 300]},
"stack": null
},
"opacity": {"value": 1}
},
"layer": [
{
"mark": {"type": "bar", "color": "#b2b7b4", "cornerRadius": 40},
"encoding": {"x": {}}
},
{
"mark": {"type": "bar", "color": "#0ef9e5", "height": 25},
"encoding": {"x": {"field": "x.mean"}}
},
{
"mark": {"type": "text", "align": "right", "dx": -10},
"encoding": {"text": {"field": "x.mean"}, "x": {"field": "x.mean"}}
},
{
"mark": {"type": "text", "align": "center", "dy": -30},
"encoding": {
"text": {"field": "x.goal.value"},
"x": {"field": "x.goal.value"}
}
},
{
"mark": {"type": "rule"},
"encoding": {
"x": {
"field": "x.goal.value",
"title": ["Target"],
"axis": {
"titleFont": "Google Sans",
"titleFontSize": 16,
"titleFontWeight": 700,
"titleY": 8
}
}
}
}
],
"config": {
"axis": {"ticks": false, "labels": false, "domain": false},
"rule": {
"strokeWidth": 4,
"strokeDash": [0.2, 8],
"strokeCap": "round",
"align": "center"
}
}
}

vega lite - persist null date/time in chart

How do I persist the null in the data on visualization with vega chart while rendering the date/time for data the timestamp. Right now, it looks like null data is getting passed as default time of 04:00
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{
"x": null,
"y": "recoPU8F3Asuc8t3n"
},
{
"x": "2017-06-02T07:00:00.000Z",
"y": "reco056sZzsAd7qVp"
},
{
"x": null,
"y": "reclQZbw7CiAegm1f"
},
{
"x": "2017-07-14T07:00:00.000Z",
"y": "recAzUhUdekIdkSVt"
},
{
"x": null,
"y": "rec0NHCpaRDP9W1pd"
},
{
"x": null,
"y": "recPYz3QNpXgrmBVy"
}
]
},
"config": {
"range": {
"category": [
"#46bfdd"
]
},
"legend": {
"disable": false,
"labelColor": "#333",
"labelFontSize": 11,
"symbolSize": 30,
"rowPadding": 4,
"symbolType": "circle",
"symbolStrokeWidth": 0,
"titleColor": "#666666",
"titleFontSize": 11,
"titlePadding": 10,
"titleFontWeight": 500,
"orient": "right"
},
"axisY": {
"tickMinStep": 1,
"format": "~s",
"formatType": "number"
},
"axis": {
"domainColor": "#E8E8E8",
"gridColor": "#E8E8E8",
"tickColor": "#E8E8E8",
"grid": true,
"gridWidth": 1,
"labelColor": "#666666",
"labelFontSize": 11,
"labelLimit": 180,
"titleColor": "#999999",
"tickSize": 16,
"titleFontSize": 13,
"titlePadding": 10,
"titleFontWeight": 400,
"labelPadding": 4,
"titleLimit": 180
},
"autosize": {
"type": "fit",
"contains": "padding"
},
"axisLeft": {
"labelFontSize": 11,
"labelColor": "#999999",
"labelLimit": 180,
"titleFontSize": 13,
"titleFontWeight": 400,
"titleLimit": 180
},
"style": {
"label": {
"align": "left",
"baseline": "middle",
"dx": 4
},
"cell": {
"stroke": "transparent"
}
}
},
"mark": {
"type": "bar",
"width": {
"band": 0.7
},
"tooltip": true,
"cornerRadiusEnd": 3,
"cursor": "pointer",
"color": "#4787cd"
},
"params": [
{
"name": "highlight",
"select": {
"type": "point",
"on": "mouseover"
}
},
{
"name": "select",
"select": "point"
}
],
"encoding": {
"x": {
"field": "x",
"type": "nominal",
"axis": {
"labelAngle": -90,
"format": "%I:%M",
"formatType": "time",
"title": "Reservation On"
},
"sort": {
"encoding": "x",
"order": "ascending"
},
"timeUnit": "hoursminutes"
},
"y": {
"field": "y",
"type": "quantitative",
"aggregate": "count",
"axis": {
"title": "Number of records"
}
},
"tooltip": [
{
"field": "x",
"title": "Reservation On",
"format": "%I:%M",
"formatType": "time",
"timeUnit": "hoursminutes"
},
{
"field": "y",
"type": "quantitative",
"aggregate": "count",
"title": "Number of records"
}
],
"fillOpacity": {
"condition": [
{
"param": "select",
"value": 1
}
],
"value": 0.3
},
"strokeWidth": {
"condition": [
{
"param": "select",
"empty": false,
"value": 2
},
{
"param": "highlight",
"empty": false,
"value": 1
}
],
"value": 0
}
},
"transform": [
],
"height": 372,
"width": 536
}
One way to do this is by replacing your "format" with an appropriate "labelExpr":
"axis": {
"labelAngle": -90,
"labelExpr": "isValid(datum.value) ? timeFormat(datum.value, '%I:%M') : 'null'",
"title": "Reservation On"
}

How to change Shape and Color of points in Vega Scatter Plot?

I have a scatter plot generated with contours code in Vega.
Plot looks like
Based on 3rd field, differentiated the points with colour as Blue and Green Dots, but couldn't see the difference very clearly.
Is it possible to Change the Shape and Colour (atleast one) of the points to make the difference more visible
Code
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"title": {
"text": "Outlier Distribution between Duration Vs Age",
"anchor": "middle",
"fontSize": 16,
"frame": "group",
"offset": 4
},
"signals": [
{
"name": "bandwidth", "value": 0.5,
"bind": {"input": "range", "min": -1, "max": 1, "step": 0.1}
}
],
"data": [
{
"name": "source",
"url" : {
"index": "tenant_id.model_training_artefact",
"body": {
"size":10000,
"_source": ["duration", "credit_amount", "asnm", "age", "outlier"]
}
}
"format": {"property": "hits.hits"},
},
{
"name": "density",
"source": "source",
"transform": [
{
"type": "kde2d",
"groupby": ["_source.outlier"],
"size": [{"signal": "width"}, {"signal": "height"}],
"x": {"expr": "scale('x', datum.duration)"},
"y": {"expr": "scale('y', datum.age)"},
"bandwidth": {"signal": "[bandwidth, bandwidth]"}
}
]
},
{
"name": "contours",
"source": "density",
"transform": [
{
"type": "isocontour",
"field": "grid",
"levels": 4
}
]
}
],
"scales": [
{
"name": "x",
"type": "linear",
"round": true,
"nice": true,
"zero": true,
"domain": {"data": "source", "field": "_source.duration"},
"range": "width"
},
{
"name": "y",
"type": "linear",
"round": true,
"nice": true,
"zero": true,
"domain": {"data": "source", "field": "_source.age"},
"range": "height"
},
{
"name": "color",
"type": "ordinal",
"domain": {
"data": "source", "field": "_source.outlier",
"sort": {"order": "descending"}
},
"range": "category"
}
],
"axes": [
{
"scale": "x",
"grid": true,
"domain": false,
"orient": "bottom",
"tickCount": 5,
"title": "Duration"
},
{
"scale": "y",
"grid": true,
"domain": false,
"orient": "left",
"titlePadding": 5,
"title": "Age"
}
],
"legends": [
{"stroke": "color", "symbolType": "stroke"}
],
"marks": [
{
"name": "marks",
"type": "symbol",
"from": {"data": "source"},
"encode": {
"update": {
"x": {"scale": "x", "field": "_source.duration"},
"y": {"scale": "y", "field": "_source.age"},
"size": {"value": 50},
"fill": {"scale": "color" , "field": "_source.outlier"}
}
}
},
{
"type": "image",
"from": {"data": "density"},
"encode": {
"update": {
"x": {"value": 0},
"y": {"value": 0},
"width": {"signal": "width"},
"height": {"signal": "height"},
"aspect": {"value": false}
}
},
"transform": [
{
"type": "heatmap",
"field": "datum.grid",
"color": {"expr": "scale('color', datum.datum.outlier)"}
}
]
},
{
"type": "path",
"clip": true,
"from": {"data": "contours"},
"encode": {
"enter": {
"strokeWidth": {"value": 1},
"strokeOpacity": {"value": 1},
"stroke": {"scale": "color", "field": "outlier"}
}
},
"transform": [
{ "type": "geopath", "field": "datum.contour" }
]
}
]
}
Try defining scales for mark symbol color, shape and size.
For example, assuming your field outlier has 3 possible values:
"scales": [
...
{
"name": "scale_symbol_color",
"type": "ordinal",
"domain": {
"data": "source", "field": "_source.outlier",
"sort": {"order": "descending"}
},
"range": ["red", "orange", "blue"]
},
{
"name": "scale_symbol_shape",
"type": "ordinal",
"domain": {
"data": "source", "field": "_source.outlier",
"sort": {"order": "descending"}
},
"range": ["triangle", "square", "circle"]
},
{
"name": "scale_symbol_size",
"type": "ordinal",
"domain": {
"data": "source", "field": "_source.outlier",
"sort": {"order": "descending"}
},
"range": [400, 300, 200]
}
],
...
"marks": [
{
"name": "marks",
"type": "symbol",
"from": {"data": "source"},
"encode": {
"update": {
"x": {"scale": "x", "field": "_source.duration"},
"y": {"scale": "y", "field": "_source.age"},
"size": {"value": 50},
"fill": {"scale": "scale_symbol_color" , "field": "_source.outlier"},
"shape": {"scale": "scale_symbol_shape" , "field": "_source.outlier"},
"size": {"scale": "scale_symbol_size" , "field": "_source.outlier"},
}
}
},
...
Vega docs:
https://vega.github.io/vega/docs/scales/#ordinal
https://vega.github.io/vega/docs/marks/symbol/

Sankey Diagram (Alluvial Diagram) in Vega-lite

Anyone having an idea on how to create Sankey diagrams like those in Vega-lite?
https://observablehq.com/#d3/sankey-diagram
Input would be data like
From | To | Amount
Using the blog post from Yuri Astrakhan, I created the following in Vega.
{
"$schema": "https://vega.github.io/schema/vega/v5.2.json",
"height": 300,
"width": 600,
"data": [
{
"name": "rawData",
"values": [
{"key": {"stk1": "aa", "stk2": "cc"}, "doc_count": 7},
{"key": {"stk1": "aa", "stk2": "bb"}, "doc_count": 4},
{"key": {"stk1": "bb", "stk2": "aa"}, "doc_count": 8},
{"key": {"stk1": "bb", "stk2": "bb"}, "doc_count": 6},
{"key": {"stk1": "bb", "stk2": "cc"}, "doc_count": 3},
{"key": {"stk1": "cc", "stk2": "aa"}, "doc_count": 9}
],
"transform": [
{"type": "formula", "expr": "datum.key.stk1", "as": "stk1"},
{"type": "formula", "expr": "datum.key.stk2", "as": "stk2"},
{"type": "formula", "expr": "datum.doc_count", "as": "size"}
]
},
{
"name": "nodes",
"source": "rawData",
"transform": [
{
"type": "filter",
"expr": "!groupSelector || groupSelector.stk1 == datum.stk1 || groupSelector.stk2 == datum.stk2"
},
{"type": "formula", "expr": "datum.stk1+datum.stk2", "as": "key"},
{"type": "fold", "fields": ["stk1", "stk2"], "as": ["stack", "grpId"]},
{
"type": "formula",
"expr": "datum.stack == 'stk1' ? datum.stk1+' '+datum.stk2 : datum.stk2+' '+datum.stk1",
"as": "sortField"
},
{
"type": "stack",
"groupby": ["stack"],
"sort": {"field": "sortField", "order": "descending"},
"field": "size"
},
{"type": "formula", "expr": "(datum.y0+datum.y1)/2", "as": "yc"}
]
},
{
"name": "groups",
"source": "nodes",
"transform": [
{
"type": "aggregate",
"groupby": ["stack", "grpId"],
"fields": ["size"],
"ops": ["sum"],
"as": ["total"]
},
{
"type": "stack",
"groupby": ["stack"],
"sort": {"field": "grpId", "order": "descending"},
"field": "total"
},
{"type": "formula", "expr": "scale('y', datum.y0)", "as": "scaledY0"},
{"type": "formula", "expr": "scale('y', datum.y1)", "as": "scaledY1"},
{
"type": "formula",
"expr": "datum.stack == 'stk1'",
"as": "rightLabel"
},
{
"type": "formula",
"expr": "datum.total/domain('y')[1]",
"as": "percentage"
}
]
},
{
"name": "destinationNodes",
"source": "nodes",
"transform": [{"type": "filter", "expr": "datum.stack == 'stk2'"}]
},
{
"name": "edges",
"source": "nodes",
"transform": [
{"type": "filter", "expr": "datum.stack == 'stk1'"},
{
"type": "lookup",
"from": "destinationNodes",
"key": "key",
"fields": ["key"],
"as": ["target"]
},
{
"type": "linkpath",
"orient": "horizontal",
"shape": "diagonal",
"sourceY": {"expr": "scale('y', datum.yc)"},
"sourceX": {"expr": "scale('x', 'stk1') + bandwidth('x')"},
"targetY": {"expr": "scale('y', datum.target.yc)"},
"targetX": {"expr": "scale('x', 'stk2')"}
},
{
"type": "formula",
"expr": "range('y')[0]-scale('y', datum.size)",
"as": "strokeWidth"
},
{
"type": "formula",
"expr": "datum.size/domain('y')[1]",
"as": "percentage"
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"range": "width",
"domain": ["stk1", "stk2"],
"paddingOuter": 0.05,
"paddingInner": 0.95
},
{
"name": "y",
"type": "linear",
"range": "height",
"domain": {"data": "nodes", "field": "y1"}
},
{
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "rawData", "field": "stk1"}
},
{
"name": "stackNames",
"type": "ordinal",
"range": ["Source", "Destination"],
"domain": ["stk1", "stk2"]
}
],
"axes": [
{
"orient": "bottom",
"scale": "x",
"encode": {
"labels": {
"update": {"text": {"scale": "stackNames", "field": "value"}}
}
}
},
{"orient": "left", "scale": "y"}
],
"marks": [
{
"type": "path",
"name": "edgeMark",
"from": {"data": "edges"},
"clip": true,
"encode": {
"update": {
"stroke": [
{
"test": "groupSelector && groupSelector.stack=='stk1'",
"scale": "color",
"field": "stk2"
},
{"scale": "color", "field": "stk1"}
],
"strokeWidth": {"field": "strokeWidth"},
"path": {"field": "path"},
"strokeOpacity": {
"signal": "!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 0.9 : 0.3"
},
"zindex": {
"signal": "!groupSelector && (groupHover.stk1 == datum.stk1 || groupHover.stk2 == datum.stk2) ? 1 : 0"
},
"tooltip": {
"signal": "datum.stk1 + ' → ' + datum.stk2 + ' ' + format(datum.size, ',.0f') + ' (' + format(datum.percentage, '.1%') + ')'"
}
},
"hover": {"strokeOpacity": {"value": 1}}
}
},
{
"type": "rect",
"name": "groupMark",
"from": {"data": "groups"},
"encode": {
"enter": {
"fill": {"scale": "color", "field": "grpId"},
"width": {"scale": "x", "band": 1}
},
"update": {
"x": {"scale": "x", "field": "stack"},
"y": {"field": "scaledY0"},
"y2": {"field": "scaledY1"},
"fillOpacity": {"value": 0.6},
"tooltip": {
"signal": "datum.grpId + ' ' + format(datum.total, ',.0f') + ' (' + format(datum.percentage, '.1%') + ')'"
}
},
"hover": {"fillOpacity": {"value": 1}}
}
},
{
"type": "text",
"from": {"data": "groups"},
"interactive": false,
"encode": {
"update": {
"x": {
"signal": "scale('x', datum.stack) + (datum.rightLabel ? bandwidth('x') + 8 : -8)"
},
"yc": {"signal": "(datum.scaledY0 + datum.scaledY1)/2"},
"align": {"signal": "datum.rightLabel ? 'left' : 'right'"},
"baseline": {"value": "middle"},
"fontWeight": {"value": "bold"},
"text": {
"signal": "abs(datum.scaledY0-datum.scaledY1) > 13 ? datum.grpId : ''"
}
}
}
},
{
"type": "group",
"data": [
{
"name": "dataForShowAll",
"values": [{}],
"transform": [{"type": "filter", "expr": "groupSelector"}]
}
],
"encode": {
"enter": {
"xc": {"signal": "width/2"},
"y": {"value": 30},
"width": {"value": 80},
"height": {"value": 30}
}
},
"marks": [
{
"type": "group",
"name": "groupReset",
"from": {"data": "dataForShowAll"},
"encode": {
"enter": {
"cornerRadius": {"value": 6},
"fill": {"value": "#f5f5f5"},
"stroke": {"value": "#c1c1c1"},
"strokeWidth": {"value": 2},
"height": {"field": {"group": "height"}},
"width": {"field": {"group": "width"}}
},
"update": {"opacity": {"value": 1}},
"hover": {"opacity": {"value": 0.7}}
},
"marks": [
{
"type": "text",
"interactive": false,
"encode": {
"enter": {
"xc": {"field": {"group": "width"}, "mult": 0.5},
"yc": {
"field": {"group": "height"},
"mult": 0.5,
"offset": 2
},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"fontWeight": {"value": "bold"},
"text": {"value": "Show All"}
}
}
}
]
}
]
},
{
"type": "rect",
"from": {"data": "nodes"},
"encode": {
"enter": {
"stroke": {"value": "#000"},
"strokeWidth": {"value": 2},
"width": {"scale": "x", "band": 1},
"x": {"scale": "x", "field": "stack"},
"y": {"field": "y0", "scale": "y"},
"y2": {"field": "y1", "scale": "y"}
}
}
}
],
"signals": [
{
"name": "groupHover",
"value": {},
"on": [
{
"events": "#groupMark:mouseover",
"update": "{stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}"
},
{"events": "mouseout", "update": "{}"}
]
},
{
"name": "groupSelector",
"value": false,
"on": [
{
"events": "#groupMark:click!",
"update": "{stack:datum.stack, stk1:datum.stack=='stk1' && datum.grpId, stk2:datum.stack=='stk2' && datum.grpId}"
},
{
"events": [
{"type": "click", "markname": "groupReset"},
{"type": "dblclick"}
],
"update": "false"
}
]
}
]
}
It's a little bit dated, but this blog post shows how to do this kind of 'Sankey' diagram within Kibana using the 'Vega' visualisations.
https://www.elastic.co/blog/sankey-visualization-with-vega-in-kibana
I've played with it a bit a few years ago; it's possible certainly, and rewarding, but that complexity does come at a cost.