use scirs2_cluster::preprocess::standardize;
use scirs2_cluster::vq::{kmeans, kmeans2, vq};
use scirs2_cluster::{BoundaryType, ColorScheme, DimensionalityReduction};
use scirs2_core::ndarray::Array2;
#[cfg(feature = "plotters")]
use scirs2_cluster::{save_clustering_plot, PlotFormat, PlotOutput};
#[cfg(feature = "egui")]
use scirs2_cluster::launch_interactive_visualization;
use scirs2_cluster::VisualizationConfig;
#[allow(dead_code)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Native Plotting Demo for scirs2-cluster");
println!("======================================");
let data = Array2::from_shape_vec((300, 2), generate_sample_data())?;
println!("Generated {} data points with 2 features", data.nrows());
let standardized = standardize(data.view(), true)?;
let k = 3;
let (centroids, _distortion) = kmeans(
standardized.view(),
k,
Some(100), Some(1e-4), Some(true), Some(42), )?;
let (labels_usize, _) = vq(standardized.view(), centroids.view())?;
let labels = labels_usize.mapv(|x| x as i32);
println!("K-means clustering completed with {} clusters", k);
#[cfg(feature = "plotters")]
{
println!("\nCreating static plots with plotters...");
let vis_config = VisualizationConfig {
color_scheme: ColorScheme::ColorblindFriendly,
point_size: 4.0,
point_opacity: 0.8,
show_centroids: true,
show_boundaries: false,
boundary_type: BoundaryType::ConvexHull,
interactive: false,
animation: None,
dimensionality_reduction: DimensionalityReduction::None,
};
let png_output = PlotOutput {
format: PlotFormat::PNG,
dimensions: (1000, 800),
dpi: 300,
background_color: "#FFFFFF".to_string(),
show_grid: true,
show_axes: true,
title: Some("K-means Clustering Results".to_string()),
axis_labels: (
Some("Standardized Feature 1".to_string()),
Some("Standardized Feature 2".to_string()),
None,
),
};
save_clustering_plot(
standardized.view(),
&labels,
Some(¢roids),
"clustering_result.png",
Some(&vis_config),
Some(&png_output),
)?;
println!("✓ Saved PNG plot: clustering_result.png");
let svg_output = PlotOutput {
format: PlotFormat::SVG,
dimensions: (1000, 800),
title: Some("K-means Clustering Results (Vector Graphics)".to_string()),
..png_output
};
save_clustering_plot(
standardized.view(),
&labels,
Some(¢roids),
"clustering_result.svg",
Some(&vis_config),
Some(&svg_output),
)?;
println!("✓ Saved SVG plot: clustering_result.svg");
}
#[cfg(not(feature = "plotters"))]
{
println!("\nStatic plotting with plotters is not available.");
println!("Enable with: cargo run --example native_plotting_demo --features plotters");
}
#[cfg(feature = "egui")]
{
println!("\nLaunching interactive visualization with egui...");
println!("Use mouse to pan and zoom, click clusters in the legend to highlight them.");
let vis_config = VisualizationConfig {
color_scheme: ColorScheme::Viridis,
point_size: 6.0,
point_opacity: 0.9,
show_centroids: true,
show_boundaries: false,
boundary_type: BoundaryType::Ellipse,
interactive: true,
animation: None,
dimensionality_reduction: DimensionalityReduction::None,
};
launch_interactive_visualization(
standardized.view(),
&labels,
Some(¢roids),
Some(&vis_config),
)?;
}
#[cfg(not(feature = "egui"))]
{
println!("\nInteractive visualization with egui is not available.");
println!("Enable with: cargo run --example native_plotting_demo --features egui");
}
println!("\nDemo completed!");
Ok(())
}
#[allow(dead_code)]
fn generate_sample_data() -> Vec<f64> {
use scirs2_core::random::prelude::*;
use scirs2_core::random::Normal;
let mut rng = StdRng::seed_from_u64(42);
let mut data = Vec::with_capacity(600);
let normal1 = Normal::new(0.0, 0.5).expect("Operation failed");
for _ in 0..100 {
data.push(rng.sample(normal1)); data.push(rng.sample(normal1)); }
let normal2_x = Normal::new(4.0, 0.5).expect("Operation failed");
let normal2_y = Normal::new(0.0, 0.5).expect("Operation failed");
for _ in 0..100 {
data.push(rng.sample(normal2_x)); data.push(rng.sample(normal2_y)); }
let normal3_x = Normal::new(2.0, 0.5).expect("Operation failed");
let normal3_y = Normal::new(3.0, 0.5).expect("Operation failed");
for _ in 0..100 {
data.push(rng.sample(normal3_x)); data.push(rng.sample(normal3_y)); }
data
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample_data_generation() {
let data = generate_sample_data();
assert_eq!(data.len(), 600); }
#[test]
fn test_clustering_pipeline() {
let data =
Array2::from_shape_vec((300, 2), generate_sample_data()).expect("Operation failed");
let standardized = standardize(data.view(), true).expect("Operation failed");
let (centroids, labels) = kmeans2(
standardized.view(),
3,
Some(10), Some(1e-4),
None, None, None, Some(42), )
.expect("Operation failed");
assert_eq!(centroids.nrows(), 3);
assert_eq!(centroids.ncols(), 2);
assert_eq!(labels.len(), 300);
for &label in labels.iter() {
assert!(label < 3);
}
}
}