cairo_draw.py 99.7 KB
Newer Older
2001
2002
2003
2004
2005

                bstack = state.get_bstack()
                bs = [s.vp["b"].a for s in bstack[:l+1]]
                bs[-1][:] = 0

2006
                if not overlap:
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
                    b = state.project_level(l).b
                    u = GraphView(g, vfilt=b.a == tb[picked])
                    u.vp["b"] = state.levels[0].b
                    u = Graph(u, prune=True)
                    b = u.vp["b"]
                    bs[0] = b.a
                else:
                    be = orig_state.project_level(l).get_edge_blocks()
                    emask = g.new_edge_property("bool")
                    for e in g.edges():
                        rs = be[e]
                        if rs[0] == tb[picked] and rs[1] == tb[picked]:
                            emask[e] = True
2020
2021
2022
                    u = GraphView(g, efilt=emask)
                    d = u.degree_property_map("total")
                    u = GraphView(u, vfilt=d.fa > 0)
2023
2024
2025
2026
2027
2028
2029
                    u.ep["be"] = orig_state.levels[0].get_edge_blocks()
                    u = Graph(u, prune=True)
                    be = u.ep["be"]
                    s = OverlapBlockState(u, b=be)
                    bs[0] = s.b.a.copy()

                nstate = NestedBlockState(u, bs=bs,
2030
                                          base_type=type(state.levels[0]),
2031
                                          state_args=state.state_args)
2032

2033
2034
2035
2036
2037
2038
                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,
2039
                               subsample_edges=subsample_edges,
2040
2041
2042
                               deg_order=deg_order, empty_branches=False,
                               no_main=True, **kwargs_)

2043
        if key_id == ord('r'):
2044
2045
2046
2047
            if layout == "radial":
                x, y = ungroup_vector_property(pos, [0, 1])
                x.fa -= x.fa.mean()
                y.fa -= y.fa.mean()
2048
                angle = t_orig.new_vertex_property("double")
2049
2050
                angle.fa = (numpy.arctan2(y.fa, x.fa) + 2 * numpy.pi) % (2 * numpy.pi)
                tpos = radial_tree_layout(t_orig,
2051
                                          root=t_orig.vertex(t_orig.num_vertices(True) - 1),
2052
                                          rel_order=angle)
2053
                gg.copy_property(gg.own_property(tpos), pos)
2054

2055
2056
2057
2058
2059
2060
            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
2061
2062
2063

            widget.fit_to_window()
            widget.regenerate_surface(reset=True)
2064
2065
            widget.queue_draw()

2066
2067
    if ("output" not in kwargs and not kwargs.get("inline", is_draw_inline) and
        kwargs.get("mplfig", None) is None):
2068
2069
2070
        kwargs["layout_callback"] = update_cts
        kwargs["key_press_callback"] = draw_branch

2071
2072
2073
    if "eorder" in kwargs:
        kwargs["eorder"] = eorder

2074
2075
2076
    vorder = kwargs.pop("vorder", None)
    if vorder is None:
        vorder = g.degree_property_map("total")
2077
    tvorder = u.own_property(tvorder)
2078
2079
    tvorder.fa[:g.num_vertices()] = vorder.fa

2080
2081
2082
2083
    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())

2084
    pos = graph_draw(u, pos, vprops=t_vprops, eprops=t_eprops, vorder=tvorder,
2085
2086
                     **kwargs)

2087
    if isinstance(pos, PropertyMap):
2088
        t_orig.copy_property(pos, tpos, g=u)
2089
        pos = g.own_property(pos)
2090
    else:
2091
        t_orig.copy_property(pos[0], tpos, g=u)
2092
2093
        pos = (g.own_property(pos[0]),
               g.own_property(pos[1]))
2094
    return pos, t_orig, tpos
2095

2096

2097
def get_bip_hierachy_pos(state, aspect=1., node_weight=None):
2098

2099
    if state.levels[0].overlap:
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
        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)

2128
    root = t.vertex(t.num_vertices(True) - 1)
2129
2130
    if root.out_degree() > 2:
        clabel = is_bipartite(g, partition=True)[1].copy("int")
2131
        if state.levels[0].overlap:
2132
2133
            ostate = OverlapBlockState(g, b=clabel)
            ostate = orig_state.copy(clabel=clabel)
2134
            bc = ostate.propagate_clabel(len(state.levels) - 2)
2135
2136
        else:
            state = state.copy(clabel=clabel)
2137
            bc = state.propagate_clabel(len(state.levels) - 2)
2138

2139
        ps = list(root.out_neighbors())
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
        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:
2158
            w[v] = 1 if node_weight is None else node_weight[v]
2159
        parent, = v.in_neighbors()
2160
2161
2162
2163
2164
2165
        w[parent] += w[v]

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

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

2166
    p1, p2 = root.out_neighbors()
2167

2168
2169
    if ((w[p1] == w[p2] and p1.out_degree() > p2.out_degree()) or
        w[p1] > w[p2]):
2170
2171
2172
        p1, p2 = p2, p1

    L = len(state.levels)
2173
2174
    pos[p1] = (-1 / L * .5 * aspect, 0)
    pos[p2] = (+1 / L * .5 * aspect, 0)
2175
2176
2177
2178
2179
2180

    for i, p in enumerate([p1, p2]):
        roots = [p]
        while len(roots) > 0:
            nroots = []
            for r in roots:
2181
                cw = pos[r][1] - w[r] / (2. * w[p])
2182
                for v in sorted(r.out_neighbors(), key=lambda a: order[a]):
2183
2184
                    pos[v] = (0, 0)
                    if i == 0:
2185
                        pos[v][0] = pos[r][0] - 1 / L * .5 * aspect
2186
                    else:
2187
                        pos[v][0] = pos[r][0] + 1 / L * .5 * aspect
2188
                    pos[v][1] = cw + w[v] / (2. * w[p])
2189
2190
2191
2192
2193
2194
                    cw += w[v] / w[p]
                    nroots.append(v)
            roots = nroots
    return pos


2195
2196
2197
2198
2199
# Handle cairo contexts from cairocffi

try:
    import cairocffi
    import ctypes
2200
    pycairo_aux = ctypes.PyDLL(os.path.dirname(os.path.abspath(__file__)) + "/libgt_pycairo_aux.so")
2201
2202
    pycairo_aux.gt_PycairoContext_FromContext.restype = ctypes.c_void_p
    pycairo_aux.gt_PycairoContext_FromContext.argtypes = 3 * [ctypes.c_void_p]
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
    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.
2219
    address = pycairo_aux.gt_PycairoContext_FromContext(
2220
2221
2222
2223
2224
2225
2226
2227
2228
        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]
2229

2230
# Bottom imports to avoid circular dependency issues
2231
2232
from .. inference import get_hierarchy_tree, NestedBlockState, BlockState, \
    OverlapBlockState