Fit a cover on the data. This method constructs centers and radii in each dimension given the `perc_overlap` and `n_cube`.

        Parameters
        ============

        data: array-like
            Data to apply the cover to. Warning: First column must be an index column.

        Returns
        ========

        centers: list of arrays
            A list of centers for each cube

def fit(self, data):
        """ Fit a cover on the data. This method constructs centers and radii in each dimension given the `perc_overlap` and `n_cube`.

        Parameters
        ============

        data: array-like
            Data to apply the cover to. Warning: First column must be an index column.

        Returns
        ========

        centers: list of arrays
            A list of centers for each cube

        """


        # TODO: support indexing into any columns
        di = np.array(range(1, data.shape[1]))
        indexless_data = data[:, di]
        n_dims = indexless_data.shape[1]

        # support different values along each dimension

        ## -- is a list, needs to be array
        ## -- is a singleton, needs repeating
        if isinstance(self.n_cubes, Iterable):
            n_cubes = np.array(self.n_cubes)
            assert (
                len(n_cubes) == n_dims
            ), "Custom cubes in each dimension must match number of dimensions"
        else:
            n_cubes = np.repeat(self.n_cubes, n_dims)

        if isinstance(self.perc_overlap, Iterable):
            perc_overlap = np.array(self.perc_overlap)
            assert (
                len(perc_overlap) == n_dims
            ), "Custom cubes in each dimension must match number of dimensions"
        else:
            perc_overlap = np.repeat(self.perc_overlap, n_dims)

        assert all(0.0 <= p <= 1.0 for p in perc_overlap), (
            "Each overlap percentage must be between 0.0 and 1.0., not %s"
            % perc_overlap
        )

        bounds = self._compute_bounds(indexless_data)
        ranges = bounds[1] - bounds[0]

        # (n-1)/n |range|
        inner_range = ((n_cubes - 1) / n_cubes) * ranges
        inset = (ranges - inner_range) / 2

        # |range| / (2n ( 1 - p))
        radius = ranges / (2 * (n_cubes) * (1 - perc_overlap))

        # centers are fixed w.r.t perc_overlap
        zip_items = list(bounds)  # work around 2.7,3.4 weird behavior
        zip_items.extend([n_cubes, inset])
        centers_per_dimension = [
            np.linspace(b + r, c - r, num=n) for b, c, n, r in zip(*zip_items)
        ]
        centers = [np.array(c) for c in product(*centers_per_dimension)]

        self.centers_ = centers
        self.radius_ = radius
        self.inset_ = inset
        self.inner_range_ = inner_range
        self.bounds_ = bounds
        self.di_ = di

        if self.verbose > 0:
            print(
                " - Cover - centers: %s\ninner_range: %s\nradius: %s"
                % (self.centers_, self.inner_range_, self.radius_)
            )

        return centers