I've just tried to do some code for Treemap. Treemap concept can be found here. As an exercise I've tried to find the solution without reading the article.
Then, I came across this code: http://www.scipy.org/Cookbook/Matplotlib/TreeMap. The main problem is that I missed the algorithm, my code is not so simple, elegant, short and clean. And I used OOP because I didn't know how to do without it (at university I learned no C, no functional programming, only OOP).
Another issue is that I wanted to make a list of rectangles with no dependencies from the render engine (no matplotlib, maybe I'm writing something for openGL and pyqt), so I need some Rectangle with coordinates normalized between 0 and 1.
This is my code, which I'm no proud of: it is too verbose, redundant and not KISS, and maybe it could also be a bit more readable:
class Rectangle(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
def __repr__(self):
return "Rect - x:{0}, y:{1}, width:{2}, height:{3}".format(self.x, self.y, self.width, self.height)
class Node(object):
iter_method = iter
size_method = int
def __init__(self, content, depth=0):
self.depth = depth
self.childs = []
try:
self.value = Node.size_method(content)
except TypeError:
self.childs = [Node(x, depth+1) for x in Node.iter_method(content)]
self.value = sum(child.value for child in self.childs)
@property
def leaf(self):
return len(self.childs)>0
def __repr__(self):
s = "{0}Node:{1}".format('\t'*self.depth, self.value)
if self.leaf:
s += '\n'+'\n'.join(str(child) for child in self.childs)
return s
class TreeMap(object):
def __init__(self, root):
self.root = root
self.rects = []
self.build(self.root, Rectangle(0,0,1,1))
def build(self, node, rect, horizzontal=True):
node.rect = rect
self.rects.append( rect )
sizes = [child.value for child in node.childs]
total_size = node.value
if horizzontal:
x = 0.0
for child in node.childs:
y = rect.y
w = (child.value*rect.width) / float(total_size)
h = rect.height
self.build(child, Rectangle(x,y,w,h), not horizzontal)
x += w
else:
y = 0.0
for child in node.childs:
x = rect.x
h = (child.value*rect.height) / float(total_size)
w = rect.width
self.build(child, Rectangle(x,y,w,h), not horizzontal)
x += w
import unittest
class Test_TreeMap(unittest.TestCase):
def test_build_depth0(self):
nodes = (2,1,(2,2))
known = (1, 1), (2.0/7, 1), (1.0/7, 1), (4.0/7, 1), (4.0/7, 0.5), (4.0/7, 0.5)
Node.iter_method = iter
Node.size_method = int
root = Node(nodes)
t = TreeMap(root)
widths = tuple((rect.width, rect.height) for rect in t.rects)
self.assertEqual(known, widths)
unittest.main()