Ejemplo n.º 1
0
 def simplify_graph(infr, graph=None, copy=True):
     if graph is None:
         graph = infr.graph
     simple = graph.copy() if copy else graph
     ut.nx_delete_edge_attr(simple, infr.visual_edge_attrs)
     ut.nx_delete_node_attr(simple, infr.visual_node_attrs + ['pin'])
     return simple
Ejemplo n.º 2
0
    def initialize_visual_node_attrs(infr, graph=None):
        infr.print('initialize_visual_node_attrs!!!')
        infr.print('initialize_visual_node_attrs', 3)
        # import networkx as nx
        if graph is None:
            graph = infr.graph

        # nx.set_node_attributes(graph, name='framewidth', values=3.0)
        # nx.set_node_attributes(graph, name='shape', values=ut.dzip(annot_nodes, ['rect']))
        ut.nx_delete_node_attr(graph, 'size')
        ut.nx_delete_node_attr(graph, 'width')
        ut.nx_delete_node_attr(graph, 'height')
        ut.nx_delete_node_attr(graph, 'radius')

        infr._viz_init_nodes = True
        infr._viz_image_config_dirty = False
Ejemplo n.º 3
0
def show_arch_nx_graph(layers, fnum=None, fullinfo=True):
    r"""

    CommandLine:
        python -m ibeis_cnn.draw_net show_arch_nx_graph:0 --show
        python -m ibeis_cnn.draw_net show_arch_nx_graph:1 --show

    Example0:
        >>> # ENABLE_DOCTEST
        >>> from ibeis_cnn.draw_net import *  # NOQA
        >>> from ibeis_cnn import models
        >>> model = models.mnist.MNISTModel(batch_size=128, output_dims=10,
        >>>                                 data_shape=(24, 24, 3))
        >>> model.init_arch()
        >>> layers = model.get_all_layers()
        >>> show_arch_nx_graph(layers)
        >>> ut.quit_if_noshow()
        >>> import plottool as pt
        >>> ut.show_if_requested()

    Example1:
        >>> # ENABLE_DOCTEST
        >>> from ibeis_cnn.draw_net import *  # NOQA
        >>> from ibeis_cnn import models
        >>> model = models.SiameseCenterSurroundModel(autoinit=True)
        >>> layers = model.get_all_layers()
        >>> show_arch_nx_graph(layers)
        >>> ut.quit_if_noshow()
        >>> import plottool as pt
        >>> ut.show_if_requested()

    """
    import networkx as nx
    import plottool as pt
    import ibeis_cnn.__LASAGNE__ as lasange
    #from matplotlib import offsetbox
    #import matplotlib as mpl

    REMOVE_BATCH_SIZE = True
    from ibeis_cnn import net_strs

    def get_hex_color(layer_type):
        if 'Input' in layer_type:
            return '#A2CECE'
        if 'Conv2D' in layer_type:
            return '#7C9ABB'
        if 'Dense' in layer_type:
            return '#6CCF8D'
        if 'Pool' in layer_type:
            return '#9D9DD2'
        if 'SoftMax' in layer_type:
            return '#7E9FD9'
        else:
            return '#{0:x}'.format(hash(layer_type + 'salt') % 2 ** 24)

    node_dict = {}
    edge_list = []
    edge_attrs = ut.ddict(dict)

    # Make layer ids (ensure no duplicates)
    layer_to_id = {
        l: repr(l) if l.name is None else l.name
        for l in set(layers)
    }
    keys_ = layer_to_id.keys()
    dups = ut.find_duplicate_items(layer_to_id.values())
    for dupval, dupidxs in dups.items():
        newval_fmt = dupval + '_%d'
        for layer in ut.take(keys_, dupidxs):
            newid = ut.get_nonconflicting_string(newval_fmt, layer_to_id.values())
            layer_to_id[layer] = newid

    def layerid(layer):
        return layer_to_id[layer]

    main_nodes = []

    for i, layer in enumerate(layers):
        layer_info = net_strs.get_layer_info(layer)
        layer_type = layer_info['classalias']

        key = layerid(layer)

        color = get_hex_color(layer_info['classalias'])
        # Make label
        lines = []
        if layer_info['name'] is not None:
            lines.append(layer_info['name'])
        if fullinfo:
            lines.append(layer_info['classalias'])
            for attr, val in layer_info['layer_attrs'].items():
                if attr == 'shape' and REMOVE_BATCH_SIZE:
                    val = val[1:]
                if attr == 'output_shape' and REMOVE_BATCH_SIZE:
                    val = val[1:]
                lines.append('{0}: {1}'.format(attr, val))

            nonlinearity = layer_info.get('nonlinearity')
            if nonlinearity is not None:
                alias_map = {
                    'LeakyRectify': 'LReLU',
                }
                val = layer_info['nonlinearity']['type']
                val = alias_map.get(val, val)
                lines.append('nonlinearity:\n{0}'.format(val))

        label = '\n'.join(lines)

        # append node
        is_main_layer = len(layer.params) > 0
        #is_main_layer = len(lasange.layers.get_all_params(layer, trainable=True)) > 0
        if layer_info['classname'] in lasange.layers.normalization.__all__:
            is_main_layer = False
        if layer_info['classname'] in lasange.layers.special.__all__:
            is_main_layer = False
        if layer_info['classname'].startswith('BatchNorm'):
            is_main_layer = False
        if layer_info['classname'].startswith('ElemwiseSum'):
            is_main_layer = True

        if layer_type == 'Input':
            is_main_layer = True

        if hasattr(layer, '_is_main_layer'):
            is_main_layer = layer._is_main_layer

        #if getattr(layer, 'name', '') is not None and getattr(layer, 'name', '') .endswith('/sum'):
        #    is_main_layer = True

        node_attr = dict(name=key, label=label, color=color,
                         fillcolor=color, style='filled',
                         is_main_layer=is_main_layer)

        node_attr['is_main_layer'] = is_main_layer
        if is_main_layer:
            main_nodes.append(key)
        node_attr['classalias'] = layer_info['classalias']

        if is_main_layer or node_attr['classalias'].startswith('Conv'):
            if hasattr(layer, 'shape'):
                if len(layer.shape) == 3:
                    node_attr['out_size'] = (layer.shape[2],
                                             layer.shape[1])
                    node_attr['depth'] = layer.output_shape[0]
            if hasattr(layer, 'output_shape'):
                if len(layer.output_shape) == 4:
                    depth = layer.output_shape[1]
                    width, height = (layer.output_shape[3],
                                     layer.output_shape[2])
                    xshift = -width * (.1 / (depth ** (1 / 3))) / 3
                    yshift = height * (.1 / (depth ** (1 / 3))) / 2
                    node_attr['depth'] = depth
                    node_attr['xshift'] = xshift
                    node_attr['yshift'] = yshift
                    node_attr['out_size'] = (width, height)

                if len(layer.output_shape) == 2:
                    node_attr['out_size'] = (1,
                                             layer.output_shape[1])

        node_dict[key] = node_attr

        _input_layers = []
        if hasattr(layer, 'input_layers'):
            _input_layers += layer.input_layers
        if hasattr(layer, 'input_layer'):
            _input_layers += [layer.input_layer]

        for input_layer in _input_layers:
            parent_key = layerid(input_layer)
            edge = (parent_key, key)
            edge_list.append(edge)

    main_size_ = np.array((100, 100)) * 4
    sub_size = np.array((75, 50)) * 4

    # Setup scaled width and heights
    out_size_list = [v['out_size'] for v in node_dict.values() if 'out_size' in v]
    out_size_list = np.array(out_size_list)
    #out_size_list = out_size_list[out_size_list.T[0] > 1]
    area_arr = np.prod(out_size_list, axis=1)
    main_outsize = np.array(out_size_list[area_arr.argmax()])
    #main_outsize = np.array(out_size_list[area_arr.argmin()])
    scale = main_size_ / main_outsize

    scale_dense_max = .25
    scale_dense_min = 8

    for k, v in node_dict.items():
        if v['is_main_layer'] or v['classalias'].startswith('Conv'):
            if 'out_size' in v:
                # Make dense layers more visible
                if v['classalias'] == 'Dense':
                    v['shape'] = 'rect'
                    v['width'] = scale_dense_min
                    if v['out_size'][1] > main_outsize[1]:
                        v['height'] =  v['out_size'][1] * scale[1] * scale_dense_max
                    elif v['out_size'][1] < scale_dense_min:
                        v['height'] = scale_dense_min * v['out_size'][1]
                    else:
                        v['height'] = v['out_size'][1]
                elif v['classalias'].startswith('Conv'):
                    v['shape'] = 'stack'
                    #v['shape'] = 'rect'
                    v['width'] = v['out_size'][0] * scale[0]
                    v['height'] =  v['out_size'][1] * scale[1]
                else:
                    v['shape'] = 'rect'
                    v['width'] = v['out_size'][0] * scale[0]
                    v['height'] =  v['out_size'][1] * scale[1]
            else:
                v['shape'] = 'rect'
                v['width'] = main_size_[0]
                v['height'] = main_size_[1]
        else:
            #v['shape'] = 'ellipse'
            v['shape'] = 'rect'
            v['style'] = 'rounded'
            v['width'] = sub_size[0]
            v['height'] = sub_size[1]

    key_order = ut.take(layer_to_id, layers)
    node_dict = ut.dict_subset(node_dict, key_order)

    #print('node_dict = ' + ut.repr3(node_dict))

    # Create the networkx graph structure
    G = nx.DiGraph()
    G.add_nodes_from(node_dict.items())
    G.add_edges_from(edge_list)
    for key, val in edge_attrs.items():
        nx.set_edge_attributes(G, key, val)

    # Add invisible structure
    #main_nodes = [key for key, val in
    #              nx.get_node_attributes(G, 'is_main_layer').items() if val]

    main_children = ut.odict()

    #for n1, n2 in ut.itertwo(main_nodes):
    #    print('n1, n2 = %r %r' % (n1, n2))
    #    import utool
    #    utool.embed()
    #    children = ut.nx_all_nodes_between(G, n1, n2)
    #    if n1 in children:
    #        children.remove(n1)
    #    if n2 in children:
    #        children.remove(n2)
    #    main_children[n1] = children

    #    #pass
    #main_children[main_nodes[-1]] = []

    for n1 in main_nodes:
        main_children[n1] = []
        # Main nodes only place constraints on nodes in the next main group.
        # Not their own
        next_main = None
        G.node[n1]['group'] = n1
        for (_, n2) in nx.bfs_edges(G, n1):
            if next_main is None:
                if n2 in main_nodes:
                    next_main = n2
                else:
                    G.node[n2]['group'] = n1
                    main_children[n1].append(n2)
            else:
                if n2 not in list(nx.descendants(G, next_main)):
                    G.node[n2]['group'] = n1
                    main_children[n1].append(n2)

    # Custom positioning
    x = 0
    y = 1000
    #print('main_children = %s' % (ut.repr3(main_children),))

    #main_nodes = ut.isect(list(nx.topological_sort(G)), main_nodes)
    xpad = main_size_[0] * .3
    ypad = main_size_[1] * .3

    # Draw each main node, and then put its children under it
    # Then move to the left and draw the next main node.
    cumwidth = 0
    for n1 in main_nodes:
        cumheight = 0

        maxwidth = G.node[n1]['width']
        for n2 in main_children[n1]:
            maxwidth = max(maxwidth, G.node[n2]['width'])

        cumwidth += xpad
        cumwidth += maxwidth / 2

        pos = np.array([x + cumwidth, y - cumheight])
        G.node[n1]['pos'] = pos
        G.node[n1]['pin'] = 'true'

        height = G.node[n1]['height']
        cumheight += height / 2

        for n2 in main_children[n1]:
            height = G.node[n2]['height']
            cumheight += ypad
            cumheight += height / 2
            pos = np.array([x + cumwidth, y - cumheight])
            G.node[n2]['pos'] = pos
            G.node[n2]['pin'] = 'true'
            cumheight += height / 2

        cumwidth += maxwidth / 2

    # Pin everybody
    nx.set_node_attributes(G, 'pin', 'true')
    layoutkw = dict(prog='neato', splines='line')
    #layoutkw = dict(prog='neato', splines='spline')
    layoutkw = dict(prog='neato', splines='ortho')
    G_ = G.copy()
    # delete lables for positioning
    _labels = nx.get_node_attributes(G_, 'label')
    ut.nx_delete_node_attr(G_, 'label')
    nx.set_node_attributes(G_, 'label', '')
    nolayout = False
    if nolayout:
        G_.remove_edges_from(list(G_.edges()))
    else:
        layout_info = pt.nx_agraph_layout(G_, inplace=True, **layoutkw)  # NOQA
    # reset labels
    if not nolayout:
        nx.set_node_attributes(G_, 'label', _labels)
    _ = pt.show_nx(G_, fontsize=8, arrow_width=.3, layout='custom', fnum=fnum)  # NOQA
    #pt.adjust_subplots(top=1, bot=0, left=0, right=1)
    pt.plt.tight_layout()
