grape-icon

Grape

swift package indexswift package index

一个用于图表可视化和高效力模拟的 Swift 库。



示例

力导向图

这是一个力导向图,可视化了悲惨世界中人物共同出现的网络。仔细看看动画

Grape_0.3.0.mov

源代码:Miserables.swift


visionOS 中的力导向图

这与第一个示例中的图相同,在 RealityView 中渲染

Grape_0.3.0_visionOS.mov

源代码:ForceDirectedGraph3D/ContentView.swift


Mermaid 可视化

基于您输入的动态图结构,支持点击和拖动手势,全部在 100 行视图代码内完成。

Grape_0.6.1_Mermaid.mov

源代码:MermaidVisualization.swift


晶格模拟

一个 36x36 的力导向晶格。

Grape_0.3.0_lattice.mov

源代码:Lattice.swift

拖动手势

一个渲染具有 60 个顶点的环的示例,启用了拖动手势。

Screen.Recording.2023-11-07.at.00.45.42.mov

源代码:MyRing.swift



安装

要通过将 Grape 作为包添加到 Xcode 项目中使用它

https://github.com/swiftgraphs/Grape

要在 SwiftPM 项目中使用 Grape,请将其添加到您的 Package.swift

dependencies: [
    .package(url: "https://github.com/swiftgraphs/Grape", from: "1.1.0")
]
.product(name: "Grape", package: "Grape"),

注意

Grape 模块依赖于 Observation 框架。可以使用社区提供的 shim(例如 swift-perception)进行向后部署。

在 1.0 版本发布之前,Grape 模块可能会在小版本更改中引入破坏性的 API 更改。

ForceSimulation 模块现在在公共 API 方面是稳定的。



开始使用

Grape 包含 2 个模块


Grape 模块

有关详细用法,请参阅文档。这里是一个快速示例

import Grape

struct MyGraph: View {

    // States including running status, transformation, etc.
    // Gives you a handle to control the states.
    @State var graphStates = ForceDirectedGraphState() 
    
    var body: some View {
        ForceDirectedGraph(states: graphStates) {
            
            // Declare nodes and links like you would do in Swift Charts.
            NodeMark(id: 0).foregroundStyle(.green)
            NodeMark(id: 1).foregroundStyle(.blue)
            NodeMark(id: 2).foregroundStyle(.yellow)

            Series(0..<2) { i in
                LinkMark(from: i, to: i+1)
            }
            
        } force: {
            .link()
            .center()
            .manyBody()
        }
    }
}

ForceSimulation 模块

请参考文档或展开此部分以了解有关此模块的更多信息。

ForceSimulation 模块主要包含 3 个概念,KineticsForceProtocolSimulation

A diagram showing the relationships of `Kinetics`, `ForceProtocol` and `Simulation`. A `Simulation` contains a `Kinetics` and a `ForceProtocol`.


模拟和力的基本概念可以在这里找到:力模拟 - D3。 您可以通过像这样使用 Simulation 简单地创建模拟

import simd
import ForceSimulation

// assuming you’re simulating 4 nodes
let nodeCount = 4


// Connect them
let links = [(0, 1), (1, 2), (2, 3), (3, 0)] 

/// Create a 2D force composited with 4 primitive forces.
let myForce = SealedForce2D {
    // Forces are namespaced under `Kinetics<Vector>`
    // here we only use `Kinetics<SIMD2<Double>>`, i.e. `Kinetics2D`
    Kinetics2D.ManyBodyForce(strength: -30)
    Kinetics2D.LinkForce(
        stiffness: .weightedByDegree(k: { _, _ in 1.0 }),
        originalLength: .constant(35)
    )
    Kinetics2D.CenterForce(center: .zero, strength: 1)
    Kinetics2D.CollideForce(radius: .constant(3))
}

/// Create a simulation, the dimension is inferred from the force.
let mySimulation = Simulation(
    nodeCount: nodeCount,
    links: links.map { EdgeID(source: $0.0, target: $0.1) },
    forceField: myForce
) 

/// Force is ready to start! run `tick` to iterate the simulation.

for mySimulation in 0..<120 {
    mySimulation.tick()
    let positions = mySimulation.kinetics.position.asArray()
    /// Do something with the positions.
}

有关更多详细信息,请参见示例



路线图

2D simd ND simd Metal
NdTree
Simulation
 LinkForce
 ManyBodyForce
 CenterForce
 CollideForce
 PositionForce
 RadialForce
SwiftUI View
 Basic Visualization
 Gestures
 Node Styling
 Link Styling 🚧
 Animatable Transition 🚧


性能


Simulation

Grape 使用 simd 来计算位置和速度。目前,对示例图(2D)迭代 120 次需要 ~0.005 秒。(77 个顶点,254 条边,具有多体、中心、碰撞和链接力。在 M1 Max 上发布版本,使用命令 swift test -c release 测试

对于 3D 模拟,相同的图和相同的配置需要 ~0.008 秒。

重要提示

由于大量使用泛型(某些在调试模式下未专门化),调试版本中的性能比发布版本慢约 100 倍。


KDTree

根据此测试用例,此软件包中的 BufferedKDTree 比 Apple 的 GameKit 中的 GKQuadtree~22 倍。 但是,请注意,将 Swift 结构与 NSObject 进行比较是不公平的,并且它们的行为也不同。


鸣谢

该库深受 D3.js(Data-Driven Documents) 的杰出工作的影响。