def guess_formatter(values, precision=1, commas=True, parens=True, nan='nan', prefix=None, pcts=0,
                    trunc_dot_zeros=0):
    """Based on the values, return the most suitable formatter
    Parameters
    ----------
    values : Series, DataFrame, scalar, list, tuple, or ndarray
             Values used to determine which formatter is the best fit
    """
    formatter_args = dict(precision=precision, commas=commas, parens=parens, nan=nan, prefix=prefix,
                          trunc_dot_zeros=trunc_dot_zeros)

    try:
        if isinstance(values, pd.datetime) and values.hour == 0 and values.minute == 0:
            return new_datetime_formatter()
        elif is_datetime_arraylike(values):
            # basic date formatter if no hours or minutes
            if hasattr(values, 'dt'):
                if (values.dt.hour == 0).all() and (values.dt.minute == 0).all():
                    return new_datetime_formatter()
            elif isinstance(values, pd.Series):
                if values.dropna().apply(lambda d: d.hour == 0).all() and values.apply(lambda d: d.minute == 0).all():
                    return new_datetime_formatter()
            elif isinstance(values, pd.DataFrame):
                if values.dropna().applymap(lambda d: d != d or (d.hour == 0 and d.minute == 0)).all().all():
                    return new_datetime_formatter()

        elif isinstance(values, pd.Series):
            aval = values.abs()
            vmax, vmin = aval.max(), aval.min()
        elif isinstance(values, np.ndarray):
            if values.ndim == 2:
                avalues = pd.DataFrame(values).abs()
                vmax = avalues.max().max()
                vmin = avalues.min().min()
            elif values.ndim == 1:
                aval = pd.Series(values).abs()
                vmax, vmin = aval.max(), aval.min()
            else:
                raise ValueError('cannot accept frame with more than 2-dimensions')
        elif isinstance(values, pd.DataFrame):
            avalues = values.abs()
            vmax = avalues.max().max()
            vmin = avalues.min().min()
        elif isinstance(values, (list, tuple)):
            vmax = max(values)
            vmin = min(values)
        else:
            vmax = vmin = abs(values)

        if np.isnan(vmin):
            return new_float_formatter(**formatter_args)
        else:
            min_digits = 0 if vmin == 0 else math.floor(math.log10(vmin))
            # max_digits = math.floor(math.log10(vmax))
            if min_digits >= 12:
                return new_trillions_formatter(**formatter_args)
            elif min_digits >= 9:
                return new_billions_formatter(**formatter_args)
            elif min_digits >= 6:
                return new_millions_formatter(**formatter_args)
            elif min_digits >= 3:
                return new_thousands_formatter(**formatter_args)
            elif pcts and min_digits < 0 and vmax < 1:
                return new_percent_formatter(**formatter_args)
            else:
                if isinstance(vmax, int):
                    formatter_args.pop('precision')
                    return new_int_formatter(**formatter_args)
                else:
                    return new_float_formatter(**formatter_args)
    except:
        # import sys
        # e = sys.exc_info()[0]
        return lambda x: x
Based on the values, return the most suitable formatter
    Parameters
    ----------
    values : Series, DataFrame, scalar, list, tuple, or ndarray
             Values used to determine which formatter is the best fit