Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

.nornir/graphnav-vg-guide.md

facett-graphnav V.G — guide

Class: guide · the how-to for the elevated GRAPH NAVIGATOR. Concepts: graphnav-vg-design.md. Beginner walkthrough: graphnav-vg-for-idiots.md.

Build one

use facett_graphnav::{GraphNav, Msg, LayoutKind, Metric, Partition, ExportFormat};

let mut nav = GraphNav::demo();          // or GraphNav::new("title", my_prop_graph)

GraphNav is a facett_core::Facet — drop it in a deck, or drive it headlessly by folding Msgs and reading nav.state_json().

Navigate (the camera)

Drag to pan, scroll to zoom on the canvas. Programmatically / from a robot:

nav.update(Msg::CameraZoom(1.5));            // scroll-zoom in (clamped 0.25..4.0)
nav.update(Msg::CameraPan([0.2, -0.1]));     // pan in world units
nav.update(Msg::FitView);                    // ⊙ fit — reset pan+zoom
nav.update(Msg::SelectNode("p3".into()));
nav.update(Msg::ZoomToSelection);            // ⊹ focus — centre + zoom the selection
let cam = nav.state_json()["camera"];        // { pan:[x,y], zoom }

Toolbar buttons ⊙ fit / ⊹ focus do the same. Labels fade in as you zoom past 1.6×; hovering a node dims the rest and highlights its neighbourhood.

Encode data as appearance (ranking + partition)

Size and colour are three independent channels:

nav.update(Msg::SetSizeBy(Some(Metric::Degree)));        // node radius ∝ degree
nav.update(Msg::SetColorMetric(Some(Metric::PageRank))); // sequential ramp (low→high)
nav.update(Msg::SetPartition(Some(Partition::Louvain))); // categorical hue by community

In the UI: the size: / ramp: / partition: toolbar row. Read it back at state_json.appearance (size_by, color_mode, partition_count) and per-node radius/color under canvas.nodes.

Open the data-laboratory table

let node_batch = nav.node_batch();   // Arrow RecordBatch: id,label,caption,degree,pagerank,betweenness,community
let edge_batch = nav.edge_batch();   // Arrow RecordBatch: src,dst,type,weight
let grid = facett_grid::Grid::from_record_batch("nodes", &node_batch);

Two-way selection sync is a plain row↔index map:

if let Some(msg) = nav.select_node_row(3) { nav.update(msg); } // grid → canvas
let row = nav.selected_node_row();                              // canvas → grid

Import / export (Gephi's front door)

let gexf = nav.export(ExportFormat::Gexf);        // also GraphMl / Json / Dot / Csv
let back = GraphNav::import("in", ExportFormat::Gexf, &gexf)?;   // GraphMl / Json too

GEXF/GraphML carry the label + properties + computed metrics (degree, pagerank, betweenness, Louvain community) as attributes. Import is tolerant of the XML Gephi / NetworkX / yEd emit. DOT/CSV are write-only (import returns Err).

Read the stats

let s = nav.stats();   // also at state_json.stats
// { nodes, edges, density, avg_degree, components, largest_component,
//   modularity, communities, avg_clustering, transitivity, diameter, avg_path_length }

The 📊 stats collapsible panel shows the same scalars.

In facett-demo

Run the demo and open the V.G tab. Toggle 🖈 canvas / ▦ table. The tab is driven by the Swedish population graph; a robot drive lives in facett-demo/tests/vg_lab.rs.