A Venn diagram icon — three overlapping circles with random positions, sizes, and colors for each of the eight regions.
Each venndicon is a small SVG built from three circles drawn on a square canvas. The circles overlap to create a classic Venn diagram with eight distinct regions, and every region gets its own randomly chosen color.
Each circle has a random center position (anywhere from 20% to 80% of the canvas on each axis) and a random radius (40% to 100% of the canvas width). With three circles that is 9 random geometric values. Then 8 random colors are chosen — one for each region of the Venn diagram. In total, 17 random values define a venndicon.
When a seed integer is provided the random number generator is deterministic, so the same seed always produces the same venndicon. Here are seeds 0 through 15:
These portraits are each composed entirely of venndicons — 6,400 for the square grids and 6,348 for the taller one. Hover over any cell to see it highlighted; click to pin. In the paired view (Dad & Mom), the same venndicon is highlighted in both images simultaneously.
Hover to highlight · click to pin
Hover a cell in either image to see the same venndicon highlighted in both
A grid of venndicons can be arranged so that, when viewed from a distance, the grid approximates a target photograph. The process has four steps:
The "distance" between a venndicon and an image cell is the sum of squared Euclidean RGB distances across all four quadrants:
distance = sum(
(rv − ri)2 + (gv − gi)2 + (bv − bi)2
for each quadrant in [TL, TR, BL, BR]
)
Using four quadrants rather than a single average gives the matching spatial awareness — a venndicon that is dark on top and bright on bottom will be placed where the photo has the same gradient, not just a similar overall luminance.
The assignment problem is: given n workers and m jobs with a cost for every worker–job pair, find a one-to-one assignment of workers to jobs that minimizes total cost. In our case the "workers" are venndicons and the "jobs" are image cells.
The algorithm was published by Harold Kuhn in 1955 and named "the Hungarian method" because it was largely based on earlier work by two Hungarian mathematicians, Dénes König and Jenő Egerváry. James Munkres refined it in 1957, which is why it is also known as the Kuhn–Munkres algorithm or the Munkres assignment algorithm.
Build an n × m cost matrix C where entry C[i][j] is the color distance between venndicon i and image cell j. For an 80×80 grid that is 6,400 cells, so the matrix has 6,400 columns. If we generate 6,400 venndicons the matrix is square; if we generate more (say 7,000) then the algorithm naturally picks the best 6,400 from the pool.
| Cell 0 | Cell 1 | Cell 2 | Cell 3 | |
|---|---|---|---|---|
| V 0 | 4120 | 310 | 8900 | 5430 |
| V 1 | 520 | 6780 | 3200 | 9100 |
| V 2 | 7600 | 4300 | 2100 | 890 |
| V 3 | 3100 | 5500 | 670 | 4200 |
Highlighted entries show the optimal assignment that minimizes total cost.
The algorithm proceeds iteratively, maintaining a system of dual variables (potentials) for rows and columns. At each step it tries to extend a maximum matching among the "tight" edges (those where the cost equals the sum of the row and column potentials). The core loop is:
The algorithm runs in O(n3) time in the worst case, where
n = max(workers, jobs). For our 80×80 grid (6,400 cells) this is on the order of
2.6×1011 operations in the very worst case, though in practice
scipy.optimize.linear_sum_assignment uses an optimized C implementation (the
Jonker–Volgenant algorithm, also known as LAPJV) that finishes in seconds.
A greedy approach — assign the lowest-cost pair first, then the next, and so on — is fast but produces suboptimal results. Early assignments can "steal" good venndicons from cells that have no other good match. The Hungarian algorithm guarantees the global optimum: no rearrangement of the same venndicons can reduce total color distance.
When matching the same pool of venndicons against multiple photographs (as in the gallery above), a shared pool is generated once, and the Hungarian algorithm runs independently for each image. This means every image gets its own optimal arrangement of the same set of venndicons. The viewer above lets you hover over a cell in one image and see where that same venndicon ended up in the other — they travel to very different positions because each image has its own optimal layout.