Exemple #1
0
 def _add_circle_item(self):
     if self._points is None:
         return
     self._circle_item = QGraphicsEllipseItem()
     self._circle_item.setRect(QRectF(-1., -1., 2., 2.))
     self._circle_item.setPen(pg.mkPen(QColor(0, 0, 0), width=2))
     self.plot_widget.addItem(self._circle_item)
Exemple #2
0
 def update_circle(self):
     if self.scatterplot_item is not None and not self.circle_item:
         self.circle_item = QGraphicsEllipseItem()
         self.circle_item.setRect(QRectF(-1, -1, 2, 2))
         color = self.plot_widget.palette().color(QPalette.Text)
         self.circle_item.setPen(pg.mkPen(color, width=2))
         self.plot_widget.addItem(self.circle_item)
Exemple #3
0
 def __init__(self, pen = QPen(Qt.black), brush = QBrush(Qt.NoBrush), xCenter = 0.0, yCenter = 0.0, radius = 1.0):
     OWCurve.__init__(self)
     self._item = QGraphicsEllipseItem(self)
     self.center = xCenter, yCenter
     self.radius = radius
     self._rect = QRectF(xCenter-radius, yCenter-radius, 2*radius, 2*radius)
     self.set_pen(pen)
     self.set_brush(brush)
Exemple #4
0
    def __init__(self, color, parent):
        super().__init__(parent)

        height, width = self.SIZE.height(), self.SIZE.width()
        self.__circle = QGraphicsEllipseItem(0, 0, height, width)
        self.__circle.setBrush(QBrush(color))
        self.__circle.setPen(QPen(QColor(0, 0, 0, 0)))
        self.__circle.setParentItem(self)
Exemple #5
0
 def _add_circle_item(self):
     if not len(self._points):
         return
     r = self.radius / 100 + 1e-5
     pen = pg.mkPen(QColor(Qt.lightGray), width=1, cosmetic=True)
     self._circle_item = QGraphicsEllipseItem()
     self._circle_item.setRect(QRectF(-r, -r, 2 * r, 2 * r))
     self._circle_item.setPen(pen)
     self.plot_widget.addItem(self._circle_item)
Exemple #6
0
class LegendItemCircle(ColorIndicator):
    """Legend circle item.

    The legend circle item is a small colored circle image that can be plugged
    into the legend in front of the text object.

    This should only really be used in conjunction with ˙LegendItem˙.

    Parameters
    ----------
    color : QColor
        The color of the square.
    parent : QGraphicsItem

    See Also
    --------
    LegendItemSquare

    """

    SIZE = QSizeF(12, 12)
    _size_hint = SIZE

    def __init__(self, color, parent):
        super().__init__(parent)

        height, width = self.SIZE.height(), self.SIZE.width()
        self.__circle = QGraphicsEllipseItem(0, 0, height, width)
        self.__circle.setBrush(QBrush(color))
        self.__circle.setPen(QPen(QColor(0, 0, 0, 0)))
        self.__circle.setParentItem(self)
        self._size_hint = QSizeF(self.__circle.boundingRect().size())

    def sizeHint(self, size_hint, size_constraint=None, *args, **kwargs):
        return self._size_hint
    def test_anchoritem(self):
        anchoritem = NodeAnchorItem(None)
        self.scene.addItem(anchoritem)

        path = QPainterPath()
        path.addEllipse(0, 0, 100, 100)

        anchoritem.setAnchorPath(path)

        anchor = AnchorPoint()
        anchoritem.addAnchor(anchor)

        ellipse1 = QGraphicsEllipseItem(-3, -3, 6, 6)
        ellipse2 = QGraphicsEllipseItem(-3, -3, 6, 6)
        self.scene.addItem(ellipse1)
        self.scene.addItem(ellipse2)

        anchor.scenePositionChanged.connect(ellipse1.setPos)

        with self.assertRaises(ValueError):
            anchoritem.addAnchor(anchor)

        anchor1 = AnchorPoint()
        anchoritem.addAnchor(anchor1)

        anchor1.scenePositionChanged.connect(ellipse2.setPos)

        self.assertSequenceEqual(anchoritem.anchorPoints(), [anchor, anchor1])

        self.assertSequenceEqual(anchoritem.anchorPositions(), [0.5, 0.5])
        anchoritem.setAnchorPositions([0.5, 0.0])

        self.assertSequenceEqual(anchoritem.anchorPositions(), [0.5, 0.0])

        def advance():
            t = anchoritem.anchorPositions()
            t = [(t + 0.05) % 1.0 for t in t]
            anchoritem.setAnchorPositions(t)

        timer = QTimer(anchoritem, interval=10)
        timer.start()
        timer.timeout.connect(advance)

        self.qWait()
        timer.stop()
Exemple #8
0
    def _anchor_circle(self, variables):
        # minimum visible anchor radius (radius)
        min_radius = self._get_min_radius()
        axisitems = []
        for anchor, var in zip(self.plotdata.axes, variables[:]):
            axitem = AnchorItem(
                line=QLineF(0, 0, *anchor),
                text=var.name,
            )
            axitem.setVisible(np.linalg.norm(anchor) > min_radius)
            axitem.setPen(pg.mkPen((100, 100, 100)))
            axitem.setArrowVisible(True)
            self.viewbox.addItem(axitem)
            axisitems.append(axitem)

        self.plotdata.axisitems = axisitems
        if self.placement == self.Placement.Circular:
            return

        hidecircle = QGraphicsEllipseItem()
        hidecircle.setRect(
            QRectF(-min_radius, -min_radius, 2 * min_radius, 2 * min_radius))

        _pen = QPen(Qt.lightGray, 1)
        _pen.setCosmetic(True)
        hidecircle.setPen(_pen)

        self.viewbox.addItem(hidecircle)
        self.plotdata.hidecircle = hidecircle
Exemple #9
0
    def _anchor_circle(self):
        # minimum visible anchor radius (radius)
        minradius = self.radius / 100 + 1e-5
        for item in chain(self.plotdata.anchoritem, self.plotdata.items):
            self.viewbox.removeItem(item)
        self.plotdata.anchoritem = []
        self.plotdata.items = []
        for anchor, var in zip(self.plotdata.anchors,
                               self.data.domain.attributes):
            if True or np.linalg.norm(anchor) > minradius:
                axitem = AnchorItem(
                    line=QLineF(0, 0, *anchor),
                    text=var.name,
                )
                axitem.setVisible(np.linalg.norm(anchor) > minradius)
                axitem.setPen(pg.mkPen((100, 100, 100)))
                axitem.setArrowVisible(True)
                self.plotdata.anchoritem.append(axitem)
                self.viewbox.addItem(axitem)

        hidecircle = QGraphicsEllipseItem()
        hidecircle.setRect(
            QRectF(-minradius, -minradius, 2 * minradius, 2 * minradius))

        _pen = QPen(Qt.lightGray, 1)
        _pen.setCosmetic(True)
        hidecircle.setPen(_pen)
        self.viewbox.addItem(hidecircle)
        self.plotdata.items.append(hidecircle)
        self.plotdata.hidecircle = hidecircle
 def pie_chart(self, x, y, r, dist, colors):
     start_angle = 0
     dist = np.asarray(dist)
     spans = dist / (float(np.sum(dist)) or 1) * 360 * 16
     for span, color in zip(spans, colors):
         if not span:
             continue
         if self.explode:
             mid_ang = (start_angle + span / 2) / 360 / 16 * 2 * pi
             dx = r / 30 * cos(mid_ang)
             dy = r / 30 * sin(mid_ang)
         else:
             dx = dy = 0
         ellipse = QGraphicsEllipseItem(x - r / 2 + dx, y - r / 2 - dy, r,
                                        r)
         if len(spans) > 1:
             ellipse.setStartAngle(start_angle)
             ellipse.setSpanAngle(span)
         ellipse.setBrush(QColor(*color))
         self.scene.addItem(ellipse)
         start_angle += span
Exemple #11
0
class CircleCurve(OWCurve):
    """
        Displays a circle on the plot

        :param pen: The pen used to draw the outline of the circle
        :type pen: QPen

        :param brush: The brush used to paint the inside of the circle
        :type brush: QBrush

        :param xCenter: The x coordinate of the circle's center
        :type xCenter: float

        :param yCenter: The y coordinate of the circle's center
        :type yCenter: float

        :param radius: The circle's radius
        :type radius: float
    """
    def __init__(self, pen = QPen(Qt.black), brush = QBrush(Qt.NoBrush), xCenter = 0.0, yCenter = 0.0, radius = 1.0):
        OWCurve.__init__(self)
        self._item = QGraphicsEllipseItem(self)
        self.center = xCenter, yCenter
        self.radius = radius
        self._rect = QRectF(xCenter-radius, yCenter-radius, 2*radius, 2*radius)
        self.set_pen(pen)
        self.set_brush(brush)

    def update_properties(self):
        self._item.setRect(self.graph_transform().mapRect(self.data_rect()))
        self._item.setPen(self.pen())
        self._item.setBrush(self.brush())

    def data_rect(self):
        x, y = self.center
        r = self.radius
        return QRectF(x-r, y-r, 2*r, 2*r)
 def place_point(_x, _y, _c):
     item = QGraphicsEllipseItem()
     item.setX(_x)
     item.setY(_y)
     item.setRect(0, 0, self.POINT_R, self.POINT_R)
     color = QColor(*_c)
     item.setPen(QPen(color))
     item.setBrush(QBrush(color))
     self._group.addToGroup(item)
Exemple #13
0
class OWFreeVizGraph(OWVizGraph):
    radius = settings.Setting(0)

    def __init__(self, scatter_widget, parent):
        super().__init__(scatter_widget, parent)
        self._points = []
        self._point_items = []

    def update_radius(self):
        if self._circle_item is None:
            return

        r = self.radius / 100 + 1e-5
        for point, axitem in zip(self._points, self._point_items):
            axitem.setVisible(np.linalg.norm(point) > r)
        self._circle_item.setRect(QRectF(-r, -r, 2 * r, 2 * r))

    def set_view_box_range(self):
        self.view_box.setRange(RANGE)

    def can_show_indicator(self, pos):
        if not len(self._points):
            return False, None

        r = self.radius / 100 + 1e-5
        mask = np.zeros((len(self._points)), dtype=bool)
        mask[np.linalg.norm(self._points, axis=1) > r] = True
        distances = distance.cdist([[pos.x(), pos.y()]], self._points)[0]
        distances = distances[mask]
        if len(distances) and np.min(distances) < self.DISTANCE_DIFF:
            return True, np.flatnonzero(mask)[np.argmin(distances)]
        return False, None

    def _remove_point_items(self):
        for item in self._point_items:
            self.plot_widget.removeItem(item)
        self._point_items = []

    def _add_point_items(self):
        r = self.radius / 100 + 1e-5
        for point, var in zip(self._points, self._attributes):
            axitem = AnchorItem(line=QLineF(0, 0, *point), text=var.name)
            axitem.setVisible(np.linalg.norm(point) > r)
            axitem.setPen(pg.mkPen((100, 100, 100)))
            self.plot_widget.addItem(axitem)
            self._point_items.append(axitem)

    def _add_circle_item(self):
        if not len(self._points):
            return
        r = self.radius / 100 + 1e-5
        pen = pg.mkPen(QColor(Qt.lightGray), width=1, cosmetic=True)
        self._circle_item = QGraphicsEllipseItem()
        self._circle_item.setRect(QRectF(-r, -r, 2 * r, 2 * r))
        self._circle_item.setPen(pen)
        self.plot_widget.addItem(self._circle_item)

    def _add_indicator_item(self, point_i):
        x, y = self._points[point_i]
        dx = (self.view_box.childGroup.mapToDevice(QPoint(1, 0)) -
              self.view_box.childGroup.mapToDevice(QPoint(-1, 0))).x()
        self._indicator_item = MoveIndicator(x, y, 600 / dx)
        self.plot_widget.addItem(self._indicator_item)
    def __init__(self):
        super().__init__()

        self.data = None
        self.subset_data = None
        self._subset_mask = None
        self._selection = None  # np.array
        self.__replot_requested = False
        self._new_plotdata()

        self.variable_x = ContinuousVariable("radviz-x")
        self.variable_y = ContinuousVariable("radviz-y")

        box = gui.vBox(self.mainArea, True, margin=0)
        self.graph = OWRadvizGraph(self, box, "Plot", view_box=RadvizInteractiveViewBox)
        self.graph.hide_axes()

        box.layout().addWidget(self.graph.plot_widget)
        plot = self.graph.plot_widget

        SIZE_POLICY = (QSizePolicy.Minimum, QSizePolicy.Maximum)

        self.variables_selection = VariablesSelection()
        self.model_selected = VariableListModel(enable_dnd=True)
        self.model_other = VariableListModel(enable_dnd=True)
        self.variables_selection(self, self.model_selected, self.model_other)

        self.vizrank, self.btn_vizrank = RadvizVizRank.add_vizrank(
            self.controlArea, self, "Suggest features", self.vizrank_set_attrs
        )
        self.btn_vizrank.setSizePolicy(*SIZE_POLICY)
        self.variables_selection.add_remove.layout().addWidget(self.btn_vizrank)

        self.viewbox = plot.getViewBox()
        self.replot = None

        g = self.graph.gui
        pp_box = g.point_properties_box(self.controlArea)
        pp_box.setSizePolicy(*SIZE_POLICY)
        self.models = g.points_models

        box = gui.vBox(self.controlArea, "Plot Properties")
        box.setSizePolicy(*SIZE_POLICY)
        g.add_widget(g.JitterSizeSlider, box)

        g.add_widgets([g.ShowLegend, g.ClassDensity, g.LabelOnlySelected], box)

        zoom_select = self.graph.box_zoom_select(self.controlArea)
        zoom_select.setSizePolicy(*SIZE_POLICY)

        self.icons = gui.attributeIconDict

        p = self.graph.plot_widget.palette()
        self.graph.set_palette(p)

        gui.auto_commit(
            self.controlArea,
            self,
            "auto_commit",
            "Send Selection",
            auto_label="Send Automatically",
        )

        self.graph.zoom_actions(self)

        self._circle = QGraphicsEllipseItem()
        self._circle.setRect(QRectF(-1.0, -1.0, 2.0, 2.0))
        self._circle.setPen(pg.mkPen(QColor(0, 0, 0), width=2))
class OWRadviz(widget.OWWidget):
    name = "Radviz"
    description = "Radviz"

    icon = "icons/Radviz.svg"
    priority = 240

    class Inputs:
        data = Input("Data", Table, default=True)
        data_subset = Input("Data Subset", Table)

    class Outputs:
        selected_data = Output("Selected Data", Table, default=True)
        annotated_data = Output(ANNOTATED_DATA_SIGNAL_NAME, Table)
        components = Output("Components", Table)

    settings_version = 1
    settingsHandler = settings.DomainContextHandler()

    variable_state = settings.ContextSetting({})

    auto_commit = settings.Setting(True)
    graph = settings.SettingProvider(OWRadvizGraph)
    vizrank = settings.SettingProvider(RadvizVizRank)

    jitter_sizes = [0, 0.1, 0.5, 1.0, 2.0]

    ReplotRequest = QEvent.registerEventType()

    graph_name = "graph.plot_widget.plotItem"

    class Information(widget.OWWidget.Information):
        sql_sampled_data = widget.Msg("Data has been sampled")

    class Warning(widget.OWWidget.Warning):
        no_features = widget.Msg("At least 2 features have to be chosen")

    class Error(widget.OWWidget.Error):
        sparse_data = widget.Msg("Sparse data is not supported")
        no_features = widget.Msg(
            "At least 3 numeric or categorical variables are required"
        )
        no_instances = widget.Msg("At least 2 data instances are required")

    def __init__(self):
        super().__init__()

        self.data = None
        self.subset_data = None
        self._subset_mask = None
        self._selection = None  # np.array
        self.__replot_requested = False
        self._new_plotdata()

        self.variable_x = ContinuousVariable("radviz-x")
        self.variable_y = ContinuousVariable("radviz-y")

        box = gui.vBox(self.mainArea, True, margin=0)
        self.graph = OWRadvizGraph(self, box, "Plot", view_box=RadvizInteractiveViewBox)
        self.graph.hide_axes()

        box.layout().addWidget(self.graph.plot_widget)
        plot = self.graph.plot_widget

        SIZE_POLICY = (QSizePolicy.Minimum, QSizePolicy.Maximum)

        self.variables_selection = VariablesSelection()
        self.model_selected = VariableListModel(enable_dnd=True)
        self.model_other = VariableListModel(enable_dnd=True)
        self.variables_selection(self, self.model_selected, self.model_other)

        self.vizrank, self.btn_vizrank = RadvizVizRank.add_vizrank(
            self.controlArea, self, "Suggest features", self.vizrank_set_attrs
        )
        self.btn_vizrank.setSizePolicy(*SIZE_POLICY)
        self.variables_selection.add_remove.layout().addWidget(self.btn_vizrank)

        self.viewbox = plot.getViewBox()
        self.replot = None

        g = self.graph.gui
        pp_box = g.point_properties_box(self.controlArea)
        pp_box.setSizePolicy(*SIZE_POLICY)
        self.models = g.points_models

        box = gui.vBox(self.controlArea, "Plot Properties")
        box.setSizePolicy(*SIZE_POLICY)
        g.add_widget(g.JitterSizeSlider, box)

        g.add_widgets([g.ShowLegend, g.ClassDensity, g.LabelOnlySelected], box)

        zoom_select = self.graph.box_zoom_select(self.controlArea)
        zoom_select.setSizePolicy(*SIZE_POLICY)

        self.icons = gui.attributeIconDict

        p = self.graph.plot_widget.palette()
        self.graph.set_palette(p)

        gui.auto_commit(
            self.controlArea,
            self,
            "auto_commit",
            "Send Selection",
            auto_label="Send Automatically",
        )

        self.graph.zoom_actions(self)

        self._circle = QGraphicsEllipseItem()
        self._circle.setRect(QRectF(-1.0, -1.0, 2.0, 2.0))
        self._circle.setPen(pg.mkPen(QColor(0, 0, 0), width=2))

    def resizeEvent(self, event):
        self._update_points_labels()

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        self.graph.update_tooltip(event.modifiers())

    def keyReleaseEvent(self, event):
        super().keyReleaseEvent(event)
        self.graph.update_tooltip(event.modifiers())

    def vizrank_set_attrs(self, attrs):
        if not attrs:
            return
        self.variables_selection.display_none()
        self.model_selected[:] = attrs[:]
        self.model_other[:] = [v for v in self.model_other if v not in attrs]

    def _new_plotdata(self):
        self.plotdata = namespace(
            valid_mask=None,
            embedding_coords=None,
            points=None,
            arcarrows=[],
            point_labels=[],
            rand=None,
            data=None,
        )

    def update_colors(self):
        self._vizrank_color_change()
        self.cb_class_density.setEnabled(self.graph.can_draw_density())

    def sizeHint(self):
        return QSize(800, 500)

    def clear(self):
        """
        Clear/reset the widget state
        """
        self.data = None
        self.model_selected.clear()
        self.model_other.clear()
        self._clear_plot()

    def _clear_plot(self):
        self._new_plotdata()
        self.graph.plot_widget.clear()

    def invalidate_plot(self):
        """
        Schedule a delayed replot.
        """
        if not self.__replot_requested:
            self.__replot_requested = True
            QApplication.postEvent(
                self, QEvent(self.ReplotRequest), Qt.LowEventPriority - 10
            )

    def init_attr_values(self):
        self.graph.set_domain(self.data)

    def _vizrank_color_change(self):
        attr_color = self.graph.attr_color
        is_enabled = (
            self.data is not None
            and not self.data.is_sparse()
            and (len(self.model_other) + len(self.model_selected)) > 3
            and len(self.data) > 1
        )
        self.btn_vizrank.setEnabled(
            is_enabled
            and attr_color is not None
            and not np.isnan(
                self.data.get_column_view(attr_color)[0].astype(float)
            ).all()
        )
        self.vizrank.initialize()

    @Inputs.data
    def set_data(self, data):
        """
        Set the input dataset and check if data is valid.

        Args:
            data (Orange.data.table): data instances
        """

        def sql(data):
            self.Information.sql_sampled_data.clear()
            if isinstance(data, SqlTable):
                if data.approx_len() < 4000:
                    data = Table(data)
                else:
                    self.Information.sql_sampled_data()
                    data_sample = data.sample_time(1, no_cache=True)
                    data_sample.download_data(2000, partial=True)
                    data = Table(data_sample)
            return data

        def settings(data):
            # get the default encoded state, replacing the position with Inf
            state = VariablesSelection.encode_var_state(
                [list(self.model_selected), list(self.model_other)]
            )
            state = {
                key: (source_ind, np.inf) for key, (source_ind, _) in state.items()
            }

            self.openContext(data.domain)
            selected_keys = [
                key for key, (sind, _) in self.variable_state.items() if sind == 0
            ]

            if set(selected_keys).issubset(set(state.keys())):
                pass

            # update the defaults state (the encoded state must contain
            # all variables in the input domain)
            state.update(self.variable_state)
            # ... and restore it with saved positions taking precedence over
            # the defaults
            selected, other = VariablesSelection.decode_var_state(
                state, [list(self.model_selected), list(self.model_other)]
            )
            return selected, other

        def is_sparse(data):
            if data.is_sparse():
                self.Error.sparse_data()
                data = None
            return data

        def are_features(data):
            domain = data.domain
            vars = [
                var
                for var in chain(domain.class_vars, domain.metas, domain.attributes)
                if var.is_primitive()
            ]
            if len(vars) < 3:
                self.Error.no_features()
                data = None
            return data

        def are_instances(data):
            if len(data) < 2:
                self.Error.no_instances()
                data = None
            return data

        self.clear_messages()
        self.btn_vizrank.setEnabled(False)
        self.closeContext()
        self.clear()
        self.information()
        self.Error.clear()
        for f in [sql, is_sparse, are_features, are_instances]:
            if data is None:
                break
            data = f(data)

        if data is not None:
            self.data = data
            self.init_attr_values()
            domain = data.domain
            vars = [
                v for v in chain(domain.metas, domain.attributes) if v.is_primitive()
            ]
            self.model_selected[:] = vars[:5]
            self.model_other[:] = vars[5:] + list(domain.class_vars)
            self.model_selected[:], self.model_other[:] = settings(data)
            self._selection = np.zeros(len(data), dtype=np.uint8)
            self.invalidate_plot()
        else:
            self.data = None

    @Inputs.data_subset
    def set_subset_data(self, subset):
        """
        Set the supplementary input subset dataset.

        Args:
            subset (Orange.data.table): subset of data instances
        """
        self.subset_data = subset
        self._subset_mask = None
        self.controls.graph.alpha_value.setEnabled(subset is None)

    def handleNewSignals(self):
        if self.data is not None:
            self._clear_plot()
            if self.subset_data is not None and self._subset_mask is None:
                dataids = self.data.ids.ravel()
                subsetids = np.unique(self.subset_data.ids)
                self._subset_mask = np.in1d(dataids, subsetids, assume_unique=True)
            self.setup_plot(reset_view=True)
            self.cb_class_density.setEnabled(self.graph.can_draw_density())
        else:
            self.init_attr_values()
            self.graph.new_data(None)
        self._vizrank_color_change()
        self.commit()

    def customEvent(self, event):
        if event.type() == OWRadviz.ReplotRequest:
            self.__replot_requested = False
            self._clear_plot()
            self.setup_plot(reset_view=True)
        else:
            super().customEvent(event)

    def closeContext(self):
        self.variable_state = VariablesSelection.encode_var_state(
            [list(self.model_selected), list(self.model_other)]
        )
        super().closeContext()

    def prepare_radviz_data(self, variables):
        ec, points, valid_mask = radviz(self.data, variables, self.plotdata.points)
        self.plotdata.embedding_coords = ec
        self.plotdata.points = points
        self.plotdata.valid_mask = valid_mask

    def setup_plot(self, reset_view=True):
        if self.data is None:
            return
        self.graph.jitter_continuous = True
        self.__replot_requested = False

        variables = list(self.model_selected)
        if len(variables) < 2:
            self.Warning.no_features()
            self.graph.new_data(None)
            return

        self.Warning.clear()
        self.prepare_radviz_data(variables)

        if self.plotdata.embedding_coords is None:
            return

        domain = self.data.domain
        new_metas = domain.metas + (self.variable_x, self.variable_y)
        domain = Domain(
            attributes=domain.attributes, class_vars=domain.class_vars, metas=new_metas
        )
        mask = self.plotdata.valid_mask
        array = np.zeros((len(self.data), 2), dtype=np.float)
        array[mask] = self.plotdata.embedding_coords
        data = self.data.transform(domain)
        data[:, self.variable_x] = array[:, 0].reshape(-1, 1)
        data[:, self.variable_y] = array[:, 1].reshape(-1, 1)
        subset_data = (
            data[self._subset_mask & mask]
            if self._subset_mask is not None and len(self._subset_mask)
            else None
        )
        self.plotdata.data = data
        self.graph.new_data(data[mask], subset_data)
        if self._selection is not None:
            self.graph.selection = self._selection[self.plotdata.valid_mask]
        self.graph.update_data(self.variable_x, self.variable_y, reset_view=reset_view)
        self.graph.plot_widget.addItem(self._circle)
        self.graph.scatterplot_points = ScatterPlotItem(
            x=self.plotdata.points[:, 0], y=self.plotdata.points[:, 1]
        )
        self._update_points_labels()
        self.graph.plot_widget.addItem(self.graph.scatterplot_points)

    def randomize_indices(self):
        ec = self.plotdata.embedding_coords
        self.plotdata.rand = (
            np.random.choice(len(ec), MAX_POINTS, replace=False)
            if len(ec) > MAX_POINTS
            else None
        )

    def manual_move(self):
        self.__replot_requested = False

        if self.plotdata.rand is not None:
            rand = self.plotdata.rand
            valid_mask = self.plotdata.valid_mask
            data = self.data[valid_mask]
            selection = self._selection[valid_mask]
            selection = selection[rand]
            ec, _, valid_mask = radviz(
                data, list(self.model_selected), self.plotdata.points
            )
            assert sum(valid_mask) == len(data)
            data = data[rand]
            ec = ec[rand]
            data_x = data.X
            data_y = data.Y
            data_metas = data.metas
        else:
            self.prepare_radviz_data(list(self.model_selected))
            ec = self.plotdata.embedding_coords
            valid_mask = self.plotdata.valid_mask
            data_x = self.data.X[valid_mask]
            data_y = self.data.Y[valid_mask]
            data_metas = self.data.metas[valid_mask]
            selection = self._selection[valid_mask]

        attributes = (self.variable_x, self.variable_y) + self.data.domain.attributes
        domain = Domain(
            attributes=attributes,
            class_vars=self.data.domain.class_vars,
            metas=self.data.domain.metas,
        )
        data = Table.from_numpy(
            domain, X=np.hstack((ec, data_x)), Y=data_y, metas=data_metas
        )
        self.graph.new_data(data, None)
        self.graph.selection = selection
        self.graph.update_data(self.variable_x, self.variable_y, reset_view=True)
        self.graph.plot_widget.addItem(self._circle)
        self.graph.scatterplot_points = ScatterPlotItem(
            x=self.plotdata.points[:, 0], y=self.plotdata.points[:, 1]
        )
        self._update_points_labels()
        self.graph.plot_widget.addItem(self.graph.scatterplot_points)

    def _update_points_labels(self):
        if self.plotdata.points is None:
            return
        for point_label in self.plotdata.point_labels:
            self.graph.plot_widget.removeItem(point_label)
        self.plotdata.point_labels = []
        sx, sy = self.graph.view_box.viewPixelSize()

        for row in self.plotdata.points:
            ti = TextItem()
            metrics = QFontMetrics(ti.textItem.font())
            text_width = ((RANGE.width()) / 2.0 - np.abs(row[0])) / sx
            name = row[2].name
            ti.setText(name)
            ti.setTextWidth(text_width)
            ti.setColor(QColor(0, 0, 0))
            br = ti.boundingRect()
            width = (
                metrics.width(name) if metrics.width(name) < br.width() else br.width()
            )
            width = sx * (width + 5)
            height = sy * br.height()
            ti.setPos(row[0] - (row[0] < 0) * width, row[1] + (row[1] > 0) * height)
            self.plotdata.point_labels.append(ti)
            self.graph.plot_widget.addItem(ti)

    def _update_jitter(self):
        self.invalidate_plot()

    def reset_graph_data(self, *_):
        if self.data is not None:
            self.graph.rescale_data()
            self._update_graph()

    def _update_graph(self, reset_view=True, **_):
        self.graph.zoomStack = []
        if self.graph.data is None:
            return
        self.graph.update_data(self.variable_x, self.variable_y, reset_view=reset_view)

    def update_density(self):
        self._update_graph(reset_view=True)

    def selection_changed(self):
        if self.graph.selection is not None:
            self._selection[self.plotdata.valid_mask] = self.graph.selection
        self.commit()

    def prepare_data(self):
        pass

    def commit(self):
        selected = annotated = components = None
        graph = self.graph
        if self.plotdata.data is not None:
            name = self.data.name
            data = self.plotdata.data
            mask = self.plotdata.valid_mask.astype(int)
            mask[mask == 1] = (
                graph.selection if graph.selection is not None else [False * len(mask)]
            )
            selection = (
                np.array([], dtype=np.uint8) if mask is None else np.flatnonzero(mask)
            )
            if len(selection):
                selected = data[selection]
                selected.name = name + ": selected"
                selected.attributes = self.data.attributes
            if graph.selection is not None and np.max(graph.selection) > 1:
                annotated = create_groups_table(data, mask)
            else:
                annotated = create_annotated_table(data, selection)
            annotated.attributes = self.data.attributes
            annotated.name = name + ": annotated"

            comp_domain = Domain(
                self.plotdata.points[:, 2], metas=[StringVariable(name="component")]
            )

            metas = np.array([["RX"], ["RY"], ["angle"]])
            angle = np.arctan2(
                np.array(self.plotdata.points[:, 1].T, dtype=float),
                np.array(self.plotdata.points[:, 0].T, dtype=float),
            )
            components = Table.from_numpy(
                comp_domain,
                X=np.row_stack((self.plotdata.points[:, :2].T, angle)),
                metas=metas,
            )
            components.name = name + ": components"

        self.Outputs.selected_data.send(selected)
        self.Outputs.annotated_data.send(annotated)
        self.Outputs.components.send(components)

    def send_report(self):
        if self.data is None:
            return

        def name(var):
            return var and var.name

        caption = report.render_items_vert(
            (
                ("Color", name(self.graph.attr_color)),
                ("Label", name(self.graph.attr_label)),
                ("Shape", name(self.graph.attr_shape)),
                ("Size", name(self.graph.attr_size)),
                (
                    "Jittering",
                    self.graph.jitter_size != 0
                    and "{} %".format(self.graph.jitter_size),
                ),
            )
        )
        self.report_plot()
        if caption:
            self.report_caption(caption)
 def put_point(_x, _y):
     item = QGraphicsEllipseItem()
     item.setX(_x)
     item.setY(_y)
     item.setRect(0, 0, self.POINT_R, self.POINT_R)
     color = QColor(*colors.pop().astype(int))
     item.setPen(QPen(color))
     item.setBrush(QBrush(color))
     self.__group.addToGroup(item)
Exemple #17
0
class OWGraphWithAnchors(OWScatterPlotBase, ParameterSetter):
    """
    Graph for projections in which dimensions can be manually moved

    Class is used as a graph base class for OWFreeViz and OWRadviz."""
    DISTANCE_DIFF = 0.08

    def __init__(self, scatter_widget, parent, view_box=DraggableItemsViewBox):
        super().__init__(scatter_widget, parent, view_box)
        self.anchor_items = None
        self.circle_item = None
        self.indicator_item = None
        self._tooltip_delegate = MouseEventDelegate(self.help_event,
                                                    self.show_indicator_event)
        self.plot_widget.scene().installEventFilter(self._tooltip_delegate)

    def clear(self):
        super().clear()
        self.anchor_items = None
        self.circle_item = None
        self.indicator_item = None

    def update_coordinates(self):
        super().update_coordinates()
        if self.scatterplot_item is not None:
            self.update_anchors()
            self.update_circle()
            self.set_view_box_range()
            self.view_box.setAspectLocked(True, 1)

    def update_anchors(self):
        raise NotImplementedError

    def update_circle(self):
        if self.scatterplot_item is not None and not self.circle_item:
            self.circle_item = QGraphicsEllipseItem()
            self.circle_item.setRect(QRectF(-1, -1, 2, 2))
            self.circle_item.setPen(pg.mkPen(QColor(0, 0, 0), width=2))
            self.plot_widget.addItem(self.circle_item)

    def reset_button_clicked(self):
        self.set_view_box_range()

    def set_view_box_range(self):
        raise NotImplementedError

    def closest_draggable_item(self, pos):
        return None

    def show_indicator(self, anchor_idx):
        self._update_indicator_item(anchor_idx)

    def show_indicator_event(self, ev):
        scene = self.plot_widget.scene()
        if self.scatterplot_item is None or scene.drag_tooltip.isVisible():
            return False
        if self.view_box.mouse_state == 1:
            return True

        pos = self.scatterplot_item.mapFromScene(ev.scenePos())
        anchor_idx = self.closest_draggable_item(pos)
        if anchor_idx is not None:
            self._update_indicator_item(anchor_idx)
            if self.view_box.mouse_state == 0:
                self.view_box.setCursor(Qt.OpenHandCursor)
        else:
            if self.indicator_item is not None:
                self.plot_widget.removeItem(self.indicator_item)
                self.indicator_item = None
            self.view_box.setCursor(Qt.ArrowCursor)
        return True

    def _update_indicator_item(self, anchor_idx):
        if self.indicator_item is not None:
            self.plot_widget.removeItem(self.indicator_item)
        self._add_indicator_item(anchor_idx)

    def _add_indicator_item(self, anchor_idx):
        pass
Exemple #18
0
 def update_circle(self):
     if self.scatterplot_item is not None and not self.circle_item:
         self.circle_item = QGraphicsEllipseItem()
         self.circle_item.setRect(QRectF(-1, -1, 2, 2))
         self.circle_item.setPen(pg.mkPen(QColor(0, 0, 0), width=2))
         self.plot_widget.addItem(self.circle_item)
Exemple #19
0
    def test_anchoritem(self):
        anchoritem = NodeAnchorItem(None)
        anchoritem.setAnimationEnabled(False)
        self.scene.addItem(anchoritem)

        path = QPainterPath()
        path.addEllipse(0, 0, 100, 100)

        anchoritem.setAnchorPath(path)

        anchor = AnchorPoint()
        anchoritem.addAnchor(anchor)

        ellipse1 = QGraphicsEllipseItem(-3, -3, 6, 6)
        ellipse2 = QGraphicsEllipseItem(-3, -3, 6, 6)
        self.scene.addItem(ellipse1)
        self.scene.addItem(ellipse2)

        anchor.scenePositionChanged.connect(ellipse1.setPos)

        with self.assertRaises(ValueError):
            anchoritem.addAnchor(anchor)

        anchor1 = AnchorPoint()
        anchoritem.addAnchor(anchor1)

        anchor1.scenePositionChanged.connect(ellipse2.setPos)

        self.assertSequenceEqual(anchoritem.anchorPoints(), [anchor, anchor1])

        self.assertSequenceEqual(anchoritem.anchorPositions(), [2 / 3, 1 / 3])

        anchoritem.setAnchorPositions([0.5, 0.0])
        self.assertSequenceEqual(anchoritem.anchorPositions(), [0.5, 0.0])

        def advance():
            t = anchoritem.anchorPositions()
            t = [(t + 0.05) % 1.0 for t in t]
            anchoritem.setAnchorPositions(t)

        timer = QTimer(anchoritem, interval=10)
        timer.start()
        timer.timeout.connect(advance)

        self.qWait()
        timer.stop()

        anchoritem.setAnchorOpen(True)
        anchoritem.setHovered(True)
        self.assertEqual(*[p.scenePos() for p in anchoritem.anchorPoints()])
        anchoritem.setAnchorOpen(False)
        self.assertNotEqual(*[p.scenePos() for p in anchoritem.anchorPoints()])
        anchoritem.setAnchorOpen(False)
        anchoritem.setHovered(True)
        self.assertNotEqual(*[p.scenePos() for p in anchoritem.anchorPoints()])

        anchoritem = NodeAnchorItem(None)

        anchoritem.setSignals([
            InputSignal("first", "object", "set_first"),
            InputSignal("second", "object", "set_second")
        ])
        self.assertListEqual(
            anchoritem._NodeAnchorItem__pathStroker.dashPattern(),
            list(anchoritem._NodeAnchorItem__unanchoredDash))
        anchoritem.setAnchorOpen(True)
        anchoritem.setHovered(True)
        self.assertListEqual(
            anchoritem._NodeAnchorItem__pathStroker.dashPattern(),
            list(anchoritem._NodeAnchorItem__channelDash))
Exemple #20
0
 def __init__(self, *args):
     QGraphicsEllipseItem.__init__(self, *args)
     self.setRect(-3.5, -3.5, 7., 7.)
     self.setPen(QPen(Qt.NoPen))
     self.setBrush(QBrush(QColor("#9CACB4")))
     self.__hover = False
Exemple #21
0
class OWRadvizGraph(OWVizGraph):
    def __init__(self, scatter_widget, parent):
        super().__init__(scatter_widget, parent, RadvizInteractiveViewBox)
        self._text_items = []

    def set_point(self, i, x, y):
        angle = np.arctan2(y, x)
        super().set_point(i, np.cos(angle), np.sin(angle))

    def set_view_box_range(self):
        self.view_box.setRange(RANGE, padding=0.025)

    def can_show_indicator(self, pos):
        if self._points is None:
            return False, None

        np_pos = np.array([[pos.x(), pos.y()]])
        distances = distance.cdist(np_pos, self._points[:, :2])[0]
        if len(distances) and np.min(distances) < self.DISTANCE_DIFF:
            return True, np.argmin(distances)
        return False, None

    def update_items(self):
        super().update_items()
        self._update_text_items()

    def _update_text_items(self):
        self._remove_text_items()
        self._add_text_items()

    def _remove_text_items(self):
        for item in self._text_items:
            self.plot_widget.removeItem(item)
        self._text_items = []

    def _add_text_items(self):
        if self._points is None:
            return
        for point in self._points:
            ti = TextItem()
            ti.setText(point[2].name)
            ti.setColor(QColor(0, 0, 0))
            ti.setPos(point[0], point[1])
            self._text_items.append(ti)
            self.plot_widget.addItem(ti)

    def _add_point_items(self):
        if self._points is None:
            return
        x, y = self._points[:, 0], self._points[:, 1]
        self._point_items = ScatterPlotItem(x=x, y=y)
        self.plot_widget.addItem(self._point_items)

    def _add_circle_item(self):
        if self._points is None:
            return
        self._circle_item = QGraphicsEllipseItem()
        self._circle_item.setRect(QRectF(-1., -1., 2., 2.))
        self._circle_item.setPen(pg.mkPen(QColor(0, 0, 0), width=2))
        self.plot_widget.addItem(self._circle_item)

    def _add_indicator_item(self, point_i):
        if point_i is None:
            return
        x, y = self._points[point_i][:2]
        col = self.view_box.mouse_state
        dx = (self.view_box.childGroup.mapToDevice(QPoint(1, 0)) -
              self.view_box.childGroup.mapToDevice(QPoint(-1, 0))).x()
        self._indicator_item = MoveIndicator(np.arctan2(y, x), col, 6000 / dx)
        self.plot_widget.addItem(self._indicator_item)