Пример #1
0
    def _get_figure_widget(self):
        config = Config()
        trace = go.Parcats(
            dimensions=[{
                "label": col,
                "values": self.data_source.data[col]
            } for col in self.selected_columns],
            line=dict(
                color=config.color_scale[1][1],
                colorscale=config.color_scale,
                cmin=0,
                cmax=1,
                shape="hspline",
            ),
        )

        figure_widget = go.FigureWidget(
            data=[trace],
            layout=go.Layout(
                margin=dict(l=20, r=20, b=20, t=20, pad=5),
                autosize=True,
                showlegend=False,
            ),
        )

        figure_widget.data[0].on_click(self.on_selection)
        return trace, figure_widget
Пример #2
0
    def _get_figure_widget(self):
        config = Config()
        trace = go.Box(
            y=self.data_source.data[self.column_select.value],
            boxmean="sd",
            boxpoints=self.box_point_select.value,
            jitter=0.5,
            pointpos=-1.8,
            hoverinfo="skip",
            marker={"color": "rgb(%d,%d,%d)" % config.select_color},
            selected={
                "marker": {
                    "color": "rgb(%d,%d,%d)" % config.select_color,
                    "opacity": config.alpha,
                }
            },
            unselected={
                "marker": {
                    "color": "rgb(%d,%d,%d)" % config.deselect_color,
                    "opacity": config.alpha / 2,
                }
            },
            showlegend=False,
        )

        figure_widget = go.FigureWidget(
            data=[trace],
            layout=go.Layout(
                dragmode="select",
                margin=dict(l=15, r=15, b=15, t=15, pad=2),
                xaxis=dict(zeroline=False, showticklabels=False),
            ),
        )
        return trace, figure_widget
Пример #3
0
 def _get_scatter(self):
     config = Config()
     return go.Scatter(
         x=self.data_source.data[self.x_selection.value],
         y=self.data_source.data[self.y_selection.value],
         opacity=config.alpha,
         mode="markers",
         marker={"color": "rgb(%d,%d,%d)" % config.deselect_color},
         selected={"marker": {"color": "rgb(%d,%d,%d)" % config.select_color}},
         unselected={"marker": {"opacity": config.alpha / 2}},
         showlegend=False,
     )
def populated_config():
    config = Config()
    config.alpha = 0.75
    config.select_color = (0, 0, 0)
    config.deselect_color = (0, 0, 0)
    config.color_scale = [
        [0, "rgb(%d,%d,%d)" % config.deselect_color],
        [1, "rgb(%d,%d,%d)" % config.select_color],
    ]
Пример #5
0
    def _get_par_coords(self) -> go.Parcoords:
        config = Config()

        self.trace: go.Parcoords = go.Parcoords(
            line=dict(
                color=config.color_scale[1][1],
                colorscale=config.color_scale,
                cmin=0,
                cmax=1,
            ),
            dimensions=[
                self._get_dimension_dict(col) for col in self.selected_columns
            ],
        )
        return self.trace
Пример #6
0
    def build(self) -> widgets.Widget:
        """
        Generates widgets from layout and returns the root widget for this layout.
        Rows are in a VBox while plots in the rows are in HBox widgets.

        :return: self.root_widget
        """
        wcr = WidgetClassRegistry()
        rows = [self.selection_type_widget
                ]  # first row is the selection type widget
        for r, row in enumerate(self.layout_spec):
            row_widgets = []
            if isinstance(self.row_height, int):
                current_row_height = self.row_height
            else:  # list
                current_row_height = self.row_height[r]
            for i, widget_name in enumerate(row):
                widget_cls: BaseWidget.__class__ = wcr.get_widget_class(
                    widget_name)
                widget = widget_cls(self.data_source, r, i, 1.0 / len(row),
                                    current_row_height)
                row_widgets.append(widget.build())
            h_box = widgets.HBox(row_widgets)
            rows.append(h_box)

        # workaround to include arbitrary css
        bg_color: typing.Tuple[int, int, int] = Config().select_color
        css = "<style>"
        css += ".jupyter-widgets { border-radius : 5px ; }"
        css += ".layout-{} * .jupyter-button.mod-active {{ background-color : rgb{}; color: rgb{}; }}".format(
            self._id, bg_color, text_color(bg_color)
        )  # add layout-xxx... class to buttons since this color is specific to this layout
        css += ".jupyter.button, .widget-toggle-button {border-radius : 5px; }"
        css += ".widget-dropdown > select {border-radius : 5px; }"
        css += (
            ".jupyter-widgets::-webkit-scrollbar-track { border-radius: 4px; background-color: #F5F5F5; "
            "-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.15); }")
        css += ".jupyter-widgets::-webkit-scrollbar { width: 7px; background-color: #F5F5F5; }"
        css += ".jupyter-widgets::-webkit-scrollbar-thumb {{ border-radius: 4px; background-color: rgb{col}; }}".format(
            col=(170, 170, 170))
        css += "</style>"
        rows.append(widgets.HTML(css))

        self.root_widget = widgets.VBox(
            rows, layout=widgets.Layout(margin="20px 0px 10px 0px"))
        return self.root_widget