Ejemplo n.º 4
0
def intraoccurrence_connected():
    r"""
    CommandLine:
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show --postcut
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show --smaller

    Example:
        >>> # DISABLE_DOCTEST
        >>> from ibeis.scripts.specialdraw import *  # NOQA
        >>> result = intraoccurrence_connected()
        >>> print(result)
        >>> ut.quit_if_noshow()
        >>> import plottool as pt
        >>> ut.show_if_requested()
    """
    import ibeis
    import plottool as pt
    from ibeis.viz import viz_graph
    import networkx as nx
    pt.ensure_pylab_qt4()
    ibs = ibeis.opendb(defaultdb='PZ_Master1')
    nid2_aid = {
        #4880: [3690, 3696, 3703, 3706, 3712, 3721],
        4880: [3690, 3696, 3703],
        6537: [3739],
        6653: [7671],
        6610: [7566, 7408],
        #6612: [7664, 7462, 7522],
        #6624: [7465, 7360],
        #6625: [7746, 7383, 7390, 7477, 7376, 7579],
        6630: [7586, 7377, 7464, 7478],
        #6677: [7500]
    }
    nid2_dbaids = {4880: [33, 6120, 7164], 6537: [7017, 7206], 6653: [7660]}
    if ut.get_argflag('--small') or ut.get_argflag('--smaller'):
        del nid2_aid[6630]
        del nid2_aid[6537]
        del nid2_dbaids[6537]
        if ut.get_argflag('--smaller'):
            nid2_dbaids[4880].remove(33)
            nid2_aid[4880].remove(3690)
            nid2_aid[6610].remove(7408)
        #del nid2_aid[4880]
        #del nid2_dbaids[4880]

    aids = ut.flatten(nid2_aid.values())

    temp_nids = [1] * len(aids)
    postcut = ut.get_argflag('--postcut')
    aids_list = ibs.group_annots_by_name(aids)[0]
    ensure_edges = 'all' if True or not postcut else None
    unlabeled_graph = viz_graph.make_netx_graph_from_aid_groups(
        ibs,
        aids_list,
        #invis_edges=invis_edges,
        ensure_edges=ensure_edges,
        temp_nids=temp_nids)
    viz_graph.color_by_nids(unlabeled_graph,
                            unique_nids=[1] *
                            len(list(unlabeled_graph.nodes())))
    viz_graph.ensure_node_images(ibs, unlabeled_graph)
    nx.set_node_attributes(unlabeled_graph, 'shape', 'rect')
    #unlabeled_graph = unlabeled_graph.to_undirected()

    # Find the "database exemplars for these annots"
    if False:
        gt_aids = ibs.get_annot_groundtruth(aids)
        gt_aids = [ut.setdiff(s, aids) for s in gt_aids]
        dbaids = ut.unique(ut.flatten(gt_aids))
        dbaids = ibs.filter_annots_general(dbaids, minqual='good')
        ibs.get_annot_quality_texts(dbaids)
    else:
        dbaids = ut.flatten(nid2_dbaids.values())
    exemplars = nx.DiGraph()
    #graph = exemplars  # NOQA
    exemplars.add_nodes_from(dbaids)

    def add_clique(graph, nodes, edgeattrs={}, nodeattrs={}):
        edge_list = ut.upper_diag_self_prodx(nodes)
        graph.add_edges_from(edge_list, **edgeattrs)
        return edge_list

    for aids_, nid in zip(*ibs.group_annots_by_name(dbaids)):
        add_clique(exemplars, aids_)
    viz_graph.ensure_node_images(ibs, exemplars)
    viz_graph.color_by_nids(exemplars, ibs=ibs)

    nx.set_node_attributes(unlabeled_graph, 'framewidth', False)
    nx.set_node_attributes(exemplars, 'framewidth', 4.0)

    nx.set_node_attributes(unlabeled_graph, 'group', 'unlab')
    nx.set_node_attributes(exemplars, 'group', 'exemp')

    #big_graph = nx.compose_all([unlabeled_graph])
    big_graph = nx.compose_all([exemplars, unlabeled_graph])

    # add sparse connections from unlabeled to exemplars
    import numpy as np
    rng = np.random.RandomState(0)
    if True or not postcut:
        for aid_ in unlabeled_graph.nodes():
            flags = rng.rand(len(exemplars)) > .5
            nid_ = ibs.get_annot_nids(aid_)
            exnids = np.array(ibs.get_annot_nids(list(exemplars.nodes())))
            flags = np.logical_or(exnids == nid_, flags)
            exmatches = ut.compress(list(exemplars.nodes()), flags)
            big_graph.add_edges_from(list(ut.product([aid_], exmatches)),
                                     color=pt.ORANGE,
                                     implicit=True)
    else:
        for aid_ in unlabeled_graph.nodes():
            flags = rng.rand(len(exemplars)) > .5
            exmatches = ut.compress(list(exemplars.nodes()), flags)
            nid_ = ibs.get_annot_nids(aid_)
            exnids = np.array(ibs.get_annot_nids(exmatches))
            exmatches = ut.compress(exmatches, exnids == nid_)
            big_graph.add_edges_from(list(ut.product([aid_], exmatches)))
        pass

    nx.set_node_attributes(big_graph, 'shape', 'rect')
    #if False and postcut:
    #    ut.nx_delete_node_attr(big_graph, 'nid')
    #    ut.nx_delete_edge_attr(big_graph, 'color')
    #    viz_graph.ensure_graph_nid_labels(big_graph, ibs=ibs)
    #    viz_graph.color_by_nids(big_graph, ibs=ibs)
    #    big_graph = big_graph.to_undirected()

    layoutkw = {
        'sep': 1 / 5,
        'prog': 'neato',
        'overlap': 'false',
        #'splines': 'ortho',
        'splines': 'spline',
    }

    as_directed = False
    #as_directed = True
    #hacknode = True
    hacknode = 0

    graph = big_graph
    ut.nx_ensure_agraph_color(graph)
    if hacknode:
        nx.set_edge_attributes(graph, 'taillabel',
                               {e: str(e[0])
                                for e in graph.edges()})
        nx.set_edge_attributes(graph, 'headlabel',
                               {e: str(e[1])
                                for e in graph.edges()})

    explicit_graph = pt.get_explicit_graph(graph)
    _, layout_info = pt.nx_agraph_layout(explicit_graph,
                                         orig_graph=graph,
                                         inplace=True,
                                         **layoutkw)

    if ut.get_argflag('--smaller'):
        graph.node[7660]['pos'] = np.array([550, 350])
        graph.node[6120]['pos'] = np.array([200, 600]) + np.array([350, -400])
        graph.node[7164]['pos'] = np.array([200, 480]) + np.array([350, -400])
        nx.set_node_attributes(graph, 'pin', 'true')
        _, layout_info = pt.nx_agraph_layout(graph, inplace=True, **layoutkw)
    elif ut.get_argflag('--small'):
        graph.node[7660]['pos'] = np.array([750, 350])
        graph.node[33]['pos'] = np.array([300, 600]) + np.array([350, -400])
        graph.node[6120]['pos'] = np.array([500, 600]) + np.array([350, -400])
        graph.node[7164]['pos'] = np.array([410, 480]) + np.array([350, -400])
        nx.set_node_attributes(graph, 'pin', 'true')
        _, layout_info = pt.nx_agraph_layout(graph, inplace=True, **layoutkw)

    if not postcut:
        #pt.show_nx(graph.to_undirected(), layout='agraph', layoutkw=layoutkw,
        #           as_directed=False)
        #pt.show_nx(graph, layout='agraph', layoutkw=layoutkw,
        #           as_directed=as_directed, hacknode=hacknode)

        pt.show_nx(graph,
                   layout='custom',
                   layoutkw=layoutkw,
                   as_directed=as_directed,
                   hacknode=hacknode)
    else:
        #explicit_graph = pt.get_explicit_graph(graph)
        #_, layout_info = pt.nx_agraph_layout(explicit_graph, orig_graph=graph,
        #                                     **layoutkw)

        #layout_info['edge']['alpha'] = .8
        #pt.apply_graph_layout_attrs(graph, layout_info)

        #graph_layout_attrs = layout_info['graph']
        ##edge_layout_attrs  = layout_info['edge']
        ##node_layout_attrs  = layout_info['node']

        #for key, vals in layout_info['node'].items():
        #    #print('[special] key = %r' % (key,))
        #    nx.set_node_attributes(graph, key, vals)

        #for key, vals in layout_info['edge'].items():
        #    #print('[special] key = %r' % (key,))
        #    nx.set_edge_attributes(graph, key, vals)

        #nx.set_edge_attributes(graph, 'alpha', .8)
        #graph.graph['splines'] = graph_layout_attrs.get('splines', 'line')
        #graph.graph['splines'] = 'polyline'   # graph_layout_attrs.get('splines', 'line')
        #graph.graph['splines'] = 'line'

        cut_graph = graph.copy()
        edge_list = list(cut_graph.edges())
        edge_nids = np.array(ibs.unflat_map(ibs.get_annot_nids, edge_list))
        cut_flags = edge_nids.T[0] != edge_nids.T[1]
        cut_edges = ut.compress(edge_list, cut_flags)
        cut_graph.remove_edges_from(cut_edges)
        ut.nx_delete_node_attr(cut_graph, 'nid')
        viz_graph.ensure_graph_nid_labels(cut_graph, ibs=ibs)

        #ut.nx_get_default_node_attributes(exemplars, 'color', None)
        ut.nx_delete_node_attr(cut_graph,
                               'color',
                               nodes=unlabeled_graph.nodes())
        aid2_color = ut.nx_get_default_node_attributes(cut_graph, 'color',
                                                       None)
        nid2_colors = ut.group_items(aid2_color.values(),
                                     ibs.get_annot_nids(aid2_color.keys()))
        nid2_colors = ut.map_dict_vals(ut.filter_Nones, nid2_colors)
        nid2_colors = ut.map_dict_vals(ut.unique, nid2_colors)
        #for val in nid2_colors.values():
        #    assert len(val) <= 1
        # Get initial colors
        nid2_color_ = {
            nid: colors_[0]
            for nid, colors_ in nid2_colors.items() if len(colors_) == 1
        }

        graph = cut_graph
        viz_graph.color_by_nids(cut_graph, ibs=ibs, nid2_color_=nid2_color_)
        nx.set_node_attributes(cut_graph, 'framewidth', 4)

        pt.show_nx(cut_graph,
                   layout='custom',
                   layoutkw=layoutkw,
                   as_directed=as_directed,
                   hacknode=hacknode)

    pt.zoom_factory()
