Пример #1
0
def heights(g, scale=-1):
    """ Compute the order of all vertices at scale `scale`.
    
    If scale == -1, the compute the order for vertices at the finer scale.
    """
    heights = {}
    if scale <= 0:
        for vid in traversal.iter_mtg2(g, g.root):
            pid = g.parent(vid)
            p_height = -1 if pid is None else heights[pid]
            heights[vid] = p_height+1
    else:
        for rid in g.roots_iter(scale=scale):
            for vid in traversal.pre_order2(g, rid):
                pid = g.parent(vid)
                p_height = -1 if pid is None else heights[pid]
                heights[vid] = p_height+1

    return heights
Пример #2
0
def orders(g, scale=-1):
    """ Compute the order of all vertices at scale `scale`.
    
    If scale == -1, the compute the order for vertices at the finer scale.
    """
    orders = {}
    if scale <= 0:
        for vid in traversal.iter_mtg2(g, g.root):
            pid = g.parent(vid)
            p_order = 0 if pid is None else orders[pid]
            orders[vid] = p_order+1 if g.edge_type(vid) == '+' else p_order
    else:
        for rid in g.roots_iter(scale=scale):
            for vid in traversal.pre_order2(g, rid):
                pid = g.parent(vid)
                p_order = 0 if pid is None else orders[pid]
                orders[vid] = p_order+1 if g.edge_type(vid) == '+' else p_order

    return orders
Пример #3
0
def layout2d(g,
             vid=None,
             origin=(0, 0),
             steps=(4, 8),
             property_name='position'):
    """ Compute 2d coordinates for each vertex.

    This method compute a 2D layout of a tree or a MTG at a specific scale.
    This will allow to plot tree in matplotlib for instance.

    :Usage:

    .. code-block:: python

        >>> g.reindex()
        >>> g1 = g.reindex(copy=True)
        >>> mymap = dict(zip(list(traversal.iter_mtg2(g,g.root)), range(len(g))))
        >>> g2 = g.reindex(mapping=mymap, copy=True)

    :Optional Parameters:

        - `origin` : a 2D point for the root of the tree.
        - `property` (str) : Name of the property storing the 2D coordinates.

    :Returns:

        - a MTG
    """
    if vid is None:
        vid = g.root
        if hasattr(g, 'max_scale'):
            vid = g.component_roots_at_scale_iter(g.root, g.max_scale()).next()

# Algorithm
# 1. the y is defined by the Height of a node
# 2. The x is computed using non intersecting bounding box

    x_step, y_step = steps

    y = {}
    vtxs = traversal.pre_order2(g, vid)
    vtxs.next()
    y[vid] = origin[1]
    for v in vtxs:
        y[v] = y[g.parent(v)] + y_step

    bbox = {}
    for v in traversal.post_order2(g, vid):
        children = g.children(v)
        if not children:
            bbox[v] = 2 * x_step
        else:
            has_successor = [
                cid for cid in children if g.edge_type(cid) == '<'
            ]
            # 2 is for symmetry
            bbox[v] = sum(bbox[cid] for cid in children)
            if not has_successor:
                bbox[v] += 2 * x_step

    x = {}
    vtxs = traversal.pre_order2(g, vid)
    x[vid] = int(bbox[vid] / 2.)

    for v in vtxs:
        _width = bbox[v]
        kids = g.children(v)
        successor = [cid for cid in kids if g.edge_type(cid) == '<']
        ramifs = [cid for cid in kids if g.edge_type(cid) == '+']
        _min = x[v]
        _max = x[v]
        for cid in successor:
            _x = x[cid] = x[v]
            width = bbox[cid]
            _min = _x - max(1, width / 2) - x_step
            _max = _x + max(1, width / 2) + x_step

        weights = [bbox[rid] for rid in ramifs]

        def mean_ind(weights):
            left = bool(random() < 0.5)
            mid = sum(weights) / 2.
            total = 0
            n = 0
            for w in weights:
                if total + w <= mid:
                    total += w
                else:
                    break
                n += 1

            if total - mid > 1 and left:
                n += 1
            if n == 0 and len(weights) > 1:
                n += 1
            return n

        n = mean_ind(weights)
        for rid in reversed(ramifs[:n]):
            width = bbox[rid]
            x[rid] = _min - max(1, width / 2)
            _min -= width
        for rid in ramifs[n:]:
            width = bbox[rid]
            x[rid] = _max + max(1, width / 2)
            _max += width

# TODO: The tree s not well proportionned because we impose a constraint that the
# < is aligned to its parent

    position = dict((k, (x[k], y[k])) for k in y)
    g.properties()[property_name] = position

    return g