Пример #7
0
 def _get_histograms(self):
     col = self.column_select.value
     config = Config()
     fig = go.Figure(layout=go.Layout(
         margin=dict(l=5, r=5, b=5, t=5, pad=2)))
     fig.add_trace(
         go.Histogram(
             x=self.data[col],
             opacity=max(config.alpha, 0.75),
             marker={"color": "rgb(%d,%d,%d)" % config.deselect_color},
             selected={
                 "marker": {
                     "color": "rgb(%d,%d,%d)" % config.deselect_color
                 }
             },
             unselected={"marker": {
                 "opacity": 0.4
             }},
             hoverinfo="skip",
             histnorm="",
             bingroup=1,
         ))
     fig.add_trace(
         go.Histogram(
             x=self.brushed_data[col],
             opacity=1.0,
             # mode='markers',
             marker={"color": "rgb(%d,%d,%d)" % config.select_color},
             selected={
                 "marker": {
                     "color": "rgb(%d,%d,%d)" % config.select_color
                 }
             },
             unselected={"marker": {
                 "opacity": 1.0
             }},
             hoverinfo="skip",
             histnorm="",
             bingroup=1,
         ))
     fig.update_layout(barmode="overlay",
                       showlegend=False,
                       dragmode="select")
     return fig
    def apply_size_constraints(self, widget):
        """
        Adds styling to a widget to control the height, width, margin, padding and border.
        Sets min and max_width to conform to the relative size of the widget, minus the margin.
        Sets min and max_width to conform to the max_height parameter.
        Adds a margin to the widget and also a padding with the same size.

        :param widget: An IPython widget to which the layout should be applied.
        :return: The same widget with updated layout.
        """
        with widget.hold_trait_notifications():
            margin = 5
            num_widgets_in_row = int(round(1 / self.relative_size)) - 1
            size_mod = (
                3 * num_widgets_in_row
            )  # because a border is added to each widget we have to subtract that (2px) + 1px for safety
            widget.layout.min_width = (
                "calc("
                + str(self.relative_size * 100)
                + "%"
                + " - %dpx)" % (margin + size_mod)
            )
            widget.layout.max_width = (
                "calc("
                + str(self.relative_size * 100)
                + "%"
                + " - %dpx)" % (margin + size_mod)
            )
            widget.layout.max_height = "%dpx" % self.max_height
            widget.layout.min_height = "%dpx" % self.max_height
            widget.layout.margin = "%dpx %dpx %dpx %dpx" % (
                margin,
                margin,
                margin,
                margin,
            )
            widget.layout.padding = "%dpx %dpx %dpx %dpx" % (
                margin,
                margin,
                margin,
                margin,
            )
            widget.layout.border = "2px solid rgb(%d,%d,%d)" % Config().select_color
        return widget
Пример #9
0
    def __init__(
        self,
        data: typing.Union[DataFrame, DataSource],
        layout: typing.Union[str, typing.List[typing.List[str]]] = "default",
        categorical_columns: typing.Union[typing.List[str], None] = None,
        row_height: typing.Union[int, typing.List[int]] = 400,
        sample: typing.Union[float, int, None] = None,
        select_color: typing.Union[str, typing.Tuple[int, int, int]] = "#323EEC",
        deselect_color: typing.Union[str, typing.Tuple[int, int, int]] = "#8A8C93",
        alpha: float = 0.75,
        seed: typing.Union[int, None] = None,
    ):
        """

        :param data: A pandas.DataFrame object or a :class:`DataSource`.
        :param layout: Layout specification name or explicit definition of widget names in rows.
            Those columns have to include all columns of the DataFrame
            which have type `object`, `str`, `bool` or `category`.
            This means it can only add columns which do not have the aforementioned types.
            Defaults to 'default'.
        :param categorical_columns: If given, specifies which columns are to be interpreted as categorical.
            Defaults to None.
        :param row_height: Height in pixels each row should have. If given an integer, each row has the height
            specified by that value, if given a list of integers, each value in the list specifies the height of
            the corresponding row.
            Defaults to 400.
        :param sample: Int or float value specifying if the DataFrame should be sub-sampled.
            When an int is given, the DataFrame will be limited to that number of rows given by the value.
            When a float is given, the DataFrame will include the fraction of rows given by the value.
            Defaults to None.
        :param select_color: RGB tuple or hex color specifying the color display selected data points.
            Values in the tuple have to be between 0 and 255 inclusive or a hex string that converts to
            such RGB values.
            Defaults to '#323EEC'.
        :param deselect_color: RGB tuple or hex color specifying the color display deselected data points.
            Values in the tuple have to be between 0 and 255 inclusive or a hex string that converts to
            such RGB values.
            Defaults to '#8A8C93'.
        :param alpha: Opacity of data points when applicable ranging from 0.0 to 1.0 inclusive. Defaults to 0.75.
        :param seed: Random seed used for sampling the data.
            Values can be any integer between 0 and 2**32 - 1 inclusive or None.
            Defaults to None.
        """
        super().__init__()

        validate.validate_data(data)
        validate.validate_alpha(alpha)
        validate.validate_color(select_color)
        validate.validate_color(deselect_color)

        if isinstance(select_color, str):
            self.select_color: typing.Tuple[int, int, int] = hex_to_rgb(select_color)
        elif isinstance(select_color, tuple):
            self.select_color: typing.Tuple[int, int, int] = select_color

        if isinstance(deselect_color, str):
            self.deselect_color: typing.Tuple[int, int, int] = hex_to_rgb(
                deselect_color
            )
        elif isinstance(deselect_color, tuple):
            self.deselect_color: typing.Tuple[int, int, int] = deselect_color

        self.alpha = alpha
        self.color_scale = [
            [0, "rgb(%d,%d,%d)" % self.deselect_color],
            [1, "rgb(%d,%d,%d)" % self.select_color],
        ]

        config = Config()
        config["alpha"] = self.alpha
        config["select_color"] = self.select_color
        config["deselect_color"] = self.deselect_color
        config["color_scale"] = self.color_scale

        if isinstance(data, DataFrame):
            self.data_source = DataSource(
                df=data,
                categorical_columns=categorical_columns,
                sample=sample,
                seed=seed,
            )
        elif isinstance(data, DataSource):
            self.data_source = data

        self.layout = AnalysisLayout(
            layout=layout, row_height=row_height, data_source=self.data_source
        )

        if self.data_source.few_num_cols and len(self._check_numerical_plots()) != 0:
            warnings.warn(
                "The passed DataFrame only has %d NUMERICAL column, which is insufficient for some plots "
                "like Parallel Coordinates. These plots will not be displayed."
                % len(self.data_source.numerical_columns)
            )

        if self.data_source.few_cat_cols and len(self._check_categorical_plots()) != 0:
            warnings.warn(
                "The passed DataFrame only has %d CATEGORICAL column, which is insufficient for some plots "
                "like Parallel Categories. These plots will not be displayed."
                % len(self.data_source.numerical_columns)
            )
def test_config_store_and_get():
    config = Config()
    val = [1, 3]
    config["val"] = val
    assert config["val"] is val
def test_config_singleton():
    config1 = Config()
    config2 = Config()
    assert config1 is config2
def test_config_attribute_error():
    config = Config()
    val = "hello"
    with pytest.raises(ValueError):
        config.keys = val
def test_config_attributes():
    config = Config()
    val = "hello"
    config.val = val
    assert config.val is val
def populated_config():
    config = Config()
    config.alpha = 0.75
    config.select_color = (0, 0, 0)
    config.deselect_color = (0, 0, 0)