Ejemplo n.º 5
0
def nx_agraph_layout(graph, orig_graph=None, inplace=False, verbose=None, **kwargs):
    r"""
    orig_graph = graph
    graph = layout_graph

    References:
        http://www.graphviz.org/content/attrs
        http://www.graphviz.org/doc/info/attrs.html
    """
    import networkx as nx
    import pygraphviz

    kwargs = kwargs.copy()
    prog = kwargs.pop('prog', 'dot')
    if prog != 'dot':
        kwargs['overlap'] = kwargs.get('overlap', 'false')
    kwargs['splines'] = kwargs.get('splines', 'spline')
    kwargs['notranslate'] = 'true'  # for neato postprocessing
    argparts = ['-G%s=%s' % (key, str(val))
                for key, val in kwargs.items()]
    args = ' '.join(argparts)
    splines = kwargs['splines']
    if verbose is None:
        verbose = ut.VERBOSE
    if verbose:
        print('args = %r' % (args,))
    # Convert to agraph format
    graph_ = graph.copy()

    ut.nx_ensure_agraph_color(graph_)

    # Reduce size to be in inches not pixels
    # FIXME: make robust to param settings
    # Hack to make the w/h of the node take thae max instead of
    # dot which takes the minimum
    shaped_nodes = [n for n, d in graph_.nodes(data=True) if 'width' in d]
    node_attrs = ut.dict_take(graph_.node, shaped_nodes)
    width_px = np.array(ut.take_column(node_attrs, 'width'))
    height_px = np.array(ut.take_column(node_attrs, 'height'))
    scale = np.array(ut.dict_take_column(node_attrs, 'scale', default=1.0))

    width_in = width_px / 72.0 * scale
    height_in = height_px / 72.0 * scale
    width_in_dict = dict(zip(shaped_nodes, width_in))
    height_in_dict = dict(zip(shaped_nodes, height_in))
    nx.set_node_attributes(graph_, 'width', width_in_dict)
    nx.set_node_attributes(graph_, 'height', height_in_dict)
    ut.nx_delete_node_attr(graph_, 'scale')

    # Check for any nodes with groupids
    node_to_groupid = nx.get_node_attributes(graph_, 'groupid')
    if node_to_groupid:
        groupid_to_nodes = ut.group_items(*zip(*node_to_groupid.items()))
    else:
        groupid_to_nodes = {}
    # Initialize agraph format
    #import utool
    #utool.embed()
    ut.nx_delete_None_edge_attr(graph_)
    agraph = nx.nx_agraph.to_agraph(graph_)
    # Add subgraphs labels
    # TODO: subgraph attrs
    group_attrs = graph.graph.get('groupattrs', {})
    for groupid, nodes in groupid_to_nodes.items():
        # subgraph_attrs = {}
        subgraph_attrs = group_attrs.get(groupid, {}).copy()
        cluster_flag = True
        # FIXME: make this more natural to specify
        if 'cluster' in subgraph_attrs:
            cluster_flag = subgraph_attrs['cluster']
            del subgraph_attrs['cluster']
        # subgraph_attrs = dict(rankdir='LR')
        # subgraph_attrs = dict(rankdir='LR')
        # subgraph_attrs['rank'] = 'min'
        # subgraph_attrs['rank'] = 'source'
        name = groupid
        if cluster_flag:
            # graphviz treast subgraphs labeld with cluster differently
            name = 'cluster_' + groupid
        else:
            name = groupid
        agraph.add_subgraph(nodes, name, **subgraph_attrs)
    for node in graph_.nodes():
        # force pinning of node points
        anode = pygraphviz.Node(agraph, node)
        if anode.attr['pin'] == 'true':
            if anode.attr['pos'] is not None and len(anode.attr['pos']) > 0 and not anode.attr['pos'].endswith('!'):
                import re
                #utool.embed()
                ptstr_ = anode.attr['pos']
                #print('ptstr_ = %r' % (ptstr_,))
                ptstr = ptstr_.strip('[]').strip(' ').strip('()')
                #print('ptstr = %r' % (ptstr,))
                ptstr_list = [x.rstrip(',') for x in re.split(r'\s+', ptstr)]
                #print('ptstr_list = %r' % (ptstr_list,))
                pt_list = list(map(float, ptstr_list))
                #print('pt_list = %r' % (pt_list,))
                pt_arr = np.array(pt_list) / 72.0
                #print('pt_arr = %r' % (pt_arr,))
                new_ptstr_list = list(map(str, pt_arr))
                new_ptstr = ','.join(new_ptstr_list) + '!'
                #print('new_ptstr = %r' % (new_ptstr,))
                anode.attr['pos'] = new_ptstr

    # Run layout
    #print('prog = %r' % (prog,))
    if ut.VERBOSE or verbose > 0:
        print('BEFORE LAYOUT\n' + str(agraph))
    agraph.layout(prog=prog, args=args)
    agraph.draw(ut.truepath('~/test_graphviz_draw.png'))
    if ut.VERBOSE or verbose > 1:
        print('AFTER LAYOUT\n' + str(agraph))

    # TODO: just replace with a single dict of attributes
    node_layout_attrs = ut.ddict(dict)
    edge_layout_attrs = ut.ddict(dict)

    #for node in agraph.nodes():
    for node in graph_.nodes():
        anode = pygraphviz.Node(agraph, node)
        node_attrs = parse_anode_layout_attrs(anode)
        for key, val in node_attrs.items():
            node_layout_attrs[key][node] = val

    edges = list(ut.nx_edges(graph_, keys=True))

    for edge in edges:
        aedge = pygraphviz.Edge(agraph, *edge)
        edge_attrs = parse_aedge_layout_attrs(aedge)
        for key, val in edge_attrs.items():
            edge_layout_attrs[key][edge] = val

    if orig_graph is not None and kwargs.get('draw_implicit', True):
        # ADD IN IMPLICIT EDGES
        layout_edges = set(ut.nx_edges(graph_, keys=True))
        orig_edges = set(ut.nx_edges(orig_graph, keys=True))
        implicit_edges = list(orig_edges - layout_edges)
        #all_edges = list(set.union(orig_edges, layout_edges))
        needs_implicit = len(implicit_edges) > 0
        if needs_implicit:
            # Pin down positions
            for node in agraph.nodes():
                anode = pygraphviz.Node(agraph, node)
                anode.attr['pin'] = 'true'
                anode.attr['pos'] += '!'

            # Add new edges to route
            for iedge in implicit_edges:
                data = orig_graph.get_edge_data(*iedge)
                agraph.add_edge(*iedge, **data)

            if ut.VERBOSE or verbose:
                print('BEFORE IMPLICIT LAYOUT\n' + str(agraph))
            # Route the implicit edges (must use neato)

            control_node = pygraphviz.Node(agraph, node)
            #print('control_node = %r' % (control_node,))
            node1_attr1 = parse_anode_layout_attrs(control_node)
            #print('node1_attr1 = %r' % (node1_attr1,))

            implicit_kw = kwargs.copy()
            implicit_kw['overlap'] = 'true'
            #del implicit_kw['overlap']  # can cause node positions to change
            argparts = ['-G%s=%s' % (key, str(val))
                        for key, val in implicit_kw.items()]
            args = ' '.join(argparts)
            #print('args = %r' % (args,))

            #import utool
            #utool.embed()

            agraph.layout(prog='neato', args='-n ' + args)
            agraph.draw(ut.truepath('~/implicit_test_graphviz_draw.png'))
            if ut.VERBOSE or verbose:
                print('AFTER IMPLICIT LAYOUT\n' + str(agraph))

            control_node = pygraphviz.Node(agraph, node)
            print('control_node = %r' % (control_node,))
            node1_attr2 = parse_anode_layout_attrs(control_node)
            print('node1_attr2 = %r' % (node1_attr2,))

            # graph positions shifted
            # This is not the right place to divide by 72
            translation = (node1_attr1['pos'] - node1_attr2['pos'] )
            #print('translation = %r' % (translation,))
            #translation = np.array([0, 0])
            print('translation = %r' % (translation,))

            #for iedge in all_edges:
            for iedge in implicit_edges:
                aedge = pygraphviz.Edge(agraph, *iedge)
                iedge_attrs = parse_aedge_layout_attrs(aedge, translation)
                for key, val in iedge_attrs.items():
                    edge_layout_attrs[key][iedge] = val

    graph_layout_attrs = dict(
        splines=splines
    )

    layout_info = {
        'graph': graph_layout_attrs,
        'edge': dict(edge_layout_attrs),
        'node': dict(node_layout_attrs),
    }

    if inplace:
        if orig_graph is not None:
            graph = orig_graph
        apply_graph_layout_attrs(graph, layout_info)

    return graph, layout_info
