Exemple #1
0
def color_by_nids(graph, unique_nids=None, ibs=None, nid2_color_=None):
    """ Colors edges and nodes by nid """
    # TODO use ut.color_nodes
    import wbia.plottool as pt

    ensure_graph_nid_labels(graph, unique_nids, ibs=ibs)
    node_to_nid = nx.get_node_attributes(graph, 'nid')
    unique_nids = ut.unique(node_to_nid.values())
    ncolors = len(unique_nids)
    if (ncolors) == 1:
        unique_colors = [pt.UNKNOWN_PURP]
    else:
        if nid2_color_ is not None:
            unique_colors = pt.distinct_colors(ncolors + len(nid2_color_) * 2)
        else:
            unique_colors = pt.distinct_colors(ncolors)
    # Find edges and aids strictly between two nids
    nid_to_color = dict(zip(unique_nids, unique_colors))
    if nid2_color_ is not None:
        # HACK NEED TO ENSURE COLORS ARE NOT REUSED
        nid_to_color.update(nid2_color_)
    edge_aids = list(graph.edges())
    edge_nids = ut.unflat_take(node_to_nid, edge_aids)
    flags = [nids[0] == nids[1] for nids in edge_nids]
    flagged_edge_aids = ut.compress(edge_aids, flags)
    flagged_edge_nids = ut.compress(edge_nids, flags)
    flagged_edge_colors = [nid_to_color[nids[0]] for nids in flagged_edge_nids]
    edge_to_color = dict(zip(flagged_edge_aids, flagged_edge_colors))
    node_to_color = ut.map_dict_vals(ut.partial(ut.take, nid_to_color),
                                     node_to_nid)
    nx.set_edge_attributes(graph, name='color', values=edge_to_color)
    nx.set_node_attributes(graph, name='color', values=node_to_color)
Exemple #2
0
def make_colorcodes(model):
    """
    python -m wbia.algo.hots.bayes --exec-make_name_model --show
    python -m wbia.algo.hots.bayes --exec-cluster_query --show
    python -m wbia --tf demo_bayesnet --ev :nA=4,nS=2,Na=n0,rand_scores=True --show --verbose
    python -m wbia --tf demo_bayesnet --ev :nA=4,nS=3,Na=n0,rand_scores=True --show --verbose
    """
    import wbia.plottool as pt

    ttype_colors = {}
    ttype_scalars = {}

    # Hacked in custom colors

    if 'name' in model.ttype2_template:
        basis = model.ttype2_template['name'].basis
        card = len(basis)
        colors = pt.distinct_colors(max(card, 10))[:card]
        ttype_colors['name'] = colors
        ttype_scalars['name'] = np.linspace(0, 1, len(basis))

    if 'score' in model.ttype2_template:
        cmap_, mn, mx = 'plasma', 0.15, 1.0
        _cmap = pt.plt.get_cmap(cmap_)

        def cmap(x):
            return _cmap((x * mx) + mn)

        basis = model.ttype2_template['score'].basis
        scalars = np.linspace(0, 1, len(basis))
        # scalars = np.linspace(0, 1, 100)
        colors = pt.scores_to_color(scalars,
                                    cmap_=cmap_,
                                    reverse_cmap=False,
                                    cmap_range=(mn, mx))
        colors = [pt.lighten_rgb(c, 0.4) for c in colors]
        ttype_scalars['score'] = scalars
        ttype_colors['score'] = colors

    return ttype_colors, ttype_scalars
