docs: def make_score_tabular(
          row_lbls, col_lbls, values, title=None, out_of=None, bold_best=False,
          flip=False, bigger_is_better=True, multicol_lbls=None, FORCE_INT=False,
          precision=None, SHORTEN_ROW_LBLS=False, col_align='l', col_sep='|',
          multicol_sep='|', centerline=True, astable=False, table_position='',
          AUTOFIX_LATEX=True, **kwargs):
      r"""
      makes a LaTeX tabular for displaying scores or errors
  
      Args:
          row_lbls (list of str):
          col_lbls (list of str):
          values (ndarray):
          title (str):  (default = None)
          out_of (None): (default = None)
          bold_best (bool): (default = True)
          flip (bool): (default = False)
          table_position (str) : eg '[h]'
  
      Returns:
          str: tabular_str
  
      CommandLine:
          python -m utool.util_latex --test-make_score_tabular:0 --show
          python -m utool.util_latex --test-make_score_tabular:1 --show
          python -m utool.util_latex --test-make_score_tabular:2 --show
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> from utool.util_latex import *  # NOQA
          >>> import utool as ut
          >>> row_lbls = ['config1', 'config2']
          >>> col_lbls = ['score \leq 1', 'metric2']
          >>> values = np.array([[1.2, 2], [3.2, 4]])
          >>> title = 'title'
          >>> out_of = 10
          >>> bold_best = True
          >>> flip = False
          >>> tabular_str = make_score_tabular(row_lbls, col_lbls, values, title, out_of, bold_best, flip)
          >>> result = tabular_str
          >>> print(result)
          >>> ut.quit_if_noshow()
          >>> render_latex_text(tabular_str)
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> from utool.util_latex import *  # NOQA
          >>> import utool as ut
          >>> row_lbls = ['config1']
          >>> col_lbls = ['score \leq 1', 'metric2']
          >>> values = np.array([[1.2, 2]])
          >>> title = 'title'
          >>> out_of = 10
          >>> bold_best = True
          >>> flip = False
          >>> tabular_str = make_score_tabular(row_lbls, col_lbls, values, title, out_of, bold_best, flip)
          >>> result = tabular_str
          >>> print(result)
          >>> ut.quit_if_noshow()
          >>> render_latex_text(tabular_str)
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> from utool.util_latex import *  # NOQA
          >>> import utool as ut
          >>> row_lbls = ['config1', 'config2']
          >>> col_lbls = ['score \leq 1', 'metric2', 'foobar']
          >>> multicol_lbls = [('spam', 1), ('eggs', 2)]
          >>> values = np.array([[1.2, 2, -3], [3.2, 4, -2]])
          >>> title = 'title'
          >>> out_of = 10
          >>> bold_best = True
          >>> flip = False
          >>> tabular_str = make_score_tabular(row_lbls, col_lbls, values, title, out_of, bold_best, flip, multicol_lbls=multicol_lbls)
          >>> result = tabular_str
          >>> print(result)
          >>> ut.quit_if_noshow()
          >>> render_latex_text(tabular_str)
      """
      import utool as ut
      if flip:
          bigger_is_better = not bigger_is_better
          flip_repltups = [
              ('<=', '>'),
              ('>', '<='),
              ('\\leq', '\\gt'),
              ('\\geq', '\\lt'),
              ('score', 'error')
          ]
          col_lbls = [replace_all(lbl, flip_repltups) for lbl in col_lbls]
          if title is not None:
              title = replace_all(title, flip_repltups)
          if out_of is not None:
              values = out_of - values
  
      # Abbreviate based on common substrings
      common_rowlbl = None
      if SHORTEN_ROW_LBLS:
          if isinstance(row_lbls, list):
              row_lbl_list = row_lbls
          else:
              row_lbl_list = row_lbls.flatten().tolist()
          # Split the rob labels into the alg components
          #algcomp_list = [lbl.split(')_') for lbl in row_lbl_list]
          longest = long_substr(row_lbl_list)
          common_strs = []
          while len(longest) > 10:
              common_strs += [longest]
              row_lbl_list = [row.replace(longest, '...') for row in row_lbl_list]
              longest = long_substr(row_lbl_list)
          common_rowlbl = ('...'.join(common_strs)).replace(')_', ')_\n')
          row_lbls = row_lbl_list
          if len(row_lbl_list) == 1:
              common_rowlbl = row_lbl_list[0]
              row_lbls = ['0']
  
      # Stack values into a tabular body
      # TODO: need ability to specify datatypes
      def ensurelist(row_values):
          try:
              return row_values.tolist()
          except AttributeError:
              return row_values
  
      if False:
          # Numpy formatting
          def padvec(shape=(1, 1)):
              pad = np.array([[' ' for c in range(shape[1])] for r in range(shape[0])])
              return pad
          col_lbls = ensure_rowvec(col_lbls)
          row_lbls = ensure_colvec(row_lbls)
          _0 = np.vstack([padvec(), row_lbls])
          _1 = np.vstack([col_lbls, values])
          body = np.hstack([_0, _1])
          body = [[str_ for str_ in row] for row in body]
      else:
          assert len(row_lbls) == len(values)
          body = [[' '] + col_lbls]
          body += [[row_lbl] + ensurelist(row_values) for row_lbl, row_values in zip(row_lbls, values)]
      #import utool as ut
      # Fix things in each body cell
      DO_PERCENT = True
      try:
          for r in range(len(body)):
              for c in range(len(body[0])):
                  # In data land
                  if r > 0 and c > 0:
                      if precision is not None:
                          # Hack
                          if ut.is_float(body[r][c]):
                              fmtstr = '%.' + str(precision) + 'f'
                              body[r][c] = fmtstr % (float(body[r][c]),)
                      # Force integer
                      if FORCE_INT:
                          body[r][c] = str(int(float(body[r][c])))
                  body[r][c] = str(body[r][c])
                  # Remove bad formatting;
                  if AUTOFIX_LATEX:
                      body[r][c] = escape_latex(body[r][c])
      except Exception as ex:
          import utool as ut
          print('len(row_lbls) = %r' % (len(row_lbls),))
          print('len(col_lbls) = %r' % (len(col_lbls),))
          print('len(values) = %r' % (values,))
          print('ut.depth_profile(values) = %r' % (ut.depth_profile(values),))
          ut.printex(ex, keys=['r', 'c'])
          raise
  
      # Bold the best values
      if bold_best:
          best_col_scores = values.max(0) if bigger_is_better else values.min(0)
          rows_to_bold = [np.where(values[:, colx] == best_col_scores[colx])[0]
                          for colx in range(len(values.T))]
          for colx, rowx_list in enumerate(rows_to_bold):
              for rowx in rowx_list:
                  body[rowx + 1][colx + 1] = '\\txtbf{' + body[rowx + 1][colx + 1] + '}'
  
      # More fixing after the bold is in place
      for r in range(len(body)):
          for c in range(len(body[0])):
              # In data land
              if r > 0 and c > 0:
                  if out_of is not None:
                      body[r][c] = body[r][c] + '/' + str(out_of)
                      if DO_PERCENT:
                          percent = ' = %.1f%%' % float(100 * values[r - 1, c - 1] / out_of)
                          body[r][c] += escape_latex(percent)
  
      # Align columns for pretty printing
      body = np.array(body)
      ALIGN_BODY = True
      if ALIGN_BODY:
          new_body_cols = []
          for col in body.T:
              colstrs = list(map(str, ensurelist(col)))
              collens = list(map(len, colstrs))
              maxlen = max(collens)
              newcols = [str_ + (' ' * (maxlen - len(str_))) for str_ in colstrs]
              new_body_cols += [newcols]
          body = np.array(new_body_cols).T
  
      # Build Body (and row layout)
      HLINE_SEP = True
      rowvalsep = ''
      colvalsep = ' & '
      endl = '\\\\\n'
      hline = r'\hline'
      #extra_rowsep_pos_list = [1]  # rows to insert an extra hline after
      extra_rowsep_pos_list = []  # rows to insert an extra hline after
      if HLINE_SEP:
          rowvalsep = hline + '\n'
      # rowstr list holds blocks of rows
      rowstr_list = [colvalsep.join(row) + endl for row in body]
      #rowstr_list = [row[0] + rowlbl_sep + colvalsep.join(row[1:]) + endl for row in body]
      #rowstr_list = [(
      #    ('' if len(row) == 0 else row[0])
      #    if len(row) <= 1 else
      #    row[0] + rowlblcol_sep + colvalsep.join(row[1:]) + endl)
      #    for row in body]
      rowsep_list = [rowvalsep for row in rowstr_list[0:-1]]  # should be len 1 less than rowstr_list
      # Insert multicolumn names
      if multicol_lbls is not None:
          # TODO: label of the row labels
          multicol_sep
          multicols = [latex_multicolumn(multicol, size, 'c' + multicol_sep) for multicol, size in multicol_lbls]
          multicol_str = latex_multirow('', 2) + colvalsep + colvalsep.join(multicols) + endl
          ncols = sum([tup[1] for tup in multicol_lbls])
          mcol_sep = '\\cline{2-%d}\n' % (ncols + 1,)
          rowstr_list = [multicol_str] + rowstr_list
          rowsep_list = [mcol_sep] + rowsep_list
          #extra_rowsep_pos_list += [1]
  
      # Insert title
      if title is not None and not astable:
          tex_title = latex_multicolumn(title, len(body[0])) + endl
          rowstr_list = [tex_title] + rowstr_list
          rowsep_list = [rowvalsep] + rowsep_list
          #extra_rowsep_pos_list += [2]
  
      # Apply an extra hline (for label)
      #extra_rowsep_pos_list = []
      for pos in sorted(extra_rowsep_pos_list)[::-1]:
          rowstr_list.insert(pos, '')
          rowsep_list.insert(pos, rowvalsep)
      #tabular_body = rowvalsep.join(rowstr_list)
      from six.moves import zip_longest
      tabular_body = ''.join([row if sep is None else row + sep for row, sep in zip_longest(rowstr_list, rowsep_list)])
  
      # Build Column Layout
      col_align_list = [col_align] * len(body[0])
      #extra_collayoutsep_pos_list = [1]
      extra_collayoutsep_pos_list = []
      for pos in  sorted(extra_collayoutsep_pos_list)[::-1]:
          col_align_list.insert(pos, '')
      #col_layaout_sep_list = rowlblcol_sep  # TODO
  
      rowlblcol_sep = '|'
      # Build build internal seprations between column alignments
      # Defaults to just the normal col_sep
      col_align_sep_list = [col_sep] * (len(col_align_list) - 1)
      # Adjust for the separations between row labels and the actual row data
      if len(col_align_sep_list) > 0:
          col_align_sep_list[0] = rowlblcol_sep
      # Continue multicolumn sepratation
      if multicol_lbls is not None:
          multicol_offsets = ut.cumsum(ut.get_list_column(multicol_lbls, 1))
          for offset in multicol_offsets:
              if offset < len(col_align_sep_list):
                  col_align_sep_list[offset] = multicol_sep
  
      from six.moves import zip_longest
      _tmp = [ut.filter_Nones(tup) for tup in zip_longest(col_align_list, col_align_sep_list)]
      col_layout = ''.join(ut.flatten(_tmp))
  
      #if len(col_align_list) > 1:
      #    col_layout = col_align_list[0] + rowlblcol_sep + col_sep.join(col_align_list[1:])
      #else:
      #    col_layout = col_sep.join(col_align_list)
  
      tabular_head = (r'\begin{tabular}{|%s|}' % col_layout) + '\n'
      tabular_tail = r'\end{tabular}'
  
      if centerline:
          tabular_head = r'\centerline{' + '\n' + tabular_head
          tabular_tail = tabular_tail + '}'
  
      if astable:
          #tabular_head = r'\begin{centering}' + '\n' + tabular_head
          tabular_head = r'\centering' + '\n' + tabular_head
          tabular_head = r'\begin{table}' + table_position + '\n' + tabular_head
  
          lblstr = latex_sanitize_command_name(kwargs.get('label', title))
          caption = title
          if AUTOFIX_LATEX:
              caption = escape_latex(caption)
          caption = '\n% ---\n' + caption + '\n% ---\n'
          #tabular_head = r'\end{centering}' + '\n' + tabular_head
          tabular_tail = tabular_tail + '\n\caption[%s]{%s}\n\label{tbl:%s}\n\end{table}' % (lblstr, caption, lblstr)
  
      tabular_str = rowvalsep.join([tabular_head, tabular_body, tabular_tail])
      topsep = '\\hline\n' if True else '\\toprule\n'
      botsep = '\\hline\n' if True else '\\bottomrule\n'
      tabular_str = tabular_head + topsep + tabular_body + botsep + tabular_tail
  
      if common_rowlbl is not None:
          #tabular_str += escape_latex('\n\nThe following parameters were held fixed:\n' + common_rowlbl)
          pass
      return tabular_str