简体   繁体   English

如何使用 Vega/Vega-lite 渲染类/组织/流程/状态图/图表

[英]How to render class/org/flow/state chart/diagrams with Vega / Vega-lite

I can't find an example of a state/class/flow chart/org chart diagram with Vega.我找不到 Vega 的状态/类/流程图/组织结构图示例。 Are there any out there?外面有吗?

It feels like Vega is perfectly suited for this (if a bit overpowered), but without an example to start from it's a rather steep learning curve.感觉 Vega 非常适合这个(如果有点过分),但没有一个例子可以从它开始,这是一个相当陡峭的学习曲线。 There are some examples on a "How Vega Works" page, but no links to how they're built: “织女星的工作原理页面上有一些示例,但没有链接到它们的构建方式:

vega 工作原理图

There's also the tree layout example, but it's not clear how one would begin converting this into blocks suitable for a flow-chart style diagram.还有树布局示例,但不清楚如何开始将其转换为适合流程图样式图的块。

在此处输入图片说明

Here's some examples of the sort of output desired (plus other shapes eg diamonds/triangles) from eg mermaid.js这是来自例如mermaid.js 的所需输出类型的一些示例(以及其他形状,例如菱形/三角形)

类图

Suppose you're able to represent your chart as follows:假设您可以按如下方式表示图表:

"values": [
        {"id": "1", "parent": null, "title": "Animal"},
        {"id": "2", "parent": "1", "title": "Duck"},
        {"id": "3", "parent": "1", "title": "Fish"},
        {"id": "4", "parent": "1", "title": "Zebra"}
      ]

What you can then do is to lay the nodes out in a tree-like shape ( stratify does the job):然后你可以做的是将节点布置成树状( stratify完成这项工作):

"transform": [
        {
          "type": "stratify",
          "key": "id",
          "parentKey": "parent"
        },
        {
          "type": "tree",
          "method": "tidy",
          "separation": true,
          "size": [{"signal": "width"}, {"signal": "height"}]
        }
      ]

having laid out the nodes, you need to generate connecting lines, treelinks + linkpath combo does exactly that:布置节点后,您需要生成连接线, treelinks + linkpath组合正是这样做的:

{
      "name": "links",
      "source": "tree", // take datasource "tree" as input
      "transform": [
        { "type": "treelinks" }, // apply transform 1
        { "type": "linkpath", // follow up with next transform
          "shape": "diagonal"
          }
      ]
    }

now that you've got your data sources, you want to draw actual objects.现在您已经获得了数据源,您想要绘制实际对象。 in Vega these are called marks .在 Vega 中,这些被称为marks I guess this is where I'm going to deviate from your desired output as I'm only drawing one rectangle with a title for each data point and some basic lines to connect:我想这就是我将偏离您想要的输出的地方,因为我只绘制一个矩形,每个数据点都有一个标题和一些基本的连接线:

"marks": [
    {
      "type": "path",
      "from": {"data": "links"}, // dataset we defined above
      "encode": {
        "enter": {
          "path": {"field": "path"} // linkpath generated a dataset with "path" field in it - we just grab it here
        }
      }
    },
    {
      "type": "rect",
      "from": {"data": "tree"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    },
    {
      "type": "text",
      "from": {"data": "tree"}, // use data set we defined earlier
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "text": {"field": "title"}, // we can use data fields to display actual values
          "x": {"field": "x"}, // use data fields to draw values from
          "y": {"field": "y"},
          "dx": {"value":50}, // offset the mark to appear in rectangle center
          "dy": {"value":13},
          "align": {"value": "center"}
        }
      }
    }
  ]

