Building Graphs
Create and populate narrative graphs.
Creating a Graph
Empty Graph
use spatial_narrative::graph::NarrativeGraph;
let mut graph = NarrativeGraph::new();
From Events
use spatial_narrative::graph::NarrativeGraph;
use spatial_narrative::core::{Event, Location, Timestamp};
let events = vec![
Event::new(Location::new(40.7, -74.0), Timestamp::now(), "Event 1"),
Event::new(Location::new(40.8, -74.1), Timestamp::now(), "Event 2"),
];
let graph = NarrativeGraph::from_events(events);
println!("Graph has {} nodes", graph.node_count());
From Narrative
let graph = NarrativeGraph::from_events(narrative.events.clone());
Adding Events
use spatial_narrative::graph::NarrativeGraph;
let mut graph = NarrativeGraph::new();
// Add returns NodeId for later reference
let node1 = graph.add_event(event1);
let node2 = graph.add_event(event2);
// Look up node by event ID
let node = graph.get_node(&event.id);
Connecting Events
Basic Connection
use spatial_narrative::graph::EdgeType;
graph.connect(node1, node2, EdgeType::Temporal);
Weighted Connection
use spatial_narrative::graph::EdgeWeight;
// Create weighted edge
let weight = EdgeWeight::with_weight(EdgeType::Spatial, 0.8);
graph.connect_weighted(node1, node2, weight);
// With label
let weight = EdgeWeight::new(EdgeType::Causal)
.with_label("caused by");
graph.connect_weighted(node1, node2, weight);
Accessing Nodes and Edges
Get Event by Node
if let Some(event) = graph.event(node_id) {
println!("Event: {}", event.text);
}
// Mutable access
if let Some(event) = graph.event_mut(node_id) {
event.add_tag("processed");
}
Iterate Nodes
for (node_id, event) in graph.nodes() {
println!("Node {}: {}", node_id.index(), event.text);
}
Iterate Edges
for (from, to, weight) in graph.edges() {
println!("{} -> {} ({:?})",
from.index(), to.index(), weight.edge_type);
}
Filter Edges by Type
let temporal_edges = graph.edges_of_type(EdgeType::Temporal);
println!("Temporal connections: {}", temporal_edges.len());
Graph Properties
// Counts
println!("Nodes: {}", graph.node_count());
println!("Edges: {}", graph.edge_count());
println!("Empty: {}", graph.is_empty());
// Degree analysis
let in_degree = graph.in_degree(node); // Incoming edges
let out_degree = graph.out_degree(node); // Outgoing edges
println!("Node has {} in, {} out", in_degree, out_degree);
Neighbors
// Get connected nodes
let successors = graph.successors(node); // Outgoing connections
let predecessors = graph.predecessors(node); // Incoming connections
for successor in successors {
if let Some(event) = graph.event(successor) {
println!("Leads to: {}", event.text);
}
}
Checking Connectivity
// Direct connection
if graph.are_connected(node1, node2) {
println!("Directly connected");
}
// Any path exists
if graph.has_path(node1, node2) {
println!("Path exists");
}
Special Nodes
// Entry points (no predecessors)
let roots = graph.roots();
println!("Entry points: {}", roots.len());
// End points (no successors)
let leaves = graph.leaves();
println!("End points: {}", leaves.len());
Subgraphs
Extract portions of the graph:
use spatial_narrative::core::{TimeRange, GeoBounds};
// By time
let january = TimeRange::month(2024, 1);
let subgraph = graph.subgraph_temporal(&january);
println!("January subgraph: {} nodes", subgraph.graph.node_count());
// By location
let nyc = GeoBounds::new(40.4, -74.3, 41.0, -73.7);
let subgraph = graph.subgraph_spatial(&nyc);
println!("NYC subgraph: {} nodes", subgraph.graph.node_count());
SubgraphResult
let result = graph.subgraph_temporal(&range);
// The new graph
let new_graph = result.graph;
// Mapping from old to new node IDs
for (old_id, new_id) in result.node_mapping {
println!("Node {} -> {}", old_id.index(), new_id.index());
}
Example: Building a Story Graph
// Create graph from news events
let mut graph = NarrativeGraph::from_events(news_events);
// Connect by time (earlier → later)
graph.connect_temporal();
// Connect nearby events (within 1km)
graph.connect_spatial(1.0);
// Connect events sharing topics
graph.connect_thematic();
// Add manual causal links
let cause = graph.get_node(&cause_event.id).unwrap();
let effect = graph.get_node(&effect_event.id).unwrap();
graph.connect(cause, effect, EdgeType::Causal);
println!("Story graph: {} events, {} connections",
graph.node_count(), graph.edge_count());