Skip to content

Instantly share code, notes, and snippets.

@nyurik
Last active January 26, 2021 09:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nyurik/2729e86307fbc600d15c736c37392514 to your computer and use it in GitHub Desktop.
Save nyurik/2729e86307fbc600d15c736c37392514 to your computer and use it in GitHub Desktop.
{
"$schema": "https://vega.github.io/schema/vega/v3.0.json",
"data": [
{
"name": "data",
"values": {
"aggregations": {
"pairs": {
"buckets": [
{"key": "aa:cc", "doc_count": 10},
{"key": "aa:bb", "doc_count": 12},
{"key": "bb:aa", "doc_count": 8},
{"key": "bb:bb", "doc_count": 12},
{"key": "cc:aa", "doc_count": 9},
{"key": "cc:cc", "doc_count": 10}
]
}
}
},
"format": {"property": "aggregations.pairs.buckets"},
"transform": [
{"type": "formula", "expr": "slice(datum.key, 0, 2)", "as": "src"},
{"type": "formula", "expr": "slice(datum.key, 3, 5)", "as": "dst"}
]
},
{
"name": "nodes",
"source": "data",
"transform": [
{
"type": "filter",
"expr": "!groupSelector || groupSelector.src == datum.src || groupSelector.dst == datum.dst"
},
{"type": "fold", "fields": ["src", "dst"], "as": ["stack", "cc"]},
{
"type": "formula",
"expr": "if(datum.stack == 'src', datum.src+datum.dst, datum.dst+datum.src)",
"as": "sortField"
},
{
"type": "stack",
"groupby": ["stack"],
"sort": {"field": "sortField"},
"field": "doc_count"
},
{"type": "formula", "expr": "(datum.y0+datum.y1)/2", "as": "yc"}
]
},
{
"name": "groups",
"source": "nodes",
"transform": [
{
"type": "aggregate",
"groupby": ["stack", "cc"],
"fields": ["doc_count"],
"ops": ["sum"],
"as": ["total"]
},
{"type": "stack", "groupby": ["stack"], "sort": {"field": "cc"}, "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 == 'src'", "as": "rightLabel"},
{"type": "formula", "expr": "datum.total/domain('y')[1]", "as": "percentage"}
]
},
{
"name": "destinationNodes",
"source": "nodes",
"transform": [{"type": "filter", "expr": "datum.stack == 'dst'"}]
},
{
"name": "edges",
"source": "nodes",
"transform": [
{"type": "filter", "expr": "datum.stack == 'src'"},
{
"type": "lookup",
"from": "destinationNodes",
"key": "key",
"fields": ["key"],
"as": ["target"]
},
{
"type": "linkpath",
"orient": "horizontal",
"shape": {"signal": "'diagonal'"},
"sourceY": {"expr": "scale('y', datum.yc)"},
"sourceX": {"expr": "scale('x', 'src') + bandwidth('x')"},
"targetY": {"expr": "scale('y', datum.target.yc)"},
"targetX": {"expr": "scale('x', 'dst')"}
},
{
"type": "formula",
"expr": "range('y')[0]-scale('y', datum.doc_count)",
"as": "strokeWidth"
},
{"type": "formula", "expr": "datum.doc_count/domain('y')[1]", "as": "percentage"}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"range": "width",
"domain": ["src", "dst"],
"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": "data", "field": "src"}
}
],
"axes": [{"orient": "bottom", "scale": "x"}, {"orient": "left", "scale": "y"}],
"marks": [
{
"type": "path",
"name": "edgeMark",
"from": {"data": "edges"},
"encode": {
"update": {
"stroke": [
{
"test": "groupSelector && groupSelector.stack=='src'",
"scale": "color",
"field": "dst"
},
{"scale": "color", "field": "src"}
],
"strokeWidth": {"field": "strokeWidth"},
"path": {"field": "path"},
"strokeOpacity": {
"signal": "if(!groupSelector && (groupHover.src == datum.src || groupHover.dst == datum.dst), 0.6, 0.2)"
},
"tooltip": {
"signal": "datum.src + ' → ' + datum.dst + ' ' + format(datum.doc_count, ',.0f') + ' (' + format(datum.percentage, '.1%') + ')'"
}
},
"hover": {"strokeOpacity": {"value": 1}}
}
},
{
"type": "rect",
"name": "nodeMark",
"from": {"data": "groups"},
"encode": {
"enter": {"fill": {"scale": "color", "field": "cc"}, "width": {"scale": "x", "band": 1}},
"update": {
"x": {"scale": "x", "field": "stack"},
"y": {"field": "scaledY0"},
"y2": {"field": "scaledY1"},
"fillOpacity": {"signal": "if(groupSelector, 1, 0.6)"},
"tooltip": {
"signal": "datum.cc + ' ' + 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) + if(datum.rightLabel, bandwidth('x') + 5, -5)"
},
"yc": {"signal": "(datum.scaledY0 + datum.scaledY1)/2"},
"align": {"signal": "if(datum.rightLabel, 'left', 'right')"},
"baseline": {"value": "middle"},
"fontWeight": {"value": "bold"},
"text": {"signal": "if(abs(datum.scaledY0-datum.scaledY1) > 13, datum.cc, '')"}
}
}
},
{
"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": {
"opacity": {"value": 1},
"cornerRadius": {"value": 6},
"fill": {"value": "#f5f5f5"},
"stroke": {"value": "#c1c1c1"},
"strokeWidth": {"value": 2},
"height": {"signal": "item.mark.group.height"},
"width": {"signal": "item.mark.group.width"}
},
"hover": {"opacity": {"value": 0.7}}
},
"marks": [
{
"type": "text",
"interactive": false,
"encode": {
"enter": {
"xc": {"signal": "item.mark.group.width/2"},
"yc": {"signal": "item.mark.group.height/2 + 2"},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"fontWeight": {"value": "bold"},
"text": {"value": "Show All"}
}
}
}
]
}
]
}
],
"signals": [
{
"name": "groupHover",
"value": {},
"on": [
{
"events": "@nodeMark:mouseover",
"update": "{src:datum.stack=='src' && datum.cc, dst:datum.stack=='dst' && datum.cc}"
},
{"events": "mouseout", "update": "{}"}
]
},
{
"name": "groupSelector",
"value": false,
"on": [
{
"events": "@nodeMark:click!",
"update": "{stack:datum.stack, src:datum.stack=='src' && datum.cc, dst:datum.stack=='dst' && datum.cc}"
},
{"events": [{"type": "click", "markname": "groupReset"}], "update": "false"}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment