英文:
How to perform a lookup to same dataset in vega-lite
问题
I'm using vega-lite 5.6.1 within the Deneb visual for Power BI. I've built a tree/matrix hybrid visual:
Now I need to get child rows to dynamically lookup fields from their parent row. This needs to happen after the dataset has been filtered so I can allow users to collapse and expand rows.
I've tried using the Lookup Transform but can't pass in the "from" parameter since it expects a secondary dataset:
{
"data": {"name": "dataset"},
"transform": [
...,
{"filter": ... },
{"lookup": "Parent_Path", "from": ... , "key": "Child_Path", "fields": ["Horiz_Offset", "Vert_Offset"], "as": "Parent_Row"}
],
"layer": [
...
]
}
Out of desperation I experimented using the JoinAggregate Transform but it doesn't allow expressions in the "field" parameter to filter it:
{
"data": {"name": "dataset"},
"transform": [
...,
{"filter": ... },
{"joinaggregate": [{"op": "min", "field": {"value": {"expr": "child.Parent_Path == parent.Child_Path ? Horiz_Offset : null"}}, "as": "Parent_Horiz_Offset"}]}
],
"layer": [
...
]
}
Here's an example containing a hardcoded dataset. Normally the data would be passed from an external dataset as: "data": {"name": "dataset"}. Instead of passing in Parent_Horiz_Offset and Parent_Vert_Offset I want to get the values from their parent row:
{
"data": {
"values": [
{"Full_Path": "Level 1a\\Level 2a\\Level 3a\\Employee 01", "Child_Path": "Level 1a", "Parent_Path": "", "Node_Text": "Level 1a", "Horiz_Offset": 0, "Vert_Offset": 0, "Parent_Horiz_Offset": null, "Parent_Vert_Offset": null},
{"Full_Path": "Level 1a\\Level 2a\\Level 3a\\Employee 01", "Child_Path": "Level 1a\\Level 2a", "Parent_Path": "Level 1a", "Node_Text": "Level 2 a", "Horiz_Offset": 1, "Vert_Offset": 1, "Parent_Horiz_Offset": 0, "Parent_Vert_Offset": 0},
{"Full_Path": "Level 1a\\Level 2a\\Level 3a\\Employee 01", "Child_Path": "Level 1a\\Level 2a\\Level 3a", "Parent_Path": "Level 1a\\Level 2a", "Node_Text": "Level 3a", "Horiz_Offset": 2, "Vert_Offset": 2, "Parent_Horiz_Offset": 1, "Parent_Vert_Offset": 1},
{"Full_Path": "Level 1a\\Level 2a\\Level 3a\\Employee 01", "Child_Path": "Level 1a\\Level 2a\\Level 3a\\Employee 01", "Parent_Path": "Level 1a\\Level 2a\\Level 3a", "Node_Text": "Employee 01", "Horiz_Offset": 3, "Vert_Offset": 3, "Parent_Horiz_Offset": 2, "Parent_Vert_Offset": 2}
]
},
"params": [
{"name": "_indentSize", "value": 30},
{"name": "_iconSize", "value": 80},
{"name": "_rowHeight", "value": 15},
{"name": "_headerRowHeight", "value": 0}
],
"transform": [
{"window": [{"op": "dense_rank", "as": "_rowNum"}], "ignorePeers": true, "sort": [{"field": "Parent_Path", "order": "ascending"}]},
{"window": [{"op": "row_number", "as": "_index"}], "groupby": ["Child_Path"]},
{"calculate": "datum.Horiz_Offset * _indentSize", "as": "_xPos"},
{"calculate": "datum.Vert_Offset * _rowHeight", "as": "_yPos"},
{"calculate": "datum.Parent_Horiz_Offset * _indentSize", "as": "_xPos_Parent"},
{"calculate": "datum.Parent_Vert_Offset * _rowHeight", "as": "_yPos_Parent"},
{"calculate": "datum.Full_Path == datum.Child_Path", "as": "_isLeafNode"},
{"calculate": "datum.Parent_Path == ''", "as": "_isRootNode"},
{"filter": "datum._index == 1"}
],
"layer": [
{
"description": "Row Background",
"params": [{"name": "isSelected", "select": "point"}],
"mark": {"type": "rect", "stroke": "#E1E2E3", "cursor": "pointer"},
"encoding": {
"x": {"value": {"expr": "datum._xPos - 8"}},
"y": {"value": {"expr": "datum._yPos - ceil(_rowHeight / 2)"}},
"x2": {"value": {"expr": "320"}},
"y2": {"value": {"expr": "datum._yPos + floor(_rowHeight / 2)"}},
"color": {"value": {"expr": "datum._yPos % 2 == 0 ? 'white' : '#F1F2F3'"}}
}
},
{
"description": "Node line horiz",
"mark": {"type": "rule", "color": "#00002D"},
"encoding": {
"x": {"value": {"expr": "datum._xPos_Parent"}},
"x2": {"value": {"expr": "datum._xPos"}},
"y": {"value": {"expr": "datum._yPos"}},
"y2": {"value": {"expr": "datum._yPos"}},
"opacity": {"value": {"expr": "datum._isRootNode ? 0 : 1"}}
}
},
{
"description": "Node line vert",
"mark": {"type": "rule", "color": "#00002D"},
"encoding": {
"x": {"value": {"expr": "datum._xPos_Parent"}},
"x2": {"value": {"expr": "datum._xPos_Parent"}},
"y": {"value": {"expr": "datum._yPos_Parent"}},
"y2": {"value": {"expr": "datum._yPos"}},
"opacity": {"value": {"expr": "datum._isRootNode ? 0 : 1"}}
}
},
<details>
<summary>英文:</summary>
I'm using vega-lite 5.6.1 within the Deneb visual for Power BI. I've built a tree/matrix hybrid visual:
[![enter image description here](https://i.stack.imgur.com/qSQ6U.png)](https://i.stack.imgur.com/qSQ6U.png)
Now I need to get child rows to dynamically lookup fields from their parent row. This needs to happen after the dataset has been filtered so I can allow users to collapse and expand rows.
I've tried using the Lookup Transform but can't pass in the `"from":` parameter since it expects a secondary dataset:
{
"data": {"name": "dataset"},
"transform": [
...,
{"filter": ... },
{"lookup": "Parent_Path", "from": ... , "key": "Child_Path", "fields": ["Horiz_Offset", "Vert_Offset"], "as": "Parent_Row"}
],
"layer": [
...
]
}
Out of desperation I experimented using the JoinAggregate Transform but it doesn't allow expressions in the `"field":` parameter to filter it:
{
"data": {"name": "dataset"},
"transform": [
...,
{"filter": ... },
{"joinaggregate": [{"op": "min", "field": {"value": {"expr": "child.Parent_Path == parent.Child_Path ? Horiz_Offset : null"}}, "as": "Parent_Horiz_Offset"]}
],
"layer": [
...
]
}
Here's an example containing a hardcoded dataset. Normally the data would be passed from an external dataset as: `"data": {"name": "dataset"}`. Instead of passing in _Parent_Horiz_Offset_ and _Parent_Vert_Offset_ I want to get the values from their parent row.
{
"data": {
"values": [
{"Full_Path": "Level 1a\Level 2a\Level 3a\Employee 01", "Child_Path": "Level 1a", "Parent_Path": "", "Node_Text": "Level 1a", "Horiz_Offset": 0, "Vert_Offset": 0, "Parent_Horiz_Offset": null, "Parent_Vert_Offset": null},
{"Full_Path": "Level 1a\Level 2a\Level 3a\Employee 01", "Child_Path": "Level 1a\Level 2a", "Parent_Path": "Level 1a", "Node_Text": "Level 2 a", "Horiz_Offset": 1, "Vert_Offset": 1, "Parent_Horiz_Offset": 0, "Parent_Vert_Offset": 0},
{"Full_Path": "Level 1a\Level 2a\Level 3a\Employee 01", "Child_Path": "Level 1a\Level 2a\Level 3a", "Parent_Path": "Level 1a\Level 2a", "Node_Text": "Level 3a", "Horiz_Offset": 2, "Vert_Offset": 2, "Parent_Horiz_Offset": 1, "Parent_Vert_Offset": 1},
{"Full_Path": "Level 1a\Level 2a\Level 3a\Employee 01", "Child_Path": "Level 1a\Level 2a\Level 3a\Employee 01", "Parent_Path": "Level 1a\Level 2a\Level 3a", "Node_Text": "Employee 01", "Horiz_Offset": 3, "Vert_Offset": 3, "Parent_Horiz_Offset": 2, "Parent_Vert_Offset": 2}
]
},
"params": [
{"name": "_indentSize", "value": 30},
{"name": "_iconSize", "value": 80},
{"name": "_rowHeight", "value": 15},
{"name": "_headerRowHeight", "value": 0}
],
"transform": [
{"window": [{"op": "dense_rank", "as": "_rowNum"}], "ignorePeers": true, "sort": [{"field": "Parent_Path", "order": "ascending"}]},
{"window": [{"op": "row_number", "as": "_index"}], "groupby": ["Child_Path"]},
{"calculate": "datum.Horiz_Offset * _indentSize", "as": "_xPos"},
{"calculate": "datum.Vert_Offset * _rowHeight", "as": "_yPos"},
{"calculate": "datum.Parent_Horiz_Offset * _indentSize", "as": "_xPos_Parent"},
{"calculate": "datum.Parent_Vert_Offset * _rowHeight", "as": "_yPos_Parent"},
{"calculate": "datum.Full_Path == datum.Child_Path", "as": "_isLeafNode"},
{"calculate": "datum.Parent_Path == ''", "as": "_isRootNode"},
{"filter": "datum._index == 1"}
],
"layer": [
{
"description": "Row Background",
"params": [{"name": "isSelected", "select": "point"}],
"mark": {"type": "rect", "stroke": "#E1E2E3", "cursor": "pointer"},
"encoding": {
"x": {"value": {"expr": "datum._xPos - 8"}},
"y": {"value": {"expr": "datum._yPos - ceil(_rowHeight / 2)"}},
"x2": {"value": {"expr": "320"}},
"y2": {"value": {"expr": "datum._yPos + floor(_rowHeight / 2)"}},
"color": {"value": {"expr": "datum._yPos % 2 == 0 ? 'white' : '#F1F2F3'"}},
"opacity": {"condition": {"param": "isSelected", "value": 1}, "value": 0.5}
}
},
{
"description": "Node line horiz",
"mark": {"type": "rule", "color": "#00002D"},
"encoding": {
"x": {"value": {"expr": "datum._xPos_Parent"}},
"x2": {"value": {"expr": "datum._xPos"}},
"y": {"value": {"expr": "datum._yPos"}},
"y2": {"value": {"expr": "datum._yPos"}},
"opacity": {"value": {"expr": "datum._isRootNode ? 0 : 1"}}
}
},
{
"description": "Node line vert",
"mark": {"type": "rule", "color": "#00002D"},
"encoding": {
"x": {"value": {"expr": "datum._xPos_Parent"}},
"x2": {"value": {"expr": "datum._xPos_Parent"}},
"y": {"value": {"expr": "datum._yPos_Parent"}},
"y2": {"value": {"expr": "datum._yPos"}},
"opacity": {"value": {"expr": "datum._isRootNode ? 0 : 1"}}
}
},
{
"description": "Node icon",
"mark": {"type": "point"},
"encoding": {
"x": {"value": {"expr": "datum._xPos"}},
"y": {"value": {"expr": "datum._yPos"}},
"shape": {"value": {"expr": "datum._isLeafNode ? 'circle' : 'square'"}}
}
},
{
"description": "Node text",
"mark": {"type": "text"},
"encoding": {
"x": {"value": {"expr": "datum._xPos + 10"}},
"y": {"value": {"expr": "datum._yPos"}},
"text": {"field": "Node_Text"},
"opacity": {"condition": {"param": "isSelected", "value": 1}, "value": 0.5}
}
}
],
"config": {
"text": {
"fill": "#00002D",
"align": "left",
"font": "Arial",
"fontSize": 10
},
"point": {
"size": 80,
"opacity": 1
}
}
}
</details>
# 答案1
**得分**: 1
Nice visual. You can pass the name into the lookup transform to get what you need. e.g.
{
"lookup": "Full_Path",
"from": {
"data": {"name": "myDataset"},
"key": "Full_Path",
"fields": ["Node_Text"]
},
"as": ["test"]
}
<details>
<summary>英文:</summary>
Nice visual. You can pass the name into the lookup transform to get what you need. e.g.
{
"lookup": "Full_Path",
"from": {
"data": {"name": "myDataset"},
"key": "Full_Path",
"fields": ["Node_Text"]
},
"as": ["test"]
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论