def prepare_partial(self, X, initialization="median", k=25, **affinity_params):
        """Prepare a partial embedding which can be optimized.

        Parameters
        ----------
        X: np.ndarray
            The data matrix to be added to the existing embedding.

        initialization: Union[np.ndarray, str]
            The initial point positions to be used in the embedding space. Can
            be a precomputed numpy array, ``median``, ``weighted`` or
            ``random``. In all cases, ``median`` of ``weighted`` should be
            preferred.

        k: int
            The number of nearest neighbors to consider when initially placing
            the point onto the embedding. This is different from ``perpelxity``
            because perplexity affects optimization while this only affects the
            initial point positions.

        **affinity_params: dict
            Additional params to be passed to the ``Affinities.to_new`` method.
            Please see individual :class:`~openTSNE.affinity.Affinities`
            implementations as the parameters differ between implementations.

        Returns
        -------
        PartialTSNEEmbedding
            An unoptimized :class:`PartialTSNEEmbedding` object, prepared for
            optimization.

        """
        P, neighbors, distances = self.affinities.to_new(
            X, return_distances=True, **affinity_params
        )

        # If initial positions are given in an array, use a copy of that
        if isinstance(initialization, np.ndarray):
            init_checks.num_samples(initialization.shape[0], X.shape[0])
            init_checks.num_dimensions(initialization.shape[1], self.shape[1])

            embedding = np.array(initialization)

        # Random initialization with isotropic normal distribution
        elif initialization == "random":
            embedding = initialization_scheme.random(X, self.shape[1], self.random_state)
        elif initialization == "weighted":
            embedding = initialization_scheme.weighted_mean(
                X, self, neighbors[:, :k], distances[:, :k]
            )
        elif initialization == "median":
            embedding = initialization_scheme.median(self, neighbors[:, :k])
        else:
            raise ValueError(f"Unrecognized initialization scheme `{initialization}`.")

        return PartialTSNEEmbedding(
            embedding,
            reference_embedding=self,
            P=P,
            **self.gradient_descent_params,
        )
Prepare a partial embedding which can be optimized.

        Parameters
        ----------
        X: np.ndarray
            The data matrix to be added to the existing embedding.

        initialization: Union[np.ndarray, str]
            The initial point positions to be used in the embedding space. Can
            be a precomputed numpy array, ``median``, ``weighted`` or
            ``random``. In all cases, ``median`` of ``weighted`` should be
            preferred.

        k: int
            The number of nearest neighbors to consider when initially placing
            the point onto the embedding. This is different from ``perpelxity``
            because perplexity affects optimization while this only affects the
            initial point positions.

        **affinity_params: dict
            Additional params to be passed to the ``Affinities.to_new`` method.
            Please see individual :class:`~openTSNE.affinity.Affinities`
            implementations as the parameters differ between implementations.

        Returns
        -------
        PartialTSNEEmbedding
            An unoptimized :class:`PartialTSNEEmbedding` object, prepared for
            optimization.