cairo_draw.py 98.8 KB
Newer Older
2001
                nstate = NestedBlockState(u, bs=bs,
2002
                                          base_type=type(state.levels[0]),
2003
2004
                                          deg_corr=state.deg_corr)

2005
2006
2007
2008
2009
2010
                kwargs_ = kwargs_orig.copy()
                if "no_main" in kwargs_:
                    del kwargs_["no_main"]
                draw_hierarchy(nstate, beta=beta, vprops=vprops_orig,
                               eprops=eprops_orig, hvprops=hvprops_orig,
                               heprops=heprops_orig,
2011
                               subsample_edges=subsample_edges,
2012
2013
2014
                               deg_order=deg_order, empty_branches=False,
                               no_main=True, **kwargs_)

2015
        if key_id == ord('r'):
2016
2017
2018
2019
            if layout == "radial":
                x, y = ungroup_vector_property(pos, [0, 1])
                x.fa -= x.fa.mean()
                y.fa -= y.fa.mean()
2020
                angle = t_orig.new_vertex_property("double")
2021
2022
                angle.fa = (numpy.arctan2(y.fa, x.fa) + 2 * numpy.pi) % (2 * numpy.pi)
                tpos = radial_tree_layout(t_orig,
2023
                                          root=t_orig.vertex(t_orig.num_vertices(True) - 1),
2024
                                          rel_order=angle)
2025
                gg.copy_property(gg.own_property(tpos), pos)
2026

2027
2028
2029
2030
2031
2032
            update_cts(widget, gg, picked, pos, vprops, eprops)

            if widget.vertex_matrix is not None:
                widget.vertex_matrix.update()
            widget.picked = None
            widget.selected.fa = False
2033
2034
2035

            widget.fit_to_window()
            widget.regenerate_surface(reset=True)
2036
2037
            widget.queue_draw()

2038
    if "output" not in kwargs and not kwargs.get("inline", is_draw_inline):
2039
2040
2041
        kwargs["layout_callback"] = update_cts
        kwargs["key_press_callback"] = draw_branch

2042
2043
2044
    if "eorder" in kwargs:
        kwargs["eorder"] = eorder

2045
2046
2047
    vorder = kwargs.pop("vorder", None)
    if vorder is None:
        vorder = g.degree_property_map("total")
2048
    tvorder = u.own_property(tvorder)
2049
2050
    tvorder.fa[:g.num_vertices()] = vorder.fa

2051
2052
2053
2054
    for k, v in kwargs.items():
        if isinstance(v, PropertyMap) and v.get_graph().base is not u.base:
            kwargs[k] = u.own_property(v.copy())

2055
    pos = graph_draw(u, pos, vprops=t_vprops, eprops=t_eprops, vorder=tvorder,
2056
2057
                     **kwargs)

2058
    if isinstance(pos, PropertyMap):
2059
        t_orig.copy_property(pos, tpos, g=u)
2060
        pos = g.own_property(pos)
2061
    else:
2062
        t_orig.copy_property(pos[0], tpos, g=u)
2063
2064
        pos = (g.own_property(pos[0]),
               g.own_property(pos[1]))
2065
    return pos, t_orig, tpos
2066

2067

2068
def get_bip_hierachy_pos(state, aspect=1., node_weight=None):
2069

2070
    if state.levels[0].overlap:
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
        g = state.g
        ostate = state.levels[0]
        bv, bcin, bcout, bc = ostate.get_overlap_blocks()
        be = ostate.get_edge_blocks()

        n_r = zeros(ostate.B)
        b = g.new_vertex_property("int")
        for v in g.vertices():
            i = bc[v].a.argmax()
            b[v] = bv[v][i]
            n_r[b[v]] += 1

        orphans = [r for r in range(ostate.B) if n_r[r] == 0]

        for v in g.vertices():
            for r in orphans:
                b[v] = r

        orig_state = state
        state = state.copy()
        state.levels[0] = BlockState(g, b=b)

    g = state.g

    deg = g.degree_property_map("total")

    t, tb, order = get_hierarchy_tree(state)

2099
    root = t.vertex(t.num_vertices(True) - 1)
2100
2101
    if root.out_degree() > 2:
        clabel = is_bipartite(g, partition=True)[1].copy("int")
2102
        if state.levels[0].overlap:
2103
2104
            ostate = OverlapBlockState(g, b=clabel)
            ostate = orig_state.copy(clabel=clabel)
2105
            bc = ostate.propagate_clabel(len(state.levels) - 2)
2106
2107
        else:
            state = state.copy(clabel=clabel)
2108
            bc = state.propagate_clabel(len(state.levels) - 2)
2109

2110
        ps = list(root.out_neighbors())
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
        t.clear_vertex(root)

        p1 = t.add_vertex()
        p2 = t.add_vertex()

        t.add_edge(root, p1)
        t.add_edge(root, p2)
        for p in ps:
            if bc.a[tb[p]] == 0:
                t.add_edge(p2, p)
            else:
                t.add_edge(p1, p)

    w = t.new_vertex_property("double")
    for v in t.vertices():
        if v.in_degree() == 0:
            break
        if v.out_degree() == 0:
2129
            w[v] = 1 if node_weight is None else node_weight[v]
2130
        parent, = v.in_neighbors()
2131
2132
2133
2134
2135
2136
        w[parent] += w[v]

    pos = t.new_vertex_property("vector<double>")

    pos[root] = (0., 0.)

2137
    p1, p2 = root.out_neighbors()
2138

2139
2140
    if ((w[p1] == w[p2] and p1.out_degree() > p2.out_degree()) or
        w[p1] > w[p2]):
2141
2142
2143
        p1, p2 = p2, p1

    L = len(state.levels)
2144
2145
    pos[p1] = (-1 / L * .5 * aspect, 0)
    pos[p2] = (+1 / L * .5 * aspect, 0)
2146
2147
2148
2149
2150
2151

    for i, p in enumerate([p1, p2]):
        roots = [p]
        while len(roots) > 0:
            nroots = []
            for r in roots:
2152
                cw = pos[r][1] - w[r] / (2. * w[p])
2153
                for v in sorted(r.out_neighbors(), key=lambda a: order[a]):
2154
2155
                    pos[v] = (0, 0)
                    if i == 0:
2156
                        pos[v][0] = pos[r][0] - 1 / L * .5 * aspect
2157
                    else:
2158
                        pos[v][0] = pos[r][0] + 1 / L * .5 * aspect
2159
                    pos[v][1] = cw + w[v] / (2. * w[p])
2160
2161
2162
2163
2164
2165
                    cw += w[v] / w[p]
                    nroots.append(v)
            roots = nroots
    return pos


2166
2167
2168
2169
2170
# Handle cairo contexts from cairocffi

try:
    import cairocffi
    import ctypes
2171
    pycairo_aux = ctypes.PyDLL(os.path.dirname(os.path.abspath(__file__)) + "/libgt_pycairo_aux.so")
2172
2173
    pycairo_aux.gt_PycairoContext_FromContext.restype = ctypes.c_void_p
    pycairo_aux.gt_PycairoContext_FromContext.argtypes = 3 * [ctypes.c_void_p]
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
    ctypes.pythonapi.PyList_Append.argtypes = 2 * [ctypes.c_void_p]
except ImportError:
    pass

def _UNSAFE_cairocffi_context_to_pycairo(cairocffi_context):
    # Sanity check. Continuing with another type would probably segfault.
    if not isinstance(cairocffi_context, cairocffi.Context):
        raise TypeError('Expected a cairocffi.Context, got %r'
                        % cairocffi_context)

    # Create a reference for PycairoContext_FromContext to take ownership of.
    cairocffi.cairo.cairo_reference(cairocffi_context._pointer)
    # Casting the pointer to uintptr_t (the integer type as wide as a pointer)
    # gets the context’s integer address.
    # On CPython id(cairo.Context) gives the address to the Context type,
    # as expected by PycairoContext_FromContext.
2190
    address = pycairo_aux.gt_PycairoContext_FromContext(
2191
2192
2193
2194
2195
2196
2197
2198
2199
        int(cairocffi.ffi.cast('uintptr_t', cairocffi_context._pointer)),
        id(cairo.Context),
        None)
    assert address
    # This trick uses Python’s C API
    # to get a reference to a Python object from its address.
    temp_list = []
    assert ctypes.pythonapi.PyList_Append(id(temp_list), address) == 0
    return temp_list[0]
2200

2201
# Bottom imports to avoid circular dependency issues
2202
2203
from .. inference import get_hierarchy_tree, NestedBlockState, BlockState, \
    OverlapBlockState