Closed DW19904 closed 3 months ago
But i need the visual now to have links between nodes which are at the same level, these would be determined by a column in my dataset.
You'll need to add either "rule" or "path" mark. If they are just straight lines, then I think "rule" mark is the simplest option.
https://vega.github.io/vega/docs/marks/rule/
The mark will be based on a new table, let's say "data-same-level-links" table.
"from": {"data": "data-same-level-links"} mark property means there will be a "rule" (line) created for each row in "data-same-level-links" table.
To prepare "data-same-level-links" table, transform your data to make a table that contains x, y, x2, y2 coordinates for each red link.
You likely have a "tree" data table that is similar to this:
And you probably have a list of same level nodes to connect. Use https://vega.github.io/vega/docs/transforms/lookup/ transform to get x, y, x2, y2 coordinates from the "tree" table.
Yes thank you, i am getting there now.
I have the supporting table for the same level links, and i have an x and y coordinate from my original table (below), but i am struggling how to get the x2 and y2 coordinates in? As i need these to create the rule?
your help is much appreciated, thank you.
A link connects 2 nodes: source and target. x2 and y2 are x and y coordinates of the second (target) node.
For example: "Uncle" node has x and y coordinates "Auntie" node has x and y coordinates
Uncle-Auntie link connects both nodes by drawing a line from x, y point to x2, y2 point. x = Uncle x, y = Uncle y, x2 = Auntie x, y2 = Auntie y
If you have a list of links to create: Source Target "Uncle" "Auntie"
And a list of coordinates: Node x y "Uncle" 1 1 "Auntie" 2 3
Then you can merge both lists using lookup transform to get a list with x, y, x2, y2 coordinates for each link: Source Target x y x2 y2 "Uncle" "Auntie" 1 1 2 3
In your case different nodes have the same names (multiple "Uncle" nodes etc.), so you need to use some Ids instead of the names.
The tables are not hard-coded, in the vega, They are in the field well in PBI.
I am struggling to get the lookup transform working and this could be why i think?
I have the Source, Target, x and y as part of the dataset, but still cant figure out how to have that different dataset that includes the y2 and x2 for each rule that i require.
{ "width": 1100, "height": 600, "padding": 5, "signals": [ { "name": "labels", "value": true, "bind": {"input": "checkbox"} }, { "name": "layout", "value": "tidy", "bind": { "input": "radio", "options": ["tidy", "cluster"] } }, { "name": "links", "value": "diagonal", "bind": { "input": "select", "options": [ "line", "curve", "diagonal", "orthogonal" ] } }, { "name": "separation", "value": false, "bind": {"input": "checkbox"} } ], "data": [ { "name": "dataset", "transform": [ { "type": "stratify", "key": "id", "parentKey": "parent" }, { "type": "tree", "method": { "signal": "layout" }, "size": [ {"signal": "height"}, {"signal": "width - 100"} ], "separation": { "signal": "separation" }, "as": [ "y", "x", "depth", "children" ] } ] }, { "name": "links", "source": "dataset", "transform": [ {"type": "treelinks"}, { "type": "linkpath", "orient": "horizontal", "shape": {"signal": "links"} } ] } ], "scales": [ { "name": "color", "type": "linear", "range": { "scheme": "redyellowblue" }, "domain": { "data": "dataset", "field": "generation" }, "zero": true } ], "marks": [ { "type": "path", "from": {"data": "links"}, "encode": { "update": { "path": {"field": "path"}, "stroke": {"value": "#ccc"}, "strokeDash": { "signal": "datum.target.relationship === 'X' ? [5,5] : null" } } } }, { "type": "symbol", "from": {"data": "dataset"}, "encode": { "enter": { "size": {"value": 1000}, "stroke": {"value": "#fff"} }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "fill": { "scale": "color", "field": "generation" }, "shape": { "signal": "datum.gender === 'Male' ? 'square' : 'circle'" } } } }, { "type": "text", "from": {"data": "dataset"}, "encode": { "enter": { "text": {"field": "name"}, "fontSize": {"value": 12}, "baseline": { "value": "middle" } }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "dx": { "signal": "datum.children ? -20 : 20" }, "align": { "signal": "datum.children ? 'right' : 'left'" }, "opacity": { "signal": "labels ? 1 : 0" } } } } ] }
The tables are not hard-coded, in the vega, They are in the field well in PBI.
Once your Power BI data was loaded into the "dataset" table in Vega, you can create as many additional data tables (based on the "dataset" as you want by applying Vega transformations. This is how "links" data table is created in your Vega specification. It applies "type": "treelinks" and "type": "linkpath" transforms to the original "dataset" ("source": "dataset",).
I don't have you data so it's not clear for me how do you know between which same level nodes have to be linked together. You need to make sure you have a list of same level node pairs that you want to be linked together.
You either can create this list in Power BI and append to your dataset.
Sadly, current version of Deneb support only one "dataset", so in some case it's not easy to send data from Power BI into Deneb https://www.powerofbi.org/2024/01/16/1658/. Just an additional note regarding the "dataset", probably, but not necessary relevant to this specific issue.
Then you'll need just a lookup to add x, y, x2, y2 coordinates to the list of node pairs.
Or you probably can hardcode (?) some rule in Vega specification. Like if there are "Uncle" and "Auntie" nodes with the same parent, then they must be linked together. But this approach likely requires more tricky Vega data transforms.
If you can export data from Deneb into a .csv file and attach it, I'll probably have a chance to help with the data transformations.
Thank you so much, this is really helping with my learning of Vega and seeing how these transformations are done.
I have attached csv from deneb of the data.
Essentially the targetid column where the links need to be made, from id to targetid, thanks again.
{
"name": "data-same-level-links",
"source": "dataset",
"transform": [
{"type": "filter", "expr": "datum.targetid != null"},
{
"type": "lookup",
"from": "dataset",
"key": "targetid",
"fields": ["id"],
"values": ["x", "y"],
"as": ["x2", "y2"]
}
]
}
But this creates duplicate links (e.g. from id=2 to id=13 and from id=13 to id=2). No a big issue, it will just draw a line twice, but I suggest you to find a way to keep only one targetid for each pair. Probably you can do that in Power BI.
fantastic thank you, I have the relevant y2 and x2 now but the rule between the nodes still doesnt seem to show when i have added the rule mark in the below code, i have double checked but there must be something i am misssing.
{ "width": 1100, "height": 600, "padding": 5, "signals": [ { "name": "labels", "value": true, "bind": {"input": "checkbox"} }, { "name": "layout", "value": "tidy", "bind": { "input": "radio", "options": ["tidy", "cluster"] } }, { "name": "links", "value": "diagonal", "bind": { "input": "select", "options": [ "line", "curve", "diagonal", "orthogonal" ] } }, { "name": "separation", "value": false, "bind": {"input": "checkbox"} } ], "data": [ { "name": "dataset", "transform": [ { "type": "stratify", "key": "id", "parentKey": "parent" }, { "type": "tree", "method": { "signal": "layout" }, "size": [ {"signal": "height"}, {"signal": "width - 100"} ], "separation": { "signal": "separation" }, "as": [ "y", "x", "depth", "children" ] } ] }, { "name": "links", "source": "dataset", "transform": [ {"type": "treelinks"}, { "type": "linkpath", "orient": "horizontal", "shape": {"signal": "links"} } ] }, { "name": "data-same-level-links", "source": "dataset", "transform": [ { "type": "filter", "expr": "datum.targetid != null" }, { "type": "lookup", "from": "dataset", "key": "targetid", "fields": ["id"], "values": ["x", "y"], "as": ["x2", "y2"] } ] } ], "scales": [ { "name": "color", "type": "linear", "range": { "scheme": "redyellowblue" }, "domain": { "data": "dataset", "field": "generation" }, "zero": true } ], "marks": [ { "type": "path", "from": {"data": "links"}, "encode": { "update": { "path": {"field": "path"}, "stroke": {"value": "#ccc"}, "strokeDash": { "signal": "datum.target.relationship === 'X' ? [5,5] : null" } } } }, { "type": "symbol", "from": {"data": "dataset"}, "encode": { "enter": { "size": {"value": 1000}, "stroke": {"value": "#fff"} }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "fill": { "scale": "color", "field": "generation" }, "shape": { "signal": "datum.gender === 'Male' ? 'square' : 'circle'" } } } }, { "type": "text", "from": {"data": "dataset"}, "encode": { "enter": { "text": {"field": "name"}, "fontSize": {"value": 12}, "baseline": { "value": "middle" } }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "dx": { "signal": "datum.children ? -20 : 20" }, "align": { "signal": "datum.children ? 'right' : 'left'" }, "opacity": { "signal": "labels ? 1 : 0" } } } }, { "type": "rule", "from": { "data": "data-same-level-links"}, "encode": { "update": { "x": {"field": "x"}, "y": {"field": "y"}, "x2": {"field": "x2"}, "y2": {"field": "y2"}, "stroke": { "value": "steelblue" }, "strokeWidth": {"value": 2} } } } ] }
I don't see any problem. Although, I'm not testing in Deneb, but in Vega online editor
Shouldn't be any difference, but maybe there is some. I would verify in Deneb Vega editor if there is data in "data-same-level-links" table and compare it with what you see on my screenshot (or in Vega online editor):
Also put "rule" mark before "symbol" mark if you don't want lines to be drawn on top of the node symbols.
Thank you so much for your help! Its working perfectly now and really helped with my learning of Vega! Thanks again.
Hi,
I have the visual below:
But i need the visual now to have links between nodes which are at the same level, these would be determined by a column in my dataset. I have gone through the Vega documentation and unable to find a suitable way to get it to work. My desired outcome would look like below, note the additional red links.
Below also is my current vega code, any help or direction is appreciated.
{ "width": 1100, "height": 600, "padding": 5, "signals": [ { "name": "labels", "value": true, "bind": {"input": "checkbox"} }, { "name": "layout", "value": "tidy", "bind": { "input": "radio", "options": ["tidy", "cluster"] } }, { "name": "links", "value": "diagonal", "bind": { "input": "select", "options": [ "line", "curve", "diagonal", "orthogonal" ] } }, { "name": "separation", "value": false, "bind": {"input": "checkbox"} } ], "data": [ { "name": "dataset", "transform": [ { "type": "stratify", "key": "id", "parentKey": "parent" }, { "type": "tree", "method": { "signal": "layout" }, "size": [ {"signal": "height"}, {"signal": "width - 100"} ], "separation": { "signal": "separation" }, "as": [ "y", "x", "depth", "children" ] } ] }, { "name": "links", "source": "dataset", "transform": [ {"type": "treelinks"}, { "type": "linkpath", "orient": "horizontal", "shape": {"signal": "links"} } ] } ], "scales": [ { "name": "color", "type": "linear", "range": {"scheme": "lightgreyteal"}, "domain": {"data": "dataset", "field": "depth"}, "zero": true } ], "marks": [ { "type": "path", "from": {"data": "links"}, "encode": { "update": { "path": {"field": "path"}, "stroke": {"value": "#ccc"}, "strokeDash": {"signal": "datum.target.relationship === 'X' ? [5,5] : null"} } } }, { "type": "symbol", "from": {"data": "dataset"}, "encode": { "enter": { "size": {"value": 1000}, "stroke": {"value": "#fff"} }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "fill": { "scale": "color", "field": "depth" }, "shape": { "signal": "datum.gender === 'Male' ? 'square' : 'circle'" } } } }, { "type": "text", "from": {"data": "dataset"}, "encode": { "enter": { "text": {"field": "name"}, "fontSize": {"value": 12}, "baseline": {"value": "middle"} }, "update": { "x": {"field": "x"}, "y": {"field": "y"}, "dx": {"signal": "datum.children ? -20 : 20"}, "align": {"signal": "datum.children ? 'right' : 'left'"}, "opacity": {"signal": "labels ? 1 : 0"} } } } ] }