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)
|