""" Enhanced investor-grade visualizations - FIXED VERSION """ import plotly.graph_objects as go import plotly.express as px import pandas as pd import numpy as np from plotly.subplots import make_subplots from datetime import datetime from typing import Dict, Optional, List from core.data_models import IncidentScenario class EnhancedVisualizationEngine: """Interactive, investor-grade visualizations""" def __init__(self): self.color_palette = px.colors.qualitative.Set3 self.theme = { "background": "rgba(0,0,0,0)", "grid": "rgba(200,200,200,0.1)", "critical": "#FF6B6B", "warning": "#FFE66D", "success": "#4ECDC4", "info": "#45B7D1" } def create_interactive_timeline(self, scenario: IncidentScenario) -> go.Figure: """Create truly interactive timeline with annotations""" fig = go.Figure() # Create timeline events events = [ {"time": "T-5m", "event": "📉 Cache hit rate drops below 20%", "type": "problem"}, {"time": "T-4m", "event": "⚠️ Database load exceeds 90%", "type": "alert"}, {"time": "T-3m", "event": "🤖 ARF detects pattern", "type": "detection"}, {"time": "T-2m", "event": "🧠 Analysis complete", "type": "analysis"}, {"time": "T-1m", "event": "⚡ Healing executed", "type": "action"}, {"time": "T-0m", "event": "✅ System recovered", "type": "recovery"} ] # Color mapping color_map = { "problem": self.theme["critical"], "alert": self.theme["warning"], "detection": self.theme["info"], "analysis": "#9B59B6", "action": self.theme["success"], "recovery": "#2ECC71" } # Add events for event in events: fig.add_trace(go.Scatter( x=[event["time"]], y=[1], mode='markers+text', marker=dict( size=20, color=color_map[event["type"]], symbol='circle', line=dict(width=2, color='white') ), text=[event["event"]], textposition="top center", hoverinfo='text', name=event["type"].capitalize(), hovertemplate="%{text}
Click for details" )) # Add connecting line fig.add_trace(go.Scatter( x=[e["time"] for e in events], y=[1] * len(events), mode='lines', line=dict(color='gray', width=2, dash='dash'), hoverinfo='none', showlegend=False )) fig.update_layout( title="Interactive Incident Timeline
Click events for details", height=450, paper_bgcolor=self.theme["background"], plot_bgcolor=self.theme["background"], hovermode='closest', clickmode='event+select', yaxis=dict( showticklabels=False, range=[0.5, 1.5], gridcolor=self.theme["grid"] ), xaxis=dict( gridcolor=self.theme["grid"] ), showlegend=True, legend=dict( yanchor="top", y=0.99, xanchor="left", x=0.01 ) ) return fig def create_executive_dashboard(self, user_roi: Optional[Dict] = None) -> go.Figure: """Create comprehensive executive dashboard - FIXED VERSION""" # FIX: Handle None or empty user_roi if user_roi is None: user_roi = {} # Get ROI value safely roi_value = user_roi.get('roi_multiplier', 5.2) # If roi_value is a string with "×", convert it if isinstance(roi_value, str): if "×" in roi_value: try: roi_value = float(roi_value.replace("×", "")) except: roi_value = 5.2 else: try: roi_value = float(roi_value) except: roi_value = 5.2 fig = make_subplots( rows=2, cols=2, subplot_titles=( 'Cost Transformation', 'Team Capacity Shift', 'MTTR Comparison', 'ROI Analysis' ), vertical_spacing=0.2, horizontal_spacing=0.15 ) # 1. Cost Transformation cost_labels = ['Without ARF', 'With ARF Enterprise', 'Net Savings'] cost_values = [2.96, 1.0, 1.96] # In millions fig.add_trace( go.Bar( x=cost_labels, y=cost_values, marker_color=[self.theme["critical"], self.theme["success"], '#45B7D1'], text=[f'${v}M' for v in cost_values], textposition='auto', name='Annual Cost', hovertemplate="%{x}
Cost: $%{y}M" ), row=1, col=1 ) # 2. Team Capacity Shift activities = ['Firefighting', 'Innovation', 'Strategic Work'] before = [60, 20, 20] after = [10, 60, 30] fig.add_trace( go.Bar( x=activities, y=before, name='Before ARF', marker_color=self.theme["critical"], opacity=0.7, hovertemplate="Before: %{y}%%" ), row=1, col=2 ) fig.add_trace( go.Bar( x=activities, y=after, name='After ARF Enterprise', marker_color=self.theme["success"], opacity=0.7, hovertemplate="After: %{y}%%" ), row=1, col=2 ) # 3. MTTR Comparison mttr_methods = ['Manual', 'Traditional', 'ARF OSS', 'ARF Enterprise'] mttr_times = [120, 45, 25, 8] fig.add_trace( go.Bar( x=mttr_methods, y=mttr_times, marker_color=[self.theme["critical"], '#FFE66D', '#45B7D1', self.theme["success"]], text=[f'{t} min' for t in mttr_times], textposition='auto', name='MTTR', hovertemplate="%{x}
Resolution: %{y} min" ), row=2, col=1 ) # 4. ROI Gauge fig.add_trace( go.Indicator( mode="gauge+number+delta", value=roi_value, title={'text': "ROI Multiplier", 'font': {'size': 16}}, delta={'reference': 1.0, 'increasing': {'color': self.theme["success"]}}, gauge={ 'axis': {'range': [0, 10], 'tickwidth': 1}, 'bar': {'color': self.theme["success"]}, 'steps': [ {'range': [0, 2], 'color': 'lightgray'}, {'range': [2, 4], 'color': 'gray'}, {'range': [4, 6], 'color': 'lightgreen'}, {'range': [6, 10], 'color': self.theme["success"]} ], 'threshold': { 'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': roi_value } } ), row=2, col=2 ) # Update layout fig.update_layout( height=700, showlegend=True, paper_bgcolor=self.theme["background"], plot_bgcolor=self.theme["background"], title_text="Executive Business Dashboard", barmode='group', legend=dict( yanchor="top", y=0.99, xanchor="left", x=0.01, bgcolor='rgba(255,255,255,0.9)' ) ) # Update axes fig.update_xaxes(title_text="Cost Model", row=1, col=1, gridcolor=self.theme["grid"]) fig.update_yaxes(title_text="Annual Cost ($M)", row=1, col=1, gridcolor=self.theme["grid"]) fig.update_xaxes(title_text="Activity", row=1, col=2, gridcolor=self.theme["grid"]) fig.update_yaxes(title_text="Time Allocation (%)", row=1, col=2, gridcolor=self.theme["grid"]) fig.update_xaxes(title_text="Resolution Method", row=2, col=1, gridcolor=self.theme["grid"]) fig.update_yaxes(title_text="Minutes to Resolve", row=2, col=1, gridcolor=self.theme["grid"]) return fig