egui_graphs 0.0.17

Interactive graph visualization widget for rust powered by egui
Documentation

Crates.io docs.rs

egui_graphs

Grpah visualization implementation using egui

Screenshot 2023-04-23 at 22 02 42

Status

The project is close to the first stable version.

Currently not optimized for large graphs. The goal is to match egui drawing speed. Further optimizations are unnecessary.

Concept

The goal is to create a crate that expands egui's visualization capabilities and offers an easy-to-integrate, customizable graph visualization widget.

  • Customization and interactivity;
  • Ability to draw arbitrarily complex graphs with self-references, loops, etc.;
  • Widget does not modify the provided graph and properties; instead, it generates changes, in case of any interactions, which the client can apply.

Roadmap for v0.1.0 - first stable release


Examples

ezgif-4-3e4e4469e6

Basic

Step 1: Setting up the ExampleApp struct.

First, let's define the ExampleApp struct that will hold the graph elements and settings. The struct contains two fields: elements and settings. The elements field stores the graph's nodes and edges, while settings contains the configuration options for the GraphView widget.

pub struct ExampleApp {
    elements: Elements,
    settings: Settings,
}

Step 2: Implementing the new() function.

Next, implement the new() function for the ExampleApp struct. This function initializes the graph settings with default values and generates the graph elements.

impl ExampleApp {
    fn new(_: &CreationContext<'_>) -> Self {
        let settings = Settings::default();
        let elements = generate_graph();
        Self { settings, elements }
    }
}

Step 3: Generating the graph elements.

Create a helper function called generate_graph() that initializes the nodes and edges for the graph. In this example, we create three nodes with unique positions and three edges connecting them in a triangular pattern.

fn generate_graph() -> Elements {
    let mut nodes = HashMap::new();
    nodes.insert(0, Node::new(egui::Vec2::new(0., 30.)));
    nodes.insert(1, Node::new(egui::Vec2::new(-30., 0.)));
    nodes.insert(2, Node::new(egui::Vec2::new(30., 0.)));
    
    let mut edges = HashMap::new();
    edges.insert((0, 1), vec![Edge::new(0, 1, 0)]);
    edges.insert((1, 2), vec![Edge::new(1, 2, 0)]);
    edges.insert((2, 0), vec![Edge::new(2, 0, 0)]);   
    
    Elements::new(nodes, edges)
}

Step 4: Implementing the update() function.

Now, implement the update() function for the ExampleApp. This function creates a GraphView widget with the elements and settings, and adds it to the central panel using the ui.add() function.

impl App for ExampleApp {
    fn update(&mut self, ctx: &Context, _: &mut eframe::Frame) {
        let widget = &GraphView::new(&self.elements, &self.settings);
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.add(widget);
        });
    }
}

Step 5: Running the application.

Finally, run the application using the run_native() function with the specified native options and the ExampleApp.

fn main() {
    let native_options = eframe::NativeOptions::default();
    run_native(
        "egui_graphs_basic_demo",
        native_options,
        Box::new(|cc| Box::new(ExampleApp::new(cc))),
    )
    .unwrap();
}

Screenshot 2023-04-24 at 22 04 49

You can further customize the appearance and behavior of your graph by modifying the settings or adding more nodes and edges as needed. Don't forget to apply changes returned from the widget.

Interactive

You can check more advanced interactive example for usage references, settings description and changes apply demonstration.