Пример #4
0
def simple_layout(g,
                  vid=None,
                  origin=(0, 0),
                  steps=(4, 8),
                  property_name='position',
                  multiscale=True):
    """ Compute 2d coordinates for each vertex.

    This method compute a 2D layout of a tree or a MTG at a specific scale.
    This will allow to plot tree in matplotlib for instance.

    :Usage:

    .. code-block:: python

        >>> g = simple_layout(g)

    :Optional Parameters:

        - `origin` : a 2D point for the root of the tree.
        - `property` (str) : Name of the property storing the 2D coordinates.

    :Returns:

        - a MTG
    """
    def shuffle_post_order(tree, vtx_id):
        '''
        Traverse a tree in a postfix way.
        (from leaves to root)

        Same algorithm than post_order.
        The goal is to replace the post_order implementation.


        '''

        edge_type = tree.property('edge_type')

        def shuffle_children(vid):
            ''' Internal function to retrieve the children in a correct order:
                - Branch before successor.
            '''
            kids = tree.children(vid)
            plus = []
            successor = []
            for v in kids:
                if edge_type.get(v) == '<':
                    successor.append(v)
                else:
                    plus.append(v)
            n = len(plus)
            i = n / 2
            if n % 2 != 0:
                left = int(random() < 0.5)
                i += left
            child = plus[:i] + successor + plus[i:]

            return child

        visited = set([])

        queue = [vtx_id]

        # 1. select first '+' edges

        while queue:

            vtx_id = queue[-1]
            for vid in shuffle_children(vtx_id):
                if vid not in visited:
                    queue.append(vid)
                    break
            else:  # no child or all have been visited
                yield vtx_id
                visited.add(vtx_id)
                queue.pop()

    if vid is None:
        vid = g.root
        if hasattr(g, 'max_scale'):
            vid = g.component_roots_at_scale_iter(g.root, g.max_scale()).next()

    # Algorithm
    # 1. the y is defined by the Height of a node
    # 2. The x is computed using non intersecting bounding box

    x_step, y_step = steps
    y = {}
    vtxs = traversal.pre_order2(g, vid)
    vtxs.next()
    y[vid] = origin[1]
    for v in vtxs:
        y[v] = y[g.parent(v)] + y_step

    def leaves(g, vid):
        for v in shuffle_post_order(g, vid):
            if g.is_leaf(v):
                yield v

    def successor(g, vid):
        for cid in g.children(vid):
            if g.edge_type(cid) == '<':
                return cid
        return

    x = {}
    x_pos = origin[0]

    for v in leaves(g, vid):
        x[v] = x_pos
        x_pos += x_step * 10

    for v in shuffle_post_order(g, vid):
        if v in x:
            continue
        son_id = successor(g, v)
        if son_id:
            x[v] = x[son_id]
        else:
            children = g.children(v)
            x[v] = int(
                float(sum(x[cid] for cid in children)) / (len(children)))

    position = dict((k, (x[k], y[k])) for k in y)

    if multiscale:
        # get the position at the lower scales
        max_scale = g.scale(vid)

        for s in range(max_scale - 1, 0, -1):
            v_root = g.complex_at_scale(vid, scale=s)
            vtxs = traversal.pre_order2(g, v_root)
            for v in vtxs:
                comp_id = g.component_roots_at_scale_iter(
                    v, scale=max_scale).next()
                position[v] = position[comp_id]

    g.properties()[property_name] = position

    return g
Пример #5
0
def layout2d(g, vid=None, origin=(0,0), steps=(4,8), property_name='position'):
    """ Compute 2d coordinates for each vertex.

    This method compute a 2D layout of a tree or a MTG at a specific scale.
    This will allow to plot tree in matplotlib for instance.

    :Usage:

    .. code-block:: python

        >>> g.reindex()
        >>> g1 = g.reindex(copy=True)
        >>> mymap = dict(zip(list(traversal.iter_mtg2(g,g.root)), range(len(g))))
        >>> g2 = g.reindex(mapping=mymap, copy=True)

    :Optional Parameters:

        - `origin` : a 2D point for the root of the tree.
        - `property` (str) : Name of the property storing the 2D coordinates.

    :Returns:

        - a MTG
    """
    if vid is None:
        vid = g.root
        if hasattr(g, 'max_scale'):
            vid = g.component_roots_at_scale_iter(g.root, g.max_scale()).next()

	# Algorithm
	# 1. the y is defined by the Height of a node
	# 2. The x is computed using non intersecting bounding box

    x_step, y_step = steps

    y= {}
    vtxs = traversal.pre_order2(g,vid)
    vtxs.next()
    y[vid] = origin[1]
    for v in vtxs:
        y[v] = y[g.parent(v)]+y_step

    bbox = {}
    for v in traversal.post_order2(g,vid):
        children = g.children(v)
        if not children:
            bbox[v] = 2*x_step
        else:
            has_successor = [cid for cid in children if g.edge_type(cid)=='<']
            # 2 is for symmetry
            bbox[v] = sum(bbox[cid] for cid in children)
            if not has_successor:
                bbox[v]+=2*x_step

    x ={}
    vtxs = traversal.pre_order2(g,vid)
    x[vid] = int(bbox[vid]/2.)

    for v in vtxs:
        _width = bbox[v]
        kids = g.children(v)
        successor = [cid for cid in kids if g.edge_type(cid)=='<']
        ramifs = [cid for cid in kids if g.edge_type(cid)=='+']
        _min = x[v]; _max = x[v]
        for cid in successor:
            _x = x[cid] = x[v]
            width = bbox[cid]
            _min = _x-max(1,width/2)-x_step
            _max = _x+max(1,width/2)+x_step

        weights = [bbox[rid] for rid in ramifs]

        def mean_ind(weights):
            left = bool(random()<0.5)
            mid= sum(weights)/2.
            total = 0
            n = 0
            for w in weights:
                if total+w <= mid:
                    total+= w
                else:
                    break
                n+=1

            if total-mid > 1 and left:
                n+=1
            if n == 0 and len(weights)>1:
                n+=1
            return n

        n = mean_ind(weights)
        for rid in reversed(ramifs[:n]):
            width = bbox[rid]
            x[rid] = _min - max(1,width/2)
            _min -= width
        for rid in ramifs[n:]:
            width = bbox[rid]
            x[rid] = _max + max(1,width/2)
            _max += width

	# TODO: The tree s not well proportionned because we impose a constraint that the
	# < is aligned to its parent

    position = dict((k, (x[k],y[k])) for k in y)
    g.properties()[property_name] = position

    return g