Ejemplo n.º 6
0
def make_agraph(graph):
    # FIXME; use this in nx_agraph_layout instead to comparementalize more
    import networkx as nx
    import pygraphviz
    # Convert to agraph format
    graph_ = graph.copy()

    ut.nx_ensure_agraph_color(graph_)
    # Reduce size to be in inches not pixels
    # FIXME: make robust to param settings
    # Hack to make the w/h of the node take thae max instead of
    # dot which takes the minimum
    shaped_nodes = [n for n, d in graph_.nodes(data=True) if 'width' in d]
    node_attrs = ut.dict_take(graph_.node, shaped_nodes)
    width_px = np.array(ut.take_column(node_attrs, 'width'))
    height_px = np.array(ut.take_column(node_attrs, 'height'))
    scale = np.array(ut.dict_take_column(node_attrs, 'scale', default=1.0))

    width_in = width_px / 72.0 * scale
    height_in = height_px / 72.0 * scale
    width_in_dict = dict(zip(shaped_nodes, width_in))
    height_in_dict = dict(zip(shaped_nodes, height_in))
    nx.set_node_attributes(graph_, 'width', width_in_dict)
    nx.set_node_attributes(graph_, 'height', height_in_dict)
    ut.nx_delete_node_attr(graph_, 'scale')

    # Check for any nodes with groupids
    node_to_groupid = nx.get_node_attributes(graph_, 'groupid')
    if node_to_groupid:
        groupid_to_nodes = ut.group_items(*zip(*node_to_groupid.items()))
    else:
        groupid_to_nodes = {}
    # Initialize agraph format
    #import utool
    #utool.embed()
    ut.nx_delete_None_edge_attr(graph_)
    agraph = nx.nx_agraph.to_agraph(graph_)
    # Add subgraphs labels
    # TODO: subgraph attrs
    for groupid, nodes in groupid_to_nodes.items():
        subgraph_attrs = {}
        #subgraph_attrs = dict(rankdir='LR')
        #subgraph_attrs['rank'] = 'min'
        subgraph_attrs['rank'] = 'same'
        name = groupid
        name = 'cluster_' + groupid
        agraph.add_subgraph(nodes, name, **subgraph_attrs)
    for node in graph_.nodes():
        # force pinning of node points
        anode = pygraphviz.Node(agraph, node)
        if anode.attr['pin'] == 'true':
            if anode.attr['pos'] is not None and not anode.attr['pos'].endswith('!'):
                import re
                #utool.embed()
                ptstr = anode.attr['pos'].strip('[]').strip(' ')
                ptstr_list = re.split(r'\s+', ptstr)
                pt_arr = np.array(list(map(float, ptstr_list))) / 72.0
                #print('pt_arr = %r' % (pt_arr,))
                new_ptstr_list = list(map(str, pt_arr))
                new_ptstr = ','.join(new_ptstr_list) + '!'
                #print('new_ptstr = %r' % (new_ptstr,))
                anode.attr['pos'] = new_ptstr
    return agraph
