| """ |
| Enhanced investor-grade visualizations |
| """ |
|
|
| 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() |
| |
| |
| 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_map = { |
| "problem": self.theme["critical"], |
| "alert": self.theme["warning"], |
| "detection": self.theme["info"], |
| "analysis": "#9B59B6", |
| "action": self.theme["success"], |
| "recovery": "#2ECC71" |
| } |
| |
| |
| 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="<b>%{text}</b><br>Click for details<extra></extra>" |
| )) |
| |
| |
| 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="<b>Interactive Incident Timeline</b><br><sup>Click events for details</sup>", |
| 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""" |
| fig = make_subplots( |
| rows=2, cols=2, |
| subplot_titles=( |
| '<b>Cost Transformation</b>', |
| '<b>Team Capacity Shift</b>', |
| '<b>MTTR Comparison</b>', |
| '<b>ROI Analysis</b>' |
| ), |
| vertical_spacing=0.2, |
| horizontal_spacing=0.15 |
| ) |
| |
| |
| cost_labels = ['Without ARF', 'With ARF Enterprise', 'Net Savings'] |
| cost_values = [2.96, 1.0, 1.96] |
| |
| 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="<b>%{x}</b><br>Cost: $%{y}M<extra></extra>" |
| ), |
| row=1, col=1 |
| ) |
| |
| |
| 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}%%<extra></extra>" |
| ), |
| 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}%%<extra></extra>" |
| ), |
| row=1, col=2 |
| ) |
| |
| |
| 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="<b>%{x}</b><br>Resolution: %{y} min<extra></extra>" |
| ), |
| row=2, col=1 |
| ) |
| |
| |
| roi_value = user_roi.get('roi_multiplier', 5.2) if user_roi else 5.2 |
| |
| fig.add_trace( |
| go.Indicator( |
| mode="gauge+number+delta", |
| value=roi_value, |
| title={'text': "<b>ROI Multiplier</b>", '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 |
| ) |
| |
| |
| fig.update_layout( |
| height=700, |
| showlegend=True, |
| paper_bgcolor=self.theme["background"], |
| plot_bgcolor=self.theme["background"], |
| title_text="<b>Executive Business Dashboard</b>", |
| barmode='group', |
| legend=dict( |
| yanchor="top", |
| y=0.99, |
| xanchor="left", |
| x=0.01, |
| bgcolor='rgba(255,255,255,0.9)' |
| ) |
| ) |
| |
| |
| 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 |