use std::collections::{BTreeMap, HashMap};
pub use facett_core::{Edge, Facet, FacetCaps, Layout, Node, Scene, Theme, draw, hash_color, set_theme, theme};
mod depgraph;
pub use depgraph::{DepEdge, DepGraphView, DepNode, draw_arrow};
pub fn scene_from_labeled_edges<I>(rows: I) -> Scene
where
I: IntoIterator<Item = (i64, i64, String, String)>,
{
let mut scene = Scene::new();
let mut idx: HashMap<i64, usize> = HashMap::new();
for (s, d, sl, dl) in rows {
let si = *idx.entry(s).or_insert_with(|| scene.node(sl.clone(), hash_color(&sl)));
let di = *idx.entry(d).or_insert_with(|| scene.node(dl.clone(), hash_color(&dl)));
scene.edge(si, di);
}
scene
}
pub struct GraphView {
pub scene: Scene,
pub layout: Layout,
pub empty_hint: String,
pub title: String,
}
impl GraphView {
pub fn new(scene: Scene) -> Self {
Self { scene, layout: Layout::default(), empty_hint: "empty".into(), title: "graph".into() }
}
pub fn empty_hint(mut self, hint: impl Into<String>) -> Self {
self.empty_hint = hint.into();
self
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = title.into();
self
}
pub fn show(&self, ui: &mut egui::Ui) {
draw(ui, &self.scene, self.layout, &self.empty_hint);
}
pub fn label_counts(&self) -> BTreeMap<String, usize> {
let mut m = BTreeMap::new();
for n in &self.scene.nodes {
*m.entry(n.label.clone()).or_insert(0) += 1;
}
m
}
}
impl Facet for GraphView {
fn title(&self) -> &str {
&self.title
}
fn ui(&mut self, ui: &mut egui::Ui) {
self.show(ui);
}
fn state_json(&self) -> serde_json::Value {
serde_json::json!({
"nodes": self.scene.nodes.len(),
"edges": self.scene.edges.len(),
"labels": self.label_counts(),
})
}
fn caps(&self) -> FacetCaps {
FacetCaps::NONE.themeable().resizable()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builds_scene_from_labeled_edges() {
let scene = scene_from_labeled_edges(vec![
(1, 2, "Person".into(), "Company".into()),
(1, 3, "Person".into(), "Address".into()),
]);
assert_eq!(scene.nodes.len(), 3, "1, 2, 3 distinct");
assert_eq!(scene.edges.len(), 2);
assert_eq!(scene.nodes[0].label, "Person");
}
}