Exemple #3
0
def show_model(model, evidence={}, soft_evidence={}, **kwargs):
    """
    References:
        http://stackoverflow.com/questions/22207802/pygraphviz-networkx-set-node-level-or-layer

    Ignore:
        pkg-config --libs-only-L libcgraph
        sudo apt-get  install libgraphviz-dev -y
        sudo apt-get  install libgraphviz4 -y

        # sudo apt-get install pkg-config
        sudo apt-get install libgraphviz-dev
        # pip install git+git://github.com/pygraphviz/pygraphviz.git
        pip install pygraphviz
        python -c "import pygraphviz; print(pygraphviz.__file__)"

        sudo pip3 install pygraphviz --install-option="--include-path=/usr/include/graphviz" --install-option="--library-path=/usr/lib/graphviz/"
        python3 -c "import pygraphviz; print(pygraphviz.__file__)"

    CommandLine:
        python -m wbia.algo.hots.bayes --exec-show_model --show

    Example:
        >>> # DISABLE_DOCTEST
        >>> from wbia.algo.hots.bayes import *  # NOQA
        >>> model = '?'
        >>> evidence = {}
        >>> soft_evidence = {}
        >>> result = show_model(model, evidence, soft_evidence)
        >>> print(result)
        >>> ut.quit_if_noshow()
        >>> import wbia.plottool as pt
        >>> ut.show_if_requested()
    """
    if ut.get_argval('--hackmarkov') or ut.get_argval('--hackjunc'):
        draw_tree_model(model, **kwargs)
        return

    import wbia.plottool as pt
    import networkx as netx

    fnum = pt.ensure_fnum(None)
    netx_graph = model
    # netx_graph.graph.setdefault('graph', {})['size'] = '"10,5"'
    # netx_graph.graph.setdefault('graph', {})['rankdir'] = 'LR'

    pos_dict = get_hacked_pos(netx_graph)
    # pos_dict = netx.nx_agraph.pygraphviz_layout(netx_graph)
    # pos = netx.nx_agraph.nx_pydot.pydot_layout(netx_graph, prog='dot')
    # pos_dict = netx.nx_agraph.graphviz_layout(netx_graph)

    textprops = {
        'family': 'monospace',
        'horizontalalignment': 'left',
        # 'horizontalalignment': 'center',
        # 'size': 12,
        'size': 8,
    }

    netx_nodes = model.nodes(data=True)
    node_key_list = ut.get_list_column(netx_nodes, 0)
    pos_list = ut.dict_take(pos_dict, node_key_list)

    var2_post = {f.variables[0]: f for f in kwargs.get('factor_list', [])}

    prior_text = None
    post_text = None
    evidence_tas = []
    post_tas = []
    prior_tas = []
    node_color = []

    has_inferred = evidence or var2_post
    if has_inferred:
        ignore_prior_with_ttype = [SCORE_TTYPE, MATCH_TTYPE]
        show_prior = False
    else:
        ignore_prior_with_ttype = []
        # show_prior = True
        show_prior = False

    dpy = 5
    dbx, dby = (20, 20)
    takw1 = {
        'bbox_align': (0.5, 0),
        'pos_offset': [0, dpy],
        'bbox_offset': [dbx, dby]
    }
    takw2 = {
        'bbox_align': (0.5, 1),
        'pos_offset': [0, -dpy],
        'bbox_offset': [-dbx, -dby]
    }

    name_colors = pt.distinct_colors(max(model.num_names, 10))
    name_colors = name_colors[:model.num_names]

    # cmap_ = 'hot' #mx = 0.65 #mn = 0.15
    cmap_, mn, mx = 'plasma', 0.15, 1.0
    _cmap = pt.plt.get_cmap(cmap_)

    def cmap(x):
        return _cmap((x * mx) + mn)

    for node, pos in zip(netx_nodes, pos_list):
        variable = node[0]
        cpd = model.var2_cpd[variable]
        prior_marg = (cpd if cpd.evidence is None else cpd.marginalize(
            cpd.evidence, inplace=False))

        show_evidence = variable in evidence
        show_prior = cpd.ttype not in ignore_prior_with_ttype
        show_post = variable in var2_post
        show_prior |= cpd.ttype not in ignore_prior_with_ttype

        post_marg = None

        if show_post:
            post_marg = var2_post[variable]

        def get_name_color(phi):
            order = phi.values.argsort()[::-1]
            if len(order) < 2:
                dist_next = phi.values[order[0]]
            else:
                dist_next = phi.values[order[0]] - phi.values[order[1]]
            dist_total = phi.values[order[0]]
            confidence = (dist_total * dist_next)**(2.5 / 4)
            # logger.info('confidence = %r' % (confidence,))
            color = name_colors[order[0]]
            color = pt.color_funcs.desaturate_rgb(color, 1 - confidence)
            color = np.array(color)
            return color

        if variable in evidence:
            if cpd.ttype == SCORE_TTYPE:
                cmap_index = evidence[variable] / (cpd.variable_card - 1)
                color = cmap(cmap_index)
                color = pt.lighten_rgb(color, 0.4)
                color = np.array(color)
                node_color.append(color)
            elif cpd.ttype == NAME_TTYPE:
                color = name_colors[evidence[variable]]
                color = np.array(color)
                node_color.append(color)
            else:
                color = pt.FALSE_RED
                node_color.append(color)
        # elif variable in soft_evidence:
        #    color = pt.LIGHT_PINK
        #    show_prior = True
        #    color = get_name_color(prior_marg)
        #    node_color.append(color)
        else:
            if cpd.ttype == NAME_TTYPE and post_marg is not None:
                color = get_name_color(post_marg)
                node_color.append(color)
            elif cpd.ttype == MATCH_TTYPE and post_marg is not None:
                color = cmap(post_marg.values[1])
                color = pt.lighten_rgb(color, 0.4)
                color = np.array(color)
                node_color.append(color)
            else:
                # color = pt.WHITE
                color = pt.NEUTRAL
                node_color.append(color)

        if show_prior:
            if variable in soft_evidence:
                prior_color = pt.LIGHT_PINK
            else:
                prior_color = None
            prior_text = pgm_ext.make_factor_text(prior_marg, 'prior')
            prior_tas.append(
                dict(text=prior_text, pos=pos, color=prior_color, **takw2))
        if show_evidence:
            _takw1 = takw1
            if cpd.ttype == SCORE_TTYPE:
                _takw1 = takw2
            evidence_text = cpd.variable_statenames[evidence[variable]]
            if isinstance(evidence_text, int):
                evidence_text = '%d/%d' % (evidence_text + 1,
                                           cpd.variable_card)
            evidence_tas.append(
                dict(text=evidence_text, pos=pos, color=color, **_takw1))
        if show_post:
            _takw1 = takw1
            if cpd.ttype == MATCH_TTYPE:
                _takw1 = takw2
            post_text = pgm_ext.make_factor_text(post_marg, 'post')
            post_tas.append(dict(text=post_text, pos=pos, color=None,
                                 **_takw1))

    def trnps_(dict_list):
        """ tranpose dict list """
        list_dict = ut.ddict(list)
        for dict_ in dict_list:
            for key, val in dict_.items():
                list_dict[key + '_list'].append(val)
        return list_dict

    takw1_ = trnps_(post_tas + evidence_tas)
    takw2_ = trnps_(prior_tas)

    # Draw graph
    if has_inferred:
        pnum1 = (3, 1, (slice(0, 2), 0))
    else:
        pnum1 = None

    fig = pt.figure(fnum=fnum, pnum=pnum1, doclf=True)  # NOQA
    ax = pt.gca()
    # logger.info('node_color = %s' % (ut.repr3(node_color),))
    drawkw = dict(pos=pos_dict,
                  ax=ax,
                  with_labels=True,
                  node_size=1500,
                  node_color=node_color)
    netx.draw(netx_graph, **drawkw)

    hacks = []
    if len(post_tas + evidence_tas):
        hacks.append(pt.draw_text_annotations(textprops=textprops, **takw1_))
    if prior_tas:
        hacks.append(pt.draw_text_annotations(textprops=textprops, **takw2_))

    xmin, ymin = np.array(pos_list).min(axis=0)
    xmax, ymax = np.array(pos_list).max(axis=0)
    num_annots = len(model.ttype2_cpds[NAME_TTYPE])
    if num_annots > 4:
        ax.set_xlim((xmin - 40, xmax + 40))
        ax.set_ylim((ymin - 50, ymax + 50))
        fig.set_size_inches(30, 7)
    else:
        ax.set_xlim((xmin - 42, xmax + 42))
        ax.set_ylim((ymin - 50, ymax + 50))
        fig.set_size_inches(23, 7)
    fig = pt.gcf()

    title = 'num_names=%r, num_annots=%r' % (
        model.num_names,
        num_annots,
    )
    map_assign = kwargs.get('map_assign', None)

    top_assignments = kwargs.get('top_assignments', None)
    if top_assignments is not None:
        map_assign, map_prob = top_assignments[0]
        if map_assign is not None:

            def word_insert(text):
                return '' if len(text) == 0 else text + ' '

            title += '\n%sMAP: ' % (word_insert(kwargs.get('method', '')))
            title += map_assign + ' @' + '%.2f%%' % (100 * map_prob, )
    if kwargs.get('show_title', True):
        pt.set_figtitle(title, size=14)

    for hack in hacks:
        hack()

    # Hack in colorbars
    if has_inferred:
        pt.colorbar(
            np.linspace(0, 1, len(name_colors)),
            name_colors,
            lbl=NAME_TTYPE,
            ticklabels=model.ttype2_template[NAME_TTYPE].basis,
            ticklocation='left',
        )

        basis = model.ttype2_template[SCORE_TTYPE].basis
        scalars = np.linspace(0, 1, len(basis))
        scalars = np.linspace(0, 1, 100)
        colors = pt.scores_to_color(scalars,
                                    cmap_=cmap_,
                                    reverse_cmap=False,
                                    cmap_range=(mn, mx))
        colors = [pt.lighten_rgb(c, 0.4) for c in colors]

        if ut.list_type(basis) is int:
            pt.colorbar(scalars,
                        colors,
                        lbl=SCORE_TTYPE,
                        ticklabels=np.array(basis) + 1)
        else:
            pt.colorbar(scalars, colors, lbl=SCORE_TTYPE, ticklabels=basis)
            # logger.info('basis = %r' % (basis,))

    # Draw probability hist
    if has_inferred and top_assignments is not None:
        bin_labels = ut.get_list_column(top_assignments, 0)
        bin_vals = ut.get_list_column(top_assignments, 1)

        # bin_labels = ['\n'.join(ut.textwrap.wrap(_lbl, width=30)) for _lbl in bin_labels]

        pt.draw_histogram(
            bin_labels,
            bin_vals,
            fnum=fnum,
            pnum=(3, 8, (2, slice(4, None))),
            transpose=True,
            use_darkbackground=False,
            # xtick_rotation=-10,
            ylabel='Prob',
            xlabel='assignment',
        )
        pt.set_title('Assignment probabilities')
    def show_page(self, bring_to_front=False, onlyrows=None, fulldraw=True):
        """ Plots all subaxes on a page

        onlyrows is a hack to only draw a subset of the data again
        """
        if ut.VERBOSE:
            if not fulldraw:
                logger.info('[matchver] show_page(fulldraw=%r, onlyrows=%r)' %
                            (fulldraw, onlyrows))
            else:
                logger.info('[matchver] show_page(fulldraw=%r)' % (fulldraw))
        self.prepare_page(fulldraw=fulldraw)
        # Variables we will work with to paint a pretty picture
        ibs = self.ibs
        nRows = self.nRows
        colpad = 1 if self.cm is not None else 0
        nCols = self.nCols + colpad

        # Distinct color for every unique name
        unique_nids = ut.unique_ordered(
            ibs.get_annot_name_rowids(self.all_aid_list,
                                      distinguish_unknowns=False))
        unique_colors = pt.distinct_colors(len(unique_nids),
                                           brightness=0.7,
                                           hue_range=(0.05, 0.95))
        self.nid2_color = dict(zip(unique_nids, unique_colors))

        row_aids_list = self.get_row_aids_list()

        if self.cm is not None:
            logger.info('DRAWING QRES')
            pnum = (1, nCols, 1)
            if not fulldraw:
                # not doing full draw so we have to clear any axes
                # that are here already manually
                ax = self.fig.add_subplot(*pnum)
                self.clear_parent_axes(ax)
            self.cm.show_single_annotmatch(
                self.qreq_,
                self.aid2,
                fnum=self.fnum,
                pnum=pnum,
                draw_fmatch=True,
                colorbar_=False,
            )

        # For each row
        for rowx, aid_list in enumerate(row_aids_list):
            offset = rowx * nCols + 1
            if onlyrows is not None and rowx not in onlyrows:
                continue
            # ibsfuncs.assert_valid_aids(ibs, groundtruth)
            # For each column
            for colx, aid in enumerate(aid_list, start=colpad):
                if colx >= nCols:
                    break
                try:
                    nid = ibs.get_annot_name_rowids(aid)
                    if ibsfuncs.is_nid_unknown(ibs, [nid])[0]:
                        color = const.UNKNOWN_PURPLE_RGBA01
                    else:
                        color = self.nid2_color[nid]
                except Exception as ex:
                    ut.printex(ex)
                    logger.info('nid = %r' % (nid, ))
                    logger.info('self.nid2_color = %s' %
                                (ut.repr2(self.nid2_color), ))
                    raise
                px = colx + offset
                ax = self.plot_chip(int(aid),
                                    nRows,
                                    nCols,
                                    px,
                                    color=color,
                                    fulldraw=fulldraw)
                # If there are still more in this row to display
                if colx + 1 < len(aid_list) and colx + 1 >= nCols:
                    total_indices = len(aid_list)
                    current_index = self.col_offset_list[rowx] + 1
                    next_text = 'next\n%d/%d' % (current_index, total_indices)
                    next_func = functools.partial(self.rotate_row, rowx=rowx)
                    self.append_button(
                        next_text,
                        callback=next_func,
                        location='right',
                        size='33%',
                        ax=ax,
                    )

        if fulldraw:
            self.show_hud()
            hspace = 0.05 if (self.nCols) > 1 else 0.1
            subplotspar = {
                'left': 0.1,
                'right': 0.9,
                'top': 0.85,
                'bottom': 0.1,
                'wspace': 0.3,
                'hspace': hspace,
            }
            pt.adjust_subplots(**subplotspar)
        self.draw()
        self.show()
        if bring_to_front:
            self.bring_to_front()