Пример #6
0
def simple_layout(g, vid=None, origin=(0,0), steps=(4,8), property_name='position', multiscale=True):
    """ Compute 2d coordinates for each vertex.

    This method compute a 2D layout of a tree or a MTG at a specific scale.
    This will allow to plot tree in matplotlib for instance.

    :Usage:

    .. code-block:: python

        >>> g = simple_layout(g)

    :Optional Parameters:

        - `origin` : a 2D point for the root of the tree.
        - `property` (str) : Name of the property storing the 2D coordinates.

    :Returns:

        - a MTG
    """

    def shuffle_post_order(tree, vtx_id):
        '''
        Traverse a tree in a postfix way.
        (from leaves to root)

        Same algorithm than post_order.
        The goal is to replace the post_order implementation.


        '''

        edge_type = tree.property('edge_type')

        def shuffle_children(vid):
            ''' Internal function to retrieve the children in a correct order:
                - Branch before successor.
            '''
            kids = tree.children(vid)
            plus = []
            successor = []
            for v in kids:
                if edge_type.get(v) == '<':
                    successor.append(v)
                else:
                    plus.append(v)
            n = len(plus)
            i = n/2
            if n%2!=0:
                left = int(random()<0.5)
                i += left
            child = plus[:i]+successor+plus[i:]

            return child

        visited = set([])

        queue = [vtx_id]

        # 1. select first '+' edges

        while queue:

            vtx_id = queue[-1]
            for vid in shuffle_children(vtx_id):
                if vid not in visited:
                    queue.append(vid)
                    break
            else: # no child or all have been visited
                yield vtx_id
                visited.add(vtx_id)
                queue.pop()

    if vid is None:
        vid = g.root
        if hasattr(g, 'max_scale'):
            vid = g.component_roots_at_scale_iter(g.root, g.max_scale()).next()

    # Algorithm
    # 1. the y is defined by the Height of a node
    # 2. The x is computed using non intersecting bounding box

    x_step, y_step = steps
    y= {}
    vtxs = traversal.pre_order2(g,vid)
    vtxs.next()
    y[vid] = origin[1]
    for v in vtxs:
        y[v] = y[g.parent(v)]+y_step

    def leaves(g, vid):
        for v in shuffle_post_order(g,vid):
            if g.is_leaf(v):
                yield v
    def successor(g, vid):
        for cid in g.children(vid):
            if g.edge_type(cid)=='<':
                return cid
        return

    x = {}
    x_pos = origin[0]

    for v in leaves(g,vid):
        x[v] = x_pos
        x_pos += x_step*10

    for v in shuffle_post_order(g,vid):
        if v in x:
            continue
        son_id = successor(g,v)
        if son_id:
            x[v] = x[son_id]
        else:
            children = g.children(v)
            x[v] = int(float(sum(x[cid] for cid in children)) / (len(children)))


    position = dict((k, (x[k],y[k])) for k in y)

    if multiscale:
        # get the position at the lower scales
        max_scale = g.scale(vid)

        for s in range(max_scale-1,0,-1):
            v_root = g.complex_at_scale(vid, scale=s)
            vtxs = traversal.pre_order2(g, v_root)
            for v in vtxs:
                comp_id = g.component_roots_at_scale_iter(v, scale=max_scale).next()
                position[v] = position[comp_id]

    g.properties()[property_name] = position

    return g