1use scirs2_core::ndarray::Array1;
7use sklears_core::{error::Result as SklResult, types::Float};
8use std::collections::HashMap;
9use std::time::Duration;
10
11pub struct PipelineVisualizer {
13 config: VisualizationConfig,
15 graph: PipelineGraph,
17 renderer: Box<dyn RenderingEngine>,
19 export_formats: Vec<ExportFormat>,
21}
22
23#[derive(Debug, Clone)]
25pub struct GraphNode {
26 pub id: String,
28 pub node_type: String,
30 pub name: String,
32 pub parameters: HashMap<String, ParameterValue>,
34 pub inputs: Vec<IoSpecification>,
36 pub outputs: Vec<IoSpecification>,
38 pub visual_properties: VisualProperties,
40}
41
42#[derive(Debug, Clone)]
44pub struct VisualProperties {
45 pub color: Color,
47 pub shape: NodeShape,
49 pub size: NodeSize,
51 pub font: FontProperties,
53}
54
55#[derive(Debug, Clone)]
57pub enum NodeShape {
58 Rectangle,
60 Circle,
62 Diamond,
64 Ellipse,
66 RoundedRectangle,
68}
69
70#[derive(Debug, Clone)]
72pub enum NodeSize {
73 Small,
75 Medium,
77 Large,
79 Custom { width: f64, height: f64 },
81}
82
83#[derive(Debug, Clone)]
85pub struct FontProperties {
86 pub family: String,
88 pub size: f64,
90 pub weight: FontWeight,
92 pub color: Color,
94}
95
96#[derive(Debug, Clone)]
98pub enum FontWeight {
99 Normal,
101 Bold,
103 Light,
105}
106
107pub struct PipelineGraph {
109 nodes: Vec<GraphNode>,
111 edges: Vec<GraphEdge>,
113 layout: GraphLayout,
115}
116
117#[derive(Debug, Clone)]
119pub struct VisualizationConfig {
120 pub theme: VisualizationTheme,
122 pub layout_algorithm: LayoutAlgorithm,
124 pub interactive: bool,
126 pub show_metrics: bool,
128 pub animation: AnimationConfig,
130}
131
132#[derive(Debug, Clone)]
134pub enum VisualizationTheme {
135 Light,
137 Dark,
139 HighContrast,
141 Custom(CustomTheme),
143}
144
145#[derive(Debug, Clone)]
147pub struct CustomTheme {
148 pub background_color: Color,
150 pub node_colors: HashMap<String, Color>,
152 pub edge_color: Color,
154 pub text_color: Color,
156 pub accent_colors: Vec<Color>,
158}
159
160#[derive(Debug, Clone)]
162pub struct Color {
163 pub r: u8,
164 pub g: u8,
165 pub b: u8,
166 pub a: f32,
167}
168
169#[derive(Debug, Clone)]
171pub enum LayoutAlgorithm {
172 ForceDirected,
174 Hierarchical,
176 Circular,
178 Grid,
180 Manual,
182}
183
184#[derive(Debug, Clone)]
186pub struct AnimationConfig {
187 pub enabled: bool,
189 pub duration: Duration,
191 pub easing: EasingFunction,
193 pub animate_data_flow: bool,
195}
196
197#[derive(Debug, Clone)]
199pub enum EasingFunction {
200 Linear,
202 EaseIn,
204 EaseOut,
206 EaseInOut,
208 Bounce,
210 Elastic,
212}
213
214#[derive(Debug, Clone)]
216pub struct GraphLayout {
217 pub width: f64,
219 pub height: f64,
220 pub node_positions: HashMap<String, Position>,
222 pub edge_paths: HashMap<String, Vec<Position>>,
224 pub zoom: f64,
226 pub pan_offset: Position,
228}
229
230#[derive(Debug, Clone, Copy)]
232pub struct Position {
233 pub x: f64,
234 pub y: f64,
235}
236
237#[derive(Debug, Clone)]
239pub struct GraphEdge {
240 pub id: String,
242 pub from_node: String,
244 pub to_node: String,
246 pub properties: EdgeProperties,
248 pub data_flow: DataFlowInfo,
250}
251
252#[derive(Debug, Clone)]
254pub struct EdgeProperties {
255 pub color: Color,
257 pub thickness: f64,
259 pub style: EdgeStyle,
261 pub animated: bool,
263}
264
265#[derive(Debug, Clone)]
267pub enum EdgeStyle {
268 Solid,
270 Dashed,
272 Dotted,
274 DashDot,
276}
277
278#[derive(Debug, Clone)]
280pub struct DataFlowInfo {
281 pub shape: Vec<usize>,
283 pub dtype: String,
285 pub sample_data: Option<Array1<Float>>,
287 pub flow_rate: Option<f64>,
289}
290
291pub trait RenderingEngine: Send + Sync {
293 fn render(
295 &self,
296 graph: &PipelineGraph,
297 config: &VisualizationConfig,
298 ) -> SklResult<RenderedOutput>;
299
300 fn supported_formats(&self) -> Vec<ExportFormat>;
302
303 fn set_options(&mut self, options: RenderingOptions);
305}
306
307pub struct RenderedOutput {
309 pub data: Vec<u8>,
311 pub mime_type: String,
313 pub metadata: HashMap<String, String>,
315}
316
317#[derive(Debug, Clone)]
319pub enum ExportFormat {
320 SVG,
322 PNG,
324 JPEG,
326 PDF,
328 HTML,
330 JSON,
332}
333
334#[derive(Debug, Clone)]
336pub struct RenderingOptions {
337 pub resolution: (u32, u32),
339 pub quality: f64,
341 pub include_metadata: bool,
343 pub compression_level: u8,
345}
346
347impl PipelineVisualizer {
348 #[must_use]
350 pub fn new(config: VisualizationConfig) -> Self {
351 Self {
352 config,
353 graph: PipelineGraph::new(),
354 renderer: Box::new(DefaultRenderingEngine::new()),
355 export_formats: vec![ExportFormat::SVG, ExportFormat::PNG, ExportFormat::HTML],
356 }
357 }
358
359 pub fn add_pipeline(&mut self, pipeline: &dyn PipelineComponent) -> SklResult<()> {
361 let nodes = self.extract_nodes(pipeline)?;
363 let edges = self.extract_edges(pipeline)?;
364
365 self.graph.nodes.extend(nodes);
366 self.graph.edges.extend(edges);
367
368 Ok(())
369 }
370
371 pub fn visualize(&self) -> SklResult<RenderedOutput> {
373 self.renderer.render(&self.graph, &self.config)
374 }
375
376 pub fn export(&self, format: ExportFormat, path: &str) -> SklResult<()> {
378 let output = self.visualize()?;
379
380 std::fs::write(path, output.data)?;
382
383 Ok(())
384 }
385
386 fn extract_nodes(&self, _pipeline: &dyn PipelineComponent) -> SklResult<Vec<GraphNode>> {
388 Ok(Vec::new())
391 }
392
393 fn extract_edges(&self, _pipeline: &dyn PipelineComponent) -> SklResult<Vec<GraphEdge>> {
395 Ok(Vec::new())
398 }
399}
400
401pub trait PipelineComponent {
403 fn name(&self) -> &str;
405
406 fn component_type(&self) -> &str;
408
409 fn inputs(&self) -> Vec<IoSpecification>;
411
412 fn outputs(&self) -> Vec<IoSpecification>;
414
415 fn parameters(&self) -> HashMap<String, ParameterValue>;
417}
418
419#[derive(Debug, Clone)]
421pub struct IoSpecification {
422 pub name: String,
424 pub data_spec: DataSpecification,
426 pub optional: bool,
428}
429
430#[derive(Debug, Clone)]
432pub struct DataSpecification {
433 pub dtype: DataType,
435 pub shape: ShapeSpecification,
437 pub value_range: Option<(Float, Float)>,
439}
440
441#[derive(Debug, Clone)]
443pub enum DataType {
444 Float32,
446 Float64,
448 Int32,
450 Int64,
452 Boolean,
454 String,
456 Object,
458}
459
460#[derive(Debug, Clone)]
462pub enum ShapeSpecification {
463 Fixed(Vec<usize>),
465 Variable { min_dims: usize, max_dims: usize },
467 Scalar,
469 Unknown,
471}
472
473#[derive(Debug, Clone)]
475pub enum ParameterValue {
476 String(String),
478 Integer(i64),
480 Float(f64),
482 Boolean(bool),
484 Array(Vec<Float>),
486}
487
488impl Default for PipelineGraph {
489 fn default() -> Self {
490 Self::new()
491 }
492}
493
494impl PipelineGraph {
495 #[must_use]
497 pub fn new() -> Self {
498 Self {
499 nodes: Vec::new(),
500 edges: Vec::new(),
501 layout: GraphLayout::default(),
502 }
503 }
504
505 pub fn add_node(&mut self, node: GraphNode) {
507 self.nodes.push(node);
508 }
509
510 pub fn add_edge(&mut self, edge: GraphEdge) {
512 self.edges.push(edge);
513 }
514
515 #[must_use]
517 pub fn nodes_by_type(&self, node_type: &str) -> Vec<&GraphNode> {
518 self.nodes
519 .iter()
520 .filter(|n| n.node_type.as_str() == node_type)
521 .collect()
522 }
523}
524
525impl Default for GraphLayout {
526 fn default() -> Self {
527 Self {
528 width: 800.0,
529 height: 600.0,
530 node_positions: HashMap::new(),
531 edge_paths: HashMap::new(),
532 zoom: 1.0,
533 pan_offset: Position { x: 0.0, y: 0.0 },
534 }
535 }
536}
537
538pub struct DefaultRenderingEngine {
540 options: RenderingOptions,
541}
542
543impl Default for DefaultRenderingEngine {
544 fn default() -> Self {
545 Self::new()
546 }
547}
548
549impl DefaultRenderingEngine {
550 #[must_use]
552 pub fn new() -> Self {
553 Self {
554 options: RenderingOptions {
555 resolution: (800, 600),
556 quality: 0.9,
557 include_metadata: true,
558 compression_level: 6,
559 },
560 }
561 }
562}
563
564impl RenderingEngine for DefaultRenderingEngine {
565 fn render(
566 &self,
567 _graph: &PipelineGraph,
568 _config: &VisualizationConfig,
569 ) -> SklResult<RenderedOutput> {
570 Ok(RenderedOutput {
572 data: b"<svg></svg>".to_vec(),
573 mime_type: "image/svg+xml".to_string(),
574 metadata: HashMap::new(),
575 })
576 }
577
578 fn supported_formats(&self) -> Vec<ExportFormat> {
579 vec![ExportFormat::SVG, ExportFormat::PNG, ExportFormat::HTML]
580 }
581
582 fn set_options(&mut self, options: RenderingOptions) {
583 self.options = options;
584 }
585}