docs: def show_keys(cls, keys=None, indent=0, grouped=False, func=None,
                    include_links=False, *args, **kwargs):
          """
          Classmethod to return a nice looking table with the given formatoptions
  
          Parameters
          ----------
          %(Plotter._enhance_keys.parameters)s
          indent: int
              The indentation of the table
          grouped: bool, optional
              If True, the formatoptions are grouped corresponding to the
              :attr:`Formatoption.groupname` attribute
  
          Other Parameters
          ----------------
          func: function or None
              The function the is used for returning (by default it is printed
              via the :func:`print` function or (when using the gui) in the
              help explorer). The given function must take a string as argument
          include_links: bool or None, optional
              Default False. If True, links (in restructured formats) are
              included in the description. If None, the behaviour is determined
              by the :attr:`psyplot.plotter.Plotter.include_links` attribute.
          %(Plotter._enhance_keys.other_parameters)s
  
          Returns
          -------
          results of `func`
              None if `func` is the print function, otherwise anything else
  
          See Also
          --------
          show_summaries, show_docs"""
          def titled_group(groupname):
              bars = str_indent + '*' * len(groupname) + '\n'
              return bars + str_indent + groupname + '\n' + bars
  
          keys = cls._enhance_keys(keys, *args, **kwargs)
          str_indent = " " * indent
          func = func or default_print_func
          # call this function recursively when grouped is True
          if grouped:
              grouped_keys = DefaultOrderedDict(list)
              for fmto in map(lambda key: getattr(cls, key), keys):
                  grouped_keys[fmto.groupname].append(fmto.key)
              text = ""
              for group, keys in six.iteritems(grouped_keys):
                  text += titled_group(group) + cls.show_keys(
                      keys, indent=indent, grouped=False, func=six.text_type,
                      include_links=include_links) + '\n\n'
              return func(text.rstrip())
  
          if not keys:
              return
          n = len(keys)
          ncols = min([4, n])  # number of columns
          # The number of cells in the table is one of the following cases:
          #     1. The number of columns and equal to the number of keys
          #     2. The number of keys
          #     3. The number of keys plus the empty cells in the last column
          ncells = n + ((ncols - (n % ncols)) if n != ncols else 0)
          if include_links or (include_links is None and cls.include_links):
              long_keys = list(map(lambda key: ':attr:`~%s.%s.%s`' % (
                  cls.__module__, cls.__name__, key), keys))
          else:
              long_keys = keys
          maxn = max(map(len, long_keys))  # maximal lenght of the keys
          # extend with empty cells
          long_keys.extend([' ' * maxn] * (ncells - n))
          bars = (str_indent + '+-' + ("-"*(maxn) + "-+-")*ncols)[:-1]
          lines = ('| %s |\n%s' % (' | '.join(
              key.ljust(maxn) for key in long_keys[i:i+ncols]), bars)
              for i in range(0, n, ncols))
          text = bars + "\n" + str_indent + ("\n" + str_indent).join(
              lines)
          if six.PY2:
              text = text.encode('utf-8')
  
          return func(text)