# The transition from quantity to quality, in multicolor pictures

In many natural systems, we observe phase transitions, or sudden emergence of qualitatively different behaviour once a certain threshold is reached through gradual, quantitative changes. This insight opens some interesting doors for conceptualising (the evolutionary roots of) human language, but this isn’t the post to elaborate on these. Here, I just want to offer a graphical illustration, using a rather more simple model, of how small, barely perceptible changes of the local properties of a system can drastically change its global properties.

Below, you see black and white pictures of a 2-dimensional random matrix of 0s and 1s, 1s black. The three pictures represent the results for three different probabilities `P` for a dot to become a 1 during the stage in which the matrix is generated, 57%, 59%, and 61%. I dare you to guess which is which without enlarging the images in order to be able to read what it says in the title bar! I know I couldn’t for my life, they all look the same to me. But exactly within this range of values of `P`, the global property of connectivity or permeability of the system changes in dramatic ways. If, instead of blackening all 1s, we sort them into clusters of mutually connected spots (through paths only using the four main directions), and code those clusters with color, we’ll see that with P-values as high as 0.585, we still get a haphazard assemblage of clusters of various size (in this and the following picture, the single largest cluster is coded black, the second largest red, and for the rest, the other colors are recycled as often as may be necessary, so when you see a large patch of, say, orange, it doesn’t necessarily mean that they’re indeed one and the same cluster, but for black and red you can be sure they are): Alas, once we move up to 0.595, the global structure has changed: We’re no longer looking at a multitude of independent clusters of roughly comparable size, but rather at a supercluster that alone alone covers a clear majority of the 1s, with all other essentially just islands within the sea of points that are connected to the the supercluster: Not a lot changes when we go further up to 0.6 – the islands just become smaller: By just increasing the ratio of ones so slightly that you won’t even notice the difference in a black-and-white representation, we’ve come to the point where you can walk almost anywhere from any starting point without ever stepping on the zeros.

(Code below fold)

```import numpy as np, random as rd, Tkinter as tk, sys
sys.setrecursionlimit(10000)
from collections import Counter

def display_array(width, height, P, screenwidth=500, screenheight=500,title=None):
"""color version"""
# create nested list of 0s and 1, with
# frequency of 1s ~P:
list = [[int(rd.uniform(0,1) < P) for i in range(width)] for j in range(height)]

# function marking a non-0 spot and finding
# neighbours in the same cluster:
def find_neighbours(i,j, index):
list[i][j] += index
for neighbour in [(i,(j-1)%width),(i,(j+1)%width),((i-1)%height,j),((i+1)%height,j)]:
x,y = neighbour
if list[x][y] == 1:
find_neighbours(x,y,index)

# identify 1s that haven't yet been assigned
# to a cluster and make them the nucleus of
# a new cluster with unique code:
index = 1
for i in range(height):
for j in range(width):
if list[i][j] == 1:
find_neighbours(i,j,index)
index += 1

#identify the 2 largest clusters:
counter = Counter()
for sublist in list:
for item in sublist:
if item:
counter[item] += 1
mode = [counter.most_common(2)[i] for i in range(2)]

# plot matrix, 1st and 2nd most largest
# clusters are marked black and red,
# for the rest, colors are cycled
colors = ["green", "yellow", "purple", "grey", "blue", "cyan", "orange", "pink"]
app = tk.Tk()
if title == None:
title = str(P * 100)+"%"
app.wm_title(title)
C = tk.Canvas(app, width = screenwidth, height = screenheight)
rwidth = (screenwidth-10)/float(width)
rheight = (screenheight-10)/float(height)
for i in range(width):
for j in range(height):
if list[j][i] == mode:
C.create_rectangle(5+ i * rwidth, 5 + j * rheight, 5 + (i+1) * rwidth, 5 + (j+1) * rheight, fill="black", width=0)
elif list[j][i] == mode:
C.create_rectangle(5+ i * rwidth, 5 + j * rheight, 5 + (i+1) * rwidth, 5 + (j+1) * rheight, fill="red", width=0)
elif list[j][i]:
C.create_rectangle(5+ i * rwidth, 5 + j * rheight, 5 + (i+1) * rwidth, 5 + (j+1) * rheight, fill=colors[list[j][i]%8], width=0)
C.grid(column=0,row=0)

# save button:
def save():
eps = title + time.strftime("%Y-%m-%d_%H-%M", time.localtime()) + ".eps"
C.postscript(colormode = "color", file = eps)
app.quit()
tk.Button(app,text="Save&Quit",command=save).grid(column=1,row=0)

def display_array_bw(width, height, P, screenwidth=500, screenheight=500,title=None):
"""black and white version"""
# create nested list of 0s and 1, with
# frequency of 1s ~P:
list = [[int(rd.uniform(0,1) < P) for i in range(width)] for j in range(height)]

# plot matrix, all 1s marked black
app = tk.Tk()
if title == None:
title = str(P * 100)+"%"
app.wm_title(title)
C = tk.Canvas(app, width = screenwidth, height = screenheight)
rwidth = (screenwidth-10)/float(width)
rheight = (screenheight-10)/float(height)
for i in range(width):
for j in range(height):
if list[j][i]:
C.create_rectangle(5+ i * rwidth, 5 + j * rheight, 5 + (i+1) * rwidth, 5 + (j+1) * rheight, fill="black", width=0)
C.grid(column=0,row=0)

# save button:
def save():
eps = title + time.strftime("%Y-%m-%d_%H-%M", time.localtime()) + ".eps"
C.postscript(colormode = "color", file = eps)
app.quit()
tk.Button(app,text="Save&Quit",command=save).grid(column=1,row=0)

for i in np.arange(.57,.61, .005):
title = "600x325 "+str(i*100)+"%"
display_array_bw(600,325,i,1200,650,title)
display_array(600,325,i,1200,650,title)
```