Skip to content

Instantly share code, notes, and snippets.

@eat-
Created February 27, 2011 21:44

Revisions

  1. eat- revised this gist Feb 28, 2011. 2 changed files with 39 additions and 38 deletions.
    68 changes: 35 additions & 33 deletions radial_grouper.py
    Original file line number Diff line number Diff line change
    @@ -24,34 +24,38 @@ def _leafs(p):
    return argsort(p[0])

    def _create_leaf_nodes(ndx):
    n= []
    nodes= []
    for k in xrange(len(ndx)):
    n.append(Node(ndx[k], []))
    return n
    nodes.append(Node(ndx[k], []))
    return nodes

    def _link_and_create_nodes(_n, n_, cn, groups):
    n, n0= [], 0
    nodes, n0= [], 0
    for k in xrange(len(groups)):
    n.append(Node(n_+ n0, [cn[m] for m in groups[k]]))
    nodes.append(Node(n_+ n0, [cn[m] for m in groups[k]]))
    n0+= 1
    return n_, n_+ n0, n
    return n_, n_+ n0, nodes

    def _create_tree(p, r0, shrnk, tols):
    def _process_level(nodes, polar, p, tol, scale, _n, n_):
    groups, p= _groub_by(p, tol, scale* polar[1, _n])
    _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
    polar[:, _n: n_]= p
    return nodes, polar, _n, n_

    def _create_tree(p, r0, scale, tols):
    if None is tols:
    tols= .3* pi/ 2** arange(5)[::-1]
    _n, n_= 0, p.shape[1]
    polar= ones((2, (len(tols)+ 2)* n_))
    polar[0, :n_], polar[1, :n_]= p[0], r0
    # leafs
    nodes= _create_leaf_nodes(_leafs(p))
    groups, p= _groub_by(polar[0, _leafs(p)], tols[0], shrnk* polar[1, _n])
    _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
    polar[:, _n: n_]= p
    nodes, polar, _n, n_= _process_level(
    nodes, polar, polar[0, _leafs(p)], tols[0], scale, _n, n_)
    # links
    for tol in tols[1:]:
    groups, p= _groub_by(polar[0, _n: n_], tol, shrnk* polar[1, _n])
    _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
    polar[:, _n: n_]= p
    nodes, polar, _n, n_= _process_level(
    nodes, polar, polar[0, _n: n_], tol, scale, _n, n_)
    # root
    polar[:, n_]= [0., 0.]
    return Node(n_, nodes), polar[:, :n_+ 1]
    @@ -60,31 +64,29 @@ def _simplify(self):
    # ToDo: combine single linkages
    return self._root

    def _call(self, node0, node1, a, f, level):
    ndx= [node0.ndx, node1.ndx]
    f(self, a[:, ndx], ndx, level)
    def _call(self, node0, node1, f, level):
    f(self, [node0.ndx, node1.ndx], level)

    def pre_order(self, node0, a, f, level= 0):
    def pre_order(self, node0, f, level= 0):
    for node1 in node0.lnk:
    _call(self, node0, node1, a, f, level)
    pre_order(self, node1, a, f, level+ 1)
    _call(self, node0, node1, f, level)
    pre_order(self, node1, f, level+ 1)

    def post_order(self, node0, a, f, level= 0):
    def post_order(self, node0, f, level= 0):
    for node1 in node0.lnk:
    post_order(self, node1, a, f, level+ 1)
    _call(self, node0, node1, a, f, level)
    post_order(self, node1, f, level+ 1)
    _call(self, node0, node1, f, level)

    class tree(object):
    def __init__(self, p, r0= pi, shrnk= .9, tols= None):
    def __init__(self, p, r0= pi, scale= .9, tols= None):
    self._n= p.shape[1]
    self._root, self._p= _create_tree(p, r0, shrnk, tols)
    self._c= from_polar(self._p)
    self._root, self._p= _create_tree(p, r0, scale, tols)

    def traverse(self, f, order= pre_order, cs= 'Cartesian'):
    a= self._c
    if cs is not 'Cartesian':
    a= self._p
    order(self, self._root, a, f, 0)
    self.points= self._p
    if cs is 'Cartesian':
    self.points= from_polar(self._p)
    order(self, self._root, f, 0)
    return self

    def simplify(self):
    @@ -103,13 +105,13 @@ def is_leaf(self, ndx):
    from numpy.random import rand
    from pylab import plot, show

    def _l(t, a, n, l):
    def _l(t, n, l):
    # print round(a, 3), n, l, t.is_root(n[0]), t.is_leaf(n[1])
    plot(a[0, :], a[1, :])
    plot(t.points[0, n], t.points[1, n])
    if 0== l:
    plot(a[0, 0], a[1, 0], 's')
    plot(t.points[0, n[0]], t.points[1, n[0]], 's')
    if t.is_leaf(n[1]):
    plot(a[0, 1], a[1, 1], 'o')
    plot(t.points[0, n[1]], t.points[1, n[1]], 'o')

    n= 123
    p= r_[2* pi* rand(1, n)- pi, ones((1, n))]
    9 changes: 4 additions & 5 deletions radial_visualizer.py
    Original file line number Diff line number Diff line change
    @@ -2,19 +2,18 @@
    from pylab import plot

    # ToDo: create proper documentation
    def simple_link(t, a, ndx, level):
    def simple_link(t, ndx, level):
    """Simple_link is just a minimal example to demonstrate what can be
    achieved when it's called from _grouper.tree.traverse for each link.
    - t, tree instance
    - a, current link in chosen coordinate system
    - ndx, a pair of (from, to) indicies
    - level, of from, i.e. root is in level 0
    """
    plot(a[0, :], a[1, :])
    plot(t.points[0, ndx], t.points[1, ndx])
    if 0== level:
    plot(a[0, 0], a[1, 0], 's')
    plot(t.points[0, ndx[0]], t.points[1, ndx[0]], 's')
    if t.is_leaf(ndx[1]):
    plot(a[0, 1], a[1, 1], 'o')
    plot(t.points[0, ndx[1]], t.points[1, ndx[1]], 'o')

    # ToDO: implement more suitable link visualizers
    # No doubt, this will the part to burn most of the dev. resources
  2. @invalid-email-address Anonymous created this gist Feb 27, 2011.
    28 changes: 28 additions & 0 deletions radial_demo.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    from numpy import r_, ones, pi, sort
    from numpy.random import rand
    from radial_grouper import tree, pre_order, post_order
    from radial_visualizer import simple_link
    from pylab import axis, figure, plot, subplot

    # ToDo: create proper documentation
    def _s(sp, t, o):
    subplot(sp)
    t.traverse(simple_link, order= o)
    axis('equal')

    def demo1(n):
    p= r_[2* pi* rand(1, n)- pi, ones((1, n))]
    t= tree(p)
    f= figure()
    _s(221, t, pre_order)
    _s(222, t, post_order)
    t= tree(p, tols= sort(2e0* rand(9)))
    _s(223, t, pre_order)
    _s(224, t, post_order)
    f.show()
    # f.savefig('test.png')

    # ToDO: implement more demos

    if __name__ == '__main__':
    demo1(123)
    120 changes: 120 additions & 0 deletions radial_grouper.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    """All grouping functionality is collected here."""
    from collections import namedtuple
    from numpy import r_, arange, argsort, array, ones, pi, where
    from numpy import logical_and as land
    from radial_support import from_polar

    __all__= ['tree', 'pre_order', 'post_order']

    Node= namedtuple('Node', 'ndx lnk')

    # ToDo: enhance documentation
    def _groub_by(p, tol, r):
    g, gm, gp= [], [], p- p[0]
    while True:
    if gp[-1]< 0: break
    ndx= where(land(0.<= gp, gp< tol))[0]
    if 0< len(ndx):
    g.append(ndx)
    gm.append(p[ndx].mean())
    gp-= tol
    return g, array([gm, [r]* len(gm)])

    def _leafs(p):
    return argsort(p[0])

    def _create_leaf_nodes(ndx):
    n= []
    for k in xrange(len(ndx)):
    n.append(Node(ndx[k], []))
    return n

    def _link_and_create_nodes(_n, n_, cn, groups):
    n, n0= [], 0
    for k in xrange(len(groups)):
    n.append(Node(n_+ n0, [cn[m] for m in groups[k]]))
    n0+= 1
    return n_, n_+ n0, n

    def _create_tree(p, r0, shrnk, tols):
    if None is tols:
    tols= .3* pi/ 2** arange(5)[::-1]
    _n, n_= 0, p.shape[1]
    polar= ones((2, (len(tols)+ 2)* n_))
    polar[0, :n_], polar[1, :n_]= p[0], r0
    # leafs
    nodes= _create_leaf_nodes(_leafs(p))
    groups, p= _groub_by(polar[0, _leafs(p)], tols[0], shrnk* polar[1, _n])
    _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
    polar[:, _n: n_]= p
    # links
    for tol in tols[1:]:
    groups, p= _groub_by(polar[0, _n: n_], tol, shrnk* polar[1, _n])
    _n, n_, nodes= _link_and_create_nodes(_n, n_, nodes, groups)
    polar[:, _n: n_]= p
    # root
    polar[:, n_]= [0., 0.]
    return Node(n_, nodes), polar[:, :n_+ 1]

    def _simplify(self):
    # ToDo: combine single linkages
    return self._root

    def _call(self, node0, node1, a, f, level):
    ndx= [node0.ndx, node1.ndx]
    f(self, a[:, ndx], ndx, level)

    def pre_order(self, node0, a, f, level= 0):
    for node1 in node0.lnk:
    _call(self, node0, node1, a, f, level)
    pre_order(self, node1, a, f, level+ 1)

    def post_order(self, node0, a, f, level= 0):
    for node1 in node0.lnk:
    post_order(self, node1, a, f, level+ 1)
    _call(self, node0, node1, a, f, level)

    class tree(object):
    def __init__(self, p, r0= pi, shrnk= .9, tols= None):
    self._n= p.shape[1]
    self._root, self._p= _create_tree(p, r0, shrnk, tols)
    self._c= from_polar(self._p)

    def traverse(self, f, order= pre_order, cs= 'Cartesian'):
    a= self._c
    if cs is not 'Cartesian':
    a= self._p
    order(self, self._root, a, f, 0)
    return self

    def simplify(self):
    self._root= _simplify(self)
    return self

    def is_root(self, ndx):
    return ndx== self._p.shape[1]- 1

    def is_leaf(self, ndx):
    return ndx< self._n

    if __name__ == '__main__':
    # ToDO: add tests
    from numpy import r_, round
    from numpy.random import rand
    from pylab import plot, show

    def _l(t, a, n, l):
    # print round(a, 3), n, l, t.is_root(n[0]), t.is_leaf(n[1])
    plot(a[0, :], a[1, :])
    if 0== l:
    plot(a[0, 0], a[1, 0], 's')
    if t.is_leaf(n[1]):
    plot(a[0, 1], a[1, 1], 'o')

    n= 123
    p= r_[2* pi* rand(1, n)- pi, ones((1, n))]
    t= tree(p).simplify().traverse(_l)
    # t= tree(p).traverse(_l, cs= 'Polar')
    show()
    # print
    # t.traverse(_l, post_order, cs= 'Polar')
    31 changes: 31 additions & 0 deletions radial_support.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    """All supporting functionality is collected here."""
    from numpy import r_, arctan2, cos, sin
    from numpy import atleast_2d as a2d

    # ToDo: create proper documentation strings
    def _a(a0, a1):
    return r_[a2d(a0), a2d(a1)]

    def from_polar(p):
    """(theta, radius) to (x, y)."""
    return _a(cos(p[0])* p[1], sin(p[0])* p[1])

    def to_polar(c):
    """(x, y) to (theta, radius)."""
    return _a(arctan2(c[1], c[0]), (c** 2).sum(0)** .5)

    def d_to_polar(D):
    """Distance matrix to (theta, radius)."""
    # this functionality is to adopt for more general situations
    # intended functionality:
    # - embedd distance matrix to 2D
    # - return that embedding in polar coordinates
    pass

    if __name__ == '__main__':
    from numpy import allclose
    from numpy.random import randn
    c= randn(2, 5)
    assert(allclose(c, from_polar(to_polar(c))))

    # ToDO: implement more tests
    24 changes: 24 additions & 0 deletions radial_visualizer.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,24 @@
    """All visualization functionality is collected here."""
    from pylab import plot

    # ToDo: create proper documentation
    def simple_link(t, a, ndx, level):
    """Simple_link is just a minimal example to demonstrate what can be
    achieved when it's called from _grouper.tree.traverse for each link.
    - t, tree instance
    - a, current link in chosen coordinate system
    - ndx, a pair of (from, to) indicies
    - level, of from, i.e. root is in level 0
    """
    plot(a[0, :], a[1, :])
    if 0== level:
    plot(a[0, 0], a[1, 0], 's')
    if t.is_leaf(ndx[1]):
    plot(a[0, 1], a[1, 1], 'o')

    # ToDO: implement more suitable link visualizers
    # No doubt, this will the part to burn most of the dev. resources

    if __name__ == '__main__':
    # ToDO: implement tests
    pass