Exemple #5
0
def show_sv_simple(chip1,
                   chip2,
                   kpts1,
                   kpts2,
                   fm,
                   inliers,
                   mx=None,
                   fnum=1,
                   vert=None,
                   **kwargs):
    """

    CommandLine:
        python -m wbia.plottool.draw_sv --test-show_sv_simple --show

    Example:
        >>> # DISABLE_DOCTEST
        >>> from wbia.plottool.draw_sv import *  # NOQA
        >>> import vtool as vt
        >>> kpts1, kpts2, fm, aff_inliers, chip1, chip2, xy_thresh_sqrd = vt.testdata_matching_affine_inliers()
        >>> inliers = aff_inliers
        >>> mx = None
        >>> fnum = 1
        >>> vert = None  # ut.get_argval('--vert', type_=bool, default=None)
        >>> result = show_sv_simple(chip1, chip2, kpts1, kpts2, fm, inliers, mx, fnum, vert=vert)
        >>> print(result)
        >>> import wbia.plottool as pt
        >>> pt.show_if_requested()
    """
    import wbia.plottool as pt
    import vtool as vt

    colors = pt.distinct_colors(2, brightness=0.95)
    color1, color2 = colors[0:2]
    # Begin the drawing
    fnum = pt.ensure_fnum(fnum)
    pt.figure(fnum=fnum, pnum=(1, 1, 1), docla=True, doclf=True)
    # dmkwargs = dict(fs=None, title='Inconsistent Matches', all_kpts=False, draw_lines=True,
    #                docla=True, draw_border=True, fnum=fnum, pnum=(1, 1, 1), colors=pt.ORANGE)
    inlier_mask = vt.index_to_boolmask(inliers, maxval=len(fm))
    fm_inliers = fm.compress(inlier_mask, axis=0)
    fm_outliers = fm.compress(np.logical_not(inlier_mask), axis=0)
    xywh1, xywh2, sf_tup = pt.show_chipmatch2(chip1,
                                              chip2,
                                              vert=vert,
                                              modifysize=True,
                                              new_return=True)
    sf1, sf2 = sf_tup
    fmatch_kw = dict(ell_linewidth=2, ell_alpha=0.7, line_alpha=0.7)
    pt.plot_fmatch(xywh1,
                   xywh2,
                   kpts1,
                   kpts2,
                   fm_inliers,
                   colors=color1,
                   scale_factor1=sf1,
                   scale_factor2=sf2,
                   **fmatch_kw)
    pt.plot_fmatch(xywh1,
                   xywh2,
                   kpts1,
                   kpts2,
                   fm_outliers,
                   colors=color2,
                   scale_factor1=sf1,
                   scale_factor2=sf2,
                   **fmatch_kw)