Ejemplo n.º 7
0
def intraoccurrence_connected():
    r"""
    CommandLine:
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show --postcut
        python -m ibeis.scripts.specialdraw intraoccurrence_connected --show --smaller

    Example:
        >>> # DISABLE_DOCTEST
        >>> from ibeis.scripts.specialdraw import *  # NOQA
        >>> result = intraoccurrence_connected()
        >>> print(result)
        >>> ut.quit_if_noshow()
        >>> import plottool as pt
        >>> ut.show_if_requested()
    """
    import ibeis
    import plottool as pt
    from ibeis.viz import viz_graph
    import networkx as nx
    pt.ensure_pylab_qt4()
    ibs = ibeis.opendb(defaultdb='PZ_Master1')
    nid2_aid = {
        #4880: [3690, 3696, 3703, 3706, 3712, 3721],
        4880: [3690, 3696, 3703],
        6537: [3739],
        6653: [7671],
        6610: [7566, 7408],
        #6612: [7664, 7462, 7522],
        #6624: [7465, 7360],
        #6625: [7746, 7383, 7390, 7477, 7376, 7579],
        6630: [7586, 7377, 7464, 7478],
        #6677: [7500]
    }
    nid2_dbaids = {
        4880: [33, 6120, 7164],
        6537: [7017, 7206],
        6653: [7660]
    }
    if ut.get_argflag('--small') or ut.get_argflag('--smaller'):
        del nid2_aid[6630]
        del nid2_aid[6537]
        del nid2_dbaids[6537]
        if ut.get_argflag('--smaller'):
            nid2_dbaids[4880].remove(33)
            nid2_aid[4880].remove(3690)
            nid2_aid[6610].remove(7408)
        #del nid2_aid[4880]
        #del nid2_dbaids[4880]

    aids = ut.flatten(nid2_aid.values())

    temp_nids = [1] * len(aids)
    postcut = ut.get_argflag('--postcut')
    aids_list = ibs.group_annots_by_name(aids)[0]
    ensure_edges = 'all' if True or not postcut else None
    unlabeled_graph = viz_graph.make_netx_graph_from_aid_groups(
        ibs, aids_list,
        #invis_edges=invis_edges,
        ensure_edges=ensure_edges, temp_nids=temp_nids)
    viz_graph.color_by_nids(unlabeled_graph, unique_nids=[1] *
                            len(list(unlabeled_graph.nodes())))
    viz_graph.ensure_node_images(ibs, unlabeled_graph)
    nx.set_node_attributes(unlabeled_graph, 'shape', 'rect')
    #unlabeled_graph = unlabeled_graph.to_undirected()

    # Find the "database exemplars for these annots"
    if False:
        gt_aids = ibs.get_annot_groundtruth(aids)
        gt_aids = [ut.setdiff(s, aids) for s in gt_aids]
        dbaids = ut.unique(ut.flatten(gt_aids))
        dbaids = ibs.filter_annots_general(dbaids, minqual='good')
        ibs.get_annot_quality_texts(dbaids)
    else:
        dbaids = ut.flatten(nid2_dbaids.values())
    exemplars = nx.DiGraph()
    #graph = exemplars  # NOQA
    exemplars.add_nodes_from(dbaids)

    def add_clique(graph, nodes, edgeattrs={}, nodeattrs={}):
        edge_list = ut.upper_diag_self_prodx(nodes)
        graph.add_edges_from(edge_list, **edgeattrs)
        return edge_list

    for aids_, nid in zip(*ibs.group_annots_by_name(dbaids)):
        add_clique(exemplars, aids_)
    viz_graph.ensure_node_images(ibs, exemplars)
    viz_graph.color_by_nids(exemplars, ibs=ibs)

    nx.set_node_attributes(unlabeled_graph, 'framewidth', False)
    nx.set_node_attributes(exemplars,  'framewidth', 4.0)

    nx.set_node_attributes(unlabeled_graph, 'group', 'unlab')
    nx.set_node_attributes(exemplars,  'group', 'exemp')

    #big_graph = nx.compose_all([unlabeled_graph])
    big_graph = nx.compose_all([exemplars, unlabeled_graph])

    # add sparse connections from unlabeled to exemplars
    import numpy as np
    rng = np.random.RandomState(0)
    if True or not postcut:
        for aid_ in unlabeled_graph.nodes():
            flags = rng.rand(len(exemplars)) > .5
            nid_ = ibs.get_annot_nids(aid_)
            exnids = np.array(ibs.get_annot_nids(list(exemplars.nodes())))
            flags = np.logical_or(exnids == nid_, flags)
            exmatches = ut.compress(list(exemplars.nodes()), flags)
            big_graph.add_edges_from(list(ut.product([aid_], exmatches)),
                                     color=pt.ORANGE, implicit=True)
    else:
        for aid_ in unlabeled_graph.nodes():
            flags = rng.rand(len(exemplars)) > .5
            exmatches = ut.compress(list(exemplars.nodes()), flags)
            nid_ = ibs.get_annot_nids(aid_)
            exnids = np.array(ibs.get_annot_nids(exmatches))
            exmatches = ut.compress(exmatches, exnids == nid_)
            big_graph.add_edges_from(list(ut.product([aid_], exmatches)))
        pass

    nx.set_node_attributes(big_graph, 'shape', 'rect')
    #if False and postcut:
    #    ut.nx_delete_node_attr(big_graph, 'nid')
    #    ut.nx_delete_edge_attr(big_graph, 'color')
    #    viz_graph.ensure_graph_nid_labels(big_graph, ibs=ibs)
    #    viz_graph.color_by_nids(big_graph, ibs=ibs)
    #    big_graph = big_graph.to_undirected()

    layoutkw = {
        'sep' : 1 / 5,
        'prog': 'neato',
        'overlap': 'false',
        #'splines': 'ortho',
        'splines': 'spline',
    }

    as_directed = False
    #as_directed = True
    #hacknode = True
    hacknode = 0

    graph = big_graph
    ut.nx_ensure_agraph_color(graph)
    if hacknode:
        nx.set_edge_attributes(graph, 'taillabel', {e: str(e[0]) for e in graph.edges()})
        nx.set_edge_attributes(graph, 'headlabel', {e: str(e[1]) for e in graph.edges()})

    explicit_graph = pt.get_explicit_graph(graph)
    _, layout_info = pt.nx_agraph_layout(explicit_graph, orig_graph=graph,
                                         inplace=True, **layoutkw)

    if ut.get_argflag('--smaller'):
        graph.node[7660]['pos'] = np.array([550, 350])
        graph.node[6120]['pos'] = np.array([200, 600]) + np.array([350, -400])
        graph.node[7164]['pos'] = np.array([200, 480]) + np.array([350, -400])
        nx.set_node_attributes(graph, 'pin', 'true')
        _, layout_info = pt.nx_agraph_layout(graph,
                                             inplace=True, **layoutkw)
    elif ut.get_argflag('--small'):
        graph.node[7660]['pos'] = np.array([750, 350])
        graph.node[33]['pos'] = np.array([300, 600]) + np.array([350, -400])
        graph.node[6120]['pos'] = np.array([500, 600]) + np.array([350, -400])
        graph.node[7164]['pos'] = np.array([410, 480]) + np.array([350, -400])
        nx.set_node_attributes(graph, 'pin', 'true')
        _, layout_info = pt.nx_agraph_layout(graph,
                                             inplace=True, **layoutkw)

    if not postcut:
        #pt.show_nx(graph.to_undirected(), layout='agraph', layoutkw=layoutkw,
        #           as_directed=False)
        #pt.show_nx(graph, layout='agraph', layoutkw=layoutkw,
        #           as_directed=as_directed, hacknode=hacknode)

        pt.show_nx(graph, layout='custom', layoutkw=layoutkw,
                   as_directed=as_directed, hacknode=hacknode)
    else:
        #explicit_graph = pt.get_explicit_graph(graph)
        #_, layout_info = pt.nx_agraph_layout(explicit_graph, orig_graph=graph,
        #                                     **layoutkw)

        #layout_info['edge']['alpha'] = .8
        #pt.apply_graph_layout_attrs(graph, layout_info)

        #graph_layout_attrs = layout_info['graph']
        ##edge_layout_attrs  = layout_info['edge']
        ##node_layout_attrs  = layout_info['node']

        #for key, vals in layout_info['node'].items():
        #    #print('[special] key = %r' % (key,))
        #    nx.set_node_attributes(graph, key, vals)

        #for key, vals in layout_info['edge'].items():
        #    #print('[special] key = %r' % (key,))
        #    nx.set_edge_attributes(graph, key, vals)

        #nx.set_edge_attributes(graph, 'alpha', .8)
        #graph.graph['splines'] = graph_layout_attrs.get('splines', 'line')
        #graph.graph['splines'] = 'polyline'   # graph_layout_attrs.get('splines', 'line')
        #graph.graph['splines'] = 'line'

        cut_graph = graph.copy()
        edge_list = list(cut_graph.edges())
        edge_nids = np.array(ibs.unflat_map(ibs.get_annot_nids, edge_list))
        cut_flags = edge_nids.T[0] != edge_nids.T[1]
        cut_edges = ut.compress(edge_list, cut_flags)
        cut_graph.remove_edges_from(cut_edges)
        ut.nx_delete_node_attr(cut_graph, 'nid')
        viz_graph.ensure_graph_nid_labels(cut_graph, ibs=ibs)

        #ut.nx_get_default_node_attributes(exemplars, 'color', None)
        ut.nx_delete_node_attr(cut_graph, 'color', nodes=unlabeled_graph.nodes())
        aid2_color = ut.nx_get_default_node_attributes(cut_graph, 'color', None)
        nid2_colors = ut.group_items(aid2_color.values(), ibs.get_annot_nids(aid2_color.keys()))
        nid2_colors = ut.map_dict_vals(ut.filter_Nones, nid2_colors)
        nid2_colors = ut.map_dict_vals(ut.unique, nid2_colors)
        #for val in nid2_colors.values():
        #    assert len(val) <= 1
        # Get initial colors
        nid2_color_ = {nid: colors_[0] for nid, colors_ in nid2_colors.items()
                       if len(colors_) == 1}

        graph = cut_graph
        viz_graph.color_by_nids(cut_graph, ibs=ibs, nid2_color_=nid2_color_)
        nx.set_node_attributes(cut_graph, 'framewidth', 4)

        pt.show_nx(cut_graph, layout='custom', layoutkw=layoutkw,
                   as_directed=as_directed, hacknode=hacknode)

    pt.zoom_factory()