Circle packing
Circle Packing¶
Pack circles of given radii to minimize overlap and overall bounding box size, without any nesting or graph structure. Circle packing is one of the simplest examples of optimization for visualization.
import pathlib
import numpy as np
from IPython.display import SVG
from matplotlib import pyplot as plt
from vizopt.animation import (
SnapshotCallback,
chronophotograph,
)
from vizopt.base import OptimConfig
from vizopt.templates.circle_packing import CirclePackingOptimizer, plot_circles
rng = np.random.default_rng(0)
n_circles = 30
radii = rng.uniform(0.01, 1, size=30).tolist()
initial_node_xys = np.random.rand(n_circles, 2).astype(np.float32) * 5
optimizer = CirclePackingOptimizer(
radii=radii,
weight_total_size=10.0,
collision_offset=0.0,
initial_node_xys=initial_node_xys,
)
plot_circles(initial_node_xys, radii)
The optimizer compresses x and y independently (the total size penalty treats each axis separately), so circles are pushed into a compact rectangular arrangement rather than a circular cluster.
cb = SnapshotCallback(every=50)
result = optimizer.optimize(OptimConfig(n_iters=500, learning_rate=0.03), callback=cb)
Animation¶
Chronophotography¶
A static composite that overlays evenly-spaced snapshots: early frames appear as faint ghosts, the final frame is fully opaque.
fig = chronophotograph(
optimizer.problem_, cb.snapshots, n_frames=10, alpha_end=0.8, alpha_start=0.5
)
plt.show()