Source code for graphid.core.mixin_viz

import numpy as np
import warnings
import ubelt as ub
import networkx as nx
from functools import partial
from graphid.core.state import (POSTV, NEGTV, INCMP, UNREV, UNKWN)
from graphid.core.state import (SAME, DIFF, NULL)  # NOQA
from graphid import util


[docs] class GraphVisualization(object): """ contains plotting related code """
[docs] def _get_truth_colors(infr): # TODO: change to cs4 colors with util.Color # util.Color('dodgerblue') truth_colors = { POSTV: util.Color('blue').as01(), NEGTV: util.Color('red').as01(), INCMP: util.Color('yellow').as01(), UNKWN: util.Color('purple').as01(), UNREV: util.Color('gray').as01(), } return truth_colors
@property def _error_color(infr): return util.Color('orange').as01('bgr')
[docs] def _get_cmap(infr): if hasattr(infr, '_cmap'): return infr._cmap else: cpool = np.array([[ 0.98135718, 0.19697982, 0.02117342], [ 1. , 0.33971852, 0. ], [ 1. , 0.45278535, 0. ], [ 1. , 0.55483746, 0. ], [ 1. , 0.65106306, 0. ], [ 1. , 0.74359729, 0. ], [ 1. , 0.83348477, 0. ], [ 0.98052302, 0.92128928, 0. ], [ 0.95300175, 1. , 0. ], [ 0.59886986, 0.99652954, 0.23932718], [ 0.2 , 0.95791134, 0.44764457], [ 0.2 , 0.89937643, 0.63308702], [ 0.2 , 0.82686023, 0.7895433 ], [ 0.2 , 0.74361034, 0.89742738], [ 0.2 , 0.65085832, 0.93960823], [ 0.2 , 0.54946918, 0.90949295], [ 0.25697101, 0.44185497, 0.8138502 ]]) import matplotlib as mpl cmap = mpl.colors.ListedColormap(cpool, 'indexed') infr._cmap = cmap return infr._cmap
[docs] 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=ub.dzip(annot_nodes, ['rect'])) util.nx_delete_node_attr(graph, 'size') util.nx_delete_node_attr(graph, 'width') util.nx_delete_node_attr(graph, 'height') util.nx_delete_node_attr(graph, 'radius') infr._viz_init_nodes = True infr._viz_image_config_dirty = False
[docs] def update_node_image_config(infr, **kwargs): if not hasattr(infr, '_viz_image_config_dirty'): infr.initialize_visual_node_attrs() for key, val in kwargs.items(): assert key in infr._viz_image_config if infr._viz_image_config[key] != val: infr._viz_image_config[key] = val infr._viz_image_config_dirty = True
[docs] def update_node_image_attribute(infr, use_image=False, graph=None): if graph is None: graph = infr.graph if not hasattr(infr, '_viz_image_config_dirty'): infr.initialize_visual_node_attrs() # aid_list = list(graph.nodes()) if graph is infr.graph: infr._viz_image_config_dirty = False
[docs] def get_colored_edge_weights(infr, graph=None, highlight_reviews=True): # Update color and linewidth based on scores/weight if graph is None: graph = infr.graph truth_colors = infr._get_truth_colors() if highlight_reviews: edges = [] colors = [] for edge in graph.edges(): d = infr.get_edge_data(edge) state = d.get('evidence_decision', UNREV) meta = d.get('meta_decision', NULL) color = truth_colors[state] if state not in {POSTV, NEGTV}: # Darken and saturated same/diff edges without visual # evidence if meta == SAME: color = truth_colors[POSTV] if meta == DIFF: color = truth_colors[NEGTV] # color = util.adjust_hsv_of_rgb( # color, sat_adjust=1, val_adjust=-.3) edges.append(edge) colors.append(color) else: edges = list(graph.edges()) edge_to_weight = nx.get_edge_attributes(graph, 'normscore') weights = np.array(list(ub.take(edge_to_weight, edges, np.nan))) nan_idxs = [] if len(weights) > 0: # give nans threshold value nan_idxs = np.where(np.isnan(weights))[0] thresh = .5 weights[nan_idxs] = thresh colors = infr.get_colored_weights(weights) #print('!! weights = %r' % (len(weights),)) #print('!! edges = %r' % (len(edges),)) #print('!! colors = %r' % (len(colors),)) if len(nan_idxs) > 0: for idx in nan_idxs: colors[idx] = util.Color('gray').as01() return edges, colors
[docs] def get_colored_weights(infr, weights): cmap_ = infr._get_cmap() thresh = .5 weights[np.isnan(weights)] = thresh #colors = util.scores_to_color(weights, cmap_=cmap_, logscale=True) colors = util.scores_to_color(weights, cmap_=cmap_, score_range=(0, 1), logscale=False, cmap_range=None) return colors
@property def visual_edge_attrs(infr): """ all edge visual attrs """ return infr.visual_edge_attrs_appearance + infr.visual_edge_attrs_space @property def visual_edge_attrs_appearance(infr): """ attrs that pertain to edge color and style """ # picker doesnt really belong here return ['alpha', 'color', 'implicit', 'label', 'linestyle', 'lw', 'pos', 'stroke', 'capstyle', 'hatch', 'style', 'sketch', 'shadow', 'picker', 'linewidth'] @property def visual_edge_attrs_space(infr): """ attrs that pertain to edge positioning in a plot """ return ['ctrl_pts', 'end_pt', 'head_lp', 'headlabel', 'lp', 'start_pt', 'tail_lp', 'taillabel', 'zorder'] @property def visual_node_attrs(infr): return ['color', 'framewidth', 'image', 'label', 'pos', 'shape', 'size', 'height', 'width', 'zorder']
[docs] def simplify_graph(infr, graph=None, copy=True): if graph is None: graph = infr.graph simple = graph.copy() if copy else graph util.nx_delete_edge_attr(simple, infr.visual_edge_attrs) util.nx_delete_node_attr(simple, infr.visual_node_attrs + ['pin']) return simple
# @staticmethod # def make_viz_config(use_image, small_graph): # raise NotImplementedError('required utool, cant use') # # import dtool as dt # # import utool as ut # # class GraphVizConfig(dt.Config): # # _param_info_list = [ # # # Appearance # # ut.ParamInfo('show_image', default=use_image), # # ut.ParamInfo('in_image', default=use_image, hideif=lambda cfg: not cfg['show_image']), # # ut.ParamInfo('pin_positions', default=use_image), # # # Visibility # # ut.ParamInfo('show_reviewed_edges', small_graph), # # ut.ParamInfo('show_unreviewed_edges', small_graph), # # ut.ParamInfo('show_inferred_same', small_graph), # # ut.ParamInfo('show_inferred_diff', small_graph), # # ut.ParamInfo('highlight_reviews', True), # # ut.ParamInfo('show_recent_review', False), # # ut.ParamInfo('show_labels', small_graph), # # ut.ParamInfo('splines', 'spline' if small_graph else 'line', # # valid_values=['line', 'spline', 'ortho']), # # ut.ParamInfo('groupby', 'name_label', # # valid_values=['name_label', None]), # # ] # # return GraphVizConfig
[docs] def pin_node_layout(infr): """ Ensures a node layout exists and then sets the pin attribute on each node, which tells graphviz not to change node positions. Useful for making before and after pictures. """ # Update the node positions if they have not been set # HACK: blindly set reposition to False on 2021-10-06, unsure if that # is ok infr.update_visual_attrs(groupby='name_label', reposition=False) # Set the pin attribute infr.set_node_attrs('pin', 'true')
[docs] def update_visual_attrs(infr, graph=None, show_reviewed_edges=True, show_unreviewed_edges=False, show_inferred_diff=True, show_inferred_same=True, show_recent_review=False, highlight_reviews=True, show_inconsistency=True, wavy=False, simple_labels=False, show_labels=True, reposition=True, use_image=False, edge_overrides=None, node_overrides=None, colorby='name_label', **kwargs # hide_unreviewed_inferred=True ): infr.print('update_visual_attrs', 3) if graph is None: graph = infr.graph # if hide_cuts is not None: # # show_unreviewed_cuts = not hide_cuts # show_reviewed_cuts = not hide_cuts if not getattr(infr, '_viz_init_nodes', False): infr._viz_init_nodes = True nx.set_node_attributes(graph, name='shape', values='circle') # infr.set_node_attrs('shape', 'circle') if getattr(infr, '_viz_image_config_dirty', True): infr.update_node_image_attribute(graph=graph, use_image=use_image) def get_any(dict_, keys, default=None): for key in keys: if key in dict_: return dict_[key] return default show_cand = get_any(kwargs, ['show_candidate_edges', 'show_candidates', 'show_cand']) if show_cand is not None: show_cand = True show_reviewed_edges = True show_unreviewed_edges = True show_inferred_diff = True show_inferred_same = True if kwargs.get('show_all'): show_cand = True # alpha_low = .5 alpha_med = .9 alpha_high = 1.0 dark_background = graph.graph.get('dark_background', None) # Ensure we are starting from a clean slate # if reposition: util.nx_delete_edge_attr(graph, infr.visual_edge_attrs_appearance) # Set annotation node labels node_to_nid = None if not show_labels: nx.set_node_attributes(graph, name='label', values=ub.dzip(graph.nodes(), [''])) else: if simple_labels: nx.set_node_attributes(graph, name='label', values={n: str(n) for n in graph.nodes()}) else: if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') node_to_view = nx.get_node_attributes(graph, 'viewpoint') if node_to_view: annotnode_to_label = { aid: 'aid=%r%s\nnid=%r' % (aid, node_to_view[aid], node_to_nid[aid]) for aid in graph.nodes() } else: annotnode_to_label = { aid: 'aid=%r\nnid=%r' % (aid, node_to_nid[aid]) for aid in graph.nodes() } nx.set_node_attributes(graph, name='label', values=annotnode_to_label) # NODE_COLOR: based on name_label color_nodes(graph, labelattr=colorby, outof=kwargs.get('outof', None), sat_adjust=-.4) # EDGES: # Grab different types of edges edges, edge_colors = infr.get_colored_edge_weights( graph, highlight_reviews) # reviewed_states = nx.get_edge_attributes(graph, 'evidence_decision') reviewed_states = {e: infr.edge_decision(e) for e in infr.graph.edges()} edge_to_inferred_state = nx.get_edge_attributes(graph, 'inferred_state') # dummy_edges = [edge for edge, flag in # nx.get_edge_attributes(graph, '_dummy_edge').items() # if flag] edge_to_reviewid = nx.get_edge_attributes(graph, 'review_id') recheck_edges = [edge for edge, split in nx.get_edge_attributes(graph, 'maybe_error').items() if split] decision_to_edge = util.group_pairs(reviewed_states.items()) neg_edges = decision_to_edge[NEGTV] pos_edges = decision_to_edge[POSTV] incomp_edges = decision_to_edge[INCMP] unreviewed_edges = decision_to_edge[UNREV] inferred_same = [edge for edge, state in edge_to_inferred_state.items() if state == 'same'] inferred_diff = [edge for edge, state in edge_to_inferred_state.items() if state == 'diff'] inconsistent_external = [ edge for edge, state in edge_to_inferred_state.items() if state == 'inconsistent_external'] inferred_notcomp = [edge for edge, state in edge_to_inferred_state.items() if state == 'notcomp'] reviewed_edges = incomp_edges + pos_edges + neg_edges compared_edges = pos_edges + neg_edges uncompared_edges = util.setdiff(edges, compared_edges) nontrivial_inferred_same = util.setdiff(inferred_same, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_diff = util.setdiff(inferred_diff, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_edges = (nontrivial_inferred_same + nontrivial_inferred_diff) # EDGE_COLOR: based on edge_weight nx.set_edge_attributes(graph, name='color', values=ub.dzip(edges, edge_colors)) # LINE_WIDTH: based on review_state # unreviewed_width = 2.0 # reviewed_width = 5.0 unreviewed_width = 1.0 reviewed_width = 2.0 if highlight_reviews: nx.set_edge_attributes(graph, name='linewidth', values=ub.dzip(reviewed_edges, [reviewed_width])) nx.set_edge_attributes(graph, name='linewidth', values=ub.dzip(unreviewed_edges, [unreviewed_width])) else: nx.set_edge_attributes(graph, name='linewidth', values=ub.dzip(edges, [unreviewed_width])) # EDGE_STROKE: based on decision and maybe_error # fg = util.WHITE if dark_background else util.BLACK # nx.set_edge_attributes(graph, name='stroke', values=ub.dzip(reviewed_edges, [{'linewidth': 3, 'foreground': fg}])) if show_inconsistency: nx.set_edge_attributes(graph, name='stroke', values=ub.dzip(recheck_edges, [{'linewidth': 5, 'foreground': infr._error_color}])) # Set linestyles to emphasize PCCs # Dash lines between PCCs inferred to be different nx.set_edge_attributes(graph, name='linestyle', values=ub.dzip(inferred_diff, ['dashed'])) # Treat incomparable/incon-external inference as different nx.set_edge_attributes(graph, name='linestyle', values=ub.dzip(inferred_notcomp, ['dashed'])) nx.set_edge_attributes(graph, name='linestyle', values=ub.dzip(inconsistent_external, ['dashed'])) # Dot lines that we are unsure of nx.set_edge_attributes(graph, name='linestyle', values=ub.dzip(unreviewed_edges, ['dotted'])) # Cut edges are implicit and dashed # nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(cut_edges, [True])) # nx.set_edge_attributes(graph, name='linestyle', values=ub.dzip(cut_edges, ['dashed'])) # nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(cut_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(uncompared_edges, [True])) # Only matching edges should impose constraints on the graph layout nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(neg_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(neg_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(incomp_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(incomp_edges, [alpha_med])) # Ensure reviewed edges are visible nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(reviewed_edges, [False])) nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(reviewed_edges, [alpha_high])) if True: # Infered same edges can be allowed to constrain in order # to make things look nice sometimes nx.set_edge_attributes(graph, name='implicit', values=ub.dzip(inferred_same, [False])) nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(inferred_same, [alpha_high])) if not kwargs.get('show_same', True): nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(inferred_same, [0])) if not kwargs.get('show_diff', True): nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(inferred_diff, [0])) if not kwargs.get('show_positive_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(pos_edges, [0])) if not kwargs.get('show_negative_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(neg_edges, [0])) if not kwargs.get('show_incomparable_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(incomp_edges, [0])) if not kwargs.get('show_between', True): if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') between_edges = [(u, v) for u, v in edges if node_to_nid[u] != node_to_nid[v]] nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(between_edges, [0])) # SKETCH: based on inferred_edges # Make inferred edges wavy if wavy: # dict(scale=3.0, length=18.0, randomness=None)] nx.set_edge_attributes(graph, name='sketch', values=ub.dzip(nontrivial_inferred_edges, [dict(scale=10.0, length=64.0, randomness=None)])) # Make dummy edges more transparent # nx.set_edge_attributes(graph, name='alpha', values=ub.dzip(dummy_edges, [alpha_low])) selected_edges = kwargs.pop('selected_edges', None) # SHADOW: based on most recent # Increase visibility of nodes with the most recently changed timestamp if show_recent_review and edge_to_reviewid and selected_edges is None: review_ids = list(edge_to_reviewid.values()) recent_idxs = ub.argmax(review_ids, multi=True) recent_edges = list(ub.take(list(edge_to_reviewid.keys()), recent_idxs)) selected_edges = recent_edges if selected_edges is not None: # TODO: add photoshop-like parameters like # spread and size. offset is the same as angle and distance. nx.set_edge_attributes(graph, name='shadow', values=ub.dzip(selected_edges, [{ 'rho': .3, 'alpha': .6, 'shadow_color': 'w' if dark_background else 'k', 'offset': (0, 0), 'scale': 3.0, }])) # Z_ORDER: make sure nodes are on top nodes = list(graph.nodes()) nx.set_node_attributes(graph, name='zorder', values=ub.dzip(nodes, [10])) nx.set_edge_attributes(graph, name='zorder', values=ub.dzip(edges, [0])) nx.set_edge_attributes(graph, name='picker', values=ub.dzip(edges, [10])) # VISIBILITY: Set visibility of edges based on arguments if not show_reviewed_edges: infr.print('Making reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ub.dzip(reviewed_edges, ['invis'])) if not show_unreviewed_edges: infr.print('Making un-reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ub.dzip(unreviewed_edges, ['invis'])) if not show_inferred_same: infr.print('Making nontrivial_same edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ub.dzip(nontrivial_inferred_same, ['invis'])) if not show_inferred_diff: infr.print('Making nontrivial_diff edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ub.dzip(nontrivial_inferred_diff, ['invis'])) if selected_edges is not None: # Always show the most recent review (remove setting of invis) # infr.print('recent_edges = %r' % (recent_edges,)) nx.set_edge_attributes(graph, name='style', values=ub.dzip(selected_edges, [''])) if reposition: # LAYOUT: update the positioning layout def get_layoutkw(key, default): return kwargs.get(key, graph.graph.get(key, default)) layoutkw = dict( prog='neato', splines=get_layoutkw('splines', 'line'), fontsize=get_layoutkw('fontsize', None), fontname=get_layoutkw('fontname', None), sep=10 / 72, esep=1 / 72, nodesep=.1 ) layoutkw.update(kwargs) # print(ub.urepr(graph.edges)) try: util.nx_agraph_layout(graph, inplace=True, **layoutkw) except AttributeError: print('WARNING: errors may occur') if edge_overrides: for key, edge_to_attr in edge_overrides.items(): nx.set_edge_attributes(graph, name=key, values=edge_to_attr) if node_overrides: for key, node_to_attr in node_overrides.items(): nx.set_node_attributes(graph, name=key, values=node_to_attr)
[docs] def show_graph(infr, graph=None, use_image=False, update_attrs=True, with_colorbar=False, pnum=(1, 1, 1), zoomable=True, pickable=False, **kwargs): r""" Args: infr (?): graph (None): (default = None) use_image (bool): (default = False) update_attrs (bool): (default = True) with_colorbar (bool): (default = False) pnum (tuple): plot number(default = (1, 1, 1)) zoomable (bool): (default = True) pickable (bool): (de = False) **kwargs: verbose, with_labels, fnum, layout, ax, pos, img_dict, title, layoutkw, framewidth, modify_ax, as_directed, hacknoedge, hacknode, node_labels, arrow_width, fontsize, fontweight, fontname, fontfamilty, fontproperties Example: >>> # xdoctest: +REQUIRES(module:pygraphviz) >>> from graphid import demo >>> infr = demo.demodata_infr(ccs=util.estarmap( >>> range, [(1, 6), (6, 10), (10, 13), (13, 15), (15, 16), >>> (17, 20)])) >>> pnum_ = util.PlotNums(nRows=1, nCols=3) >>> infr.show_graph(show_cand=True, simple_labels=True, pickable=True, fnum=1, pnum=pnum_()) >>> infr.add_feedback((1, 5), INCMP) >>> infr.add_feedback((14, 18), INCMP) >>> infr.refresh_candidate_edges() >>> infr.show_graph(show_cand=True, simple_labels=True, pickable=True, fnum=1, pnum=pnum_()) >>> infr.add_feedback((17, 18), NEGTV) # add inconsistency >>> infr.apply_nondynamic_update() >>> infr.show_graph(show_cand=True, simple_labels=True, pickable=True, fnum=1, pnum=pnum_()) >>> util.show_if_requested() """ import matplotlib.pyplot as plt if graph is None: graph = infr.graph # kwargs['fontsize'] = kwargs.get('fontsize', 8) with warnings.catch_warnings(): warnings.simplefilter("ignore") if update_attrs: infr.update_visual_attrs(graph=graph, **kwargs) verbose = kwargs.pop('verbose', infr.verbose) util.show_nx(graph, layout='custom', as_directed=False, modify_ax=False, use_image=use_image, pnum=pnum, verbose=verbose, **kwargs) if zoomable: util.mplutil.zoom_factory() util.mplutil.pan_factory(plt.gca()) # if with_colorbar: # # Draw a colorbar # _normal_ticks = np.linspace(0, 1, num=11) # _normal_scores = np.linspace(0, 1, num=500) # _normal_colors = infr.get_colored_weights(_normal_scores) # cb = util.colorbar(_normal_scores, _normal_colors, lbl='weights', # ticklabels=_normal_ticks) # # point to threshold location # thresh = None # if thresh is not None: # xy = (1, thresh) # xytext = (2.5, .3 if thresh < .5 else .7) # cb.ax.annotate('threshold', xy=xy, xytext=xytext, # arrowprops=dict( # alpha=.5, fc="0.6", # connectionstyle="angle3,angleA=90,angleB=0"),) # infr.graph if graph.graph.get('dark_background', None): util.dark_background(force=True) if pickable: fig = plt.gcf() fig.canvas.mpl_connect('pick_event', partial(on_pick, infr=infr))
[docs] def show_edge(infr, edge, fnum=None, pnum=None, **kwargs): import matplotlib.pyplot as plt match = infr._exec_pairwise_match([edge])[0] fnum = util.ensure_fnum(fnum) util.figure(fnum=fnum, pnum=pnum) ax = plt.gca() showkw = dict(vert=False, heatmask=True, show_lines=False, show_ell=False, show_ori=False, show_eig=False, modifysize=True) showkw.update(kwargs) match.show(ax, **showkw)
[docs] def debug_edge_repr(infr): print('DEBUG EDGE REPR') for u, v, d in infr.graph.edges(data=True): print('edge = %r, %r' % (u, v)) print(infr.repr_edge_data(d, visual=False))
[docs] def repr_edge_data(infr, all_edge_data, visual=True): visual_edge_data = {k: v for k, v in all_edge_data.items() if k in infr.visual_edge_attrs} edge_data = util.delete_dict_keys(all_edge_data.copy(), infr.visual_edge_attrs) lines = [] if visual: lines += [('visual_edge_data: ' + ub.urepr(visual_edge_data, nl=1))] lines += [('edge_data: ' + ub.urepr(edge_data, nl=1))] return '\n'.join(lines)
[docs] def show_error_case(infr, aids, edge=None, error_edges=None, colorby=None, fnum=1): """ Example """ if error_edges is None: # compute a minimal set of edges to minimally fix the case pass sub_infr = infr.subgraph(aids) # err_graph.add_edges_from(missing_edges) subdf = sub_infr.get_edge_dataframe() mistake_edges = [] if len(subdf) > 0: mistakes = subdf[(subdf.truth != subdf.evidence_decision) & (subdf.evidence_decision != UNREV)] mistake_edges = mistakes.index.tolist() err_edges = mistake_edges + list(error_edges) missing = [e for e in err_edges if not sub_infr.has_edge(e)] # Hack, make sure you don't reuse sub_infr.graph.add_edges_from(missing) stroke = {'linewidth': 2.5, 'foreground': sub_infr._error_color} edge_overrides = { # 'alpha': {e: .05 for e in true_negatives}, 'alpha': {}, 'style': {e: '' for e in err_edges}, 'sketch': {e: None for e in err_edges}, 'linestyle': {e: 'dashed' for e in missing}, 'linewidth': {e: 2.0 for e in err_edges + missing}, 'stroke': {e: stroke for e in err_edges + missing}, } selected_kw = { 'stroke': {'linewidth': 5, 'foreground': sub_infr._error_color}, 'alpha': 1.0, } for k, v in selected_kw.items(): if k not in edge_overrides: edge_overrides[k] = {} edge_overrides[k][edge] = selected_kw[k] sub_infr.show_edge(edge, fnum=1, pnum=(2, 1, 2)) import matplotlib.pyplot as plt ax = plt.gca() xy, w, h = util.get_axis_xy_width_height(ax=ax) nx.set_node_attributes(sub_infr.graph, name='framewidth', values=1.0) nx.set_node_attributes(sub_infr.graph, name='framealign', values='outer') nx.set_node_attributes(sub_infr.graph, name='framealpha', values=0.7) sub_infr.show_graph( fnum=fnum, pnum=(2, 1, 1), show_recent_review=False, zoomable=False, pickable=False, show_cand=False, splines='spline', simple_labels=True, colorby=colorby, use_image=True, edge_overrides=edge_overrides, # ratio=1 / abs(w / h) )
show = show_graph
[docs] def on_pick(event, infr=None): print('ON PICK: %r' % (event,)) artist = event.artist plotdat = util.mplutil._get_plotdat_dict(artist) if plotdat: if 'node' in plotdat: all_node_data = util.sort_dict(plotdat['node_data'].copy()) visual_node_data = ub.dict_subset(all_node_data, infr.visual_node_attrs, None) node_data = util.delete_dict_keys(all_node_data, infr.visual_node_attrs) node = plotdat['node'] node_data['degree'] = infr.graph.degree(node) node_label = infr.pos_graph.node_label(node) print('visual_node_data: ' + ub.urepr(visual_node_data, nl=1)) print('node_data: ' + ub.urepr(node_data, nl=1)) util.cprint('node: ' + ub.urepr(plotdat['node']), 'blue') print('(pcc) node_label = %r' % (node_label,)) print('artist = %r' % (artist,)) elif 'edge' in plotdat: all_edge_data = util.sort_dict(plotdat['edge_data'].copy()) print(infr.repr_edge_data(all_edge_data)) util.cprint('edge: ' + ub.urepr(plotdat['edge']), 'blue') print('artist = %r' % (artist,)) else: print('???: ' + ub.urepr(plotdat)) print(ub.timestamp())
[docs] def color_nodes(graph, labelattr='label', brightness=.878, outof=None, sat_adjust=None): """ Colors edges and nodes by nid """ node_to_lbl = nx.get_node_attributes(graph, labelattr) unique_lbls = sorted(set(node_to_lbl.values())) ncolors = len(unique_lbls) if outof is None: if (ncolors) == 1: unique_colors = [util.Color('lightblue').as01()] elif (ncolors) == 2: # https://matplotlib.org/examples/color/named_colors.html unique_colors = ['royalblue', 'orange'] unique_colors = [util.Color(c).as01('bgr') for c in unique_colors] else: unique_colors = util.distinct_colors(ncolors, brightness=brightness) else: unique_colors = util.distinct_colors(outof, brightness=brightness) if sat_adjust: unique_colors = [ util.Color(c).adjust_hsv(0.0, sat_adjust, 0.0) for c in unique_colors ] # Find edges and aids strictly between two nids if outof is None: lbl_to_color = ub.dzip(unique_lbls, unique_colors) else: gray = util.Color('lightgray').as01('bgr') unique_colors = [gray] + unique_colors offset = max(1, min(unique_lbls)) - 1 node_to_lbl = ub.map_vals(lambda nid: max(0, nid - offset), node_to_lbl) lbl_to_color = ub.dzip(range(outof + 1), unique_colors) node_to_color = ub.map_vals(lbl_to_color, node_to_lbl) nx.set_node_attributes(graph, name='color', values=node_to_color) nx_ensure_agraph_color(graph)
[docs] def nx_ensure_agraph_color(graph): """ changes colors to hex strings on graph attrs """ def _fix_agraph_color(data): try: orig_color = data.get('color', None) alpha = data.get('alpha', None) color = orig_color if color is None and alpha is not None: color = [0, 0, 0] if color is not None: color = util.Color(color).as255() if alpha is not None: if len(color) == 3: color += [int(alpha * 255)] else: color[3] = int(alpha * 255) color = tuple(color) if len(color) == 3: data['color'] = '#%02x%02x%02x' % color else: data['color'] = '#%02x%02x%02x%02x' % color except Exception: raise for node, node_data in graph.nodes(data=True): data = node_data _fix_agraph_color(data) for u, v, edge_data in graph.edges(data=True): data = edge_data _fix_agraph_color(data)
if __name__ == '__main__': """ CommandLine: python ~/code/graphid/graphid/core/mixin_viz.py all """ import xdoctest xdoctest.doctest_module(__file__)