File size: 5,411 Bytes
1556404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python3
"""
Visualize the circle packing arrangement from the best solution
"""
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
import json
import sys
import os

def visualize_circle_packing(results_dir):
    """
    Visualize the circle packing from a results directory
    
    Args:
        results_dir: Path to the results directory (e.g., results_with_eval_service_gen50_20260203_083049)
    """
    # Construct paths
    best_dir = os.path.join(results_dir, "best")
    metrics_path = os.path.join(best_dir, "results", "metrics.json")
    npz_path = os.path.join(best_dir, "results", "extra.npz")
    
    if not os.path.exists(metrics_path):
        print(f"Error: metrics.json not found at {metrics_path}")
        return
    
    # Load the metrics data
    with open(metrics_path, 'r') as f:
        metrics = json.load(f)
    
    # Parse the centers from the string
    centers_str = metrics['primary']['public']['centers_str']
    lines = centers_str.strip().split('\n')
    
    centers = []
    for line in lines:
        # Parse format: "  centers[i] = (x, y)"
        parts = line.split('=')[1].strip()
        x, y = parts.strip('()').split(',')
        centers.append([float(x), float(y)])
    
    centers = np.array(centers)
    n_circles = len(centers)
    
    print(f"Number of circles: {n_circles}")
    print(f"Reported sum of radii: {metrics['primary']['private']['reported_sum_of_radii']}")
    
    # Try to load radii from extra.npz if it exists
    radii = None
    if os.path.exists(npz_path):
        try:
            data = np.load(npz_path)
            if 'radii' in data:
                radii = data['radii']
                print(f"Loaded radii from extra.npz")
            else:
                print("Available keys in npz:", list(data.keys()))
        except Exception as e:
            print(f"Could not load radii from npz: {e}")
    
    # If radii not available, estimate them based on distances
    if radii is None:
        print("Estimating radii based on nearest neighbor distances...")
        radii = np.zeros(n_circles)
        for i in range(n_circles):
            # Distance to walls
            x, y = centers[i]
            r_max = min(x, y, 1-x, 1-y)
            
            # Distance to other circles
            for j in range(n_circles):
                if i != j:
                    dist = np.linalg.norm(centers[i] - centers[j])
                    r_max = min(r_max, dist / 2.0)
            
            radii[i] = r_max * 0.95  # Scale down slightly to avoid overlap
    
    print(f"Radii range: [{radii.min():.4f}, {radii.max():.4f}]")
    print(f"Calculated sum of radii: {radii.sum():.4f}")
    
    # Create the visualization
    fig, ax = plt.subplots(1, 1, figsize=(12, 12))
    
    # Draw the unit square boundary
    square = patches.Rectangle((0, 0), 1, 1, linewidth=3, 
                               edgecolor='black', facecolor='lightgray', alpha=0.2)
    ax.add_patch(square)
    
    # Draw each circle
    colors = plt.cm.tab20(np.linspace(0, 1, n_circles))
    for i in range(n_circles):
        circle = patches.Circle(centers[i], radii[i], 
                               linewidth=1.5, edgecolor='darkblue', 
                               facecolor=colors[i], alpha=0.6)
        ax.add_patch(circle)
        
        # Add circle number at center
        ax.text(centers[i][0], centers[i][1], str(i), 
               ha='center', va='center', fontsize=9, fontweight='bold',
               bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0.7))
    
    # Set equal aspect ratio and limits
    ax.set_xlim(-0.05, 1.05)
    ax.set_ylim(-0.05, 1.05)
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3, linestyle='--')
    ax.set_xlabel('X', fontsize=14, fontweight='bold')
    ax.set_ylabel('Y', fontsize=14, fontweight='bold')
    ax.set_title(f'Circle Packing Visualization: {n_circles} circles\nSum of Radii = {radii.sum():.6f}', 
                fontsize=16, fontweight='bold', pad=20)
    
    # Add generation info if available
    if 'generation' in metrics:
        ax.text(0.98, 0.02, f"Generation: {metrics['generation']}", 
               transform=ax.transAxes, ha='right', va='bottom',
               fontsize=10, bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
    
    # Save the figure to the results directory
    output_path = os.path.join(best_dir, "circle_packing_visualization.png")
    plt.savefig(output_path, dpi=300, bbox_inches='tight')
    print(f"\n✓ Visualization saved to: {output_path}")
    
    # Also save to analyze/outputs for convenience
    analyze_output_dir = os.path.join(os.path.dirname(__file__), "outputs")
    os.makedirs(analyze_output_dir, exist_ok=True)
    analyze_output_path = os.path.join(analyze_output_dir, "circle_packing_visualization.png")
    plt.savefig(analyze_output_path, dpi=300, bbox_inches='tight')
    print(f"✓ Also saved to: {analyze_output_path}")
    
    plt.show()


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python visualize_circle_packing.py <results_directory>")
        print("\nExample:")
        print("  python analyze/visualize_circle_packing.py examples/circle_packing/results/results_with_eval_service_gen50_20260203_083049")
        sys.exit(1)
    
    results_dir = sys.argv[1]
    visualize_circle_packing(results_dir)