petter2025's picture
Update core/visualizations.py
fe961b9 verified
raw
history blame
16.4 kB
"""
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": "<b>ROI Multiplier</b><br>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<br>"
f"<span style='font-size: 14px; color: #6b7280'>"
f"Total: {total_manual:.0f}m manual vs {total_arf:.0f}m ARF "
f"({((total_manual - total_arf) / total_manual * 100):.0f}% faster)</span>",
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"])