7 个稳定版本

2.0.4 2022年9月27日
2.0.3 2022年2月20日
2.0.2 2021年5月2日
2.0.1 2020年11月22日
1.0.0 2020年10月9日

530算法 中排名

每月下载 29

MIT 许可证

31KB
419

Build Status Docs.rs Crates.io

id_tree_layout

一个用于可视化树结构的库,专门针对 id_tree crate。

概览

这个 crate 在开发解析器生成器时作为一个副产品逐渐发展起来。

为了检查生成的解析器的正确性,我需要可视化大型解析树。'id_tree' 自带的 write_formatted 方法对于较小的树来说非常方便,但当树开始增长时,很快就会达到其极限。

所以我想要一个更直观的东西。

结果可能看起来是这样的

example.svg

结果证明,可视化树的任务是一个普遍的任务。因此,我决定为社区提供一个独立的 crate。

在追求普遍性的同时,要完全抽象出人们可能会使用的具体树数据结构并不容易。因此,我决定使用众所周知 的 id_tree 的树实现作为这个 crate 的基础。

我想解决的另一个抽象问题是具体的节点数据类型以及它应该如何在树可视化中表示。求助于节点数据类型实现 Display 特性的实现似乎不够具体。这会意味着在图中节点可视化的表示与在控制台显示上使用的表示相同。

作为对用户代码影响最小的解决方案,我决定要求用户为其节点的数据类型实现一个单独的 trait: Visualize。这个 trait 只包含两个方法,其中只有一个方法是必须实现的。

考虑到这一点,当考虑使用这个 crate 来可视化树时,以下有两个主要的限制需要注意

  • 这个 crate 只与 id_tree crate 提供的树类型一起工作。
  • 该 crate 的用户需要为其节点的数据类型实现 Visualize trait。

该库提供了第三个抽象层次。这是关于如何在平面上嵌入节点并向用户呈现的问题,即嵌入最终以何种格式进行转换。为了简化,id_tree_layout 包提供了这个任务的简单默认解决方案,即 SvgDrawer 类型。它提供嵌入的 SVG 格式的基本表示。但如果用户想使用自己的实现,例如将嵌入打印到位图上,他可以轻松地将它集成到图生成过程中。为此,他需要实现自己的抽屉算法并为其实现 Drawer 特性。然后,他可以使用 Layouterwith_drawer 方法将其提供给绘图过程。

示例用法

use id_tree::InsertBehavior::{AsRoot, UnderNode};
use id_tree::{Node, NodeId, Tree, TreeBuilder};
use id_tree_layout::{Layouter, Visualize};

struct MyNodeData(i32);

// You need to implement id_tree_layout::Visualize for your nodes data type.
// This way you provide basic formatting information.
impl Visualize for MyNodeData {
    fn visualize(&self) -> std::string::String {
        // We simply convert the i32 value to string here.
        self.0.to_string()
    }
    fn emphasize(&self) -> bool {
        // This simply emphasizes only the leaf nodes.
        // It only works for this example.
        self.0 > 1
    }
}

fn main() {
    //      0
    //     / \
    //    1   2
    //   / \
    //  3   4
    let mut tree: Tree<MyNodeData> = TreeBuilder::new().with_node_capacity(5).build();

    let root_id: NodeId = tree.insert(Node::new(MyNodeData(0)), AsRoot).unwrap();
    let child_id: NodeId = tree.insert(Node::new(MyNodeData(1)), UnderNode(&root_id)).unwrap();
    tree.insert(Node::new(MyNodeData(2)), UnderNode(&root_id)).unwrap();
    tree.insert(Node::new(MyNodeData(3)), UnderNode(&child_id)).unwrap();
    tree.insert(Node::new(MyNodeData(4)), UnderNode(&child_id)).unwrap();

    // Here comes the visualization part.
    Layouter::new(&tree)
        .with_file_path(std::path::Path::new("test.svg"));
        .write()
        .expect("Failed writing layout")
}

依赖项

~200–475KB