(self, color_data=None, color_features=None,
             node_color_statistic=None, layout="kamada_kawai", layout_dim=2,
             n_sig_figs=3, node_scale=12, plotly_params=None)
return box
Produce the interactive Mapper widget.

        Parameters
        ----------
        color_data : array-like of length n_samples, or None, optional, \
            default: ``None``
            Data to be used to construct node colors in the Mapper graph
            (according to `color_features` and `node_color_statistic`). Must
            have the same length as `data`. ``None`` is the same as passing
            ``numpy.arange(len(data))``.

        color_features : object or None, optional, default: ``None``
            Specifies one or more feature of interest from `color_data` to be
            used, together with `node_color_statistic`, to determine node
            colors.

                1. ``None`` is equivalent to passing `color_data`.
                2. If an object implementing :meth:`transform` or
                   :meth:`fit_transform`, or a callable, it is applied to
                   `color_data` to generate the features of interest.
                3. If an index or string, or list of indices/strings, it is
                   equivalent to selecting a column or subset of columns from
                   `color_data`.

        node_color_statistic : None or callable, optional, default: ``None``
            If a callable, node colors will be computed as summary statistics
            from the feature array ``y`` determined by `color_data` and
            `color_features`. Let ``y`` have ``n`` columns (note: 1d feature
            arrays are converted to column vectors). Then, for a node
            representing a list ``I`` of row indices, there will be ``n``
            colors, each computed as ``node_color_statistic(y[I, i])`` for
            ``i`` between ``0`` and ``n``.

        layout : None, str or callable, optional, default: ``"kamada-kawai"``
            Layout algorithm for the graph. Can be any accepted value for the
            ``layout`` parameter in the :meth:`layout` method of
            :class:`igraph.Graph` [1]_.

        layout_dim : int, default: ``2``
            The number of dimensions for the layout. Can be 2 or 3.

        n_sig_figs : int or None, optional, default: ``3``
           If not ``None``, number of significant figures to which to round
           node summary statistics. If ``None``, no rounding is performed.

        node_scale : int or float, optional, default: ``12``
            Sets the scale factor used to determine the rendered size of the
            nodes. Increase for larger nodes. Implements a formula in the
            `Plotly documentation \
            <plotly.com/python/bubble-charts/#scaling-the-size-of-bubble-charts>`_.

        plotly_params : dict or None, optional, default: ``None``
            Custom parameters to configure the plotly figure. Allowed keys are
            ``"node_trace"``, ``"edge_trace"`` and ``"layout"``, and the
            corresponding values should be dictionaries containing keyword
            arguments as would be fed to the :meth:`update_traces` and
            :meth:`update_layout` methods of
            :class:`plotly.graph_objects.Figure`.

        Returns
        -------
        box : :class:`ipywidgets.VBox` object
            A box containing the following widgets: parameters of the
            clustering algorithm, parameters for the covering scheme, a Mapper
            graph arising from those parameters, a validation box, and logs.
