""" Enhanced visualization engine for ARF Demo """ import plotly.graph_objects as go import plotly.express as px import numpy as np import pandas as pd from typing import Dict, List, Any, Optional import logging logger = logging.getLogger(__name__) class EnhancedVisualizationEngine: """Enhanced visualization engine with multiple chart types""" def __init__(self): self.color_palette = { "primary": "#3b82f6", "success": "#10b981", "warning": "#f59e0b", "danger": "#ef4444", "info": "#8b5cf6", "dark": "#1e293b", "light": "#f8fafc" } def create_executive_dashboard(self, data: Optional[Dict] = None) -> go.Figure: """Create executive dashboard with ROI visualization""" if data is None: data = {"roi_multiplier": 5.2} roi_multiplier = data.get("roi_multiplier", 5.2) # Create a multi-panel executive dashboard fig = go.Figure() # Main ROI gauge fig.add_trace(go.Indicator( mode="number+gauge", value=roi_multiplier, title={"text": "ROI Multiplier
Investment Return"}, domain={'x': [0.25, 0.75], 'y': [0.6, 1]}, gauge={ 'axis': {'range': [0, 10], 'tickwidth': 1}, 'bar': {'color': self.color_palette["success"]}, 'steps': [ {'range': [0, 2], 'color': '#e5e7eb'}, {'range': [2, 4], 'color': '#d1d5db'}, {'range': [4, 6], 'color': '#10b981'}, {'range': [6, 10], 'color': '#059669'} ], 'threshold': { 'line': {'color': "black", 'width': 4}, 'thickness': 0.75, 'value': roi_multiplier } } )) # Add secondary metrics as subplots fig.add_trace(go.Indicator( mode="number", value=85, title={"text": "MTTR Reduction"}, number={'suffix': "%", 'font': {'size': 24}}, domain={'x': [0.1, 0.4], 'y': [0.2, 0.5]} )) fig.add_trace(go.Indicator( mode="number", value=94, title={"text": "Detection Accuracy"}, number={'suffix': "%", 'font': {'size': 24}}, domain={'x': [0.6, 0.9], 'y': [0.2, 0.5]} )) fig.update_layout( height=700, paper_bgcolor="rgba(0,0,0,0)", plot_bgcolor="rgba(0,0,0,0)", font={'family': "Arial, sans-serif"}, margin=dict(t=50, b=50, l=50, r=50) ) return fig def create_telemetry_plot(self, scenario_name: str, anomaly_detected: bool = True) -> go.Figure: """Create telemetry plot for a scenario""" # Generate realistic telemetry data time_points = np.arange(0, 100, 1) # Different patterns for different scenarios if "Cache" in scenario_name: base_data = 100 + 50 * np.sin(time_points * 0.2) noise = np.random.normal(0, 8, 100) metric_name = "Cache Hit Rate (%)" normal_range = (70, 95) elif "Database" in scenario_name: base_data = 70 + 30 * np.sin(time_points * 0.15) noise = np.random.normal(0, 6, 100) metric_name = "Connection Pool Usage" normal_range = (20, 60) elif "Memory" in scenario_name: base_data = 50 + 40 * np.sin(time_points * 0.1) noise = np.random.normal(0, 10, 100) metric_name = "Memory Usage (%)" normal_range = (40, 80) else: base_data = 80 + 20 * np.sin(time_points * 0.25) noise = np.random.normal(0, 5, 100) metric_name = "System Load" normal_range = (50, 90) data = base_data + noise fig = go.Figure() if anomaly_detected: # Normal operation fig.add_trace(go.Scatter( x=time_points[:70], y=data[:70], mode='lines', name='Normal Operation', line=dict(color=self.color_palette["primary"], width=3), fill='tozeroy', fillcolor='rgba(59, 130, 246, 0.1)' )) # Anomaly period fig.add_trace(go.Scatter( x=time_points[70:], y=data[70:], mode='lines', name='Anomaly Detected', line=dict(color=self.color_palette["danger"], width=3, dash='dash'), fill='tozeroy', fillcolor='rgba(239, 68, 68, 0.1)' )) # Add detection point fig.add_vline( x=70, line_dash="dash", line_color=self.color_palette["success"], annotation_text="ARF Detection", annotation_position="top" ) else: # All normal fig.add_trace(go.Scatter( x=time_points, y=data, mode='lines', name=metric_name, line=dict(color=self.color_palette["primary"], width=3), fill='tozeroy', fillcolor='rgba(59, 130, 246, 0.1)' )) # Add normal range fig.add_hrect( y0=normal_range[0], y1=normal_range[1], fillcolor="rgba(16, 185, 129, 0.1)", opacity=0.2, line_width=0, annotation_text="Normal Range", annotation_position="top left" ) fig.update_layout( title=f"📈 {metric_name} - Live Telemetry", xaxis_title="Time (minutes)", yaxis_title=metric_name, height=300, margin=dict(l=20, r=20, t=50, b=20), plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', legend=dict( orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1 ) ) return fig def create_impact_gauge(self, scenario_name: str) -> go.Figure: """Create business impact gauge""" impact_map = { "Cache Miss Storm": {"revenue": 8500, "severity": "critical"}, "Database Connection Pool Exhaustion": {"revenue": 4200, "severity": "high"}, "Kubernetes Memory Leak": {"revenue": 5500, "severity": "high"}, "API Rate Limit Storm": {"revenue": 3800, "severity": "medium"}, "Network Partition": {"revenue": 12000, "severity": "critical"}, "Storage I/O Saturation": {"revenue": 6800, "severity": "high"} } impact = impact_map.get(scenario_name, {"revenue": 5000, "severity": "medium"}) fig = go.Figure(go.Indicator( mode="gauge+number", value=impact["revenue"], title={'text': "💰 Hourly Revenue Risk", 'font': {'size': 16}}, number={'prefix': "$", 'font': {'size': 28}}, gauge={ 'axis': {'range': [0, 15000], 'tickwidth': 1}, 'bar': {'color': self._get_severity_color(impact["severity"])}, 'steps': [ {'range': [0, 3000], 'color': '#10b981'}, {'range': [3000, 7000], 'color': '#f59e0b'}, {'range': [7000, 15000], 'color': '#ef4444'} ], 'threshold': { 'line': {'color': "black", 'width': 4}, 'thickness': 0.75, 'value': impact["revenue"] } } )) fig.update_layout( height=300, margin=dict(l=20, r=20, t=50, b=20), paper_bgcolor='rgba(0,0,0,0)' ) return fig def create_agent_performance_chart(self) -> go.Figure: """Create agent performance comparison chart""" agents = ["Detection", "Recall", "Decision"] accuracy = [98.7, 92.0, 94.0] speed = [45, 30, 60] # seconds confidence = [99.8, 92.0, 94.0] fig = go.Figure(data=[ go.Bar(name='Accuracy (%)', x=agents, y=accuracy, marker_color=self.color_palette["primary"]), go.Bar(name='Speed (seconds)', x=agents, y=speed, marker_color=self.color_palette["success"]), go.Bar(name='Confidence (%)', x=agents, y=confidence, marker_color=self.color_palette["info"]) ]) fig.update_layout( title="🤖 Agent Performance Metrics", barmode='group', height=400, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', legend=dict( orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1 ) ) return fig def create_timeline_comparison(self) -> go.Figure: """Create timeline comparison chart""" phases = ["Detection", "Analysis", "Decision", "Execution", "Recovery"] manual_times = [300, 1800, 1200, 1800, 3600] # seconds arf_times = [45, 30, 60, 720, 0] # Convert to minutes for readability manual_times_min = [t/60 for t in manual_times] arf_times_min = [t/60 for t in arf_times] fig = go.Figure() fig.add_trace(go.Bar( name='Manual Process', x=phases, y=manual_times_min, marker_color=self.color_palette["danger"], text=[f"{t:.0f}m" for t in manual_times_min], textposition='auto' )) fig.add_trace(go.Bar( name='ARF Autonomous', x=phases, y=arf_times_min, marker_color=self.color_palette["success"], text=[f"{t:.0f}m" for t in arf_times_min], textposition='auto' )) total_manual = sum(manual_times_min) total_arf = sum(arf_times_min) fig.update_layout( title=f"⏰ Incident Timeline Comparison
" f"" f"Total: {total_manual:.0f}m manual vs {total_arf:.0f}m ARF " f"({((total_manual - total_arf) / total_manual * 100):.0f}% faster)", barmode='group', height=400, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', legend=dict( orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1 ), yaxis_title="Time (minutes)" ) return fig def create_roi_simulation_chart(self, roi_data: Dict) -> go.Figure: """Create ROI simulation chart""" scenarios = ["Worst Case", "Base Case", "Best Case"] roi_values = [ roi_data.get("worst_case", 4.0), roi_data.get("base_case", 5.2), roi_data.get("best_case", 6.5) ] fig = go.Figure(go.Bar( x=scenarios, y=roi_values, marker_color=[ self.color_palette["warning"], self.color_palette["success"], self.color_palette["primary"] ], text=[f"{v:.1f}×" for v in roi_values], textposition='auto' )) fig.update_layout( title="📊 ROI Simulation Scenarios", yaxis_title="ROI Multiplier", height=400, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', yaxis=dict(range=[0, max(roi_values) * 1.2]) ) # Add industry average line fig.add_hline( y=5.2, line_dash="dash", line_color="gray", annotation_text="Industry Average", annotation_position="top right" ) return fig def create_learning_graph(self, graph_type: str = "patterns") -> go.Figure: """Create learning engine visualization""" if graph_type == "patterns": return self._create_pattern_graph() elif graph_type == "dependencies": return self._create_dependency_graph() else: return self._create_action_graph() def _create_pattern_graph(self) -> go.Figure: """Create pattern recognition graph""" nodes = ["Cache Miss", "DB Pool", "Memory Leak", "API Limit", "Network"] connections = [ ("Cache Miss", "DB Pool", 0.85), ("DB Pool", "Memory Leak", 0.72), ("Memory Leak", "API Limit", 0.65), ("API Limit", "Network", 0.58), ("Cache Miss", "Network", 0.45) ] fig = go.Figure() # Add nodes for node in nodes: fig.add_trace(go.Scatter( x=[np.random.random()], y=[np.random.random()], mode='markers+text', name=node, marker=dict(size=30, color=self.color_palette["primary"]), text=[node], textposition="top center" )) # Add edges for src, dst, weight in connections: fig.add_trace(go.Scatter( x=[np.random.random(), np.random.random()], y=[np.random.random(), np.random.random()], mode='lines', line=dict(width=weight * 5, color='gray'), showlegend=False )) fig.update_layout( title="🧠 RAG Memory - Incident Pattern Graph", height=500, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', showlegend=False, xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False) ) return fig def _create_dependency_graph(self) -> go.Figure: """Create system dependency graph""" fig = go.Figure(go.Sunburst( labels=["System", "Cache", "Database", "API", "User Service", "Payment"], parents=["", "System", "System", "System", "API", "API"], values=[100, 30, 40, 30, 15, 15], marker=dict(colors=px.colors.sequential.Blues) )) fig.update_layout( title="🔗 System Dependency Map", height=500, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)' ) return fig def _create_action_graph(self) -> go.Figure: """Create action-outcome graph""" actions = ["Scale Cache", "Restart DB", "Limit API", "Monitor Memory"] success_rates = [87, 92, 78, 85] fig = go.Figure(go.Bar( x=actions, y=success_rates, marker_color=self.color_palette["success"], text=[f"{rate}%" for rate in success_rates], textposition='auto' )) fig.update_layout( title="🎯 Action Success Rates", yaxis_title="Success Rate (%)", height=400, plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)', yaxis=dict(range=[0, 100]) ) return fig def _get_severity_color(self, severity: str) -> str: """Get color for severity level""" color_map = { "critical": self.color_palette["danger"], "high": self.color_palette["warning"], "medium": self.color_palette["info"], "low": self.color_palette["success"] } return color_map.get(severity.lower(), self.color_palette["info"])