axi/examples/punchcard.py

78 lines
2.2 KiB
Python
Raw Normal View History

2017-04-30 00:11:31 +00:00
import axi
import csv
import math
MIN_SIZE = 0.01
MAX_SIZE = 0.8
def circle(cx, cy, r, n):
points = []
for i in range(n + 1):
a = 2 * math.pi * i / n
x = cx + math.cos(a) * r
y = cy + math.sin(a) * r
points.append((x, y))
return points
def fill_circle(cx, cy, cr, n):
result = []
r = cr
while r > 0:
result.append(circle(cx, cy, r, n))
r -= 0.05
result[-1].append((cx, cy))
return result
def punchcard_from_csv(csv_path):
with open(csv_path, 'rb') as fp:
reader = csv.reader(fp)
csv_rows = list(reader)
row_labels = [x[0] for x in csv_rows[1:]]
col_labels = csv_rows[0][1:]
data = []
for csv_row in csv_rows[1:]:
row = []
for value in csv_row[1:]:
try:
value = float(value)
except ValueError:
value = None
row.append(value)
data.append(row)
lo = min(x for row in data for x in row if x)
hi = max(x for row in data for x in row if x)
min_area = math.pi * (MIN_SIZE / 2.0) ** 2
max_area = math.pi * (MAX_SIZE / 2.0) ** 2
paths = []
for r, row in enumerate(data):
for c, value in enumerate(row):
if not value:
continue
pct = 1.0 * (value - lo) / (hi - lo)
pct = pct ** 0.5
area = pct * (max_area - min_area) + min_area
radius = (area / math.pi) ** 0.5
paths.extend(fill_circle(c, r, radius, 90))
for r, label in enumerate(row_labels):
d = axi.Drawing(axi.text(label.upper(), axi.TIMESR))
d = d.scale(0.02, 0.02).move(-1, r, 0.5, 0.5)
paths.extend(d.paths)
for c, label in enumerate(col_labels):
d = axi.Drawing(axi.text(label.upper(), axi.TIMESR))
d = d.scale(0.02, 0.02).move(c, -1, 0.5, 0.5)
paths.extend(d.paths)
d = axi.Drawing(paths)
d = d.scale_to_fit(12, 8.5)
print 'joining paths'
d = d.join_paths(0.02)
print 'simplifying paths'
d = d.simplify_paths(0.001)
d.render().write_to_png('out.png')
axi.draw(d)
if __name__ == '__main__':
import sys
punchcard_from_csv(sys.argv[1])