forceatlas2/
lib.rs

1#![feature(trait_alias)]
2#![warn(missing_docs)]
3#![warn(non_ascii_idents)]
4#![warn(unnameable_types)]
5#![warn(unreachable_pub)]
6#![allow(clippy::tabs_in_doc_comments)]
7
8//! Implementation of [ForceAtlas2](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4051631/) – force-directed Continuous Graph Layout Algorithm for Handy Network Visualization (i.e. position the nodes of a n-dimension graph for drawing it more human-readably)
9//!
10//! This example creates a graph containing 4 nodes indexed from 0 to 3, linked by undirected weighted edges.
11//! ```rust
12//! let mut rng = rand::thread_rng();
13//! let mut layout = forceatlas2::Layout::<f32, 2>::from_abstract(
14//! 	forceatlas2::Settings::default(),
15//! 	(0..4).map(|i| (i, forceatlas2::AbstractNode::default())),
16//! 	vec![((0, 1), 1.0), ((1, 2), 1.5), ((0, 2), 0.7), ((2, 3), 1.0)],
17//! 	&mut rng,
18//! );
19//! for _ in 0..100 {
20//! 	layout.iteration();
21//! }
22//! for node in layout.nodes.iter() {
23//! 	println!("({}, {})", node.pos.x(), node.pos.y());
24//! }
25//! ```
26//!
27//! `Layout` supports multiple collection types for nodes and edges.
28
29mod edge;
30pub mod forces;
31mod layout;
32mod node;
33pub mod trees;
34mod util;
35
36pub use edge::{EdgeBTreeMap, EdgeHashMap, EdgeVec, Edges};
37pub use layout::{Layout, Settings};
38pub use node::{AbstractNode, BuildableNodes, Node, NodeHashMap, NodeVec, Nodes};
39#[cfg(feature = "rand")]
40pub use util::sample_unit_cube;
41pub use util::{Coord, Vec2, Vec3, VecN};
42
43#[cfg(test)]
44mod tests {
45	use super::*;
46
47	/// Higher-level test
48	#[cfg(feature = "rand")]
49	#[test]
50	fn test_global() {
51		let mut rng = rand::thread_rng();
52		let mut layout = Layout::<f64, 2>::from_abstract(
53			Settings::default(),
54			(0..5).map(|i| {
55				(
56					i,
57					AbstractNode {
58						mass: 1.0,
59						size: 1.0,
60					},
61				)
62			}),
63			vec![
64				((0, 1), 1.0),
65				((0, 2), 1.0),
66				((0, 3), 1.0),
67				((1, 2), 1.0),
68				((1, 4), 1.0),
69			],
70			&mut rng,
71		);
72
73		for _ in 0..10 {
74			layout.iteration();
75		}
76
77		layout
78			.nodes
79			.iter()
80			.for_each(|node| println!("{:?}", node.pos));
81	}
82
83	// Some type to test that traits are also implemented for other than usize
84	type Id = i32;
85
86	/// Test whether the traits bounds are satisfied
87	#[test]
88	fn test_types() {
89		Layout::<f32, 2, EdgeVec<f32, usize>, NodeVec<f32, 2>, usize>::default();
90		Layout::<f32, 2, EdgeVec<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
91		Layout::<f32, 2, EdgeBTreeMap<f32, usize>, NodeVec<f32, 2>, usize>::default();
92		Layout::<f32, 2, EdgeBTreeMap<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
93		Layout::<f32, 2, EdgeHashMap<f32, usize>, NodeVec<f32, 2>, usize>::default();
94		Layout::<f32, 2, EdgeHashMap<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
95		Layout::<f32, 3, EdgeVec<f32, usize>, NodeVec<f32, 3>, usize>::default();
96		Layout::<f32, 3, EdgeVec<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
97		Layout::<f32, 3, EdgeBTreeMap<f32, usize>, NodeVec<f32, 3>, usize>::default();
98		Layout::<f32, 3, EdgeBTreeMap<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
99		Layout::<f32, 3, EdgeHashMap<f32, usize>, NodeVec<f32, 3>, usize>::default();
100		Layout::<f32, 3, EdgeHashMap<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
101	}
102}