# -*- coding: utf-8 -*-
import logging
import numpy as np
import warnings
import utool as ut
import vtool as vt # NOQA
import networkx as nx
from wbia.algo.graph.state import POSTV, NEGTV, INCMP, UNREV, UNKWN
from wbia.algo.graph.state import SAME, DIFF, NULL # NOQA
print, rrr, profile = ut.inject2(__name__)
logger = logging.getLogger('wbia')
[docs]@ut.reloadable_class
class GraphVisualization(object):
"""contains plotting related code"""
def _get_truth_colors(infr):
import wbia.plottool as pt
truth_colors = {
POSTV: pt.TRUE_BLUE,
NEGTV: pt.FALSE_RED,
INCMP: pt.YELLOW,
UNKWN: pt.UNKNOWN_PURP,
UNREV: pt.GRAY,
}
return truth_colors
@property
def _error_color(infr):
import wbia.plottool as pt
return pt.ORANGE
def _get_cmap(infr):
import wbia.plottool as pt
# return pt.plt.cm.RdYlBu
if hasattr(infr, '_cmap'):
return infr._cmap
else:
cpool = np.array(
[
[0.98135718, 0.19697982, 0.02117342],
[1.0, 0.33971852, 0.0],
[1.0, 0.45278535, 0.0],
[1.0, 0.55483746, 0.0],
[1.0, 0.65106306, 0.0],
[1.0, 0.74359729, 0.0],
[1.0, 0.83348477, 0.0],
[0.98052302, 0.92128928, 0.0],
[0.95300175, 1.0, 0.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],
]
)
cmap = pt.mpl.colors.ListedColormap(cpool, 'indexed')
# cmap = pt.interpolated_colormap([
# (pt.FALSE_RED, 0.0),
# (pt.YELLOW, 0.5),
# (pt.TRUE_BLUE, 1.0),
# ], resolution=128)
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=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
[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 infr.ibs is not None:
nx.set_node_attributes(graph, name='framewidth', values=3.0)
nx.set_node_attributes(
graph, name='shape', values=ut.dzip(aid_list, ['rect'])
)
if infr.ibs is None:
raise ValueError('Cannot show images when ibs is None')
imgpath_list = infr.ibs.depc_annot.get(
'chipthumb',
aid_list,
'img',
config=infr._viz_image_config,
read_extern=False,
)
nx.set_node_attributes(
graph, name='image', values=ut.dzip(aid_list, imgpath_list)
)
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
import wbia.plottool as pt
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 = pt.color_funcs.adjust_hsv_of_rgb(
color, sat_adjust=1, val_adjust=-0.3
)
edges.append(edge)
colors.append(color)
else:
edges = list(graph.edges())
edge_to_weight = nx.get_edge_attributes(graph, 'normscore')
weights = np.array(ut.dict_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 = 0.5
weights[nan_idxs] = thresh
colors = infr.get_colored_weights(weights)
# logger.info('!! weights = %r' % (len(weights),))
# logger.info('!! edges = %r' % (len(edges),))
# logger.info('!! colors = %r' % (len(colors),))
if len(nan_idxs) > 0:
import wbia.plottool as pt
for idx in nan_idxs:
colors[idx] = pt.GRAY
return edges, colors
[docs] @profile
def get_colored_weights(infr, weights):
import wbia.plottool as pt
# pt.rrrr()
# cmap_ = 'viridis'
# cmap_ = 'plasma'
# cmap_ = pt.plt.cm.RdYlBu
cmap_ = infr._get_cmap()
# cmap_ = pt.plt.cm.RdYlBu
# cmap_ = pt.plt.get_cmap(cmap_)
thresh = 0.5
weights[np.isnan(weights)] = thresh
# colors = pt.scores_to_color(weights, cmap_=cmap_, logscale=True)
colors = pt.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
ut.nx_delete_edge_attr(simple, infr.visual_edge_attrs)
ut.nx_delete_node_attr(simple, infr.visual_node_attrs + ['pin'])
return simple
[docs] @staticmethod
def make_viz_config(use_image, small_graph):
from wbia import dtool as dt
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] @profile
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
):
import wbia.plottool as pt
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 = 0.9
alpha_high = 1.0
dark_background = graph.graph.get('dark_background', None)
# Ensure we are starting from a clean slate
# if reposition:
ut.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=ut.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
ut.color_nodes(
graph, labelattr=colorby, outof=kwargs.get('outof', None), sat_adjust=-0.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 = ut.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 = ut.setdiff(edges, compared_edges)
nontrivial_inferred_same = ut.setdiff(
inferred_same, pos_edges + neg_edges + incomp_edges
)
nontrivial_inferred_diff = ut.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=ut.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=ut.dzip(reviewed_edges, [reviewed_width])
)
nx.set_edge_attributes(
graph,
name='linewidth',
values=ut.dzip(unreviewed_edges, [unreviewed_width]),
)
else:
nx.set_edge_attributes(
graph, name='linewidth', values=ut.dzip(edges, [unreviewed_width])
)
# EDGE_STROKE: based on decision and maybe_error
# fg = pt.WHITE if dark_background else pt.BLACK
# nx.set_edge_attributes(graph, name='stroke', values=ut.dzip(reviewed_edges, [{'linewidth': 3, 'foreground': fg}]))
if show_inconsistency:
nx.set_edge_attributes(
graph,
name='stroke',
values=ut.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=ut.dzip(inferred_diff, ['dashed'])
)
# Treat incomparable/incon-external inference as different
nx.set_edge_attributes(
graph, name='linestyle', values=ut.dzip(inferred_notcomp, ['dashed'])
)
nx.set_edge_attributes(
graph, name='linestyle', values=ut.dzip(inconsistent_external, ['dashed'])
)
# Dot lines that we are unsure of
nx.set_edge_attributes(
graph, name='linestyle', values=ut.dzip(unreviewed_edges, ['dotted'])
)
# Cut edges are implicit and dashed
# nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(cut_edges, [True]))
# nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(cut_edges, ['dashed']))
# nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(cut_edges, [alpha_med]))
nx.set_edge_attributes(
graph, name='implicit', values=ut.dzip(uncompared_edges, [True])
)
# Only matching edges should impose constraints on the graph layout
nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(neg_edges, [True]))
nx.set_edge_attributes(
graph, name='alpha', values=ut.dzip(neg_edges, [alpha_med])
)
nx.set_edge_attributes(
graph, name='implicit', values=ut.dzip(incomp_edges, [True])
)
nx.set_edge_attributes(
graph, name='alpha', values=ut.dzip(incomp_edges, [alpha_med])
)
# Ensure reviewed edges are visible
nx.set_edge_attributes(
graph, name='implicit', values=ut.dzip(reviewed_edges, [False])
)
nx.set_edge_attributes(
graph, name='alpha', values=ut.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=ut.dzip(inferred_same, [False])
)
nx.set_edge_attributes(
graph, name='alpha', values=ut.dzip(inferred_same, [alpha_high])
)
if not kwargs.get('show_same', True):
nx.set_edge_attributes(
graph, name='alpha', values=ut.dzip(inferred_same, [0])
)
if not kwargs.get('show_diff', True):
nx.set_edge_attributes(
graph, name='alpha', values=ut.dzip(inferred_diff, [0])
)
if not kwargs.get('show_positive_edges', True):
nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(pos_edges, [0]))
if not kwargs.get('show_negative_edges', True):
nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(neg_edges, [0]))
if not kwargs.get('show_incomparable_edges', True):
nx.set_edge_attributes(graph, name='alpha', values=ut.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=ut.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=ut.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=ut.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 = ut.argmax(review_ids, multi=True)
recent_edges = ut.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=ut.dzip(
selected_edges,
[
{
'rho': 0.3,
'alpha': 0.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=ut.dzip(nodes, [10]))
nx.set_edge_attributes(graph, name='zorder', values=ut.dzip(edges, [0]))
nx.set_edge_attributes(graph, name='picker', values=ut.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=ut.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=ut.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=ut.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=ut.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=ut.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=0.1,
)
layoutkw.update(kwargs)
# logger.info(ut.repr3(graph.edges))
pt.nx_agraph_layout(graph, inplace=True, **layoutkw)
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] @profile
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
CommandLine:
python -m wbia.algo.graph.mixin_viz GraphVisualization.show_graph --show
Example:
>>> # xdoctest: +REQUIRES(module:pygraphviz)
>>> # ENABLE_DOCTEST
>>> from wbia.algo.graph.mixin_viz import * # NOQA
>>> from wbia.algo.graph import demo
>>> import wbia.plottool as pt
>>> infr = demo.demodata_infr(ccs=ut.estarmap(
>>> range, [(1, 6), (6, 10), (10, 13), (13, 15), (15, 16),
>>> (17, 20)]))
>>> pnum_ = pt.make_pnum_nextgen(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_())
>>> ut.show_if_requested()
"""
import wbia.plottool as pt
if graph is None:
graph = infr.graph
# kwargs['fontsize'] = kwargs.get('fontsize', 8)
with warnings.catch_warnings():
warnings.simplefilter('ignore')
# default_update_kw = ut.get_func_kwargs(infr.update_visual_attrs)
# update_kw = ut.update_existing(default_update_kw, kwargs)
# infr.update_visual_attrs(**update_kw)
if update_attrs:
infr.update_visual_attrs(graph=graph, **kwargs)
verbose = kwargs.pop('verbose', infr.verbose)
pt.show_nx(
graph,
layout='custom',
as_directed=False,
modify_ax=False,
use_image=use_image,
pnum=pnum,
verbose=verbose,
**kwargs,
)
if zoomable:
pt.zoom_factory()
pt.pan_factory(pt.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 = pt.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):
pt.dark_background(force=True)
if pickable:
fig = pt.gcf()
fig.canvas.mpl_connect('pick_event', ut.partial(on_pick, infr=infr))
[docs] def show_edge(infr, edge, fnum=None, pnum=None, **kwargs):
import wbia.plottool as pt
match = infr._exec_pairwise_match([edge])[0]
fnum = pt.ensure_fnum(fnum)
pt.figure(fnum=fnum, pnum=pnum)
ax = pt.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 draw_aids(infr, aids, fnum=None):
from wbia.viz import viz_chip
import wbia.plottool as pt
fnum = pt.ensure_fnum(None)
fig = pt.figure(fnum=fnum)
viz_chip.show_many_chips(infr.ibs, aids, fnum=fnum)
return fig
[docs] def start_qt_interface(infr, loop=True):
import wbia.guitool as gt
from wbia.viz.viz_graph2 import AnnotGraphWidget
from wbia.plottool import abstract_interaction
import wbia.plottool as pt
pt.qtensure()
gt.ensure_qtapp()
# win = AnnotGraphWidget(infr=infr, use_image=False, init_mode='review')
win = AnnotGraphWidget(infr=infr, use_image=False, init_mode=None)
abstract_interaction.register_interaction(win)
if loop:
gt.qtapp_loop(qwin=win, freq=10)
else:
win.show()
return win
[docs] def debug_edge_repr(infr):
logger.info('DEBUG EDGE REPR')
for u, v, d in infr.graph.edges(data=True):
logger.info('edge = %r, %r' % (u, v))
logger.info(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 = ut.delete_dict_keys(all_edge_data.copy(), infr.visual_edge_attrs)
lines = []
if visual:
lines += [('visual_edge_data: ' + ut.repr2(visual_edge_data, nl=1))]
lines += [('edge_data: ' + ut.repr2(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
"""
import wbia.plottool as pt
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))
ax = pt.gca()
xy, w, h = pt.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):
import wbia.plottool as pt
logger.info('ON PICK: %r' % (event,))
artist = event.artist
plotdat = pt.get_plotdat_dict(artist)
if plotdat:
if 'node' in plotdat:
all_node_data = ut.sort_dict(plotdat['node_data'].copy())
visual_node_data = ut.dict_subset(all_node_data, infr.visual_node_attrs, None)
node_data = ut.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)
logger.info('visual_node_data: ' + ut.repr2(visual_node_data, nl=1))
logger.info('node_data: ' + ut.repr2(node_data, nl=1))
ut.cprint('node: ' + ut.repr2(plotdat['node']), 'blue')
logger.info('(pcc) node_label = %r' % (node_label,))
logger.info('artist = %r' % (artist,))
elif 'edge' in plotdat:
all_edge_data = ut.sort_dict(plotdat['edge_data'].copy())
logger.info(infr.repr_edge_data(all_edge_data))
ut.cprint('edge: ' + ut.repr2(plotdat['edge']), 'blue')
logger.info('artist = %r' % (artist,))
else:
logger.info('???: ' + ut.repr2(plotdat))
logger.info(ut.get_timestamp())