def color_nodes(graph, labelattr='label'): """ Colors edges and nodes by nid """ import plottool as pt import utool as ut import networkx as nx node_to_lbl = nx.get_node_attributes(graph, labelattr) unique_lbls = ut.unique(node_to_lbl.values()) ncolors = len(unique_lbls) if (ncolors) == 1: unique_colors = [pt.NEUTRAL_BLUE] else: unique_colors = pt.distinct_colors(ncolors) # Find edges and aids strictly between two nids lbl_to_color = dict(zip(unique_lbls, unique_colors)) node_to_color = {node: lbl_to_color[lbl] for node, lbl in node_to_lbl.items()} nx.set_node_attributes(graph, 'color', node_to_color) ut.nx_ensure_agraph_color(graph)
def draw_twoday_count(ibs, visit_info_list_): import copy visit_info_list = copy.deepcopy(visit_info_list_) aids_day1, aids_day2 = ut.take_column(visit_info_list_, 'aids') nids_day1, nids_day2 = ut.take_column(visit_info_list_, 'unique_nids') resight_nids = ut.isect(nids_day1, nids_day2) if False: # HACK REMOVE DATA TO MAKE THIS FASTER num = 20 for info in visit_info_list: non_resight_nids = list(set(info['unique_nids']) - set(resight_nids)) sample_nids2 = non_resight_nids[0:num] + resight_nids[:num] info['grouped_aids'] = ut.dict_subset(info['grouped_aids'], sample_nids2) info['unique_nids'] = sample_nids2 # Build a graph of matches if False: debug = False for info in visit_info_list: edges = [] grouped_aids = info['grouped_aids'] aids_list = list(grouped_aids.values()) ams_list = ibs.get_annotmatch_rowids_in_cliques(aids_list) aids1_list = ibs.unflat_map(ibs.get_annotmatch_aid1, ams_list) aids2_list = ibs.unflat_map(ibs.get_annotmatch_aid2, ams_list) for ams, aids, aids1, aids2 in zip(ams_list, aids_list, aids1_list, aids2_list): edge_nodes = set(aids1 + aids2) ##if len(edge_nodes) != len(set(aids)): # #print('--') # #print('aids = %r' % (aids,)) # #print('edge_nodes = %r' % (edge_nodes,)) bad_aids = edge_nodes - set(aids) if len(bad_aids) > 0: print('bad_aids = %r' % (bad_aids,)) unlinked_aids = set(aids) - edge_nodes mst_links = list(ut.itertwo(list(unlinked_aids) + list(edge_nodes)[:1])) bad_aids.add(None) user_links = [(u, v) for (u, v) in zip(aids1, aids2) if u not in bad_aids and v not in bad_aids] new_edges = mst_links + user_links new_edges = [(int(u), int(v)) for u, v in new_edges if u not in bad_aids and v not in bad_aids] edges += new_edges info['edges'] = edges # Add edges between days grouped_aids1, grouped_aids2 = ut.take_column(visit_info_list, 'grouped_aids') nids_day1, nids_day2 = ut.take_column(visit_info_list, 'unique_nids') resight_nids = ut.isect(nids_day1, nids_day2) resight_aids1 = ut.take(grouped_aids1, resight_nids) resight_aids2 = ut.take(grouped_aids2, resight_nids) #resight_aids3 = [list(aids1) + list(aids2) for aids1, aids2 in zip(resight_aids1, resight_aids2)] ams_list = ibs.get_annotmatch_rowids_between_groups(resight_aids1, resight_aids2) aids1_list = ibs.unflat_map(ibs.get_annotmatch_aid1, ams_list) aids2_list = ibs.unflat_map(ibs.get_annotmatch_aid2, ams_list) between_edges = [] for ams, aids1, aids2, rawaids1, rawaids2 in zip(ams_list, aids1_list, aids2_list, resight_aids1, resight_aids2): link_aids = aids1 + aids2 rawaids3 = rawaids1 + rawaids2 badaids = ut.setdiff(link_aids, rawaids3) assert not badaids user_links = [(int(u), int(v)) for (u, v) in zip(aids1, aids2) if u is not None and v is not None] # HACK THIS OFF user_links = [] if len(user_links) == 0: # Hack in an edge between_edges += [(rawaids1[0], rawaids2[0])] else: between_edges += user_links assert np.all(0 == np.diff(np.array(ibs.unflat_map(ibs.get_annot_nids, between_edges)), axis=1)) import plottool_ibeis as pt import networkx as nx #pt.qt4ensure() #len(list(nx.connected_components(graph1))) #print(ut.graph_info(graph1)) # Layout graph layoutkw = dict( prog='neato', draw_implicit=False, splines='line', #splines='curved', #splines='spline', #sep=10 / 72, #prog='dot', rankdir='TB', ) def translate_graph_to_origin(graph): x, y, w, h = ut.get_graph_bounding_box(graph) ut.translate_graph(graph, (-x, -y)) def stack_graphs(graph_list, vert=False, pad=None): graph_list_ = [g.copy() for g in graph_list] for g in graph_list_: translate_graph_to_origin(g) bbox_list = [ut.get_graph_bounding_box(g) for g in graph_list_] if vert: dim1 = 3 dim2 = 2 else: dim1 = 2 dim2 = 3 dim1_list = np.array([bbox[dim1] for bbox in bbox_list]) dim2_list = np.array([bbox[dim2] for bbox in bbox_list]) if pad is None: pad = np.mean(dim1_list) / 2 offset1_list = ut.cumsum([0] + [d + pad for d in dim1_list[:-1]]) max_dim2 = max(dim2_list) offset2_list = [(max_dim2 - d2) / 2 for d2 in dim2_list] if vert: t_xy_list = [(d2, d1) for d1, d2 in zip(offset1_list, offset2_list)] else: t_xy_list = [(d1, d2) for d1, d2 in zip(offset1_list, offset2_list)] for g, t_xy in zip(graph_list_, t_xy_list): ut.translate_graph(g, t_xy) nx.set_node_attributes(g, name='pin', values='true') new_graph = nx.compose_all(graph_list_) #pt.show_nx(new_graph, layout='custom', node_labels=False, as_directed=False) # NOQA return new_graph # Construct graph for count, info in enumerate(visit_info_list): graph = nx.Graph() edges = [(int(u), int(v)) for u, v in info['edges'] if u is not None and v is not None] graph.add_edges_from(edges, attr_dict={'zorder': 10}) nx.set_node_attributes(graph, name='zorder', values=20) # Layout in neato _ = pt.nx_agraph_layout(graph, inplace=True, **layoutkw) # NOQA # Extract components and then flatten in nid ordering ccs = list(nx.connected_components(graph)) root_aids = [] cc_graphs = [] for cc_nodes in ccs: cc = graph.subgraph(cc_nodes) try: root_aids.append(list(ut.nx_source_nodes(cc.to_directed()))[0]) except nx.NetworkXUnfeasible: root_aids.append(list(cc.nodes())[0]) cc_graphs.append(cc) root_nids = ibs.get_annot_nids(root_aids) nid2_graph = dict(zip(root_nids, cc_graphs)) resight_nids_ = set(resight_nids).intersection(set(root_nids)) noresight_nids_ = set(root_nids) - resight_nids_ n_graph_list = ut.take(nid2_graph, sorted(noresight_nids_)) r_graph_list = ut.take(nid2_graph, sorted(resight_nids_)) if len(n_graph_list) > 0: n_graph = nx.compose_all(n_graph_list) _ = pt.nx_agraph_layout(n_graph, inplace=True, **layoutkw) # NOQA n_graphs = [n_graph] else: n_graphs = [] r_graphs = [stack_graphs(chunk) for chunk in ut.ichunks(r_graph_list, 100)] if count == 0: new_graph = stack_graphs(n_graphs + r_graphs, vert=True) else: new_graph = stack_graphs(r_graphs[::-1] + n_graphs, vert=True) #pt.show_nx(new_graph, layout='custom', node_labels=False, as_directed=False) # NOQA info['graph'] = new_graph graph1_, graph2_ = ut.take_column(visit_info_list, 'graph') if False: _ = pt.show_nx(graph1_, layout='custom', node_labels=False, as_directed=False) # NOQA _ = pt.show_nx(graph2_, layout='custom', node_labels=False, as_directed=False) # NOQA graph_list = [graph1_, graph2_] twoday_graph = stack_graphs(graph_list, vert=True, pad=None) nx.set_node_attributes(twoday_graph, name='pin', values='true') if debug: ut.nx_delete_None_edge_attr(twoday_graph) ut.nx_delete_None_node_attr(twoday_graph) print('twoday_graph(pre) info' + ut.repr3(ut.graph_info(twoday_graph), nl=2)) # Hack, no idea why there are nodes that dont exist here between_edges_ = [edge for edge in between_edges if twoday_graph.has_node(edge[0]) and twoday_graph.has_node(edge[1])] twoday_graph.add_edges_from(between_edges_, attr_dict={'alpha': .2, 'zorder': 0}) ut.nx_ensure_agraph_color(twoday_graph) layoutkw['splines'] = 'line' layoutkw['prog'] = 'neato' agraph = pt.nx_agraph_layout(twoday_graph, inplace=True, return_agraph=True, **layoutkw)[-1] # NOQA if False: fpath = ut.truepath('~/ggr_graph.png') agraph.draw(fpath) ut.startfile(fpath) if debug: print('twoday_graph(post) info' + ut.repr3(ut.graph_info(twoday_graph))) _ = pt.show_nx(twoday_graph, layout='custom', node_labels=False, as_directed=False) # NOQA
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()
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
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
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()