Недавно библиотека визуализации графиков
egui_graphs
, написанная на rust и работающая на базе egui
для пользовательского интерфейса и petgraph
в качестве серверной части graph
, вышла в версии 0.3.0. Чтобы отпраздновать эту веху, я хотел бы продемонстрировать, насколько просто визуализировать граф и добавить интерактивности с помощью этого инструмента.
Шаг 1: Настройка структуры InteractiveApp
.
Сначала давайте определим структуру InteractiveApp
, которая будет содержать граф.
pub struct InteractiveApp {
g: StableGraph<Node<()>, Edge<()>>,
}
Шаг 2: Реализация функции new()
.
Далее давайте реализуем функцию new()
для структуры BasicApp
.
impl InteractiveApp {
fn new(_: &CreationContext<'_>) -> Self {
let g = generate_graph();
Self { g }
}
}
Здесь мы вызываем функцию generate_graph()
. Допустим, нам нужно 30 узлов и 60 ребер.
Шаг 3: Функция случайного графа.
Теперь мы создаем функцию generate_graph.
fn generate_graph() -> StableGraph<Node<()>, Edge<()>> {
let mut g: StableGraph<Node<()>, Edge<()>> = StableGraph::new();
let a = g.add_node(Node::new(egui::Vec2::new(0., SIDE_SIZE), ()));
let b = g.add_node(Node::new(egui::Vec2::new(-SIDE_SIZE, 0.), ()));
let c = g.add_node(Node::new(egui::Vec2::new(SIDE_SIZE, 0.), ()));
g.add_edge(a, b, Edge::new(()));
g.add_edge(b, c, Edge::new(()));
g.add_edge(c, a, Edge::new(()));
g
}
Шаг 4: Реализация функции update().
Теперь давайте реализуем функцию update()
для нашего Interactiveapp
. Эта функция создает виджет egui_graphs::GraphView
, предоставляющий изменяемую ссылку на наш граф, и добавляет его в egui::CentralPanel
, используя функцию ui.add()
для добавления виджетов.
impl App for InteractiveApp {
fn update(&mut self, ctx: &Context, _: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.add(
&mut GraphView::new(&mut self.g).with_interactions(&SettingsInteraction {
node_drag: true,
node_click: true,
node_select: true,
node_multiselect: true,
..Default::default()
}),
);
});
}
}
Здесь мы инициализируем GraphView
с помощью функции конструктора with_interactions
и передаем туда экземпляр SettingsInteraction
со свойствами взаимодействия. По сути, это место, которое добавляет все взаимодействия в виджет.
Шаг 5: Запуск приложения.
Наконец, запустите приложение, используя функцию run_native()
с указанными собственными параметрами и InteractiveApp
.
fn main() {
let native_options = eframe::NativeOptions::default();
run_native(
"egui_graphs_interactive_demo",
native_options,
Box::new(|cc| Box::new(InteractiveApp::new(cc))),
)
.unwrap();
}
Как только приложение будет запущено, мы увидим полностью интерактивный график с возможностью перетаскивания и выбора узлов.
Полный код для этого примера:
use eframe::{run_native, App, CreationContext};
use egui::Context;
use egui_graphs::{Edge, GraphView, Node, SettingsInteraction};
use petgraph::stable_graph::StableGraph;
const SIDE_SIZE: f32 = 50.;
pub struct InteractiveApp {
g: StableGraph<Node<()>, Edge<()>>,
}
impl InteractiveApp {
fn new(_: &CreationContext<'_>) -> Self {
let g = generate_graph();
Self { g }
}
}
impl App for InteractiveApp {
fn update(&mut self, ctx: &Context, _: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.add(
&mut GraphView::new(&mut self.g).with_interactions(&SettingsInteraction {
node_drag: true,
node_click: true,
node_select: true,
node_multiselect: true,
..Default::default()
}),
);
});
}
}
fn generate_graph() -> StableGraph<Node<()>, Edge<()>> {
let mut g: StableGraph<Node<()>, Edge<()>> = StableGraph::new();
let a = g.add_node(Node::new(egui::Vec2::new(0., SIDE_SIZE), ()));
let b = g.add_node(Node::new(egui::Vec2::new(-SIDE_SIZE, 0.), ()));
let c = g.add_node(Node::new(egui::Vec2::new(SIDE_SIZE, 0.), ()));
g.add_edge(a, b, Edge::new(()));
g.add_edge(b, c, Edge::new(()));
g.add_edge(c, a, Edge::new(()));
g
}
fn main() {
let native_options = eframe::NativeOptions::default();
run_native(
"egui_graphs_interactive_demo",
native_options,
Box::new(|cc| Box::new(InteractiveApp::new(cc))),
)
.unwrap();
}