Produce the interactive Mapper widget.
Produce the interactive Mapper widget .
def plot(self, color_data=None, color_features=None,
             node_color_statistic=None, layout="kamada_kawai", layout_dim=2,
             n_sig_figs=3, node_scale=12, plotly_params=None):
        """ Produce the interactive Mapper widget.

        Parameters
        ----------
        color_data : array-like of length n_samples, or None, optional, \
            default: ``None``
            Data to be used to construct node colors in the Mapper graph
            (according to `color_features` and `node_color_statistic`). Must
            have the same length as `data`. ``None`` is the same as passing
            ``numpy.arange(len(data))``.

        color_features : object or None, optional, default: ``None``
            Specifies one or more feature of interest from `color_data` to be
            used, together with `node_color_statistic`, to determine node
            colors.

                1. ``None`` is equivalent to passing `color_data`.
                2. If an object implementing :meth:`transform` or
                   :meth:`fit_transform`, or a callable, it is applied to
                   `color_data` to generate the features of interest.
                3. If an index or string, or list of indices/strings, it is
                   equivalent to selecting a column or subset of columns from
                   `color_data`.

        node_color_statistic : None or callable, optional, default: ``None``
            If a callable, node colors will be computed as summary statistics
            from the feature array ``y`` determined by `color_data` and
            `color_features`. Let ``y`` have ``n`` columns (note: 1d feature
            arrays are converted to column vectors). Then, for a node
            representing a list ``I`` of row indices, there will be ``n``
            colors, each computed as ``node_color_statistic(y[I, i])`` for
            ``i`` between ``0`` and ``n``.

        layout : None, str or callable, optional, default: ``"kamada-kawai"``
            Layout algorithm for the graph. Can be any accepted value for the
            ``layout`` parameter in the :meth:`layout` method of
            :class:`igraph.Graph` [1]_.

        layout_dim : int, default: ``2``
            The number of dimensions for the layout. Can be 2 or 3.

        n_sig_figs : int or None, optional, default: ``3``
           If not ``None``, number of significant figures to which to round
           node summary statistics. If ``None``, no rounding is performed.

        node_scale : int or float, optional, default: ``12``
            Sets the scale factor used to determine the rendered size of the
            nodes. Increase for larger nodes. Implements a formula in the
            `Plotly documentation \
            <plotly.com/python/bubble-charts/#scaling-the-size-of-bubble-charts>`_.

        plotly_params : dict or None, optional, default: ``None``
            Custom parameters to configure the plotly figure. Allowed keys are
            ``"node_trace"``, ``"edge_trace"`` and ``"layout"``, and the
            corresponding values should be dictionaries containing keyword
            arguments as would be fed to the :meth:`update_traces` and
            :meth:`update_layout` methods of
            :class:`plotly.graph_objects.Figure`.

        Returns
        -------
        box : :class:`ipywidgets.VBox` object
            A box containing the following widgets: parameters of the
            clustering algorithm, parameters for the covering scheme, a Mapper
            graph arising from those parameters, a validation box, and logs.

        """
        # Clone pipeline to avoid side effects from in-place parameter changes
        if self.clone_pipeline:
            self._pipeline = clone(self.pipeline)
        else:
            self._pipeline = self.pipeline

        def get_widgets_per_param(params):
            for key, value in params.items():
                style = {'description_width': 'initial'}
                description = key.split("__")[1] if "__" in key else key
                if isinstance(value, float):
                    yield (key, widgets.FloatText(
                        value=value,
                        step=0.05,
                        description=description,
                        continuous_update=False,
                        disabled=False,
                        layout=Layout(width="90%"),
                        style=style
                    ))
                elif isinstance(value, bool):
                    yield (key, widgets.ToggleButton(
                        value=value,
                        description=description,
                        disabled=False,
                        layout=Layout(width="90%"),
                        style=style
                    ))
                elif isinstance(value, int):
                    yield (key, widgets.IntText(
                        value=value,
                        step=1,
                        description=description,
                        continuous_update=False,
                        disabled=False,
                        layout=Layout(width="90%"),
                        style=style
                    ))
                elif isinstance(value, str):
                    yield (key, widgets.Text(
                        value=value,
                        description=description,
                        continuous_update=False,
                        disabled=False,
                        layout=Layout(width="90%"),
                        style=style
                    ))

        def on_parameter_change(change):
            handler.clear_logs()
            try:
                for param, value in cover_params.items():
                    if isinstance(value, (int, float, str)):
                        self._pipeline.set_params(
                            **{param: cover_params_widgets[param].value}
                        )
                for param, value in cluster_params.items():
                    if isinstance(value, (int, float, str)):
                        self._pipeline.set_params(
                            **{param: cluster_params_widgets[param].value}
                        )
                for param, value in nerve_params.items():
                    if isinstance(value, (int, bool)):
                        self._pipeline.set_params(
                            **{param: nerve_params_widgets[param].value}
                        )

                logger.info("Updating figure...")
                with self._figure.batch_update():
                    self._graph = self._pipeline.fit_transform(self.data)
                    (edge_trace, node_trace,
                     self._node_colors_color_features) = \
                        _calculate_graph_data(
                            self._graph, self._color_data_transformed,
                            node_color_statistic, layout, layout_dim,
                            n_sig_figs, node_scale
                        )
                    if colorscale_for_hoverlabel is not None:
                        min_col, max_col = \
                            np.min(self._node_colors_color_features[:, 0]), \
                            np.max(self._node_colors_color_features[:, 0])
                        hoverlabel_bgcolor = _get_colors_for_vals(
                            self._node_colors_color_features[:, 0],
                            min_col, max_col, colorscale_for_hoverlabel
                            )
                        self._figure.update_traces(
                            hoverlabel_bgcolor=hoverlabel_bgcolor,
                            selector={"name": "node_trace"}
                            )

                    self._figure.update_traces(
                        x=node_trace.x,
                        y=node_trace.y,
                        marker_color=node_trace.marker.color,
                        marker_size=node_trace.marker.size,
                        marker_sizeref=node_trace.marker.sizeref,
                        hovertext=node_trace.hovertext,
                        **({"z": node_trace.z} if layout_dim == 3 else dict()),
                        selector={"name": "node_trace"}
                    )
                    self._figure.update_traces(
                        x=edge_trace.x,
                        y=edge_trace.y,
                        **({"z": edge_trace.z} if layout_dim == 3 else dict()),
                        selector={"name": "edge_trace"}
                    )

                    # Update color by column buttons if relevant
                    if self._node_colors_color_features.shape[1] > 1:
                        hovertext_color_features = node_trace.hovertext
                        column_color_buttons = _get_column_color_buttons(
                            self._node_colors_color_features,
                            hovertext_color_features,
                            colorscale_for_hoverlabel, n_sig_figs,
                            column_names_dropdown
                        )

                        button_height = 1.1
                        self._figure.update_layout(
                            updatemenus=[
                                go.layout.Updatemenu(
                                    buttons=column_color_buttons,
                                    direction="down",
                                    pad={"r": 10, "t": 10},
                                    showactive=True,
                                    x=0.11,
                                    xanchor="left",
                                    y=button_height,
                                    yanchor="top"
                                )
                            ])

                valid.value = True
            except Exception:
                exception_data = traceback.format_exc().splitlines()
                logger.exception(exception_data[-1])
                valid.value = False

        def observe_widgets(params, widgets):
            for param, value in params.items():
                if isinstance(value, (int, float, str)):
                    widgets[param].observe(on_parameter_change, names="value")

        # Define output widget to capture logs
        out = widgets.Output()

        @out.capture()
        def click_box(change):
            if logs_box.value:
                out.clear_output()
                handler.show_logs()
            else:
                out.clear_output()

        # Initialise logging
        logger = logging.getLogger(__name__)
        handler = OutputWidgetHandler()
        handler.setFormatter(logging.Formatter(
            "%(asctime)s - [%(levelname)s] %(message)s"))
        logger.addHandler(handler)
        logger.setLevel(logging.INFO)

        # Initialise cover, cluster and nerve dictionaries of parameters and
        # widgets
        mapper_params_items = self._pipeline.get_mapper_params().items()
        cover_params = {key: value for key, value in mapper_params_items
                        if key.startswith("cover__")}
        cover_params_widgets = dict(get_widgets_per_param(cover_params))
        cluster_params = {key: value for key, value in mapper_params_items
                          if key.startswith("clusterer__")}
        cluster_params_widgets = dict(get_widgets_per_param(cluster_params))
        nerve_params = {key: value for key, value in mapper_params_items
                        if key in ["min_intersection", "contract_nodes"]}
        nerve_params_widgets = dict(get_widgets_per_param(nerve_params))

        # Initialise widgets for validating input parameters of pipeline
        valid = widgets.Valid(
            value=True,
            description="Valid parameters",
            style={"description_width": "100px"},
        )

        # Initialise widget for showing the logs
        logs_box = widgets.Checkbox(
            description="Show logs: ",
            value=False,
            indent=False
        )

        # Initialise figure with initial pipeline and config
        self._graph = self._pipeline.fit_transform(self.data)
        (self._color_data_transformed, column_names_dropdown,
         node_color_statistic) = \
            _validate_color_kwargs(self._graph, self.data, color_data,
                                   color_features, node_color_statistic,
                                   interactive=True)
        edge_trace, node_trace, self._node_colors_color_features = \
            _calculate_graph_data(
                self._graph, self._color_data_transformed,
                node_color_statistic, layout, layout_dim, n_sig_figs,
                node_scale
            )

        self._figure = _produce_static_figure(
            edge_trace, node_trace, self._node_colors_color_features,
            column_names_dropdown, layout_dim, n_sig_figs, plotly_params
        )

        colorscale_for_hoverlabel = None
        if layout_dim == 3:
            # In plot_static_mapper_graph, hoverlabel bgcolors are set to white
            # if something goes wrong in computing them according to the
            # colorscale.
            is_bgcolor_not_white = \
                self._figure.data[1].hoverlabel.bgcolor != "white"
            user_hoverlabel_bgcolor = False
            if plotly_params:
                if "node_trace" in plotly_params:
                    if "hoverlabel_bgcolor" in plotly_params["node_trace"]:
                        user_hoverlabel_bgcolor = True
            if is_bgcolor_not_white and not user_hoverlabel_bgcolor:
                colorscale_for_hoverlabel = \
                    self._figure.data[1].marker.colorscale

        observe_widgets(cover_params, cover_params_widgets)
        observe_widgets(cluster_params, cluster_params_widgets)
        observe_widgets(nerve_params, nerve_params_widgets)

        logs_box.observe(click_box, names="value")

        # Define containers for input widgets
        cover_title = HTML(value="<b>Cover parameters</b>")
        container_cover = widgets.VBox(
            children=[cover_title] + list(cover_params_widgets.values())
        )
        container_cover.layout.align_items = 'center'

        cluster_title = HTML(value="<b>Clusterer parameters</b>")
        container_cluster = widgets.VBox(
            children=[cluster_title] + list(cluster_params_widgets.values()),
        )
        container_cluster.layout.align_items = 'center'

        nerve_title = HTML(value="<b>Nerve parameters</b>")
        container_nerve = widgets.VBox(
            children=[nerve_title] + list(nerve_params_widgets.values()),
        )
        container_nerve.layout.align_items = 'center'

        container_parameters = widgets.HBox(
            children=[container_cover, container_cluster, container_nerve]
        )

        box = widgets.VBox([container_parameters, self._figure, valid,
                            logs_box, out])

        return box
