(
        data, *, min_width=0, min_bins=2, max_bins=50,
        min_unique=5, add_unique=0,
        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),
        label_fmt="%g")
return bins
Find a set of nice splits of data into bins

    The function first computes the scaling factor that is, the power of 10
    that brings the interval of values within [0, 1]. For instances, if the
    numbers come from interaval 10004001 and 10007005, the width of the
    interval is 3004, so the scaling factor is 1000.

    The function next considers bin widths that are products of scaling and
    different factors from 20 to 0.01 that make sense in decimal scale
    (see default value for argument `factors`). For each width, it rounds the
    minimal value down to this width and the maximal value up, and it computes
    the number of bins of that width that fit between these two values.
    If the number of bins is between `min_bins` and `max_bins`, and the width
    is at least `min_width`, this is a valid interval.

    If the data has no more than `min_unique` unique values, the function will
    add a set of bins that put each value into its own bin.

    If the data has no more than `add_unique` values, that last bins will put
    each value into its own bin.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_width (float): minimal bin width
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values
        min_unique (int):
            if the number of unique values are less or equal to `min_unique`,
            the function returns a single binning that matches that values in
            the data
        add_unique (int):
            similar to `min_unique` except that such bins are added to the list;
            set to 0 to disable
        factors (list of float):
            The factors with which the scaling is multiplied. Default is
            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,
            so if scaling is 1000, considered bin widths are 20000, 10000,
            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.
        label_fmt (str or Callable):
            A format string (default: "%g") used for threshold labels,
            or a function for formatting thresholds (e.g. var.str_val)

    Returns:
        bin_boundaries (list of np.ndarray): a list of bin boundaries,
            including the top boundary of the last interval, hence the list
            size equals the number bins + 1. These array match the `bin`
            argument of `numpy.histogram`.

            This is returned if `return_defs` is left `True`.

        bin_definition (list of BinDefinition):
            `BinDefinition` is a named tuple containing the beginning of the
            first bin (`start`), number of bins (`nbins`) and their widths
            (`width`). The last value can also be a `nd.array` with `nbins + 1`
            elements, which describes bins of unequal width and is used for
            binnings that match the unique values in the data (see `min_unique`
            and `add_unique`).

            This is returned if `return_defs` is `False`.
Find a set of nice splits of data into bins
Find a set of nice splits of data into bins
def decimal_binnings(
        data, *, min_width=0, min_bins=2, max_bins=50,
        min_unique=5, add_unique=0,
        factors=(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20),
        label_fmt="%g"):
    """
    Find a set of nice splits of data into bins

    The function first computes the scaling factor that is, the power of 10
    that brings the interval of values within [0, 1]. For instances, if the
    numbers come from interaval 10004001 and 10007005, the width of the
    interval is 3004, so the scaling factor is 1000.

    The function next considers bin widths that are products of scaling and
    different factors from 20 to 0.01 that make sense in decimal scale
    (see default value for argument `factors`). For each width, it rounds the
    minimal value down to this width and the maximal value up, and it computes
    the number of bins of that width that fit between these two values.
    If the number of bins is between `min_bins` and `max_bins`, and the width
    is at least `min_width`, this is a valid interval.

    If the data has no more than `min_unique` unique values, the function will
    add a set of bins that put each value into its own bin.

    If the data has no more than `add_unique` values, that last bins will put
    each value into its own bin.

    Args:
        data (np.ndarray):
            vector of data points; values may repeat, and nans and infs are
            filtered out.
        min_width (float): minimal bin width
        min_bins (int): minimal number of bins
        max_bins (int):
            maximal number of bins; the number of bins will never exceed the
            number of unique values
        min_unique (int):
            if the number of unique values are less or equal to `min_unique`,
            the function returns a single binning that matches that values in
            the data
        add_unique (int):
            similar to `min_unique` except that such bins are added to the list;
            set to 0 to disable
        factors (list of float):
            The factors with which the scaling is multiplied. Default is
            `(0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20)`,
            so if scaling is 1000, considered bin widths are 20000, 10000,
            5000, 2000, 1000, 500, 250, 200, 100, 50, 25, 20 and 10.
        label_fmt (str or Callable):
            A format string (default: "%g") used for threshold labels,
            or a function for formatting thresholds (e.g. var.str_val)

    Returns:
        bin_boundaries (list of np.ndarray): a list of bin boundaries,
            including the top boundary of the last interval, hence the list
            size equals the number bins + 1. These array match the `bin`
            argument of `numpy.histogram`.

            This is returned if `return_defs` is left `True`.

        bin_definition (list of BinDefinition):
            `BinDefinition` is a named tuple containing the beginning of the
            first bin (`start`), number of bins (`nbins`) and their widths
            (`width`). The last value can also be a `nd.array` with `nbins + 1`
            elements, which describes bins of unequal width and is used for
            binnings that match the unique values in the data (see `min_unique`
            and `add_unique`).

            This is returned if `return_defs` is `False`.
    """
    bins = []

    mn, mx, unique = _min_max_unique(data)
    if len(unique) <= max(min_unique, add_unique):
        bins.append(BinDefinition(_unique_thresholds(unique), label_fmt))
        if len(unique) <= min_unique:
            return bins

    diff = mx - mn
    f10 = 10 ** -np.floor(np.log10(diff))
    max_bins = min(max_bins, len(unique))
    for f in factors:
        width = f / f10
        if width < min_width:
            continue
        mn_ = np.floor(mn / width) * width
        mx_ = np.ceil(mx / width) * width
        nbins = np.round((mx_ - mn_) / width)
        if min_bins <= nbins <= max_bins \
                and (not bins or bins[-1].nbins != nbins):
            bins_ = mn_ + width * np.arange(nbins + 1)
            # to prevent values on the edge of the bin fall in the wrong bin
            # due to precision error on decimals that are not precise
            bins_ = np.around(bins_, decimals=np.finfo(bins_.dtype).precision)
            bin_def = BinDefinition(bins_, label_fmt, None, width)
            bins.append(bin_def)
    return bins
def decimal_binnings ( data , * , min_width = 0 , min_bins = 2 , max_bins = 50 , min_unique = 5 , add_unique = 0 , factors = ( 0.01 , 0.02 , 0.025 , 0.05 , 0.1 , 0.2 , 0.25 , 0.5 , 1 , 2 , 5 , 10 , 20 ) , label_fmt = "%g" ) : bins = [ ] mn , mx , unique = _min_max_unique ( data ) if len ( unique ) <= max ( min_unique , add_unique ) : bins . append ( BinDefinition ( _unique_thresholds ( unique ) , label_fmt ) ) if len ( unique ) <= min_unique : return bins diff = mx - mn f10 = 10 ** - np . floor ( np . log10 ( diff ) ) max_bins = min ( max_bins , len ( unique ) ) for f in factors : width = f / f10 if width < min_width : continue mn_ = np . floor ( mn / width ) * width mx_ = np . ceil ( mx / width ) * width nbins = np . round ( ( mx_ - mn_ ) / width ) if min_bins <= nbins <= max_bins and ( not bins or bins [ - 1 ] . nbins != nbins ) : bins_ = mn_ + width * np . arange ( nbins + 1 ) # to prevent values on the edge of the bin fall in the wrong bin # due to precision error on decimals that are not precise bins_ = np . around ( bins_ , decimals = np . finfo ( bins_ . dtype ) . precision ) bin_def = BinDefinition ( bins_ , label_fmt , None , width ) bins . append ( bin_def ) return bins