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 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
def test_selection_no_data(self): self.widget.graph._update_selection(QPointF(0, 5), QPointF(0, 6), 1) selected = self.get_output(self.widget.Outputs.selected_data) self.assertIsNone(selected)
def innerGlowBackgroundPixmap(color, size, radius=5): """ Draws radial gradient pixmap, then uses that to draw a rounded-corner gradient rectangle pixmap. Args: color (QColor): used as outer color (lightness 245 used for inner) size (QSize): size of output pixmap radius (int): radius of inner glow rounded corners """ key = "InnerGlowBackground " + \ color.name() + " " + \ str(radius) bg = QPixmapCache.find(key) if bg: return bg # set background colors for gradient color = color.toHsl() light_color = color.fromHsl(color.hslHue(), color.hslSaturation(), 245) dark_color = color # initialize radial gradient center = QPoint(radius, radius) pixRect = QRect(0, 0, radius * 2, radius * 2) gradientPixmap = QPixmap(radius * 2, radius * 2) gradientPixmap.fill(dark_color) # draw radial gradient pixmap pixPainter = QPainter(gradientPixmap) pixPainter.setPen(Qt.NoPen) gradient = QRadialGradient(center, radius - 1) gradient.setColorAt(0, light_color) gradient.setColorAt(1, dark_color) pixPainter.setBrush(gradient) pixPainter.drawRect(pixRect) pixPainter.end() # set tl and br to the gradient's square-shaped rect tl = QPoint(0, 0) br = QPoint(size.width(), size.height()) # fragments of radial gradient pixmap to create rounded gradient outline rectangle frags = [ # top-left corner QPainter.PixmapFragment.create( QPointF(tl.x() + radius / 2, tl.y() + radius / 2), QRectF(0, 0, radius, radius)), # top-mid 'linear gradient' QPainter.PixmapFragment.create(QPointF(tl.x() + (br.x() - tl.x()) / 2, tl.y() + radius / 2), QRectF(radius, 0, 1, radius), scaleX=(br.x() - tl.x() - 2 * radius)), # top-right corner QPainter.PixmapFragment.create( QPointF(br.x() - radius / 2, tl.y() + radius / 2), QRectF(radius, 0, radius, radius)), # left-mid 'linear gradient' QPainter.PixmapFragment.create(QPointF(tl.x() + radius / 2, tl.y() + (br.y() - tl.y()) / 2), QRectF(0, radius, radius, 1), scaleY=(br.y() - tl.y() - 2 * radius)), # mid solid QPainter.PixmapFragment.create(QPointF(tl.x() + (br.x() - tl.x()) / 2, tl.y() + (br.y() - tl.y()) / 2), QRectF(radius, radius, 1, 1), scaleX=(br.x() - tl.x() - 2 * radius), scaleY=(br.y() - tl.y() - 2 * radius)), # right-mid 'linear gradient' QPainter.PixmapFragment.create(QPointF(br.x() - radius / 2, tl.y() + (br.y() - tl.y()) / 2), QRectF(radius, radius, radius, 1), scaleY=(br.y() - tl.y() - 2 * radius)), # bottom-left corner QPainter.PixmapFragment.create( QPointF(tl.x() + radius / 2, br.y() - radius / 2), QRectF(0, radius, radius, radius)), # bottom-mid 'linear gradient' QPainter.PixmapFragment.create(QPointF(tl.x() + (br.x() - tl.x()) / 2, br.y() - radius / 2), QRectF(radius, radius, 1, radius), scaleX=(br.x() - tl.x() - 2 * radius)), # bottom-right corner QPainter.PixmapFragment.create( QPointF(br.x() - radius / 2, br.y() - radius / 2), QRectF(radius, radius, radius, radius)), ] # draw icon background to pixmap outPix = QPixmap(size.width(), size.height()) outPainter = QPainter(outPix) outPainter.setPen(Qt.NoPen) outPainter.drawPixmapFragments( frags, gradientPixmap, QPainter.PixmapFragmentHints(QPainter.OpaqueHint)) outPainter.end() QPixmapCache.insert(key, outPix) return outPix
def select_by_rectangle(self, value_rect): if self.scatterplot_item is not None: points = [point for point in self.scatterplot_item.points() if value_rect.contains(QPointF(point.pos()))] self.select(points)
def rect(self): if getattr(self, "_rect", QRectF()).isValid(): return self._rect else: return QRectF(QPointF(0, 0), self.document().size()) | \ getattr(self, "_rect", QRectF(0, 0, 1, 1))
def _get_polygon(self) -> QPolygonF: return QPolygonF([QPointF(x, y) for x, y in self.get_points()])
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()
def poly2qpoly(poly: Polygon) -> QPolygonF: return QPolygonF([QPointF(x, y) for x, y in poly.exterior.coords])
def edge_in_point(self, edge): return edge.mapFromItem( self, QPointF(self.rect().center().x(), self.rect().y()))
def shape(self): if self.__shape is None: path = self.getPath() d = self.pixelLength(QPointF(0, self.opts["mouseWidth"])) self.__shape = shape_from_path(path, width=d) return self.__shape
def test_migrate_selection(self): c = QPointF() # some we set an attribute to setattr(c, "selection", [False, True, True, False]) settings = {"context_settings": [c]} OWHyper.migrate_settings(settings, 2) self.assertEqual(settings["imageplot"]["selection_group_saved"], [(1, 1), (2, 1)])
def _add_command(self, cmd): name = "Name" if not self.hasAttr2 and isinstance( cmd, (Move, MoveSelection, Jitter, Magnet)): # tool only supported if both x and y are enabled return if isinstance(cmd, Append): cls = self.selected_class_label() points = np.array([(p.x(), p.y() if self.hasAttr2 else 0, cls) for p in cmd.points]) self.undo_stack.push(UndoCommand(Append(points), self, text=name)) elif isinstance(cmd, Move): self.undo_stack.push(UndoCommand(cmd, self, text=name)) elif isinstance(cmd, SelectRegion): indices = [ i for i, (x, y) in enumerate(self.__buffer[:, :2]) if cmd.region.contains(QPointF(x, y)) ] indices = np.array(indices, dtype=int) self._selected_indices = indices elif isinstance(cmd, DeleteSelection): indices = self._selected_indices if indices is not None and indices.size: self.undo_stack.push( UndoCommand(DeleteIndices(indices), self, text="Delete")) elif isinstance(cmd, MoveSelection): indices = self._selected_indices if indices is not None and indices.size: self.undo_stack.push( UndoCommand( Move( (self._selected_indices, slice(0, 2)), np.array([cmd.delta.x(), cmd.delta.y()]), ), self, text="Move", )) elif isinstance(cmd, DeleteIndices): self.undo_stack.push(UndoCommand(cmd, self, text="Delete")) elif isinstance(cmd, Insert): self.undo_stack.push(UndoCommand(cmd, self)) elif isinstance(cmd, AirBrush): data = create_data( cmd.pos.x(), cmd.pos.y(), self.brushRadius / 1000, int(1 + self.density / 20), cmd.rstate, ) self._add_command(Append([QPointF(*p) for p in zip(*data.T)])) elif isinstance(cmd, Jitter): point = np.array([cmd.pos.x(), cmd.pos.y()]) delta = -apply_jitter(self.__buffer[:, :2], point, self.density / 100.0, 0, cmd.rstate) self._add_command(Move((..., slice(0, 2)), delta)) elif isinstance(cmd, Magnet): point = np.array([cmd.pos.x(), cmd.pos.y()]) delta = -apply_attractor(self.__buffer[:, :2], point, self.density / 100.0, 0) self._add_command(Move((..., slice(0, 2)), delta)) else: assert False, "unreachable"
def _select_data(self): self.widget.graph._update_selection(QPointF(0, 5), QPointF(0, 6), True) assert len(self.widget.selection) == 30 return self.widget.selection
def test_selection_no_group(self): self.send_signal(self.widget.Inputs.data, self.housing) self.widget.graph._update_selection(QPointF(0, 30), QPointF(0, 40), 1) selected = self.get_output(self.widget.Outputs.selected_data) self.assertEqual(len(selected), 53)
def innerShadowPixmap(color, size, pos, length=5): """ Args: color (QColor): shadow color size (QSize): size of pixmap pos (int): shadow position int flag, use bitwise operations 1 - top 2 - right 4 - bottom 8 - left length (int): length of cast shadow """ key = "InnerShadow " + \ color.name() + " " + \ str(size) + " " + \ str(pos) + " " + \ str(length) # get cached shadow if it exists finalShadow = QPixmapCache.find(key) if finalShadow: return finalShadow # get shadow template pixmap (1-pixel linear gradient line) shadowTemplate = QPixmapCache.find("TabButtonShadowTemplate" + str(length)) if shadowTemplate is None: shadowTemplate = shadowTemplatePixmap(color, length) QPixmapCache.insert("TabButtonShadowTemplate" + str(length), shadowTemplate) finalShadow = QPixmap(size) finalShadow.fill(Qt.transparent) shadowPainter = QPainter(finalShadow) shadowPainter.setCompositionMode(QPainter.CompositionMode_Darken) # top/bottom rect targetRect = QRect(0, 0, size.width(), length) # shadow on top if pos & 1: shadowPainter.drawPixmap(targetRect, shadowTemplate, shadowTemplate.rect()) # shadow on bottom if pos & 4: shadowPainter.save() shadowPainter.translate(QPointF(0, size.height())) shadowPainter.scale(1, -1) shadowPainter.drawPixmap(targetRect, shadowTemplate, shadowTemplate.rect()) shadowPainter.restore() # left/right rect targetRect = QRect(0, 0, size.height(), shadowTemplate.rect().height()) # shadow on the right if pos & 2: shadowPainter.save() shadowPainter.translate(QPointF(size.width(), 0)) shadowPainter.rotate(90) shadowPainter.drawPixmap(targetRect, shadowTemplate, shadowTemplate.rect()) shadowPainter.restore() # shadow on left if pos & 8: shadowPainter.save() shadowPainter.translate(0, size.height()) shadowPainter.rotate(-90) shadowPainter.drawPixmap(targetRect, shadowTemplate, shadowTemplate.rect()) shadowPainter.restore() shadowPainter.end() # cache shadow QPixmapCache.insert(key, finalShadow) return finalShadow
def _select_data(self): self.widget.select_area( 1, QMouseEvent(QEvent.MouseButtonPress, QPointF(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)) return [2, 3, 9, 23, 29, 30, 34, 35, 37, 42, 47, 49]
def projection(point, line): norm = line.normalVector() norm.translate(point - norm.p1()) p = QPointF() type = line.intersect(norm, p) return p
def _update_bar_size(self): if self._silplot is not None: self._set_bar_height() self.scene.setSceneRect( QRectF(QPointF(0, 0), self._silplot.effectiveSizeHint(Qt.PreferredSize)))
def __init__(self, data, variable, parent=None, height=200, width=300, side_padding=5, top_padding=20, bar_spacing=4, border=0, border_color=None, color_attribute=None, n_bins=10): super().__init__(parent) self.height, self.width = height, width self.padding = side_padding self.bar_spacing = bar_spacing self.data = data self.attribute = data.domain[variable] self.x = data.get_column_view(self.attribute)[0].astype(np.float64) self.x_nans = np.isnan(self.x) self.x = self.x[~self.x_nans] if self.attribute.is_discrete: self.n_bins = len(self.attribute.values) elif self.attribute.is_continuous: # If the attribute is continuous but contains fewer values than the # bins, it is better to assign each their own bin. We will require # at least 2 bins so that the histogram still visually makes sense # except if there is only a single value, then we use 3 bins for # symmetry num_unique = ut.nanunique(self.x).shape[0] if num_unique == 1: self.n_bins = 3 else: self.n_bins = min(max(2, num_unique), n_bins) # Handle target variable index self.color_attribute = color_attribute if self.color_attribute is not None: self.target_var = data.domain[color_attribute] self.y = data.get_column_view(color_attribute)[0] self.y = self.y[~self.x_nans] if not np.issubdtype(self.y.dtype, np.number): self.y = self.y.astype(np.float64) else: self.target_var, self.y = None, None # Borders self.border_color = border_color if border_color is not None else '#000' if isinstance(border, tuple): assert len(border) == 4, 'Border tuple must be of size 4.' self.border = border else: self.border = (border, border, border, border) t, r, b, l = self.border def _draw_border(point_1, point_2, border_width, parent): pen = QPen(QColor(self.border_color)) pen.setCosmetic(True) pen.setWidth(border_width) line = QGraphicsLineItem(QLineF(point_1, point_2), parent) line.setPen(pen) return line top_left = QPointF(0, 0) bottom_left = QPointF(0, self.height) top_right = QPointF(self.width, 0) bottom_right = QPointF(self.width, self.height) self.border_top = _draw_border(top_left, top_right, t, self) if t else None self.border_bottom = _draw_border(bottom_left, bottom_right, b, self) if b else None self.border_left = _draw_border(top_left, bottom_left, l, self) if l else None self.border_right = _draw_border(top_right, bottom_right, r, self) if r else None # _plot_`dim` accounts for all the paddings and spacings self._plot_height = self.height self._plot_height -= top_padding self._plot_height -= t / 4 + b / 4 self._plot_width = self.width self._plot_width -= 2 * side_padding self._plot_width -= (self.n_bins - 2) * bar_spacing self._plot_width -= l / 4 + r / 4 self.__layout = QGraphicsLinearLayout(Qt.Horizontal, self) self.__layout.setContentsMargins( side_padding + r / 2, top_padding + t / 2, side_padding + l / 2, b / 2 ) self.__layout.setSpacing(bar_spacing) # If the data contains any non-NaN values, we can draw a histogram if self.x.size > 0: self.edges, self.distributions = self._histogram() self._draw_histogram()
def try_big_selection(self): self.widget.imageplot.select_square(QPointF(-100, -100), QPointF(100, 100)) self.widget.imageplot.make_selection(None)
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)
def test_select_click(self): self.send_signal("Data", self.whitelight) self.widget.imageplot.select_by_click(QPointF(1, 2)) out = self.get_output("Selection") np.testing.assert_equal(out.metas, [[1, 2]])
def _dendrogram_slider_changed(self, value): p = QPointF(value, 0) cl_height = self.dendrogram.height_at(p) self.set_cutoff_height(cl_height)
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)
def _select_data(self): rect = QRectF(QPointF(-20, -20), QPointF(20, 20)) self.widget.graph.select_by_rectangle(rect) return self.widget.graph.get_selection()
def _select_data(self): rect = QRectF(QPointF(0, 0), QPointF(1, 1)) self.widget.graph.select_by_rectangle(rect) return np.arange(len(self.data))
def __init__(self, *args): QGraphicsObject.__init__(self, *args) self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True) self.setFlag(QGraphicsItem.ItemHasNoContents, True) self.__direction = QPointF()
def anchorDirection(self): # type: () -> QPointF """ Return the preferred anchor direction. """ return QPointF(self.__direction)
def anchorScenePos(self): """ Return anchor position in scene coordinates. """ return self.mapToScene(QPointF(0, 0))
def setCutoff(self, x, y): if (x, y) != self.cutoff(): self.__setpos(Qt.Vertical | Qt.Horizontal, QPointF(x, y))