Exemple #6
0
def _pil_distinct_colors(n_colors):
    float_colors = pt.distinct_colors(n_colors)
    int_colors = [
        tuple([int(256 * f) for f in color]) for color in float_colors
    ]
    return int_colors
def show_qres(ibs, cm, qreq_=None, **kwargs):
    r"""
    Display Query Result Logic
    Defaults to: query chip, groundtruth matches, and top matches

    Args:
        ibs (wbia.IBEISController): wbia controller object
        cm (wbia.ChipMatch): object of feature correspondences and scores
        qreq_ (wbia.QueryRequest):  query request object with hyper-parameters(default = None)

    Kwargs:
        annot_mode, figtitle, make_figtitle, aug, top_aids, all_kpts,
        show_query, in_image, sidebyside, name_scoring, max_nCols,
        failed_to_match, fnum
        in_image (bool) show result  in image view if True else chip view
        annot_mode (int):
            if annot_mode == 0, then draw lines and ellipse
            elif annot_mode == 1, then dont draw lines or ellipse
            elif annot_mode == 2, then draw only lines
            elif annot_mode == 3, draw heatmask only
        See: viz_matches.show_name_matches, viz_helpers.get_query_text

    Returns:
        mpl.Figure: fig

    CommandLine:
        ./main.py --query 1 -y --db PZ_MTEST --noshow-qres
        python -m wbia.viz.viz_qres show_qres --show
        python -m wbia.viz.viz_qres show_qres --show --top-aids=10 --db=PZ_MTEST \
                --sidebyside --annot_mode=0 --notitle --no-viz_name_score \
                --qaids=5 --max_nCols=2 --adjust=.01,.01,.01

    Example:
        >>> # DISABLE_DOCTEST
        >>> from wbia.viz.viz_qres import *  # NOQA
        >>> import wbia
        >>> cm, qreq_ = wbia.testdata_cm()
        >>> kwargs = dict(
        >>>     top_aids=ut.get_argval('--top-aids', type_=int, default=3),
        >>>     sidebyside=not ut.get_argflag('--no-sidebyside'),
        >>>     annot_mode=ut.get_argval('--annot_mode', type_=int, default=1),
        >>>     viz_name_score=not ut.get_argflag('--no-viz_name_score'),
        >>>     simplemode=ut.get_argflag('--simplemode'),
        >>>     max_nCols=ut.get_argval('--max_nCols', type_=int, default=None)
        >>> )
        >>> ibs = qreq_.ibs
        >>> fig = show_qres(ibs, cm, show_query=False, qreq_=qreq_, **kwargs)
        >>> ut.show_if_requested()
    """
    # ut.print_dict(kwargs)
    annot_mode = kwargs.get('annot_mode', 1) % 4  # this is toggled
    figtitle = kwargs.get('figtitle', '')
    aug = kwargs.get('aug', '')
    top_aids = kwargs.get('top_aids', DEFAULT_NTOP)
    gt_aids = kwargs.get('gt_aids', [])
    all_kpts = kwargs.get('all_kpts', False)
    show_query = kwargs.get('show_query', False)
    in_image = kwargs.get('in_image', False)
    sidebyside = kwargs.get('sidebyside', True)
    simplemode = kwargs.get('simplemode', False)
    colorbar_ = kwargs.get('colorbar_', False)
    # name_scoring   = kwargs.get('name_scoring', False)
    viz_name_score = kwargs.get('viz_name_score', qreq_ is not None)
    max_nCols = kwargs.get('max_nCols', None)
    failed_to_match = kwargs.get('failed_to_match', False)

    fnum = pt.ensure_fnum(kwargs.get('fnum', None))

    if ut.VERBOSE and ut.NOT_QUIET:
        logger.info('query_info = ' + ut.repr2(
            ibs.get_annot_info(
                cm.qaid,
                default=True,
                gname=False,
                name=False,
                notes=False,
                exemplar=False,
            ),
            nl=4,
        ))
        logger.info('top_aids_info = ' + ut.repr2(
            ibs.get_annot_info(
                top_aids,
                default=True,
                gname=False,
                name=False,
                notes=False,
                exemplar=False,
                reference_aid=cm.qaid,
            ),
            nl=4,
        ))

    fig = pt.figure(fnum=fnum, docla=True, doclf=True)

    if isinstance(top_aids, int):
        top_aids = cm.get_top_aids(top_aids)

    if failed_to_match:
        # HACK to visually indicate failure to match in analysis
        show_query = True
        top_aids = [None] + top_aids

    nTop = len(top_aids)

    if max_nCols is None:
        max_nCols = 5
        if nTop in [6, 7]:
            max_nCols = 3
        if nTop in [8]:
            max_nCols = 4

    try:
        assert (len(list(set(top_aids).intersection(
            set(gt_aids)))) == 0), 'gts should be missed.  not in top'
    except AssertionError as ex:
        ut.printex(ex, keys=['top_aids', 'gt_aids'])
        raise

    if ut.DEBUG2:
        logger.info(cm.get_inspect_str())

    # --------------------------------------------------
    # Get grid / cell information to build subplot grid
    # --------------------------------------------------
    # Show query or not
    nQuerySubplts = 1 if show_query else 0
    # The top row is given slots for ground truths and querys
    # all aids in gt_aids should not be in top aids
    nGtSubplts = nQuerySubplts + (0 if gt_aids is None else len(gt_aids))
    # The bottom rows are for the top results
    nTopNSubplts = nTop
    nTopNCols = min(max_nCols, nTopNSubplts)
    nGTCols = min(max_nCols, nGtSubplts)
    nGTCols = max(nGTCols, nTopNCols)
    nTopNCols = nGTCols
    # Get number of rows to show groundtruth
    nGtRows = 0 if nGTCols == 0 else int(np.ceil(nGtSubplts / nGTCols))
    # Get number of rows to show results
    nTopNRows = 0 if nTopNCols == 0 else int(np.ceil(nTopNSubplts / nTopNCols))
    nGtCells = nGtRows * nGTCols
    # Total number of rows
    nRows = nTopNRows + nGtRows

    DEBUG_SHOW_QRES = 0

    if DEBUG_SHOW_QRES:
        allgt_aids = ibs.get_annot_groundtruth(cm.qaid)
        nSelGt = len(gt_aids)
        nAllGt = len(allgt_aids)
        logger.info('[show_qres]========================')
        logger.info('[show_qres]----------------')
        logger.info('[show_qres] * annot_mode=%r' % (annot_mode, ))
        logger.info('[show_qres] #nTop=%r #missed_gts=%r/%r' %
                    (nTop, nSelGt, nAllGt))
        logger.info('[show_qres] * -----')
        logger.info('[show_qres] * nRows=%r' % (nRows, ))
        logger.info('[show_qres] * nGtSubplts=%r' % (nGtSubplts, ))
        logger.info('[show_qres] * nTopNSubplts=%r' % (nTopNSubplts, ))
        logger.info('[show_qres] * nQuerySubplts=%r' % (nQuerySubplts, ))
        logger.info('[show_qres] * -----')
        logger.info('[show_qres] * nGTCols=%r' % (nGTCols, ))
        logger.info('[show_qres] * -----')
        logger.info('[show_qres] * fnum=%r' % (fnum, ))
        logger.info('[show_qres] * figtitle=%r' % (figtitle, ))
        logger.info('[show_qres] * max_nCols=%r' % (max_nCols, ))
        logger.info('[show_qres] * show_query=%r' % (show_query, ))
        logger.info('[show_qres] * kwargs=%s' % (ut.repr2(kwargs), ))

    # HACK:
    _color_list = pt.distinct_colors(nTop)
    aid2_color = {aid: _color_list[ox] for ox, aid in enumerate(top_aids)}
    ranked_aids = cm.get_top_aids()

    # Helpers
    def _show_query_fn(plotx_shift, rowcols):
        """ helper for show_qres """
        plotx = plotx_shift + 1
        pnum = (rowcols[0], rowcols[1], plotx)
        # logger.info('[viz] Plotting Query: pnum=%r' % (pnum,))
        _kwshow = dict(draw_kpts=annot_mode)
        _kwshow.update(kwargs)
        _kwshow['prefix'] = 'q'
        _kwshow['pnum'] = pnum
        _kwshow['aid2_color'] = aid2_color
        _kwshow['draw_ell'] = annot_mode >= 1
        viz_chip.show_chip(ibs, cm.qaid, annote=False, qreq_=qreq_, **_kwshow)

    def _plot_matches_aids(aid_list, plotx_shift, rowcols):
        """ helper for show_qres to draw many aids """
        _kwshow = dict(
            draw_ell=annot_mode,
            draw_pts=False,
            draw_lines=annot_mode,
            ell_alpha=0.5,
            all_kpts=all_kpts,
        )
        _kwshow.update(kwargs)
        _kwshow['fnum'] = fnum
        _kwshow['in_image'] = in_image
        _kwshow['colorbar_'] = colorbar_
        if sidebyside:
            # Draw each match side by side the query
            _kwshow['draw_ell'] = annot_mode in {1}
            _kwshow['draw_lines'] = annot_mode in {1, 2}
            _kwshow['heatmask'] = annot_mode in {3}
        else:
            # logger.info('annot_mode = %r' % (annot_mode,))
            _kwshow['draw_ell'] = annot_mode == 1
            # _kwshow['draw_pts'] = annot_mode >= 1
            # _kwshow['draw_lines'] = False
            _kwshow['show_query'] = False

        def _show_matches_fn(aid, orank, pnum):
            """ Helper function for drawing matches to one aid """
            aug = 'rank=%r\n' % orank
            _kwshow['pnum'] = pnum
            _kwshow['title_aug'] = aug
            # draw_ell = annot_mode == 1
            # draw_lines = annot_mode >= 1
            # If we already are showing the query dont show it here
            if sidebyside:
                # Draw each match side by side the query
                if viz_name_score:
                    cm.show_single_namematch(qreq_, ibs.get_annot_nids(aid),
                                             **_kwshow)
                else:
                    if simplemode:
                        _kwshow['draw_border'] = False
                        _kwshow['draw_lbl'] = False
                        _kwshow['notitle'] = True
                        _kwshow['vert'] = False
                        _kwshow['modifysize'] = True
                    cm.show_single_annotmatch(qreq_, aid, **_kwshow)
                    # viz_matches.show_matches(ibs, cm, aid, qreq_=qreq_, **_kwshow)
            else:
                # Draw each match by themselves
                data_config2_ = None if qreq_ is None else qreq_.extern_data_config2
                # _kwshow['draw_border'] = kwargs.get('draw_border', True)
                # _kwshow['notitle'] = ut.get_argflag(('--no-title', '--notitle'))
                viz_chip.show_chip(
                    ibs,
                    aid,
                    annote=False,
                    notitle=True,
                    data_config2_=data_config2_,
                    **_kwshow,
                )

        if DEBUG_SHOW_QRES:
            logger.info('[show_qres()] Plotting Chips %s:' %
                        vh.get_aidstrs(aid_list))
        if aid_list is None:
            return
        # Do lazy load before show
        # data_config2_ = None if qreq_ is None else qreq_.extern_data_config2

        # tblhack = getattr(qreq_, 'tablename', None)
        # HACK FOR HUMPBACKS
        # (Also in viz_matches)
        # if tblhack == 'vsone' or (qreq_ is not None and not qreq_._isnewreq):
        #     # precompute
        #     pass
        #     #ibs.get_annot_chips(aid_list, config2_=data_config2_, ensure=True)
        #     #ibs.get_annot_kpts(aid_list, config2_=data_config2_, ensure=True)

        for ox, aid in enumerate(aid_list):
            plotx = ox + plotx_shift + 1
            pnum = (rowcols[0], rowcols[1], plotx)
            oranks = np.where(ranked_aids == aid)[0]
            # This pair has no matches between them.
            if len(oranks) == 0:
                orank = -1
                if aid is None:
                    pt.imshow_null(
                        'Failed to find matches\nfor qaid=%r' % (cm.qaid),
                        fnum=fnum,
                        pnum=pnum,
                        fontsize=18,
                    )
                else:
                    _show_matches_fn(aid, orank, pnum)
                # if DEBUG_SHOW_QRES:
                #    logger.info('skipping pnum=%r' % (pnum,))
                continue
            if DEBUG_SHOW_QRES:
                logger.info('pnum=%r' % (pnum, ))
            orank = oranks[0] + 1
            _show_matches_fn(aid, orank, pnum)

    shift_topN = nGtCells

    if nGtSubplts == 1:
        nGTCols = 1

    if nRows == 0:
        pt.imshow_null('[viz_qres] No matches. nRows=0', fnum=fnum)
    else:
        fig = pt.figure(fnum=fnum,
                        pnum=(nRows, nGTCols, 1),
                        docla=True,
                        doclf=True)
        pt.plt.subplot(nRows, nGTCols, 1)
        # Plot Query
        if show_query:
            _show_query_fn(0, (nRows, nGTCols))
        # Plot Ground Truth (if given)
        _plot_matches_aids(gt_aids, nQuerySubplts, (nRows, nGTCols))
        # Plot Results
        _plot_matches_aids(top_aids, shift_topN, (nRows, nTopNCols))
        figtitle += aug
    if failed_to_match:
        figtitle += '\n No matches found'

    incanvas = kwargs.get('with_figtitle', not vh.NO_LBL_OVERRIDE)
    pt.set_figtitle(figtitle, incanvas=incanvas)

    # Result Interaction
    return fig