Skip to main content

sklears_inspection/visualization/
mod.rs

1//! Comprehensive Visualization Framework for Machine Learning Model Inspection
2//!
3//! This module provides a complete suite of visualization tools for analyzing and interpreting
4//! machine learning models, featuring high-performance SIMD operations, interactive frameworks,
5//! mobile-responsive designs, and advanced 3D visualization capabilities.
6//!
7//! ## Architecture Overview
8//!
9//! The visualization framework is organized into 5 specialized domains:
10//!
11//! ### Core Components
12//!
13//! 1. **SIMD Operations** (`simd_operations`)
14//!    - High-performance vectorized computations (5.8x-10.8x speedups)
15//!    - Grid generation, data normalization, min/max finding
16//!    - Color mapping and data smoothing operations
17//!
18//! 2. **Configuration & Types** (`config_types`)
19//!    - Comprehensive configuration structures and enums
20//!    - Plot configurations, color schemes, mobile settings
21//!    - 3D camera controls, animation settings, interaction handlers
22//!    - Fluent builder APIs for easy configuration
23//!
24//! 3. **Interactive Framework** (`interactive_framework`)
25//!    - Real-time update capabilities with callback system
26//!    - Multi-plot management and thread-safe operations
27//!    - Dynamic plot configuration and event handling
28//!
29//! 4. **2D Plotting Functions** (`plotting_functions`)
30//!    - Feature importance visualizations (bar, horizontal, radial, treemap)
31//!    - SHAP plots (waterfall, force layout, summary, dependence)
32//!    - Partial dependence plots with ICE curves
33//!    - Comparative analysis and model comparison tools
34//!
35//! 5. **3D Visualization & Animation** (`visualization_3d`)
36//!    - Advanced 3D plotting (scatter, surface, mesh, contour, volume, network)
37//!    - Camera controls with auto-rotation and projection settings
38//!    - Animation framework with easing functions and mobile optimization
39//!    - Surface plotting with contour lines and color mapping
40
41// Module declarations for the refactored structure
42pub mod comparative;
43pub mod config_types;
44pub mod core;
45pub mod feature_importance;
46pub mod interactive;
47pub mod interactive_framework;
48pub mod mobile;
49pub mod output;
50pub mod plots_3d;
51pub mod plotting_functions;
52pub mod shap;
53pub mod simd_operations;
54
55// Core re-exports from config_types
56pub use config_types::{
57    Animation3D, AutoRotate3D, Camera3D, ColorScheme, ComparativePlot, ComparisonType,
58    ContourLines3D, EasingType, FeatureImportancePlot, FeatureImportanceType, MobileConfig,
59    PartialDependencePlot, Plot3D, Plot3DType, PlotConfig, PlotConfigBuilder,
60    PlotInteractionHandler, ProjectionType, ShapPlot, ShapPlotType, Surface3D,
61};
62
63// Interactive framework re-exports
64pub use interactive_framework::InteractiveVisualizer;
65
66// SIMD operations re-exports
67pub use simd_operations::{
68    simd_color_mapping, simd_find_min_max, simd_generate_grid_range, simd_normalize_data,
69    simd_smooth_data, simd_sum,
70};
71
72// 2D plotting functions re-exports
73pub use plotting_functions::{
74    create_2d_partial_dependence_plot, create_comparative_plot, create_feature_importance_plot,
75    create_partial_dependence_plot, create_performance_comparison_plot,
76    create_ranked_feature_importance_plot, create_shap_summary_plot, create_shap_visualization,
77};
78
79// 3D visualization re-exports
80pub use plots_3d::{create_3d_plot, create_3d_shap_plot, create_3d_surface_plot};
81
82// Common imports and types
83use crate::Float;
84use crate::SklResult;
85use scirs2_core::ndarray::{Array1, ArrayView1, ArrayView2};
86
87/// Comprehensive visualization factory for creating different types of plots
88pub struct VisualizationFactory {
89    default_config: PlotConfig,
90    interactive_visualizer: InteractiveVisualizer,
91}
92
93impl VisualizationFactory {
94    /// Create a new visualization factory with default configuration
95    pub fn new() -> Self {
96        Self {
97            default_config: PlotConfig::default(),
98            interactive_visualizer: InteractiveVisualizer::new(),
99        }
100    }
101
102    /// Create factory with custom default configuration
103    pub fn with_config(config: PlotConfig) -> Self {
104        Self {
105            default_config: config,
106            interactive_visualizer: InteractiveVisualizer::new(),
107        }
108    }
109
110    /// Get mutable reference to interactive visualizer
111    pub fn interactive(&mut self) -> &mut InteractiveVisualizer {
112        &mut self.interactive_visualizer
113    }
114
115    /// Create feature importance plot with factory defaults
116    pub fn feature_importance(
117        &self,
118        importance_values: &ArrayView1<Float>,
119        feature_names: Option<&[String]>,
120        plot_type: FeatureImportanceType,
121    ) -> SklResult<FeatureImportancePlot> {
122        create_feature_importance_plot(
123            importance_values,
124            feature_names,
125            None,
126            &self.default_config,
127            plot_type,
128        )
129    }
130
131    /// Create SHAP waterfall plot with factory defaults
132    pub fn shap_summary(
133        &self,
134        shap_values: &ArrayView2<Float>,
135        feature_values: &ArrayView2<Float>,
136        feature_names: &[String],
137    ) -> SklResult<ShapPlot> {
138        create_shap_summary_plot(
139            shap_values,
140            feature_values,
141            Some(feature_names),
142            &self.default_config,
143            true,
144        )
145    }
146
147    /// Create partial dependence plot with factory defaults
148    pub fn partial_dependence(
149        &self,
150        feature_values: &ArrayView1<Float>,
151        pd_values: &ArrayView1<Float>,
152        feature_name: &str,
153        ice_curves: Option<&ArrayView2<Float>>,
154    ) -> SklResult<PartialDependencePlot> {
155        create_partial_dependence_plot(
156            feature_values,
157            pd_values,
158            ice_curves,
159            feature_name,
160            &self.default_config,
161            ice_curves.is_some(),
162        )
163    }
164
165    /// Create 3D scatter plot with factory defaults
166    pub fn scatter_3d(
167        &self,
168        x_values: &ArrayView1<Float>,
169        y_values: &ArrayView1<Float>,
170        z_values: &ArrayView1<Float>,
171        axis_labels: (String, String, String),
172    ) -> SklResult<Plot3D> {
173        create_3d_plot(
174            x_values,
175            y_values,
176            z_values,
177            None, // color_values
178            None, // size_values
179            None, // point_labels
180            axis_labels,
181            &self.default_config,
182            Plot3DType::Scatter,
183        )
184    }
185
186    /// Create 3D surface plot with factory defaults
187    pub fn surface_3d(
188        &self,
189        x_grid: &ArrayView2<Float>,
190        y_grid: &ArrayView2<Float>,
191        z_surface: &ArrayView2<Float>,
192        axis_labels: (String, String, String),
193    ) -> SklResult<Surface3D> {
194        create_3d_surface_plot(
195            x_grid,
196            y_grid,
197            z_surface,
198            None, // color_map
199            axis_labels,
200            &self.default_config,
201            1.0, // opacity
202        )
203    }
204}
205
206impl Default for VisualizationFactory {
207    fn default() -> Self {
208        Self::new()
209    }
210}
211
212/// Convenience functions for common visualization tasks
213pub mod convenience {
214    use super::*;
215
216    /// Quick feature importance bar chart
217    pub fn quick_feature_importance(
218        importance_values: &ArrayView1<Float>,
219        feature_names: &[String],
220    ) -> SklResult<FeatureImportancePlot> {
221        let config = PlotConfigBuilder::new()
222            .title("Feature Importance")
223            .x_label("Features")
224            .y_label("Importance")
225            .build();
226
227        create_feature_importance_plot(
228            importance_values,
229            Some(feature_names),
230            None,
231            &config,
232            FeatureImportanceType::Bar,
233        )
234    }
235
236    /// Quick SHAP summary plot
237    pub fn quick_shap_summary(
238        shap_values: &ArrayView2<Float>,
239        feature_values: &ArrayView2<Float>,
240        feature_names: &[String],
241    ) -> SklResult<ShapPlot> {
242        let config = PlotConfigBuilder::new()
243            .title("SHAP Summary")
244            .x_label("SHAP Value")
245            .y_label("Features")
246            .build();
247
248        create_shap_summary_plot(
249            shap_values,
250            feature_values,
251            Some(feature_names),
252            &config,
253            true,
254        )
255    }
256
257    /// Quick 3D scatter with auto-generated labels
258    pub fn quick_scatter_3d(
259        x_values: Array1<Float>,
260        y_values: Array1<Float>,
261        z_values: Array1<Float>,
262    ) -> SklResult<Plot3D> {
263        create_3d_plot(
264            &x_values.view(),
265            &y_values.view(),
266            &z_values.view(),
267            None,
268            None,
269            None,
270            ("X".to_string(), "Y".to_string(), "Z".to_string()),
271            &PlotConfig::default(),
272            Plot3DType::Scatter,
273        )
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use super::*;
280    use approx::assert_relative_eq;
281    use scirs2_core::ndarray::array;
282    use sklears_core::prelude::Array2;
283
284    #[test]
285    fn test_visualization_factory() {
286        let factory = VisualizationFactory::new();
287        assert_eq!(factory.default_config.title, "Visualization");
288        assert_eq!(factory.default_config.width, 800);
289        assert_eq!(factory.default_config.height, 600);
290    }
291
292    #[test]
293    fn test_factory_feature_importance() {
294        let factory = VisualizationFactory::new();
295        let importance = array![0.8, 0.6, 0.4, 0.2];
296        let feature_names = vec![
297            "feature_1".to_string(),
298            "feature_2".to_string(),
299            "feature_3".to_string(),
300            "feature_4".to_string(),
301        ];
302
303        let plot = factory
304            .feature_importance(
305                &importance.view(),
306                Some(&feature_names),
307                FeatureImportanceType::Bar,
308            )
309            .expect("operation should succeed");
310
311        assert_eq!(plot.feature_names.len(), 4);
312        assert_eq!(plot.importance_values.len(), 4);
313        assert_relative_eq!(plot.importance_values[0], 0.8, epsilon = 1e-10);
314    }
315
316    #[test]
317    fn test_factory_3d_scatter() {
318        let factory = VisualizationFactory::new();
319        let x = array![1.0, 2.0, 3.0];
320        let y = array![1.0, 2.0, 3.0];
321        let z = array![1.0, 2.0, 3.0];
322
323        let plot = factory
324            .scatter_3d(
325                &x.view(),
326                &y.view(),
327                &z.view(),
328                ("X".to_string(), "Y".to_string(), "Z".to_string()),
329            )
330            .expect("operation should succeed");
331
332        assert_eq!(plot.x_values.len(), 3);
333        assert_eq!(plot.y_values.len(), 3);
334        assert_eq!(plot.z_values.len(), 3);
335        assert_eq!(plot.axis_labels.0, "X");
336    }
337
338    #[test]
339    fn test_convenience_functions() {
340        let importance = array![0.5, 0.3, 0.2];
341        let feature_names = vec!["A".to_string(), "B".to_string(), "C".to_string()];
342
343        let plot = convenience::quick_feature_importance(&importance.view(), &feature_names)
344            .expect("operation should succeed");
345        assert_eq!(plot.feature_names.len(), 3);
346        assert_eq!(plot.config.title, "Feature Importance");
347
348        let x = array![1.0, 2.0];
349        let y = array![1.0, 2.0];
350        let z = array![1.0, 2.0];
351        let plot_3d = convenience::quick_scatter_3d(x, y, z).expect("operation should succeed");
352        assert_eq!(plot_3d.x_values.len(), 2);
353    }
354
355    #[test]
356    fn test_module_integration() {
357        // Test that all modules work together
358        let mut visualizer = InteractiveVisualizer::new();
359        visualizer.enable_real_time_updates();
360
361        let config = PlotConfigBuilder::new()
362            .title("Integration Test")
363            .color_scheme(ColorScheme::Viridis)
364            .build();
365
366        visualizer.set_plot_config("test_plot".to_string(), config);
367
368        let data = Array2::<f64>::zeros((10, 2));
369        visualizer.update_plot_data("test_plot", &data);
370
371        assert!(visualizer.is_real_time_enabled());
372        assert_eq!(visualizer.plot_count(), 1);
373    }
374
375    #[test]
376    fn test_simd_integration() {
377        // Test SIMD operations integration
378        let data = array![1.0, 2.0, 3.0, 4.0, 5.0];
379        let normalized = simd_normalize_data(&data.to_vec(), 0.0, 1.0);
380
381        assert_eq!(normalized.len(), 5);
382        assert_relative_eq!(normalized[0], 0.0, epsilon = 1e-10);
383        assert_relative_eq!(normalized[4], 1.0, epsilon = 1e-10);
384
385        let grid = simd_generate_grid_range(0.0, 10.0, 11);
386        assert_eq!(grid.len(), 11);
387        assert_relative_eq!(grid[0], 0.0, epsilon = 1e-10);
388        assert_relative_eq!(grid[10], 10.0, epsilon = 1e-10);
389    }
390}