forceatlas2 0.8.0

fast force-directed generic n-dimension graph layout
Documentation
#![feature(trait_alias)]
#![warn(missing_docs)]
#![warn(non_ascii_idents)]
#![warn(unnameable_types)]
#![warn(unreachable_pub)]
#![allow(clippy::tabs_in_doc_comments)]

//! 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)
//!
//! This example creates a graph containing 4 nodes indexed from 0 to 3, linked by undirected weighted edges.
//! ```rust
//! let mut rng = rand::thread_rng();
//! let mut layout = forceatlas2::Layout::<f32, 2>::from_abstract(
//! 	forceatlas2::Settings::default(),
//! 	(0..4).map(|i| (i, forceatlas2::AbstractNode::default())),
//! 	vec![((0, 1), 1.0), ((1, 2), 1.5), ((0, 2), 0.7), ((2, 3), 1.0)],
//! 	&mut rng,
//! );
//! for _ in 0..100 {
//! 	layout.iteration();
//! }
//! for node in layout.nodes.iter() {
//! 	println!("({}, {})", node.pos.x(), node.pos.y());
//! }
//! ```
//!
//! `Layout` supports multiple collection types for nodes and edges.

mod edge;
pub mod forces;
mod layout;
mod node;
pub mod trees;
mod util;

pub use edge::{EdgeBTreeMap, EdgeHashMap, EdgeVec, Edges};
pub use layout::{Layout, Settings};
pub use node::{AbstractNode, BuildableNodes, Node, NodeHashMap, NodeVec, Nodes};
#[cfg(feature = "rand")]
pub use util::sample_unit_cube;
pub use util::{Coord, Vec2, Vec3, VecN};

#[cfg(test)]
mod tests {
	use super::*;

	/// Higher-level test
	#[cfg(feature = "rand")]
	#[test]
	fn test_global() {
		let mut rng = rand::thread_rng();
		let mut layout = Layout::<f64, 2>::from_abstract(
			Settings::default(),
			(0..5).map(|i| {
				(
					i,
					AbstractNode {
						mass: 1.0,
						size: 1.0,
					},
				)
			}),
			vec![
				((0, 1), 1.0),
				((0, 2), 1.0),
				((0, 3), 1.0),
				((1, 2), 1.0),
				((1, 4), 1.0),
			],
			&mut rng,
		);

		for _ in 0..10 {
			layout.iteration();
		}

		layout
			.nodes
			.iter()
			.for_each(|node| println!("{:?}", node.pos));
	}

	// Some type to test that traits are also implemented for other than usize
	type Id = i32;

	/// Test whether the traits bounds are satisfied
	#[test]
	fn test_types() {
		Layout::<f32, 2, EdgeVec<f32, usize>, NodeVec<f32, 2>, usize>::default();
		Layout::<f32, 2, EdgeVec<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
		Layout::<f32, 2, EdgeBTreeMap<f32, usize>, NodeVec<f32, 2>, usize>::default();
		Layout::<f32, 2, EdgeBTreeMap<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
		Layout::<f32, 2, EdgeHashMap<f32, usize>, NodeVec<f32, 2>, usize>::default();
		Layout::<f32, 2, EdgeHashMap<f32, Id>, NodeHashMap<f32, 2, Id>, Id>::default();
		Layout::<f32, 3, EdgeVec<f32, usize>, NodeVec<f32, 3>, usize>::default();
		Layout::<f32, 3, EdgeVec<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
		Layout::<f32, 3, EdgeBTreeMap<f32, usize>, NodeVec<f32, 3>, usize>::default();
		Layout::<f32, 3, EdgeBTreeMap<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
		Layout::<f32, 3, EdgeHashMap<f32, usize>, NodeVec<f32, 3>, usize>::default();
		Layout::<f32, 3, EdgeHashMap<f32, Id>, NodeHashMap<f32, 3, Id>, Id>::default();
	}
}