cairo_draw.py 99.7 KB
Newer Older
2001
2002
2003
2004
2005
2006
2007
                                  target=picked)[0]
                l = len(state.levels) - max(len(p), 1)

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

2008
                if not overlap:
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
                    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
2022
2023
2024
                    u = GraphView(g, efilt=emask)
                    d = u.degree_property_map("total")
                    u = GraphView(u, vfilt=d.fa > 0)
2025
2026
2027
2028
2029
2030
2031
                    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,
2032
                                          base_type=type(state.levels[0]),
2033
                                          state_args=state.state_args)
2034

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

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

2057
2058
2059
2060
2061
2062
            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
2063
2064
2065

            widget.fit_to_window()
            widget.regenerate_surface(reset=True)
2066
2067
            widget.queue_draw()

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

2073
2074
2075
    if "eorder" in kwargs:
        kwargs["eorder"] = eorder

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

2082
2083
2084
2085
    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())

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

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

2098

2099
def get_bip_hierachy_pos(state, aspect=1., node_weight=None):
2100

2101
    if state.levels[0].overlap:
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
2128
2129
        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)

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

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

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

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

2168
    p1, p2 = root.out_neighbors()
2169

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

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

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


2197
2198
2199
2200
2201
# Handle cairo contexts from cairocffi

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

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