def plot ( self , color_data = None , color_features = None , node_color_statistic = None , layout = "kamada_kawai" , layout_dim = 2 , n_sig_figs = 3 , node_scale = 12 , plotly_params = None ) : # Clone pipeline to avoid side effects from in-place parameter changes if self . clone_pipeline : self . _pipeline = clone ( self . pipeline ) else : self . _pipeline = self . pipeline def get_widgets_per_param ( params ) : for key , value in params . items ( ) : style = { 'description_width' : 'initial' } description = key . split ( "__" ) [ 1 ] if "__" in key else key if isinstance ( value , float ) : yield ( key , widgets . FloatText ( value = value , step = 0.05 , description = description , continuous_update = False , disabled = False , layout = Layout ( width = "90%" ) , style = style ) ) elif isinstance ( value , bool ) : yield ( key , widgets . ToggleButton ( value = value , description = description , disabled = False , layout = Layout ( width = "90%" ) , style = style ) ) elif isinstance ( value , int ) : yield ( key , widgets . IntText ( value = value , step = 1 , description = description , continuous_update = False , disabled = False , layout = Layout ( width = "90%" ) , style = style ) ) elif isinstance ( value , str ) : yield ( key , widgets . Text ( value = value , description = description , continuous_update = False , disabled = False , layout = Layout ( width = "90%" ) , style = style ) ) def on_parameter_change ( change ) : handler . clear_logs ( ) try : for param , value in cover_params . items ( ) : if isinstance ( value , ( int , float , str ) ) : self . _pipeline . set_params ( * * { param : cover_params_widgets [ param ] . value } ) for param , value in cluster_params . items ( ) : if isinstance ( value , ( int , float , str ) ) : self . _pipeline . set_params ( * * { param : cluster_params_widgets [ param ] . value } ) for param , value in nerve_params . items ( ) : if isinstance ( value , ( int , bool ) ) : self . _pipeline . set_params ( * * { param : nerve_params_widgets [ param ] . value } ) logger . info ( "Updating figure..." ) with self . _figure . batch_update ( ) : self . _graph = self . _pipeline . fit_transform ( self . data ) ( edge_trace , node_trace , self . _node_colors_color_features ) = _calculate_graph_data ( self . _graph , self . _color_data_transformed , node_color_statistic , layout , layout_dim , n_sig_figs , node_scale ) if colorscale_for_hoverlabel is not None : min_col , max_col = np . min ( self . _node_colors_color_features [ : , 0 ] ) , np . max ( self . _node_colors_color_features [ : , 0 ] ) hoverlabel_bgcolor = _get_colors_for_vals ( self . _node_colors_color_features [ : , 0 ] , min_col , max_col , colorscale_for_hoverlabel ) self . _figure . update_traces ( hoverlabel_bgcolor = hoverlabel_bgcolor , selector = { "name" : "node_trace" } ) self . _figure . update_traces ( x = node_trace . x , y = node_trace . y , marker_color = node_trace . marker . color , marker_size = node_trace . marker . size , marker_sizeref = node_trace . marker . sizeref , hovertext = node_trace . hovertext , * * ( { "z" : node_trace . z } if layout_dim == 3 else dict ( ) ) , selector = { "name" : "node_trace" } ) self . _figure . update_traces ( x = edge_trace . x , y = edge_trace . y , * * ( { "z" : edge_trace . z } if layout_dim == 3 else dict ( ) ) , selector = { "name" : "edge_trace" } ) # Update color by column buttons if relevant if self . _node_colors_color_features . shape [ 1 ] > 1 : hovertext_color_features = node_trace . hovertext column_color_buttons = _get_column_color_buttons ( self . _node_colors_color_features , hovertext_color_features , colorscale_for_hoverlabel , n_sig_figs , column_names_dropdown ) button_height = 1.1 self . _figure . update_layout ( updatemenus = [ go . layout . Updatemenu ( buttons = column_color_buttons , direction = "down" , pad = { "r" : 10 , "t" : 10 } , showactive = True , x = 0.11 , xanchor = "left" , y = button_height , yanchor = "top" ) ] ) valid . value = True except Exception : exception_data = traceback . format_exc ( ) . splitlines ( ) logger . exception ( exception_data [ - 1 ] ) valid . value = False def observe_widgets ( params , widgets ) : for param , value in params . items ( ) : if isinstance ( value , ( int , float , str ) ) : widgets [ param ] . observe ( on_parameter_change , names = "value" ) # Define output widget to capture logs out = widgets . Output ( ) @ out . capture ( ) def click_box ( change ) : if logs_box . value : out . clear_output ( ) handler . show_logs ( ) else : out . clear_output ( ) # Initialise logging logger = logging . getLogger ( __name__ ) handler = OutputWidgetHandler ( ) handler . setFormatter ( logging . Formatter ( "%(asctime)s - [%(levelname)s] %(message)s" ) ) logger . addHandler ( handler ) logger . setLevel ( logging . INFO ) # Initialise cover, cluster and nerve dictionaries of parameters and # widgets mapper_params_items = self . _pipeline . get_mapper_params ( ) . items ( ) cover_params = { key : value for key , value in mapper_params_items if key . startswith ( "cover__" ) } cover_params_widgets = dict ( get_widgets_per_param ( cover_params ) ) cluster_params = { key : value for key , value in mapper_params_items if key . startswith ( "clusterer__" ) } cluster_params_widgets = dict ( get_widgets_per_param ( cluster_params ) ) nerve_params = { key : value for key , value in mapper_params_items if key in [ "min_intersection" , "contract_nodes" ] } nerve_params_widgets = dict ( get_widgets_per_param ( nerve_params ) ) # Initialise widgets for validating input parameters of pipeline valid = widgets . Valid ( value = True , description = "Valid parameters" , style = { "description_width" : "100px" } , ) # Initialise widget for showing the logs logs_box = widgets . Checkbox ( description = "Show logs: " , value = False , indent = False ) # Initialise figure with initial pipeline and config self . _graph = self . _pipeline . fit_transform ( self . data ) ( self . _color_data_transformed , column_names_dropdown , node_color_statistic ) = _validate_color_kwargs ( self . _graph , self . data , color_data , color_features , node_color_statistic , interactive = True ) edge_trace , node_trace , self . _node_colors_color_features = _calculate_graph_data ( self . _graph , self . _color_data_transformed , node_color_statistic , layout , layout_dim , n_sig_figs , node_scale ) self . _figure = _produce_static_figure ( edge_trace , node_trace , self . _node_colors_color_features , column_names_dropdown , layout_dim , n_sig_figs , plotly_params ) colorscale_for_hoverlabel = None if layout_dim == 3 : # In plot_static_mapper_graph, hoverlabel bgcolors are set to white # if something goes wrong in computing them according to the # colorscale. is_bgcolor_not_white = self . _figure . data [ 1 ] . hoverlabel . bgcolor != "white" user_hoverlabel_bgcolor = False if plotly_params : if "node_trace" in plotly_params : if "hoverlabel_bgcolor" in plotly_params [ "node_trace" ] : user_hoverlabel_bgcolor = True if is_bgcolor_not_white and not user_hoverlabel_bgcolor : colorscale_for_hoverlabel = self . _figure . data [ 1 ] . marker . colorscale observe_widgets ( cover_params , cover_params_widgets ) observe_widgets ( cluster_params , cluster_params_widgets ) observe_widgets ( nerve_params , nerve_params_widgets ) logs_box . observe ( click_box , names = "value" ) # Define containers for input widgets cover_title = HTML ( value = "<b>Cover parameters</b>" ) container_cover = widgets . VBox ( children = [ cover_title ] + list ( cover_params_widgets . values ( ) ) ) container_cover . layout . align_items = 'center' cluster_title = HTML ( value = "<b>Clusterer parameters</b>" ) container_cluster = widgets . VBox ( children = [ cluster_title ] + list ( cluster_params_widgets . values ( ) ) , ) container_cluster . layout . align_items = 'center' nerve_title = HTML ( value = "<b>Nerve parameters</b>" ) container_nerve = widgets . VBox ( children = [ nerve_title ] + list ( nerve_params_widgets . values ( ) ) , ) container_nerve . layout . align_items = 'center' container_parameters = widgets . HBox ( children = [ container_cover , container_cluster , container_nerve ] ) box = widgets . VBox ( [ container_parameters , self . _figure , valid , logs_box , out ] ) return box