tostido's picture
download
raw
59.4 kB
"""
🎨 LIGHTWEIGHT VISUALIZATION VIEWER
This is a separate lightweight process that ONLY displays visualizations.
All computation happens in the backend - this just reads snapshots and displays them.
This dramatically reduces CPU usage because:
- No simulation computation
- No data processing
- Only matplotlib display updates
- Updates at a lower rate (e.g., every 2-5 frames)
"""
import time
import json
import os
import sys
import logging
from typing import Dict, Any, Optional, List
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.gridspec as gridspec
from matplotlib import colors as mcolors
import numpy as np
import tkinter as tk
from tkinter import ttk
logger = logging.getLogger(__name__)
# Import visualization modules (but they'll only render, not compute)
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
def get_project_root():
"""
Get the project root directory robustly.
Uses multiple detection methods in order of reliability:
1. Looks for marker files (config.json, .git, README.md) starting from script location
2. Falls back to corrected path calculation (1 level up from reality_simulator/)
3. Caches result for performance
Returns:
str: Absolute path to project root directory
"""
# Check cache first (performance optimization)
if hasattr(get_project_root, '_cached_root'):
return get_project_root._cached_root
# Get current script location
script_dir = os.path.dirname(os.path.abspath(__file__))
# reality_sim_dir = reality_simulator/ directory
reality_sim_dir = os.path.dirname(script_dir)
# For reality_simulator/visualization_viewer.py, the project root is reality_sim_dir's parent
# But we check multiple levels to be robust
marker_files = ['config.json', '.git', 'README.md', 'requirements.txt', 'LICENSE']
# Method 1: Check reality_sim_dir's parent (most common case)
# If script is at reality_simulator/visualization_viewer.py, project root is parent of reality_simulator/
potential_root = os.path.dirname(reality_sim_dir)
for marker in marker_files:
marker_path = os.path.join(potential_root, marker)
if os.path.exists(marker_path):
# Found marker file - this is the project root
get_project_root._cached_root = potential_root
return potential_root
# Method 2: Check reality_sim_dir itself (if config.json is in reality_simulator/)
for marker in marker_files:
marker_path = os.path.join(reality_sim_dir, marker)
if os.path.exists(marker_path):
get_project_root._cached_root = reality_sim_dir
return reality_sim_dir
# Method 3: Check potential_root's parent (if nested deeper)
parent_of_potential = os.path.dirname(potential_root)
for marker in marker_files:
marker_path = os.path.join(parent_of_potential, marker)
if os.path.exists(marker_path):
get_project_root._cached_root = parent_of_potential
return parent_of_potential
# Method 4: Last resort - use potential_root (corrected: only 1 level up, not 2)
# This matches the corrected calculation
if os.path.exists(potential_root):
get_project_root._cached_root = potential_root
return potential_root
# Method 5: Ultimate fallback
get_project_root._cached_root = reality_sim_dir
return reality_sim_dir
def read_visualization_data() -> Optional[Dict[str, Any]]:
"""Read visualization data from shared state file"""
try:
project_root = get_project_root()
shared_state_file = os.path.join(project_root, "data", ".shared_simulation_state.json")
logger.debug(f"Checking for file at: {shared_state_file}")
if os.path.exists(shared_state_file):
logger.debug("File exists, reading...")
with open(shared_state_file, 'r') as f:
shared_state = json.load(f)
timestamp = shared_state.get('timestamp', 0)
age = time.time() - timestamp
logger.debug(f"File timestamp: {timestamp}, age: {age:.1f}s")
has_viz_data = 'visualization_data' in shared_state
has_data = 'data' in shared_state
logger.debug(f"Has visualization_data: {has_viz_data}, has data: {has_data}")
# Check if data is recent (within last 60 seconds)
if age < 60.0: # Accept data up to 60 seconds old
result = shared_state.get('visualization_data', shared_state.get('data', {}))
logger.debug(f"Returning data with {len(result)} keys: {list(result.keys())}")
return result
else:
logger.debug(f"Data too old (age: {age:.1f}s > 60s)")
else:
logger.debug("File does not exist")
return None
except Exception as e:
logger.error(f"Error reading visualization data: {e}")
import traceback
traceback.print_exc()
return None
class LightweightVisualizationViewer:
"""Lightweight viewer that only displays pre-computed data"""
def __init__(self, update_interval: float = 0.5, precision_config: Dict[str, float] = None):
"""
Args:
update_interval: How often to update visualizations (seconds)
precision_config: Dictionary of precision values for different metrics
"""
self.update_interval = update_interval
self.last_update = 0
self.root = None
self.notebook = None
self.tab_figures = {} # Store figures for each tab
self.tab_axes = {} # Store axes for each tab
self.tab_canvases = {} # Store canvas widgets for each tab
self.tab_frames = {}
self.active_visualizations = [
"network_graph", "evolution_tree", "consciousness_gauge",
"performance_monitor", "particle_cloud"
]
self.network_layout_cache = {} # Cache network layouts to prevent jumping
self.grid_profiles = self._build_grid_profiles()
self.current_grid_profile_index = 0
self.grid_profile_button = None
self.last_visualization_data: Optional[Dict[str, Any]] = None
self.max_edges_to_plot = 2500
self.max_particles_to_plot = 1200
# Load precision configuration
self.precision_config = precision_config or {
'fitness': 0.000001,
'consciousness': 0.000001,
'performance_cpu': 0.0001,
'performance_fps': 10
}
plt.ion() # Interactive mode
def _build_grid_profiles(self) -> List[Dict[str, Any]]:
"""Define grid styling/metric profiles for the network graph."""
return [
{
"name": "Topology Matrix",
"description": "Connectivity & clustering emphasis",
"axis_color": "#00d1ff",
"grid_color": "#0094cc",
"pane_color": "#00141d",
"pane_alpha": 0.7,
"grid_alpha": 0.25,
"plane_color": "#004466",
"plane_alpha": 0.18,
"grid_lines": 6,
"metrics": [
{"label": "Connectivity", "path": "network.connectivity", "format": ".2f"},
{"label": "Avg Degree", "path": "derived.avg_degree", "format": ".2f"},
{"label": "Clustering", "path": "derived.clustering", "format": ".2f"}
]
},
{
"name": "Stability Field",
"description": "Network stability & Phi alignment",
"axis_color": "#56f39a",
"grid_color": "#50c878",
"pane_color": "#0b1a12",
"pane_alpha": 0.75,
"grid_alpha": 0.3,
"plane_color": "#1f4d2f",
"plane_alpha": 0.22,
"grid_lines": 5,
"metrics": [
{"label": "Stability", "path": "network.stability", "format": ".2f"},
{"label": "Phi Score", "path": "consciousness.last_analysis.overall_score", "format": ".2f"},
{"label": "Emergence", "path": "consciousness.last_analysis.metrics.emergence_confidence", "format": ".2f"}
]
},
{
"name": "Agency Flow",
"description": "Language integration & feedback",
"axis_color": "#ff5fd1",
"grid_color": "#c441ff",
"pane_color": "#190018",
"pane_alpha": 0.65,
"grid_alpha": 0.35,
"plane_color": "#3b003a",
"plane_alpha": 0.2,
"grid_lines": 5,
"metrics": [
{"label": "Language %", "path": "derived.language_ratio", "format": ".1%"},
{"label": "Connections", "path": "derived.connections", "format": ".0f"},
{"label": "Organisms", "path": "derived.organisms", "format": ".0f"}
]
}
]
def create_unified_window(self):
"""Create tabbed visualization window"""
try:
if len(self.active_visualizations) == 0:
return
# Create main tkinter window
self.root = tk.Tk()
self.root.title("Reality Simulator - Live Metrics")
self.root.geometry("600x600") # Square window, 50% smaller than original
# Create notebook for tabs
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Create a tab and figure for each visualization
for viz_name in self.active_visualizations:
# Create tab frame
tab_frame = ttk.Frame(self.notebook)
# Create matplotlib figure for this tab (reduced size, square format)
fig = plt.Figure(figsize=(6, 6), facecolor='black')
ax = fig.add_subplot(111)
# Store figure and axes
self.tab_figures[viz_name] = fig
self.tab_axes[viz_name] = ax
self.tab_frames[viz_name] = tab_frame
# Embed figure in tkinter frame
canvas = FigureCanvasTkAgg(fig, tab_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
# Add toolbar for navigation (zoom, pan, etc.)
toolbar = NavigationToolbar2Tk(canvas, tab_frame)
toolbar.update()
# Store canvas
self.tab_canvases[viz_name] = canvas
# Add tab with friendly name
tab_label = viz_name.replace('_', ' ').title()
self.notebook.add(tab_frame, text=tab_label)
if viz_name == "network_graph":
self._create_grid_profile_button(tab_frame)
logger.info("✅ Created tabbed visualization window")
except Exception as e:
logger.error(f"❌ Error creating window: {e}")
import traceback
traceback.print_exc()
def _create_grid_profile_button(self, tab_frame):
"""Place the grid profile cycle button on the network tab."""
if not self.grid_profiles:
return
button = tk.Button(
tab_frame,
text=self._grid_button_text(),
command=self.cycle_grid_profile,
bg="#050505",
fg="white",
activebackground="#1a1a1a",
activeforeground="white",
relief=tk.FLAT,
padx=12,
pady=6,
font=("Segoe UI", 9, "bold"),
cursor="hand2"
)
button.place(relx=0.02, rely=0.98, anchor='sw')
self.grid_profile_button = button
def _grid_button_text(self) -> str:
if not self.grid_profiles:
return "Grid Profiles"
profile = self.grid_profiles[self.current_grid_profile_index]
return f"Grid: {profile['name']}"
def cycle_grid_profile(self):
"""Cycle through available grid profiles and refresh the network view."""
if not self.grid_profiles:
return
self.current_grid_profile_index = (self.current_grid_profile_index + 1) % len(self.grid_profiles)
if self.grid_profile_button:
self.grid_profile_button.config(text=self._grid_button_text())
if self.last_visualization_data and "network_graph" in self.tab_axes:
self.render_network_graph(self.last_visualization_data, self.tab_axes["network_graph"])
if "network_graph" in self.tab_canvases:
self.tab_canvases["network_graph"].draw()
def _apply_grid_profile(self, ax, profile: Dict[str, Any]):
"""Apply axis/grid styling based on the active profile."""
if not profile or getattr(ax, 'name', '') != '3d':
return
pane_color = profile.get("pane_color", "#000000")
pane_alpha = profile.get("pane_alpha", 0.6)
grid_color = profile.get("grid_color", "#444444")
axis_color = profile.get("axis_color", "#ffffff")
grid_alpha = profile.get("grid_alpha", 0.2)
pane_rgba = mcolors.to_rgba(pane_color, pane_alpha)
# Matplotlib changed attributes from w_xaxis→xaxis; support both.
axes = []
for attr in ("w_xaxis", "xaxis"):
axis = getattr(ax, attr, None)
if axis:
axes.append(axis)
break
for attr in ("w_yaxis", "yaxis"):
axis = getattr(ax, attr, None)
if axis:
axes.append(axis)
break
for attr in ("w_zaxis", "zaxis"):
axis = getattr(ax, attr, None)
if axis:
axes.append(axis)
break
for axis in axes:
setter = getattr(axis, "set_pane_color", None)
if callable(setter):
setter(pane_rgba)
if hasattr(axis, "line"):
axis.line.set_color(axis_color)
axinfo = getattr(axis, "_axinfo", None)
if axinfo and "grid" in axinfo:
axinfo["grid"]["color"] = grid_color
axinfo["grid"]["alpha"] = grid_alpha
def _draw_profile_label(self, ax, profile: Dict[str, Any], data: Dict[str, Any], derived: Dict[str, Any]):
"""Render profile-specific metric labels."""
if not profile:
return
lines = [f"{profile['name']} Grid"]
description = profile.get("description")
if description:
lines.append(description)
for metric in profile.get("metrics", []):
label = metric.get("label", "Metric")
path = metric.get("path", "")
fmt = metric.get("format", ".2f")
value = self._get_metric_value(data, path, derived, default=0.0)
formatted = self._format_metric(value, fmt)
lines.append(f"{label}: {formatted}")
ax.text2D(
0.02,
0.02,
"\n".join(lines),
transform=ax.transAxes,
ha='left',
va='bottom',
fontsize=8,
color='white',
bbox=dict(facecolor='black', alpha=0.45, edgecolor='white', linewidth=0.5)
)
def _get_metric_value(self, data: Dict[str, Any], path: str, derived: Dict[str, Any], default: float = 0.0):
"""Fetch nested metric using dotted path with derived overrides."""
if not path:
return default
if path.startswith("derived."):
key = path.split(".", 1)[1]
return derived.get(key, default)
value = data
for part in path.split('.'):
if isinstance(value, dict):
value = value.get(part)
else:
return default
if value is None:
return default
if isinstance(value, (int, float, np.number)):
return float(value)
try:
return float(value)
except Exception:
return default
def _format_metric(self, value, fmt: str):
"""Format metric values with graceful fallback."""
try:
return format(value, fmt)
except Exception:
return str(value)
def _draw_profile_planes(self, ax, profile: Dict[str, Any], xs: list, ys: list, zs: list):
"""Render subtle grid planes for depth/contrast."""
if not profile or not xs:
return
plane_color = profile.get("plane_color", "#333333")
plane_alpha = profile.get("plane_alpha", 0.15)
grid_lines = max(3, int(profile.get("grid_lines", 5)))
x_min, x_max = min(xs), max(xs)
y_min, y_max = min(ys), max(ys)
z_min, z_max = min(zs), max(zs)
x_vals = np.linspace(x_min, x_max, grid_lines)
y_vals = np.linspace(y_min, y_max, grid_lines)
z_vals = np.linspace(z_min, z_max, grid_lines)
# XY plane at lowest Z
z_level = z_min - (z_max - z_min) * 0.05
for x in x_vals:
ax.plot([x, x], [y_min, y_max], [z_level, z_level], color=plane_color, alpha=plane_alpha, linewidth=0.8)
for y in y_vals:
ax.plot([x_min, x_max], [y, y], [z_level, z_level], color=plane_color, alpha=plane_alpha, linewidth=0.8)
# YZ plane at min X
x_level = x_min - (x_max - x_min) * 0.05
for y in y_vals:
ax.plot([x_level, x_level], [y, y], [z_min, z_max], color=plane_color, alpha=plane_alpha * 0.9, linewidth=0.8)
for z in z_vals:
ax.plot([x_level, x_level], [y_min, y_max], [z, z], color=plane_color, alpha=plane_alpha * 0.9, linewidth=0.8)
# XZ plane at max Y
y_level = y_max + (y_max - y_min) * 0.05
for x in x_vals:
ax.plot([x, x], [y_level, y_level], [z_min, z_max], color=plane_color, alpha=plane_alpha * 0.8, linewidth=0.8)
for z in z_vals:
ax.plot([x_min, x_max], [y_level, y_level], [z, z], color=plane_color, alpha=plane_alpha * 0.8, linewidth=0.8)
def render_network_graph(self, data: Dict[str, Any], ax):
"""Render network graph in interactive 3D with cached layout"""
try:
import networkx as nx
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 - ensures 3D support
# Ensure 3D axes for interactive rotation
if getattr(ax, 'name', '') != '3d':
fig = ax.figure
try:
fig.delaxes(ax)
except Exception:
pass
ax = fig.add_subplot(111, projection='3d')
self.tab_axes["network_graph"] = ax
ax.cla()
ax.set_facecolor('black')
network_data = data.get("network", {})
network_info = network_data.get("network", {})
num_orgs = network_info.get("organisms", 0)
num_conns = network_info.get("connections", 0)
if num_orgs > 0 and num_conns > 0:
# Reconstruct graph
G = nx.Graph()
for i in range(num_orgs):
G.add_node(i)
graph_edges = network_info.get('graph_edges', [])
if graph_edges and len(graph_edges) > self.max_edges_to_plot:
graph_edges = graph_edges[:self.max_edges_to_plot]
if graph_edges:
for edge in graph_edges:
if len(edge) >= 2:
G.add_edge(edge[0], edge[1])
else:
if num_conns > 0:
# Ring + a few random edges
for i in range(num_orgs):
G.add_edge(i, (i + 1) % num_orgs)
import random
random.seed(42)
added = num_orgs
while added < num_conns and added < num_orgs * 2:
n1, n2 = random.sample(range(num_orgs), 2)
if not G.has_edge(n1, n2):
G.add_edge(n1, n2)
added += 1
if len(G.nodes()) > 0:
# Cache 3D layout (prevents recompute & lag)
graph_key = ("3d", num_orgs, num_conns, tuple(sorted(G.edges())))
if graph_key not in self.network_layout_cache:
pos = nx.spring_layout(G, dim=3, k=1.2, iterations=50, seed=42)
self.network_layout_cache[graph_key] = pos
else:
pos = self.network_layout_cache[graph_key]
# Extract coordinates
xs = []
ys = []
zs = []
for n in G.nodes():
p = pos[n]
xs.append(p[0])
ys.append(p[1])
zs.append(p[2])
# Node colors (placeholder)
node_colors = [0.5 + 0.3 * (i % 3) / 3.0 for i in G.nodes()]
# Draw network (3D, interactive)
ax.scatter(xs, ys, zs, c=node_colors, cmap='plasma', s=20, alpha=0.9, edgecolors='white', linewidths=0.2)
# Draw edges
for i, j in G.edges():
p1, p2 = pos[i], pos[j]
ax.plot([p1[0], p2[0]], [p1[1], p2[1]], [p1[2], p2[2]], color='cyan', alpha=0.5, linewidth=0.7)
ax.set_title(f'Network Graph (3D) - {num_orgs} Organisms, {num_conns} Connections',
fontsize=12, fontweight='bold', color='white', pad=10)
ax.set_xticks([]); ax.set_yticks([]); ax.set_zticks([])
ax.set_box_aspect((1, 1, 1)) # Equal aspect
# Overlay key indicators (quantifies the plot)
try:
avg_deg = (2 * len(G.edges())) / max(1, len(G.nodes()))
clustering = nx.average_clustering(G)
except Exception:
avg_deg, clustering = 0.0, 0.0
language_connections = network_info.get('language_connections', 0)
language_ratio = (language_connections / max(1, len(G.edges()))) if len(G.edges()) else 0.0
# ==================================================================
# COMPREHENSIVE DIAGNOSTIC PANELS (utilizing empty space)
# ==================================================================
# Panel 1: TOP-LEFT - Network Topology Metrics
stability = network_data.get('stability', 0.0)
connectivity = network_data.get('connectivity', 0.0)
panel1_text = (
f"━━━ NETWORK TOPOLOGY ━━━\n"
f"Nodes: {len(G.nodes())}\n"
f"Edges: {len(G.edges())}\n"
f"Avg Degree: {avg_deg:.2f}\n"
f"Clustering: {clustering:.3f}\n"
f"Stability: {stability:.3f}\n"
f"Connectivity: {connectivity:.3f}"
)
ax.text2D(0.10, 0.90, panel1_text, transform=ax.transAxes,
ha='left', va='top', fontsize=8, color='cyan',
bbox=dict(facecolor='black', alpha=0.7, edgecolor='cyan', linewidth=1),
family='monospace')
# Panel 2: TOP-RIGHT - Neural & ML Insights
neural_data = data.get('neural', {})
ml_data = data.get('ml', {})
neural_enabled = neural_data.get('enabled', False)
ml_enabled = ml_data.get('enabled', False)
panel2_lines = ["━━━ NEURAL & ML ━━━"]
if neural_enabled:
# Check for error state first
if 'error' in neural_data:
error_msg = neural_data['error']
# Truncate long error messages
if len(error_msg) > 40:
error_msg = error_msg[:37] + "..."
panel2_lines.extend([
f"🧠 Neural: ERROR",
f"{error_msg}"
])
else:
training_loss = neural_data.get('training_loss')
avg_loss = neural_data.get('avg_loss')
epsilon = neural_data.get('avg_epsilon', neural_data.get('epsilon', 0.0))
organisms_tracked = neural_data.get('organisms_tracked', 0)
training_steps = neural_data.get('training_steps', 0)
# Granular loss components (EMA smoothed)
ema_loss = neural_data.get('ema_loss')
ema_rl = neural_data.get('ema_rl_loss')
ema_lang = neural_data.get('ema_language_loss')
ema_concept = neural_data.get('ema_concept_loss')
# Use EMA loss if available (smoother), else avg_loss, else training_loss
if ema_loss is not None:
loss_str = f"{ema_loss:.4f}"
elif training_loss is not None:
loss_str = f"{training_loss:.4f}"
elif avg_loss is not None and avg_loss != 'N/A' and avg_loss != 0.0:
loss_str = f"{float(avg_loss):.4f}"
elif training_steps > 0:
# Training has started but waiting for next batch
loss_str = "Batching..."
elif organisms_tracked > 0:
# Organisms exist but need experiences (< batch_size)
loss_str = "Collecting..."
else:
# No organisms with neural brains yet
loss_str = "Warming..."
epsilon_val = epsilon if epsilon is not None else 0.0
panel2_lines.extend([
f"🧠 Neural: ACTIVE",
f"Loss: {loss_str} (EMA)",
f"Epsilon: {epsilon_val:.3f}",
f"Tracked: {organisms_tracked}",
f"Steps: {training_steps}"
])
# Add granular loss breakdown if available
if ema_rl is not None or ema_lang is not None or ema_concept is not None:
panel2_lines.append("─── Loss Breakdown ───")
if ema_rl is not None:
panel2_lines.append(f" RL: {ema_rl:.4f}")
if ema_lang is not None:
panel2_lines.append(f" Lang: {ema_lang:.4f}")
if ema_concept is not None:
panel2_lines.append(f" Concept: {ema_concept:.4f}")
else:
panel2_lines.append("🧠 Neural: OFF")
if ml_enabled:
clustering = ml_data.get('clustering', {})
anomalies = ml_data.get('anomalies', {})
n_clusters = clustering.get('n_clusters', 0)
anomaly_ratio = anomalies.get('anomaly_ratio', 0.0)
panel2_lines.extend([
f"🔬 ML: ACTIVE",
f"Clusters: {n_clusters}",
f"Anomalies: {anomaly_ratio:.1%}"
])
else:
panel2_lines.append("🔬 ML: OFF")
panel2_text = "\n".join(panel2_lines)
ax.text2D(0.90, 0.90, panel2_text, transform=ax.transAxes,
ha='right', va='top', fontsize=8, color='magenta',
bbox=dict(facecolor='black', alpha=0.7, edgecolor='magenta', linewidth=1),
family='monospace')
# Panel 3: BOTTOM-LEFT - Evolution Metrics (compact)
evolution_data = data.get('evolution', {})
generation = evolution_data.get('generation', 0)
best_fitness = evolution_data.get('best_fitness', 0.0)
avg_fitness = evolution_data.get('avg_fitness', 0.0)
population_size = evolution_data.get('population_size', 0)
panel3_text = (
f"━━━ EVOLUTION ━━━\n"
f"Gen: {generation} | Pop: {population_size}\n"
f"Best: {best_fitness:.4f}\n"
f"Avg: {avg_fitness:.4f}"
)
ax.text2D(0.10, 0.10, panel3_text, transform=ax.transAxes,
ha='left', va='bottom', fontsize=7, color='lime',
bbox=dict(facecolor='black', alpha=0.7, edgecolor='lime', linewidth=1),
family='monospace')
# ==================================================================
# Panel 6: LEFT-CENTER - EXPLORER (Body) - Comprehensive
# ==================================================================
explorer_data = data.get('explorer', {})
phase_sync = data.get('phase_sync', {})
explorer_sync = phase_sync.get('explorer', {})
explorer_phase = explorer_data.get('phase', explorer_sync.get('phase', 'unknown'))
breath_cycle = explorer_data.get('breath_cycle', 0)
breath_depth = explorer_data.get('breath_depth', 0)
vp_calcs = explorer_data.get('vp_calculations', explorer_sync.get('vp_calculations', 0))
sovereign_ids = explorer_data.get('sovereign_ids_count', explorer_sync.get('sovereign_ids', 0))
stability_score = explorer_sync.get('stability_score', 0.0)
genesis_proximity = explorer_sync.get('genesis_proximity', 0.0)
is_ready = explorer_sync.get('is_ready', False)
breath_cycles = explorer_sync.get('breath_cycles', breath_cycle)
# Phase icon mapping
phase_icons = {'genesis': '🌱', 'sovereign': '👑', 'unknown': '❓', 'transition': '🌉'}
phase_icon = phase_icons.get(explorer_phase.lower(), '🦋')
# Ready status
ready_status = "✅ READY" if is_ready else "⏳ Building..."
panel6_lines = [
"━━━ EXPLORER (Body) ━━━",
f"{phase_icon} Phase: {explorer_phase.upper()}",
f"🌬️ Breath: {breath_cycles} cycles",
f"📊 VP Calcs: {vp_calcs}",
f"👤 Sovereigns: {sovereign_ids}",
f"📈 Stability: {stability_score:.3f}",
f"🎯 Genesis→: {genesis_proximity:.1%}",
f"Status: {ready_status}"
]
panel6_text = "\n".join(panel6_lines)
ax.text2D(0.02, 0.50, panel6_text, transform=ax.transAxes,
ha='left', va='center', fontsize=7, color='#00FFAA',
bbox=dict(facecolor='black', alpha=0.8, edgecolor='#00FFAA', linewidth=1),
family='monospace')
# ==================================================================
# Panel 7: RIGHT-CENTER - DJINN KERNEL (Right Wing) - Comprehensive
# ==================================================================
djinn_kernel_data = data.get('djinn_kernel', {})
sync_data = phase_sync.get('synchronization', {})
network_sync = phase_sync.get('network', {})
vp_value = djinn_kernel_data.get('violation_pressure', 0.0)
vp_classification = djinn_kernel_data.get('vp_classification', 'VP0')
tape_cells = djinn_kernel_data.get('tape_cells', 0)
tape_position = djinn_kernel_data.get('tape_position', 0)
trait_count = djinn_kernel_data.get('trait_count', 0)
vp_calculations = djinn_kernel_data.get('vp_calculations', 0)
# Phase sync metrics
collapse_proximity = network_sync.get('collapse_proximity', 0.0)
is_collapsed = network_sync.get('is_collapsed', False)
phase_aligned = sync_data.get('aligned', False)
proximity_diff = sync_data.get('proximity_difference', 0.0)
# VP classification icons and colors
vp_icons = {'VP0': '🟢', 'VP1': '🟡', 'VP2': '🟠', 'VP3': '🔴', 'VP4': '💀'}
vp_icon = vp_icons.get(vp_classification, '⚪')
# Collapse status
collapse_status = "💥 COLLAPSED" if is_collapsed else f"📉 {collapse_proximity:.1%}"
# Alignment status
align_status = "🔗 ALIGNED" if phase_aligned else f"⚡ Δ{proximity_diff:.2f}"
panel7_lines = [
"━━━ DJINN KERNEL (Wing) ━━━",
f"{vp_icon} VP: {vp_value:.4f} [{vp_classification}]",
f"📝 Traits: {trait_count}",
f"📼 Tape: {tape_position}/{tape_cells} cells",
f"🔢 Calcs: {vp_calculations}",
f"🌀 Collapse: {collapse_status}",
f"⚖️ Sync: {align_status}"
]
# Add component breakdown if available
breakdown = djinn_kernel_data.get('component_breakdown', {})
if breakdown:
top_components = sorted(breakdown.items(), key=lambda x: abs(x[1]), reverse=True)[:2]
for comp_name, comp_val in top_components:
short_name = comp_name[:8]
panel7_lines.append(f" {short_name}: {comp_val:.3f}")
panel7_text = "\n".join(panel7_lines)
ax.text2D(0.98, 0.50, panel7_text, transform=ax.transAxes,
ha='right', va='center', fontsize=7, color='#FF6B6B',
bbox=dict(facecolor='black', alpha=0.8, edgecolor='#FF6B6B', linewidth=1),
family='monospace')
# Panel 4: BOTTOM-RIGHT - ConfigTuner & Meta-Cognitive
config_tuner_data = data.get('config_tuner', {})
tuner_enabled = config_tuner_data.get('enabled', False)
panel4_lines = ["━━━ META-COGNITIVE ━━━"]
if tuner_enabled:
tuner_mode = config_tuner_data.get('mode', 'unknown')
tuner_stats = config_tuner_data.get('stats', {})
total_actions = tuner_stats.get('total_actions', 0)
success_rate = tuner_stats.get('success_rate', 0.0)
recent_actions = tuner_stats.get('recent_actions', [])
total_atoms = tuner_stats.get('total_atoms', 0)
avg_stability = tuner_stats.get('avg_stability', 0.0)
# Get last action if available
last_action = ""
if recent_actions and len(recent_actions) > 0:
last = recent_actions[-1]
param_short = last.get('param', '').split('.')[-1][:10]
last_action = f"Last: {param_short}"
elif total_actions == 0 and total_atoms > 0:
# Show learning status when no actions yet
last_action = f"Learning ({total_atoms} params)"
# Show status based on actions
if total_actions > 0:
action_str = f"Actions: {total_actions}"
else:
action_str = f"Actions: Evaluating..."
panel4_lines.extend([
f"🧠🔧 Tuner: {tuner_mode.upper()}",
action_str,
f"Success: {success_rate:.1%}",
f"{last_action}"
])
else:
panel4_lines.append("🧠🔧 Tuner: OFF")
# Add quantum info if available
quantum_data = data.get('quantum', {})
if quantum_data:
quantum_states = quantum_data.get('states', 0)
panel4_lines.extend([
f"⚛️ Quantum: {quantum_states} states"
])
panel4_text = "\n".join(panel4_lines)
ax.text2D(0.90, 0.10, panel4_text, transform=ax.transAxes,
ha='right', va='bottom', fontsize=7, color='yellow',
bbox=dict(facecolor='black', alpha=0.7, edgecolor='yellow', linewidth=1),
family='monospace')
# Panel 5: CENTER-BOTTOM - Phase Transition / System Harmony
# Show synchronization status between all systems
exploration_tracking = data.get('exploration_tracking', {})
language_data = data.get('language', {})
# Calculate overall system harmony
harmony_score = 1.0 - proximity_diff if proximity_diff < 1.0 else 0.0
# Determine system status
if is_collapsed and is_ready:
system_status = "🌉 TRANSITION ACHIEVED"
status_color = '#00FF00'
elif phase_aligned:
system_status = "🔄 PHASES ALIGNED"
status_color = '#00FFFF'
elif harmony_score > 0.8:
system_status = "🎵 HARMONIZING"
status_color = '#FFFF00'
else:
system_status = "⚡ DIVERGENT"
status_color = '#FF6600'
# Language metrics
vocab_size = language_data.get('vocab_size', 0)
org_word_links = language_data.get('organism_word_assignments', 0) # Total word-organism links
orgs_with_words = language_data.get('organisms_with_words', 0) # Organisms that have words
# Build status text
transition_lines = [
f"━━━ SYSTEM HARMONY ━━━",
f"{system_status}",
f"🎯 Harmony: {harmony_score:.1%}",
f"📊 Ratio: {exploration_tracking.get('current_ratio', 'N/A')}",
]
# Add language info if available
if vocab_size > 0:
# Show: Vocab size | orgs with words | total word-org links
transition_lines.append(f"🗣️ Vocab: {vocab_size} | {orgs_with_words} orgs | {org_word_links} links")
transition_text = "\n".join(transition_lines)
ax.text2D(0.50, 0.10, transition_text, transform=ax.transAxes,
ha='center', va='bottom', fontsize=7, color=status_color,
bbox=dict(facecolor='black', alpha=0.7, edgecolor=status_color, linewidth=1),
family='monospace')
profile = self.grid_profiles[self.current_grid_profile_index] if self.grid_profiles else {}
derived = {
"avg_degree": avg_deg,
"clustering": clustering,
"language_ratio": language_ratio,
"connections": len(G.edges()),
"organisms": len(G.nodes())
}
self._apply_grid_profile(ax, profile)
# Bottom menu removed per user request - was showing cluster_sizes and running off window
# self._draw_profile_label(ax, profile, data, derived)
self._draw_profile_planes(ax, profile, xs, ys, zs)
else:
ax.text2D(0.5, 0.5, f'{num_orgs} Organisms\n{num_conns} Connections',
transform=ax.transAxes, ha='center', va='center', fontsize=12, color='white')
else:
ax.text2D(0.5, 0.5, 'No Network Data Available',
transform=ax.transAxes, ha='center', va='center', fontsize=12, color='white')
except Exception as e:
print(f"[Viewer] Error rendering network: {e}")
import traceback
traceback.print_exc()
def render_evolution_tree(self, data: Dict[str, Any], ax):
"""Render evolution tree from pre-computed data"""
try:
ax.clear()
ax.set_facecolor('black')
evolution_data = data.get("evolution", {})
generation = evolution_data.get("generation", 0)
best_fitness = evolution_data.get("best_fitness", 0)
avg_fitness = evolution_data.get("avg_fitness", 0)
population_size = evolution_data.get("population_size", 0)
# Split into two subplots for larger display
gs = gridspec.GridSpec(1, 2, figure=ax.figure, width_ratios=[1, 1], wspace=0.3)
ax1 = ax.figure.add_subplot(gs[0])
ax2 = ax.figure.add_subplot(gs[1])
# Left: Fitness (with larger labels)
bars1 = ax1.bar(['Best', 'Avg'], [best_fitness, avg_fitness],
color=['cyan', 'magenta'], alpha=0.8, edgecolor='white', linewidth=2)
ax1.set_ylabel('Fitness (0-1)', fontsize=14, color='white')
ax1.set_title('Fitness Scores', fontsize=16, fontweight='bold', color='white', pad=15)
ax1.set_ylim(0, 1)
ax1.tick_params(labelsize=12, colors='white')
ax1.grid(True, alpha=0.3, axis='y', color='gray')
ax1.set_facecolor('black')
# Add value labels on bars
for bar in bars1:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height + 0.02,
f'{height:.4f}', ha='center', va='bottom',
fontsize=12, color='white', fontweight='bold')
# Right: Population info (with larger labels)
bars2 = ax2.barh(['Gen', 'Pop'], [generation, population_size],
color=['yellow', 'green'], alpha=0.8, edgecolor='white', linewidth=2)
ax2.set_xlabel('Value', fontsize=14, color='white')
ax2.set_title('Status', fontsize=16, fontweight='bold', color='white', pad=15)
ax2.tick_params(labelsize=12, colors='white')
ax2.grid(True, alpha=0.3, axis='x', color='gray')
ax2.set_facecolor('black')
# Add value labels on bars
for bar in bars2:
width = bar.get_width()
ax2.text(width + max(generation, population_size) * 0.02, bar.get_y() + bar.get_height()/2.,
f'{int(width)}', ha='left', va='center',
fontsize=12, color='white', fontweight='bold')
# Set figure title
ax.figure.suptitle(f'Evolution - Generation {generation}',
fontsize=18, fontweight='bold', color='white', y=0.98)
# Add precision indicators
precision = self.precision_config.get('fitness', 0.000001)
ax1.text(0.02, 0.98, f'±{precision:.1e}', transform=ax1.transAxes,
fontsize=10, alpha=0.7, verticalalignment='top', color='white')
ax2.text(0.02, 0.98, f'±{precision:.1e}', transform=ax2.transAxes,
fontsize=10, alpha=0.7, verticalalignment='top', color='white')
# Remove original ax
ax.axis('off')
except Exception as e:
print(f"[Viewer] Error rendering evolution: {e}")
def render_consciousness_gauge(self, data: Dict[str, Any], ax):
"""Render consciousness gauge from pre-computed data"""
try:
ax.cla()
ax.set_facecolor('black')
consciousness_data = data.get("consciousness", {})
score = 0
if consciousness_data and isinstance(consciousness_data, dict):
last_analysis = consciousness_data.get("last_analysis", {})
if isinstance(last_analysis, dict):
score = last_analysis.get("overall_score", 0) or 0
# Title
ax.set_title('Consciousness Gauge', fontsize=16, fontweight='bold', color='white', pad=10)
# Large numeric
ax.text(0.5, 0.7, f'{score:.6f}', ha='center', va='center',
fontsize=30, fontweight='bold', color='cyan', transform=ax.transAxes)
ax.text(0.5, 0.58, '0.0 → 1.0', ha='center', va='center',
fontsize=10, color='gray', transform=ax.transAxes)
# Horizontal bar
ax.barh([0], [score], color='cyan', alpha=0.9, edgecolor='white', linewidth=2, height=0.18)
ax.set_xlim(0, 1)
ax.set_yticks([])
ax.tick_params(colors='white')
ax.grid(True, axis='x', alpha=0.2, color='gray')
# Precision
precision = self.precision_config.get('consciousness', 0.000001)
ax.text(0.02, 0.95, f'±{precision:.1e}', transform=ax.transAxes,
fontsize=9, alpha=0.7, color='white', va='top')
except Exception as e:
print(f"[Viewer] Error rendering consciousness: {e}")
def render_performance_monitor(self, data: Dict[str, Any], ax):
"""Render performance monitor from pre-computed data"""
try:
ax.cla()
ax.set_facecolor('black')
lattice_data = data.get("lattice", {})
cpu_usage = float(lattice_data.get("cpu_usage", 0) or 0)
ram_usage = float(lattice_data.get("ram_usage", 0) or 0)
simulation_data = data.get("simulation", {})
fps = float(simulation_data.get("fps", 10) or 10)
ax.set_title('Performance Monitor', fontsize=16, fontweight='bold', color='white', pad=10)
# Draw bars in-place to avoid subplot overdraw
labels = ['CPU %', 'RAM GB', 'FPS']
values = [cpu_usage, ram_usage, fps]
colors = ['red', 'blue', 'green']
bars = ax.bar(labels, values, color=colors, alpha=0.85, edgecolor='white', linewidth=1.5)
ax.tick_params(colors='white', labelsize=11)
ax.grid(True, axis='y', alpha=0.25, color='gray')
for bar, val in zip(bars, values):
ax.text(bar.get_x() + bar.get_width()/2., val + max(values) * 0.03,
f'{val:.2f}', ha='center', va='bottom', fontsize=10, color='white', fontweight='bold')
cpu_prec = self.precision_config.get('performance_cpu', 0.0001)
fps_prec = self.precision_config.get('performance_fps', 10)
ax.text(0.02, 0.95, f'±CPU {cpu_prec:.1e} | ±FPS {fps_prec}', transform=ax.transAxes,
fontsize=9, alpha=0.7, color='white', va='top')
except Exception as e:
print(f"[Viewer] Error rendering performance: {e}")
def render_particle_cloud(self, data: Dict[str, Any], ax):
"""Render particle cloud in 3D with interactive rotation"""
try:
from mpl_toolkits.mplot3d import Axes3D # noqa: F401
# Ensure 3D axes
if getattr(ax, 'name', '') != '3d':
fig = ax.figure
try:
fig.delaxes(ax)
except Exception:
pass
ax = fig.add_subplot(111, projection='3d')
self.tab_axes["particle_cloud"] = ax
ax.cla()
ax.set_facecolor('black')
lattice_data = data.get("lattice", {})
particle_count = int(lattice_data.get("particles", 0) or 0)
if particle_count > 0:
positions = None
particle_positions = lattice_data.get('particle_positions', [])
if particle_positions:
positions = np.array(particle_positions[:self.max_particles_to_plot])
# If positions are 2D, lift into 3D with small z jitter
if positions.ndim == 2 and positions.shape[1] == 2:
zs = np.random.default_rng(42).normal(0.0, 0.02, size=positions.shape[0])
positions = np.column_stack((positions, zs))
else:
# Synthetic 3D cloud fallback
rng = np.random.default_rng(42)
theta = rng.uniform(0, 2*np.pi, size=min(particle_count, 100))
phi = rng.uniform(0, np.pi, size=min(particle_count, 100))
r = 0.4 + 0.1 * rng.random(size=min(particle_count, 100))
xs = r * np.sin(phi) * np.cos(theta)
ys = r * np.sin(phi) * np.sin(theta)
zs = r * np.cos(phi)
positions = np.column_stack((xs, ys, zs))
# Normalize for nice cube display
pos_min = positions.min(axis=0)
pos_max = positions.max(axis=0)
ranges = np.maximum(pos_max - pos_min, 1e-9)
positions = (positions - pos_min) / ranges
ax.scatter(positions[:, 0], positions[:, 1], positions[:, 2],
c=np.arange(len(positions)), cmap='plasma', s=15,
alpha=0.85, edgecolors='white', linewidths=0.2)
ax.set_title(f'Particle Cloud (3D) - {particle_count} Particles',
fontsize=12, fontweight='bold', color='white', pad=10)
ax.set_xticks([]); ax.set_yticks([]); ax.set_zticks([])
ax.set_box_aspect((1, 1, 1))
else:
ax.text2D(0.5, 0.5, 'No Particle Data Available',
transform=ax.transAxes, ha='center', va='center', fontsize=12, color='white')
except Exception as e:
print(f"[Viewer] Error rendering particles: {e}")
import traceback
traceback.print_exc()
def update_visualizations(self, data: Dict[str, Any]):
"""Update all visualizations with new data"""
if self.root is None:
self.create_unified_window()
if self.root is None or len(self.tab_axes) == 0:
return
try:
print(f"[Viewer] Updating visualizations with data keys: {list(data.keys()) if data else 'None'}")
self.last_visualization_data = data
# Update each visualization in its respective tab
if "network_graph" in self.tab_axes:
print("[Viewer] Rendering network graph...")
self.render_network_graph(data, self.tab_axes["network_graph"])
if "network_graph" in self.tab_canvases:
self.tab_canvases["network_graph"].draw()
print("[Viewer] Network graph canvas drawn")
else:
print("[Viewer] ERROR: Network graph canvas not found")
if "evolution_tree" in self.tab_axes:
print("[Viewer] Rendering evolution tree...")
self.render_evolution_tree(data, self.tab_axes["evolution_tree"])
if "evolution_tree" in self.tab_canvases:
self.tab_canvases["evolution_tree"].draw()
print("[Viewer] Evolution tree canvas drawn")
else:
print("[Viewer] ERROR: Evolution tree canvas not found")
if "consciousness_gauge" in self.tab_axes:
print("[Viewer] Rendering consciousness gauge...")
self.render_consciousness_gauge(data, self.tab_axes["consciousness_gauge"])
if "consciousness_gauge" in self.tab_canvases:
self.tab_canvases["consciousness_gauge"].draw()
print("[Viewer] Consciousness gauge canvas drawn")
else:
print("[Viewer] ERROR: Consciousness gauge canvas not found")
if "performance_monitor" in self.tab_axes:
print("[Viewer] Rendering performance monitor...")
self.render_performance_monitor(data, self.tab_axes["performance_monitor"])
if "performance_monitor" in self.tab_canvases:
self.tab_canvases["performance_monitor"].draw()
print("[Viewer] Performance monitor canvas drawn")
else:
print("[Viewer] ERROR: Performance monitor canvas not found")
if "particle_cloud" in self.tab_axes:
print("[Viewer] Rendering particle cloud...")
self.render_particle_cloud(data, self.tab_axes["particle_cloud"])
if "particle_cloud" in self.tab_canvases:
self.tab_canvases["particle_cloud"].draw()
print("[Viewer] Particle cloud canvas drawn")
else:
print("[Viewer] ERROR: Particle cloud canvas not found")
# Process tkinter events
self.root.update_idletasks()
print("[Viewer] Visualization update complete")
except Exception as e:
print(f"[Viewer] Error updating visualizations: {e}")
import traceback
traceback.print_exc()
def run(self):
"""Main loop - reads data and updates display"""
print("[Viewer] 🎨 Starting lightweight visualization viewer...")
print("[Viewer] This process only displays data - all computation happens in backend")
if self.root is None:
self.create_unified_window()
if self.root is None:
print("[Viewer] ❌ Failed to create window")
return
def update_loop():
"""Update visualizations periodically"""
try:
current_time = time.time()
# Only update at specified interval (reduces CPU usage)
if current_time - self.last_update >= self.update_interval:
print(f"[Viewer] Reading visualization data...")
data = read_visualization_data()
if data:
print(f"[Viewer] Data read successfully, updating visualizations...")
self.update_visualizations(data)
self.last_update = current_time
else:
print(f"[Viewer] No data available from shared state")
# Schedule next update
if self.root.winfo_exists():
self.root.after(int(self.update_interval * 1000), update_loop)
except Exception as e:
print(f"[Viewer] Error in update loop: {e}")
import traceback
traceback.print_exc()
# Start update loop
self.root.after(100, update_loop)
# Run tkinter main loop
try:
self.root.mainloop()
except KeyboardInterrupt:
print("\n[Viewer] Shutting down...")
if self.root:
self.root.quit()
if __name__ == "__main__":
viewer = LightweightVisualizationViewer(update_interval=0.5) # Update every 0.5 seconds
viewer.run()

Xet Storage Details

Size:
59.4 kB
·
Xet hash:
2ffe2a6ed2d6a8fa8fcfb1822ff27fdf1a3ac0c7356f3e61370aeb2d5371601f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.