(self, X, y=None)
return graph
Construct a Mapper graph from a refined Mapper cover.

        Parameters
        ----------
        X : ndarray of shape (n_samples,)
            Cluster labels describing a refined cover of a dataset produced by
            the clustering step of a :class:`gtda.mapper.MapperPipeline`,
            as depicted in
            `this diagram <../../../../_images/mapper_pipeline.svg>`_. Each
            entry in `X` is a tuple of pairs of the form
            ``(pullback_set_label, partial_cluster_label)`` where
            ``partial_cluster_label`` is a cluster label within the pullback
            cover set identified by ``pullback_set_label``. The unique pairs
            correspond to nodes in the output graph.

        y : None
            There is no need for a target in a transformer, yet the pipeline
            API requires this parameter.

        Returns
        -------
        graph : :class:`igraph.Graph` object
            Undirected Mapper graph according to `X` and `min_intersection`.
            Each node is an :class:`igraph.Vertex` object with attributes
            ``"pullback_set_label"``, ``"partial_cluster_label"`` and
            ``"node_elements"``. Each edge is an :class:`igraph.Edge` object
            with a ``"weight"`` attribute which is equal to the size of the
            intersection between the data subsets associated to its two nodes.
            If `store_edge_elements` is ``True`` each edge also has an
            additional attribute ``"edge_elements"``.
Construct a Mapper graph from a refined Mapper cover.
Construct a Mapper graph from a refined Mapper cover .
def fit_transform(self, X, y=None):
        """Construct a Mapper graph from a refined Mapper cover.

        Parameters
        ----------
        X : ndarray of shape (n_samples,)
            Cluster labels describing a refined cover of a dataset produced by
            the clustering step of a :class:`gtda.mapper.MapperPipeline`,
            as depicted in
            `this diagram <../../../../_images/mapper_pipeline.svg>`_. Each
            entry in `X` is a tuple of pairs of the form
            ``(pullback_set_label, partial_cluster_label)`` where
            ``partial_cluster_label`` is a cluster label within the pullback
            cover set identified by ``pullback_set_label``. The unique pairs
            correspond to nodes in the output graph.

        y : None
            There is no need for a target in a transformer, yet the pipeline
            API requires this parameter.

        Returns
        -------
        graph : :class:`igraph.Graph` object
            Undirected Mapper graph according to `X` and `min_intersection`.
            Each node is an :class:`igraph.Vertex` object with attributes
            ``"pullback_set_label"``, ``"partial_cluster_label"`` and
            ``"node_elements"``. Each edge is an :class:`igraph.Edge` object
            with a ``"weight"`` attribute which is equal to the size of the
            intersection between the data subsets associated to its two nodes.
            If `store_edge_elements` is ``True`` each edge also has an
            additional attribute ``"edge_elements"``.

        """
        # TODO: Include a validation step for X
        # Graph construction -- vertices with their metadata
        labels_to_indices = defaultdict(list)
        for i, sample in enumerate(X):
            for node_id_pair in sample:
                labels_to_indices[node_id_pair].append(i)
        labels_to_indices = {key: np.array(value)
                             for key, value in labels_to_indices.items()}
        n_nodes = len(labels_to_indices)
        graph = Graph(n_nodes)

        # labels_to_indices is a dictionary of, say, N key-value pairs of the
        # form (pullback_set_label, partial_cluster_label): node_elements.
        # Hence, zip(*labels_to_indices) generates two tuples of length N, each
        # corresponding to a type of node attribute in the final graph.
        node_attributes = zip(*labels_to_indices)
        graph.vs["pullback_set_label"] = next(node_attributes)
        graph.vs["partial_cluster_label"] = next(node_attributes)
        graph.vs["node_elements"] = [*labels_to_indices.values()]

        # Graph construction -- edges with weights given by intersection sizes.
        # In general, we need all information in `nodes` to narrow down the set
        # of combinations to check, especially when `contract_nodes` is True.
        nodes = zip(*zip(*labels_to_indices), labels_to_indices.values())
        node_index_pairs, weights, intersections, mapping = \
            self._generate_edge_data(nodes, n_nodes)
        graph.es["weight"] = 1
        graph.add_edges(node_index_pairs)
        graph.es["weight"] = weights
        if self.store_edge_elements:
            graph.es["edge_elements"] = intersections
        if self.contract_nodes:
            # Due to the order in which itertools.combinations produces pairs,
            # and to the preference given to node 1 in the if-elif-else clause
            # in `_subset_check_metadata_append`, `mapping` is guaranteed to
            # send everything to one of its fixed points after sufficiently
            # many repeated applications and, by construction, no two pairs of
            # indices in `_limit_mapping(mapping)` can correspond to data
            # subsets which are in a subset relation. Thus the nodes are
            # correctly contracted by `_limit_mapping(mapping)`.
            limit_mapping = _limit_mapping(mapping)
            graph.contract_vertices(limit_mapping,
                                    combine_attrs="first")
            graph.delete_vertices([i for i in graph.vs.indices
                                   if i != limit_mapping[i]])

        return graph
def fit_transform ( self , X , y = None ) : # TODO: Include a validation step for X # Graph construction -- vertices with their metadata labels_to_indices = defaultdict ( list ) for i , sample in enumerate ( X ) : for node_id_pair in sample : labels_to_indices [ node_id_pair ] . append ( i ) labels_to_indices = { key : np . array ( value ) for key , value in labels_to_indices . items ( ) } n_nodes = len ( labels_to_indices ) graph = Graph ( n_nodes ) # labels_to_indices is a dictionary of, say, N key-value pairs of the # form (pullback_set_label, partial_cluster_label): node_elements. # Hence, zip(*labels_to_indices) generates two tuples of length N, each # corresponding to a type of node attribute in the final graph. node_attributes = zip ( * labels_to_indices ) graph . vs [ "pullback_set_label" ] = next ( node_attributes ) graph . vs [ "partial_cluster_label" ] = next ( node_attributes ) graph . vs [ "node_elements" ] = [ * labels_to_indices . values ( ) ] # Graph construction -- edges with weights given by intersection sizes. # In general, we need all information in `nodes` to narrow down the set # of combinations to check, especially when `contract_nodes` is True. nodes = zip ( * zip ( * labels_to_indices ) , labels_to_indices . values ( ) ) node_index_pairs , weights , intersections , mapping = self . _generate_edge_data ( nodes , n_nodes ) graph . es [ "weight" ] = 1 graph . add_edges ( node_index_pairs ) graph . es [ "weight" ] = weights if self . store_edge_elements : graph . es [ "edge_elements" ] = intersections if self . contract_nodes : # Due to the order in which itertools.combinations produces pairs, # and to the preference given to node 1 in the if-elif-else clause # in `_subset_check_metadata_append`, `mapping` is guaranteed to # send everything to one of its fixed points after sufficiently # many repeated applications and, by construction, no two pairs of # indices in `_limit_mapping(mapping)` can correspond to data # subsets which are in a subset relation. Thus the nodes are # correctly contracted by `_limit_mapping(mapping)`. limit_mapping = _limit_mapping ( mapping ) graph . contract_vertices ( limit_mapping , combine_attrs = "first" ) graph . delete_vertices ( [ i for i in graph . vs . indices if i != limit_mapping [ i ] ] ) return graph