r'''
Determine bin-edges.

:arguments:

  **data** (``<array_like>``)
    Input data. The histogram is computed over the flattened array.

:options:

  **bins** ([``10``] | ``<int>``)
    The number of bins.

  **mode** ([``'equal'`` | ``<str>``)
    Mode with which to compute the bin-edges:
    * ``'equal'``: each bin has equal width.
    * ``'log'``: logarithmic spacing.
    * ``'uniform'``: uniform number of data-points per bin.

  **min_count** (``<int>``)
    The minimum number of data-points per bin.

  **min_width** (``<float>``)
    The minimum width of each bin.

  **integer** ([``False``] | [``True``])
    If ``True``, bins not encompassing an integer are removed
    (e.g. a bin with edges ``[1.1, 1.9]`` is removed, but ``[0.9, 1.1]`` is not removed).

  **remove_empty_edges** ([``True``] | [``False``])
    Remove empty bins at the beginning or the end.

:returns:

  **bin_edges** (``<array of dtype float>``)
    The edges to pass into histogram.

def histogram_bin_edges(data, bins=10, mode='equal', min_count=None, integer=False, remove_empty_edges=True, min_width=None):
  r'''
Determine bin-edges.

:arguments:

  **data** (``<array_like>``)
    Input data. The histogram is computed over the flattened array.

:options:

  **bins** ([``10``] | ``<int>``)
    The number of bins.

  **mode** ([``'equal'`` | ``<str>``)
    Mode with which to compute the bin-edges:
    * ``'equal'``: each bin has equal width.
    * ``'log'``: logarithmic spacing.
    * ``'uniform'``: uniform number of data-points per bin.

  **min_count** (``<int>``)
    The minimum number of data-points per bin.

  **min_width** (``<float>``)
    The minimum width of each bin.

  **integer** ([``False``] | [``True``])
    If ``True``, bins not encompassing an integer are removed
    (e.g. a bin with edges ``[1.1, 1.9]`` is removed, but ``[0.9, 1.1]`` is not removed).

  **remove_empty_edges** ([``True``] | [``False``])
    Remove empty bins at the beginning or the end.

:returns:

  **bin_edges** (``<array of dtype float>``)
    The edges to pass into histogram.
  '''

  # determine the bin-edges

  if mode == 'equal':

    bin_edges = np.linspace(np.min(data),np.max(data),bins+1)

  elif mode == 'log':

    bin_edges = np.logspace(np.log10(np.min(data)),np.log10(np.max(data)),bins+1)

  elif mode == 'uniform':

    # - check
    if hasattr(bins, "__len__"):
      raise IOError('Only the number of bins can be specified')

    # - use the minimum count to estimate the number of bins
    if min_count is not None and min_count is not False:
      if type(min_count) != int: raise IOError('"min_count" must be an integer number')
      bins = int(np.floor(float(len(data))/float(min_count)))

    # - number of data-points in each bin (equal for each)
    count = int(np.floor(float(len(data))/float(bins))) * np.ones(bins, dtype='int')

    # - increase the number of data-points by one is an many bins as needed,
    #   such that the total fits the total number of data-points
    count[np.linspace(0, bins-1, len(data)-np.sum(count)).astype(np.int)] += 1

    # - split the data
    idx     = np.empty((bins+1), dtype='int')
    idx[0 ] = 0
    idx[1:] = np.cumsum(count)
    idx[-1] = len(data) - 1

    # - determine the bin-edges
    bin_edges = np.unique(np.sort(data)[idx])

  else:

    raise IOError('Unknown option')

  # remove empty starting and ending bin (related to an unfortunate choice of bin-edges)

  if remove_empty_edges:

    N, _ = np.histogram(data, bins=bin_edges, density=False)

    idx = np.min(np.where(N>0)[0])
    jdx = np.max(np.where(N>0)[0])

    bin_edges = bin_edges[(idx):(jdx+2)]

  # merge bins with too few data-points (if needed)

  bin_edges = histogram_bin_edges_mincount(data, min_count=min_count, bins=bin_edges)

  # merge bins that have too small of a width

  bin_edges = histogram_bin_edges_minwidth(min_width=min_width, bins=bin_edges)

  # select only bins that encompass an integer (and retain the original bounds)

  if integer:

    idx = np.where(np.diff(np.floor(bin_edges))>=1)[0]
    idx = np.unique(np.hstack((0, idx, len(bin_edges)-1)))

    bin_edges = bin_edges[idx]

  # return

  return bin_edges