docs: def interact_gridsearch_result_images(show_result_func, cfgdict_list,
                                        cfglbl_list, cfgresult_list,
                                        score_list=None, fnum=None, figtitle='',
                                        unpack=False, max_plots=25, verbose=True,
                                        precision=3, scorelbl='score',
                                        onclick_func=None):
      """ helper function for visualizing results of gridsearch """
      assert callable(show_result_func), 'NEED FUNCTION GOT: %r' % (show_result_func,)
  
      import utool as ut
      import plottool as pt
      from plottool import plot_helpers as ph
      from plottool import interact_helpers as ih
      if verbose:
          print('Plotting gridsearch results figtitle=%r' % (figtitle,))
      if score_list is None:
          score_list = [None] * len(cfgdict_list)
      else:
          # sort by score if available
          sortx_list = ut.list_argsort(score_list, reverse=True)
          score_list = ut.take(score_list, sortx_list)
          cfgdict_list = ut.take(cfgdict_list, sortx_list)
          cfglbl_list = ut.take(cfglbl_list, sortx_list)
          cfgresult_list = ut.take(cfgresult_list, sortx_list)
      # Dont show too many results only the top few
      score_list = ut.listclip(score_list, max_plots)
  
      # Show the config results
      fig = pt.figure(fnum=fnum)
      # Get plots for each of the resutls
      nRows, nCols = pt.get_square_row_cols(len(score_list), fix=True)
      next_pnum = pt.make_pnum_nextgen(nRows, nCols)
      for cfgdict, cfglbl, cfgresult, score in zip(cfgdict_list, cfglbl_list,
                                                    cfgresult_list,
                                                    score_list):
          if score is not None:
              cfglbl += '\n' + scorelbl + '=' + ut.repr2(score, precision=precision)
          pnum = next_pnum()
          try:
              if unpack:
                  show_result_func(*cfgresult, fnum=fnum, pnum=pnum)
              else:
                  show_result_func(cfgresult, fnum=fnum, pnum=pnum)
          except Exception as ex:
              if isinstance(cfgresult, tuple):
                  #print(ut.repr4(cfgresult))
                  print(ut.depth_profile(cfgresult))
                  print(ut.list_type_profile(cfgresult))
              ut.printex(ex, 'error showing', keys=['cfgresult', 'fnum', 'pnum'])
              raise
          #pt.imshow(255 * cfgresult, fnum=fnum, pnum=next_pnum(), title=cfglbl)
          ax = pt.gca()
          pt.set_title(cfglbl, ax=ax)  # , size)
          ph.set_plotdat(ax, 'cfgdict', cfgdict)
          ph.set_plotdat(ax, 'cfglbl', cfglbl)
          ph.set_plotdat(ax, 'cfgresult', cfgresult)
      # Define clicked callback
      def on_clicked(event):
          print('\n[pt] clicked gridsearch axes')
          if event is None or event.xdata is None or event.inaxes is None:
              print('out of axes')
              pass
          else:
              ax = event.inaxes
              plotdat_dict = ph.get_plotdat_dict(ax)
              print(ut.repr4(plotdat_dict))
              cfglbl = ph.get_plotdat(ax, 'cfglbl', None)
              cfgdict = ph.get_plotdat(ax, 'cfgdict', {})
              cfgresult = ph.get_plotdat(ax, 'cfgresult', {})
              infostr_list = [
                  ('cfglbl = %s' % (cfglbl,)),
                  '',
                  ('cfgdict = ' + ut.repr4(cfgdict, sorted_=True)),
              ]
              # Call a user defined function if given
              if onclick_func is not None:
                  if unpack:
                      onclick_func(*cfgresult)
                  else:
                      onclick_func(cfgresult)
              infostr = ut.msgblock('CLICKED', '\n'.join(infostr_list))
              print(infostr)
      # Connect callbacks
      ih.connect_callback(fig, 'button_press_event', on_clicked)
      pt.set_figtitle(figtitle)