Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
E

egui_graphs

> 编程语言
Open source

Interactive graph visualization widget for rust powered by egui and petgraph

692 stars0 likes0 views
WebsiteGitHub

About

Interactive graph visualization widget for rust powered by egui and petgraph

egui_graphs

Graph visualization with rust and egui.

The project provides a GraphView for the egui framework, enabling easy visualization of interactive graphs in rust. The goal is to implement the very basic engine for graph visualization within egui, which can be easily extended and customized for your needs.

Check the web-demo for the comprehensive overview of the widget possibilities.

  • Build wasm or native;
  • Layouts and custom layout mechanism;
  • Zooming and panning;
  • Node and edge interaction reporting: click, double click, select, hover, drag;
  • Node and Edge labels;
  • Dark/Light theme support via egui context styles;
  • User stroke styling hooks (node & edge) for dynamic customization;

Table of Contents

  • Status
  • Examples
  • Features
    • Layouts
    • GraphView response
  • Repository organization
  • Run locally
    • Run the web demo (WASM)
    • Run any native example

Status

The project is not in active development. Feel free to fork it and tweak for your needs.

Examples

Basic setup example

The source code of the following steps can be found in the basic example.

Step 1: Setting up the BasicApp struct

First, let's define the BasicApp struct that will hold the graph.

pub struct BasicApp {
    g: egui_graphs::Graph,
}

Step 2: Implementing the new() function

Next, implement the new() function for the BasicApp struct.

impl BasicApp {
    fn new(_: &eframe::CreationContext) -> Self {
        Self { g: generate_graph() }
    }
}

Step 3: Generating the graph

Create a helper function called generate_graph(). In this example, we create three nodes and three edges.

fn generate_graph() -> egui_graphs::Graph {
    let mut g = egui_graphs::Graph::new();

    let a = g.add_node(());
    let b = g.add_node(());
    let c = g.add_node(());

    g.add_edge(a, b, ());
    g.add_edge(b, c, ());
    g.add_edge(c, a, ());

    g
}

Step 4: Implementing the eframe::App trait

Now, lets implement the eframe::App trait for the BasicApp. In the ui() function, we create an egui::CentralPanel and show the egui_graphs::GraphView in it.

impl eframe::App for BasicApp {
    fn ui(&mut self, ui: &mut egui::Ui, _: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ui, |ui| {
            egui_graphs::DefaultGraphView::new().show(ui, &mut self.g);
        });
    }
}

Step 5: Running the application

Finally, run the application using the eframe::run_native() function.

fn main() {
    eframe::run_native(
        "egui_graphs_basic_demo",
        eframe::NativeOptions::default(),
        Box::new(|cc| Ok(Box::new(BasicApp::new(cc)))),
    )
    .unwrap();
}

You can further customize the appearance and behavior of your graph by modifying the settings or adding more nodes and edges as needed.

Custom renderers

Custom DisplayNode and DisplayEdge implementations receive a DrawContext. Use ctx.style.labels_always(), ctx.style.resolve_node_stroke(...), and ctx.style.resolve_edge_stroke(...) inside those renderers to preserve the graph-wide label and stroke settings. The public EdgeShapeBuilder, EdgeShapeProps, and TipProps types can be used to construct the same straight, curved, looped, and arrow-tipped edge geometry as the default renderer without copying its internals.

Features

Layouts

Built-in layouts with a pluggable API. The Layout trait powers layout selection and persistence; you can plug different algorithms or implement your own.

  • Random: quick scatter for any graph (default via DefaultGraphView).
  • Hierarchical: layered (ranked) layout.
  • Force-directed: Fruchterman–Reingold baseline with optional Extras (e.g., Center Gravity).

Quick start

// Default random layout
egui_graphs::DefaultGraphView::new().show(ui, &mut graph);

// Pick a specific layout (Hierarchical)
type L = egui_graphs::LayoutHierarchical;
type S = egui_graphs::LayoutStateHierarchical;
egui_graphs::GraphView::::new().show(ui, &mut graph);

// Force‑Directed (FR) with Center Gravity
type L = egui_graphs::LayoutForceDirected;
type S = egui_graphs::FruchtermanReingoldWithCenterGravityState;
egui_graphs::GraphView::::new().show(ui, &mut graph);

In-depth: Force‑Directed layout

A naive O(n²) force-directed layout (Fruchterman–Reingold style) is included. It exposes adjustable simulation parameters (step size, damping, etc.). See the demo for a live tuning panel. Built-in options include the baseline Fruchterman–Reingold and an extended variant with composable “extras” (e.g., Center Gravity).

Select algorithm via the layout type parameter (public aliases):

use egui_graphs::{LayoutForceDirected, FruchtermanReingold, FruchtermanReingoldState};

type L = LayoutForceDirected;
type S = FruchtermanReingoldState;
egui_graphs::GraphView::::new().show(ui, &mut graph);

Extras (composable add‑ons)

Use FruchtermanReingoldWithExtras to apply base FR forces plus your extras each frame. Built-in extra: Center Gravity.

use egui_graphs::{
    LayoutForceDirected,
    FruchtermanReingoldWithCenterGravity,
    FruchtermanReingoldWithCenterGravityState,
};

type L = LayoutForceDirected;
type S = FruchtermanReingoldWithCenterGravityState;
let mut state = egui_graphs::get_layout_state::(ui, None);
state.base.is_running = true;
state.extras.0.params.c = 0.2;
egui_graphs::set_layout_state(ui, state, None);
egui_graphs::GraphView::::new().show(ui, &mut graph);
Author a custom extra

Implement ExtraForce and compose it through Extra in a tuple. Extra-force parameters are persisted with layout state, so they must implement Serialize and Deserialize. The complete runnable version is in the custom_force example.

…

Composition is order-sensitive; each enabled extra accumulates into the shared displacement vector in tuple order.

GraphView response

GraphView::show returns a GraphViewResponse. Its response field is the standard egui::Response for the allocated graph area, while changes contains the graph-specific changes produced by that call:

let result = egui_graphs::DefaultGraphView::new().show(ui, &mut graph);

if result.response.hovered() {
    // The pointer is over this GraphView.
}

for change in result.changes {
    println!("{change:?}");
}

Changes are transient and ordered by occurrence. Repeated changes are kept as separate entries, and an interaction-free frame returns an empty vector. Variants involving nodes or edges use the graph's NodeIndex or EdgeIndex type; graph-wide changes such as pan and zoom do not depend on an entity index. Store or aggregate a batch in your application when it must outlive the current frame. See the graph_view_response example for a complete application.

Repository organization

Crates:

  • crates/egui_graphs – library crate published to crates.io
  • crates/demo-core – shared demo logic (not published)
  • crates/demo-web – WASM web demo (not published)

Build from the workspace root:

cargo build --workspace

Run locally

Run the web demo (WASM)

Prerequisites:

  • Rust toolchain
  • wasm target and trunk
rustup target add wasm32-unknown-unknown
cargo install trunk # if not installed

Serve locally:

cd crates/demo-web
trunk serve
# opens http://127.0.0.1:8080 (or similar)

Build static assets:

cd crates/demo-web
trunk build
# output in crates/demo-web/dist

Run any native example

From the workspace root, specify the package and the example name:

# demo example
cargo r --release --example demo

# another example (basic)
cargo r --release --example basic

# custom force-directed layout
cargo r --release --example custom_force

# inspect per-frame GraphView responses
cargo r --release --example graph_view_response

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Rustdata-visualizationeguigraph-visualizationpetgraph

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言