In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import numpy as np
import random
import string
import math
import re


1 font point is $\frac{1}{72}$ of an inch

In [2]:
height = 1
width = 1

plt.figure(figsize=(width, height))
plt.axis([0, width, 0, height])
plt.text(0, 0, "A", fontsize=72)

Out[2]:
<matplotlib.text.Text at 0x1130002b0>

But what about width? Very hard with most fonts. Need monospace font

In [3]:
height = 1
width = 0.8
font = FontProperties()
font.set_family("monospace")

plt.figure(figsize=(width, height))
plt.axis([0, width, 0, height])
plt.text(0, 0, "T", fontproperties = font, fontsize=72)

Out[3]:
<matplotlib.text.Text at 0x113010f60>

It looks like the width is just about $\frac{4}{5}$ of the height.

Let's draw 100 random words on the screen.

In [4]:
height = 30
width = 30
font = FontProperties()
font.set_family("monospace")

plt.figure(figsize=(width, height))
plt.axis([0, width, 0, height])
for i in range(100):
text = "ABC"
size = 20 + random.random() * 210
x = random.random() * width
y = random.random() * height
plt.text(x, y, text, fontproperties = font, fontsize=size)


To make them stop overlapping, we need to record where they are.

We will use an object for the Word, and calculate the bounding box.

In [5]:
class Word:
WIDTHSCALE = 0.8
PTSIZE = 1 / 72

def __init__(self, x, y, text, size):
self.x = x
self.y = y
self.text = text
self.size = size

def right(self):
return self.x + len(self.text) * Word.WIDTHSCALE * self.size * Word.PTSIZE

def top(self):
return self.y + self.size * Word.PTSIZE

def overlap(self, other):
# http://gamemath.com/2011/09/detecting-whether-two-boxes-overlap/
if self.right() < other.x:
return False
if other.right() < self.x:
return False
if self.top() < other.y:
return False
if other.top() < self.y:
return False
return True


First algorithm. Keep generating new positions until they fit.

In [6]:
height = 30
width = 30
font = FontProperties()
font.set_family("monospace")

plt.figure(figsize=(width, height))
plt.axis([0, width, 0, height])

words = []
for i in range(100):
text = "ABC"
overlap = True
while overlap:
overlap = False

x = random.random() * width
y = random.random() * height
size = 20 + random.random() * 210

w = Word(x, y, text, size)
for ow in words:
if w.overlap(ow):
overlap = True
break

words.append(w)

for w in words:
plt.text(w.x, w.y, w.text, fontproperties = font, fontsize=w.size)