All in all I arrived at a very basic approximation of your target state.总而言之,我得到了您目标状态的一个非常基本的近似值 It's definitely not an exact match: the rectangles there should probably be replaced with groups and connection paths will need some work too.这绝对不是完全匹配:那里的矩形可能应该用groups替换,连接路径也需要一些工作。 You will notice I'm not using any signals to feed dynamic user inputs and update / exit / hover instructions - again, for simplicity.您会注意到我没有使用任何signals来提供动态用户输入和update / exit / hover指令 - 再次,为简单起见。

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "width": 800,
  "height": 300,
  "padding": 5,

  "data": [
    {
      "name": "tree",
      "values": [
        {"id": "1", "parent": null, "title": "Animal"},
        {"id": "2", "parent": "1", "title": "Duck"},
        {"id": "3", "parent": "1", "title": "Fish"},
        {"id": "4", "parent": "1", "title": "Zebra"}
      ],
      "transform": [
        {
          "type": "stratify",
          "key": "id",
          "parentKey": "parent"
        },
        {
          "type": "tree",
          "method": "tidy",
          "separation": true,
          "size": [{"signal": "width"}, {"signal": "height"}]
        }
      ]      
    },
    {
      "name": "links",
      "source": "tree",
      "transform": [
        { "type": "treelinks" },
        { "type": "linkpath",
          "shape": "diagonal"
          }
      ]
    }, 
    {
      "name": "tree-boxes",
      "source": "tree",
      "transform": [
          { 
            "type": "filter",
            "expr": "datum.parent == null"
          }
        ]
    },
    {
      "name": "tree-circles",
      "source": "tree",
      "transform": [
        {
          "type": "filter",
          "expr": "datum.parent != null"
        }
      ]
    }
  ],
  "marks": [
    {
      "type": "path",
      "from": {"data": "links"},
      "encode": {
        "enter": {
          "path": {"field": "path"}
        }
      }
    },
    {
      "type": "rect",
      "from": {"data": "tree-boxes"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    },
    {
      "type": "symbol",
      "from": {"data": "tree-circles"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    },
    {
      "type": "rect",
      "from": {"data": "tree"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    },
    {
      "type": "text",
      "from": {"data": "tree"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "text": {"field": "title"},
          "x": {"field": "x"},
          "y": {"field": "y"},
          "dx": {"value":50},
          "dy": {"value":13},
          "align": {"value": "center"}
        }
      }
    }
  ]
}

UPD : suppose, you would like to render different shapes for root and leaf nodes of your chart. UPD :假设您想为图表的根节点和叶节点呈现不同的形状。 One way to achieve this will be to add two filter transformations based on your tree dataset and filter them accordingly:实现此目的的一种方法是根据您的tree数据集添加两个filter转换并相应地过滤它们:

    {
      "name": "tree-boxes",
      "source": "tree", // grab the existing data
      "transform": [
          { 
            "type": "filter",
            "expr": "datum.parent == null" // run it through a filter defined by expression
          }
        ]
    },
    {
      "name": "tree-circles",
      "source": "tree",
      "transform": [
        {
          "type": "filter",
          "expr": "datum.parent != null"
        }
      ]
    }

then instead of rendering all marks as rect you'd want two different shapes for respective transformed datasets:然后,不是将所有标记渲染为rect而是需要为各自的转换数据集提供两种不同的形状:

{
      "type": "rect",
      "from": {"data": "tree-boxes"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    },
    {
      "type": "symbol",
      "from": {"data": "tree-circles"},
      "encode": {
        "enter": {
          "stroke": {"value": "black"},
          "width": {"value": 100},
          "height": {"value": 20},
          "x": {"field": "x"},
          "y": {"field": "y"}
        }
      }
    }

You can refer to this solution - Working with trees which covers您可以参考此解决方案 - 使用覆盖的树木

Step 1 - Extracting Nodes from Tabular Data步骤 1 - 从表格数据中提取节点

Step 2 - Extracting Links from Stratified Node Data步骤 2 - 从分层节点数据中提取链接

Step 3 - How to bring them together第 3 步 - 如何将它们组合在一起

Step 4 - Add labels第 4 步 - 添加标签

Step 5 - Add Color第 5 步 - 添加颜色

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM