def apply_selection(self, selection: List[Tuple[float, float]]):
        if self.__data_bounds is None:
            return

        (x_min, x_max), (y_min, y_max) = self.__data_bounds
        for x_start, x_stop in selection:
            p1 = QPointF(x_start, y_min)
            p2 = QPointF(x_stop, y_max)
            p1.setX(max(min(p1.x(), x_max), x_min))
            p2.setX(max(min(p2.x(), x_max), x_min))
            self.__select_range(p1, p2)
Пример #2
0
 def __get_index_at(self, p: QPointF):
     x = p.x()
     index = round(x)
     heights = self.bar_item.opts["height"]
     if 0 <= index < len(heights) and abs(x - index) <= self.bar_width / 2:
         height = heights[index]  # pylint: disable=unsubscriptable-object
         if 0 <= p.y() <= height or height <= p.y() <= 0:
             return index
     return None
Пример #3
0
 def __get_index_at(self, p: QPointF) -> Optional[int]:
     index = round(p.y())
     widths = self.marg_prob_item.opts["width"]
     if 0 <= index < len(widths) and abs(p.y() -
                                         index) <= self.bar_width / 2:
         width = widths[index]
         if 0 <= p.x() <= width:
             return index
     return None
    def __show_tooltip(self, point: QPointF):
        if not self.__show_tooltips:
            return
        instance_index = int(round(point.x(), 0))
        if self.__tooltip_data is None or instance_index < 0 or \
                instance_index >= len(self.__tooltip_data):
            return

        instance = self.__tooltip_data[instance_index]
        n_features = len(self.__fill_items) // 2
        pos_fills = self.__fill_items[:n_features]
        neg_fills = self.__fill_items[n_features:]
        pos_labels = self.__pos_labels
        neg_labels = self.__neg_labels

        view_box: ForcePlotViewBox = self.getViewBox()
        px_width, px_height = view_box.viewPixelSize()
        pos = view_box.mapViewToScene(point)
        right_side = view_box.boundingRect().width() / 2 > pos.x()

        self.__vertical_line_item = pg.InfiniteLine(instance_index)
        self.addItem(self.__vertical_line_item)

        for rgb, labels, fill_items in ((RGB_HIGH, pos_labels, pos_fills),
                                        (RGB_LOW, neg_labels, neg_fills)):
            whiter_rgb = np.array(rgb) + (255 - np.array(rgb)) * 0.7
            for i, (label, fill_item) in enumerate(zip(labels, fill_items)):
                curve1, curve2 = fill_item.curves
                y_lower = curve1.curve.getData()[1][instance_index]
                y_upper = curve2.curve.getData()[1][instance_index]
                delta_y = y_upper - y_lower
                text_item = pg.TextItem(
                    text=escape(f"{label} = {instance[label]}"),
                    color=rgb, fill=pg.mkBrush(whiter_rgb)
                )
                height = text_item.boundingRect().height() * px_height * 2
                if height < delta_y or self._contains_point(fill_item, point):
                    if right_side:
                        x_pos = instance_index + px_width * 5
                    else:
                        x_pos = instance_index - px_width * 5
                        x_pos -= px_width * text_item.boundingRect().width()
                    y_pos = y_upper - delta_y / 2

                    text_item.setPos(x_pos, y_pos)
                    self.__text_items.append(text_item)
                    self.addItem(text_item)

                    dot_color = QColor(Qt.white)
                    dot_item = pg.ScatterPlotItem(
                        x=[instance_index], y=[y_pos], size=6,
                        pen=pg.mkPen(dot_color), brush=pg.mkBrush(dot_color)
                    )
                    self.__dot_items.append(dot_item)
                    self.addItem(dot_item)
Пример #5
0
 def _dotAt(self, pos: QPointF):
     pw, ph = self.__dots.pixelWidth(), self.__dots.pixelHeight()
     for s in self.__dots.points():
         sx, sy = s.pos().x(), s.pos().y()
         s2x = s2y = s.size()
         if self.__dots.opts['pxMode']:
             s2x *= pw
             s2y *= ph
         if sx + s2x > pos.x() > sx - s2x and sy + s2y > pos.y() > sy - s2y:
             return s
     return None
Пример #6
0
def path_link_disabled(basepath):
    # type: (QPainterPath) -> QPainterPath
    """
    Return a QPainterPath 'styled' to indicate a 'disabled' link.

    A disabled link is displayed with a single disconnection symbol in the
    middle (--||--)

    Parameters
    ----------
    basepath : QPainterPath
        The base path (a simple curve spine).

    Returns
    -------
    path : QPainterPath
        A 'styled' link path
    """
    segmentlen = basepath.length()
    px = 5

    if segmentlen < 10:
        return QPainterPath(basepath)

    t = (px / 2) / segmentlen
    p1, _ = qpainterpath_simple_split(basepath, 0.50 - t)
    _, p2 = qpainterpath_simple_split(basepath, 0.50 + t)

    angle = -basepath.angleAtPercent(0.5) + 90
    angler = math.radians(angle)
    normal = QPointF(math.cos(angler), math.sin(angler))

    end1 = p1.currentPosition()
    start2 = QPointF(p2.elementAt(0).x, p2.elementAt(0).y)
    p1.moveTo(start2.x(), start2.y())
    p1.addPath(p2)

    def QPainterPath_addLine(path, line):
        # type: (QPainterPath, QLineF) -> None
        path.moveTo(line.p1())
        path.lineTo(line.p2())

    QPainterPath_addLine(p1, QLineF(end1 - normal * 3, end1 + normal * 3))
    QPainterPath_addLine(p1, QLineF(start2 - normal * 3, start2 + normal * 3))
    return p1
Пример #7
0
def path_link_disabled(basepath):
    """
    Return a QPainterPath 'styled' to indicate a 'disabled' link.

    A disabled link is displayed with a single disconnection symbol in the
    middle (--||--)

    Parameters
    ----------
    basepath : QPainterPath
        The base path (a simple curve spine).

    Returns
    -------
    path : QPainterPath
        A 'styled' link path
    """
    segmentlen = basepath.length()
    px = 5

    if segmentlen < 10:
        return QPainterPath(basepath)

    t = (px / 2) / segmentlen
    p1, _ = qpainterpath_simple_split(basepath, 0.50 - t)
    _, p2 = qpainterpath_simple_split(basepath, 0.50 + t)

    angle = -basepath.angleAtPercent(0.5) + 90
    angler = math.radians(angle)
    normal = QPointF(math.cos(angler), math.sin(angler))

    end1 = p1.currentPosition()
    start2 = QPointF(p2.elementAt(0).x, p2.elementAt(0).y)
    p1.moveTo(start2.x(), start2.y())
    p1.addPath(p2)

    def QPainterPath_addLine(path, line):
        path.moveTo(line.p1())
        path.lineTo(line.p2())

    QPainterPath_addLine(p1, QLineF(end1 - normal * 3, end1 + normal * 3))
    QPainterPath_addLine(p1, QLineF(start2 - normal * 3, start2 + normal * 3))
    return p1
Пример #8
0
    def _update_selection(self, p1: QPointF, p2: QPointF, finished: bool):
        # When finished, emit selection_changed.
        if len(self.__selection_rects) == 0:
            return
        assert self._max_item_width > 0

        rect = QRectF(p1, p2).normalized()
        if self.__orientation == Qt.Vertical:
            min_max = rect.y(), rect.y() + rect.height()
            index = int(
                (p1.x() + self._max_item_width / 2) / self._max_item_width)
        else:
            min_max = rect.x(), rect.x() + rect.width()
            index = int(
                (-p1.y() + self._max_item_width / 2) / self._max_item_width)

        index = min(index, len(self.__selection_rects) - 1)
        index = self._sorted_group_indices[index]

        self.__selection_rects[index].selection_range = min_max

        if not finished:
            return

        mask = np.bitwise_and(self.__values >= min_max[0],
                              self.__values <= min_max[1])
        if self.__group_values is not None:
            mask = np.bitwise_and(mask, self.__group_values == index)

        selection = set(np.flatnonzero(mask))
        keys = QApplication.keyboardModifiers()
        if keys & Qt.ShiftModifier:
            remove_mask = self.__group_values == index
            selection |= self.__selection - set(np.flatnonzero(remove_mask))
        if self.__selection != selection:
            self.__selection = selection
            self.selection_changed.emit(sorted(self.__selection),
                                        self._selection_ranges)
Пример #9
0
    def indexAt(self, pos: QPointF) -> Optional[int]:
        """
        Return the index of item at `pos`.
        """
        def brect(item):
            return item.mapRectToParent(item.boundingRect())

        if self.__orientation == Qt.Vertical:
            y = lambda pos: pos.y()
        else:
            y = lambda pos: pos.x()
        top = lambda idx: brect(items[idx]).top()
        bottom = lambda idx: brect(items[idx]).bottom()
        items = self.__textitems
        if not items:
            return None
        idx = bisect.bisect_right(_FuncArray(top, len(items)), y(pos)) - 1
        if idx == -1:
            idx = 0
        if top(idx) <= y(pos) <= bottom(idx):
            return idx
        else:
            return None
Пример #10
0
class SquareGraphicsItem(QGraphicsRectItem):
    """Square Graphics Item.

    Square component to draw as components for the non-interactive Pythagoras
    tree.

    Parameters
    ----------
    tree_node : TreeNode
        The tree node the square represents.
    brush : QColor, optional
        The brush to be used as the backgound brush.
    pen : QPen, optional
        The pen to be used for the border.

    """

    def __init__(self, tree_node, parent=None, **kwargs):
        self.tree_node = tree_node
        self.tree_node.graphics_item = self

        center, length, angle = tree_node.square
        self._center_point = center
        self.center = QPointF(*center)
        self.length = length
        self.angle = angle
        super().__init__(self._get_rect_attributes(), parent)
        self.setTransformOriginPoint(self.boundingRect().center())
        self.setRotation(degrees(angle))

        self.setBrush(kwargs.get('brush', QColor('#297A1F')))
        self.setPen(kwargs.get('pen', QPen(QColor('#000'))))

        self.setAcceptHoverEvents(True)
        self.setZValue(kwargs.get('zvalue', 0))
        self.z_step = Z_STEP

        # calculate the correct z values based on the parent
        if self.tree_node.parent != TreeAdapter.ROOT_PARENT:
            p = self.tree_node.parent
            # override root z step
            num_children = len(p.children)
            own_index = [1 if c.label == self.tree_node.label else 0
                         for c in p.children].index(1)

            self.z_step = int(p.graphics_item.z_step / num_children)
            base_z = p.graphics_item.zValue()

            self.setZValue(base_z + own_index * self.z_step)

    def _get_rect_attributes(self):
        """Get the rectangle attributes requrired to draw item.

        Compute the QRectF that a QGraphicsRect needs to be rendered with the
        data passed down in the constructor.

        """
        height = width = self.length
        x = self.center.x() - self.length / 2
        y = self.center.y() - self.length / 2
        return QRectF(x, y, height, width)
Пример #11
0
 def _activate_cut_line(self, pos: QPointF):
     """Activate cut line selection an set cut value to `pos.x()`."""
     self.selection_method = 1
     self.cut_line.setValue(pos.x())
     self._selection_method_changed()
Пример #12
0
class SquareGraphicsItem(QGraphicsRectItem):
    """Square Graphics Item.

    Square component to draw as components for the non-interactive Pythagoras
    tree.

    Parameters
    ----------
    tree_node : TreeNode
        The tree node the square represents.
    brush : QColor, optional
        The brush to be used as the backgound brush.
    pen : QPen, optional
        The pen to be used for the border.

    """
    def __init__(self, tree_node, parent=None, **kwargs):
        self.tree_node = tree_node
        self.tree_node.graphics_item = self

        center, length, angle = tree_node.square
        self._center_point = center
        self.center = QPointF(*center)
        self.length = length
        self.angle = angle
        super().__init__(self._get_rect_attributes(), parent)
        self.setTransformOriginPoint(self.boundingRect().center())
        self.setRotation(degrees(angle))

        self.setBrush(kwargs.get('brush', QColor('#297A1F')))
        self.setPen(kwargs.get('pen', QPen(QColor('#000'))))

        self.setAcceptHoverEvents(True)
        self.setZValue(kwargs.get('zvalue', 0))
        self.z_step = Z_STEP

        # calculate the correct z values based on the parent
        if self.tree_node.parent != TreeAdapter.ROOT_PARENT:
            p = self.tree_node.parent
            # override root z step
            num_children = len(p.children)
            own_index = [
                1 if c.label == self.tree_node.label else 0 for c in p.children
            ].index(1)

            self.z_step = int(p.graphics_item.z_step / num_children)
            base_z = p.graphics_item.zValue()

            self.setZValue(base_z + own_index * self.z_step)

    def _get_rect_attributes(self):
        """Get the rectangle attributes requrired to draw item.

        Compute the QRectF that a QGraphicsRect needs to be rendered with the
        data passed down in the constructor.

        """
        height = width = self.length
        x = self.center.x() - self.length / 2
        y = self.center.y() - self.length / 2
        return QRectF(x, y, height, width)