class ParallelCoordinatesCurve(OWCurve): def __init__(self, n_attributes, y_values, color, name=""): OWCurve.__init__(self, tooltip=name) self._item = QGraphicsPathItem(self) self.path = QPainterPath() self.fitted = False self.n_attributes = n_attributes self.n_rows = int(len(y_values) / n_attributes) self.set_style(OWCurve.Lines) if isinstance(color, tuple): self.set_pen(QPen(QColor(*color))) else: self.set_pen(QPen(QColor(color))) x_values = list(range(n_attributes)) * self.n_rows self.set_data(x_values, y_values) def update_properties(self): self.redraw_path() def redraw_path(self): self.path = QPainterPath() for segment in self.segment(self.data()): if self.fitted: self.draw_cubic_path(segment) else: self.draw_normal_path(segment) self._item.setPath(self.graph_transform().map(self.path)) self._item.setPen(self.pen()) def segment(self, data): for i in range(self.n_rows): yield data[i * self.n_attributes:(i + 1) * self.n_attributes] def draw_cubic_path(self, segment): for (x1, y1), (x2, y2) in zip(segment, segment[1:]): self.path.moveTo(x1, y1) self.path.cubicTo(QPointF(x1 + 0.5, y1), QPointF(x2 - 0.5, y2), QPointF(x2, y2)) def draw_normal_path(self, segment): if not segment: return x, y = segment[0] self.path.moveTo(x, y) for x, y in segment[1:]: self.path.lineTo(x, y)
def _addPath(self): iNode = 2 * model._nodes.index(self.__node) x0,y0 = record.states[0][iNode:iNode+2] path = QPainterPath() path.moveTo(x0,-y0) item = QGraphicsPathItem() item.setPen( QPen( QColor(0,0,255), 0 ) ) item.setPath(path) self._path = item for state in record.states[1:]: self._addPoint(state) if hasattr(record,'changeListeners'): record.changeListeners.append(self._addPoint) groupCurves.addToGroup(item)
class ParallelCoordinatesCurve(OWCurve): def __init__(self, attrCount, yData, color, name=""): OWCurve.__init__(self, tooltip=name) self._item = QGraphicsPathItem(self) self.fitted = False self.set_style(OWCurve.Lines) lineCount = len(yData) / attrCount self.attrCount = attrCount if type(color) == tuple: self.set_pen(QPen(QColor(*color))) else: self.set_pen(QPen(QColor(color))) self.set_data(range(attrCount) * lineCount, yData) def update_properties(self): if self.fitted: path = self.cubicPath() else: path = QPainterPath() for x, y in self.data(): path.lineTo(x, y) self._item.setPath(self.graph_transform().map(path)) self._item.setPen(self.pen()) def cubicPath(self): path = QPainterPath() data = self.data() for i in range(len(data) / self.attrCount): segment = data[i * self.attrCount:(i + 1) * self.attrCount] for i, p in enumerate(segment[:-1]): x1, y1 = p x2, y2 = segment[i + 1] path.moveTo(x1, y1) path.cubicTo(QPointF(x1 + 0.5, y1), QPointF(x2 - 0.5, y2), QPointF(x2, y2)) return path
class ParallelCoordinatesCurve(OWCurve): def __init__(self, attrCount, yData, color, name = ""): OWCurve.__init__(self, tooltip=name) self._item = QGraphicsPathItem(self) self.fitted = False self.set_style(OWCurve.Lines) lineCount = len(yData) / attrCount self.attrCount = attrCount if type(color) == tuple: self.set_pen(QPen(QColor(*color))) else: self.set_pen(QPen(QColor(color))) self.set_data(range(attrCount) * lineCount, yData) def update_properties(self): if self.fitted: path = self.cubicPath() else: path = QPainterPath() for x, y in self.data(): path.lineTo(x, y) self._item.setPath(self.graph_transform().map(path)) self._item.setPen(self.pen()) def cubicPath(self): path = QPainterPath() data = self.data() for i in range(len(data) / self.attrCount): segment = data[i*self.attrCount: (i + 1)*self.attrCount] for i, p in enumerate(segment[:-1]): x1, y1 = p x2, y2 = segment[i + 1] path.moveTo(x1, y1) path.cubicTo(QPointF(x1 + 0.5, y1), QPointF(x2 - 0.5, y2), QPointF(x2, y2)) return path
class PlotGrid(orangeqt.PlotItem): """ Draws a grid onto the plot :param plot: If specified, the grid will be attached to the ``plot``. :type plot: :obj:`.OWPlot` """ def __init__(self, plot=None): orangeqt.PlotItem.__init__(self) self._x_enabled = True self._y_enabled = True self._path_item = QGraphicsPathItem(self) self.set_in_background(True) if plot: self.attach(plot) self._path_item.setPen(plot.color(OWPalette.Grid)) def set_x_enabled(self, b): """ Enables or disabled vertial grid lines """ if b < 0: b = not self._x_enabled self._x_enabled = b self.update_properties() def is_x_enabled(self): """ Returns whether vertical grid lines are enabled """ return self._x_enabled def set_y_enabled(self, b): """ Enables or disabled horizontal grid lines """ if b < 0: b = not self._y_enabled self._y_enabled = b self.update_properties() def is_y_enabled(self): """ Returns whether horizontal grid lines are enabled """ return self._y_enabled def set_pen(self, pen): """ Sets the pen used for drawing the grid lines """ self._path_item.setPen(pen) def update_properties(self): p = self.plot() if p is None: return x_id, y_id = self.axes() rect = p.data_rect_for_axes(x_id, y_id) path = QPainterPath() if self._x_enabled and x_id in p.axes: for pos, label, size, _w in p.axes[x_id].ticks(): path.moveTo(pos, rect.bottom()) path.lineTo(pos, rect.top()) if self._y_enabled and y_id in p.axes: for pos, label, size, _w in p.axes[y_id].ticks(): path.moveTo(rect.left(), pos) path.lineTo(rect.right(), pos) self._path_item.setPath(self.graph_transform().map(path))
class TextAnnotation(Annotation): """Text annotation item for the canvas scheme. """ editingFinished = Signal() """Emitted when the editing is finished (i.e. the item loses focus).""" textEdited = Signal() """Emitted when the edited text changes.""" def __init__(self, parent=None, **kwargs): Annotation.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFocusPolicy(Qt.ClickFocus) self.__textMargins = (2, 2, 2, 2) rect = self.geometry().translated(-self.pos()) self.__framePen = QPen(Qt.NoPen) self.__framePathItem = QGraphicsPathItem(self) self.__framePathItem.setPen(self.__framePen) self.__textItem = GraphicsTextEdit(self) self.__textItem.setPlaceholderText(self.tr("Enter text here")) self.__textItem.setPos(2, 2) self.__textItem.setTextWidth(rect.width() - 4) self.__textItem.setTabChangesFocus(True) self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction) self.__textItem.setFont(self.font()) self.__textInteractionFlags = Qt.NoTextInteraction layout = self.__textItem.document().documentLayout() layout.documentSizeChanged.connect(self.__onDocumentSizeChanged) self.__updateFrame() def adjustSize(self): """Resize to a reasonable size. """ self.__textItem.setTextWidth(-1) self.__textItem.adjustSize() size = self.__textItem.boundingRect().size() left, top, right, bottom = self.textMargins() geom = QRectF(self.pos(), size + QSizeF(left + right, top + bottom)) self.setGeometry(geom) def setFramePen(self, pen): """Set the frame pen. By default Qt.NoPen is used (i.e. the frame is not shown). """ if pen != self.__framePen: self.__framePen = QPen(pen) self.__updateFrameStyle() def framePen(self): """Return the frame pen. """ return QPen(self.__framePen) def setFrameBrush(self, brush): """Set the frame brush. """ self.__framePathItem.setBrush(brush) def frameBrush(self): """Return the frame brush. """ return self.__framePathItem.brush() def __updateFrameStyle(self): if self.isSelected(): pen = QPen(QColor(96, 158, 215), 1.25, Qt.DashDotLine) else: pen = self.__framePen self.__framePathItem.setPen(pen) def setPlainText(self, text): """Set the annotation plain text. """ self.__textItem.setPlainText(text) def toPlainText(self): return self.__textItem.toPlainText() def setHtml(self, text): """Set the annotation rich text. """ self.__textItem.setHtml(text) def toHtml(self): return self.__textItem.toHtml() def setDefaultTextColor(self, color): """Set the default text color. """ self.__textItem.setDefaultTextColor(color) def defaultTextColor(self): return self.__textItem.defaultTextColor() def setTextMargins(self, left, top, right, bottom): """Set the text margins. """ margins = (left, top, right, bottom) if self.__textMargins != margins: self.__textMargins = margins self.__textItem.setPos(left, top) self.__textItem.setTextWidth( max(self.geometry().width() - left - right, 0)) def textMargins(self): """Return the text margins. """ return self.__textMargins def document(self): """Return the QTextDocument instance used internally. """ return self.__textItem.document() def setTextCursor(self, cursor): self.__textItem.setTextCursor(cursor) def textCursor(self): return self.__textItem.textCursor() def setTextInteractionFlags(self, flags): self.__textInteractionFlags = flags def textInteractionFlags(self): return self.__textInteractionFlags def setDefaultStyleSheet(self, stylesheet): self.document().setDefaultStyleSheet(stylesheet) def mouseDoubleClickEvent(self, event): Annotation.mouseDoubleClickEvent(self, event) if event.buttons() == Qt.LeftButton and \ self.__textInteractionFlags & Qt.TextEditable: self.startEdit() def startEdit(self): """Start the annotation text edit process. """ self.__textItem.setTextInteractionFlags(self.__textInteractionFlags) self.__textItem.setFocus(Qt.MouseFocusReason) # Install event filter to find out when the text item loses focus. self.__textItem.installSceneEventFilter(self) self.__textItem.document().contentsChanged.connect(self.textEdited) def endEdit(self): """End the annotation edit. """ self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction) self.__textItem.removeSceneEventFilter(self) self.__textItem.document().contentsChanged.disconnect(self.textEdited) cursor = self.__textItem.textCursor() cursor.clearSelection() self.__textItem.setTextCursor(cursor) self.editingFinished.emit() def __onDocumentSizeChanged(self, size): # The size of the text document has changed. Expand the text # control rect's height if the text no longer fits inside. try: rect = self.geometry() _, top, _, bottom = self.textMargins() if rect.height() < (size.height() + bottom + top): rect.setHeight(size.height() + bottom + top) self.setGeometry(rect) except Exception: log.error("error in __onDocumentSizeChanged", exc_info=True) def __updateFrame(self): rect = self.geometry() rect.moveTo(0, 0) path = QPainterPath() path.addRect(rect) self.__framePathItem.setPath(path) def resizeEvent(self, event): width = event.newSize().width() left, _, right, _ = self.textMargins() self.__textItem.setTextWidth(max(width - left - right, 0)) self.__updateFrame() QGraphicsWidget.resizeEvent(self, event) def sceneEventFilter(self, obj, event): if obj is self.__textItem and event.type() == QEvent.FocusOut: self.__textItem.focusOutEvent(event) self.endEdit() return True return Annotation.sceneEventFilter(self, obj, event) def itemChange(self, change, value): if change == QGraphicsItem.ItemSelectedHasChanged: self.__updateFrameStyle() return Annotation.itemChange(self, change, value) def changeEvent(self, event): if event.type() == QEvent.FontChange: self.__textItem.setFont(self.font()) Annotation.changeEvent(self, event)
class TextAnnotation(Annotation): """Text annotation item for the canvas scheme. """ editingFinished = Signal() """Emitted when the editing is finished (i.e. the item loses focus).""" textEdited = Signal() """Emitted when the edited text changes.""" def __init__(self, parent=None, **kwargs): Annotation.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFocusPolicy(Qt.ClickFocus) self.__textMargins = (2, 2, 2, 2) rect = self.geometry().translated(-self.pos()) self.__framePathItem = QGraphicsPathItem(self) self.__framePathItem.setPen(QPen(Qt.NoPen)) self.__textItem = GraphicsTextEdit(self) self.__textItem.setPlaceholderText(self.tr("Enter text here")) self.__textItem.setPos(2, 2) self.__textItem.setTextWidth(rect.width() - 4) self.__textItem.setTabChangesFocus(True) self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction) self.__textItem.setFont(self.font()) self.__textInteractionFlags = Qt.NoTextInteraction layout = self.__textItem.document().documentLayout() layout.documentSizeChanged.connect(self.__onDocumentSizeChanged) self.__updateFrame() def adjustSize(self): """Resize to a reasonable size. """ self.__textItem.setTextWidth(-1) self.__textItem.adjustSize() size = self.__textItem.boundingRect().size() left, top, right, bottom = self.textMargins() geom = QRectF(self.pos(), size + QSizeF(left + right, top + bottom)) self.setGeometry(geom) def setFramePen(self, pen): """Set the frame pen. By default Qt.NoPen is used (i.e. the frame is not shown). """ self.__framePathItem.setPen(pen) def framePen(self): """Return the frame pen. """ return self.__framePathItem.pen() def setFrameBrush(self, brush): """Set the frame brush. """ self.__framePathItem.setBrush(brush) def frameBrush(self): """Return the frame brush. """ return self.__framePathItem.brush() def setPlainText(self, text): """Set the annotation plain text. """ self.__textItem.setPlainText(text) def toPlainText(self): return self.__textItem.toPlainText() def setHtml(self, text): """Set the annotation rich text. """ self.__textItem.setHtml(text) def toHtml(self): return self.__textItem.toHtml() def setDefaultTextColor(self, color): """Set the default text color. """ self.__textItem.setDefaultTextColor(color) def defaultTextColor(self): return self.__textItem.defaultTextColor() def setTextMargins(self, left, top, right, bottom): """Set the text margins. """ margins = (left, top, right, bottom) if self.__textMargins != margins: self.__textMargins = margins self.__textItem.setPos(left, top) self.__textItem.setTextWidth( max(self.geometry().width() - left - right, 0) ) def textMargins(self): """Return the text margins. """ return self.__textMargins def document(self): """Return the QTextDocument instance used internally. """ return self.__textItem.document() def setTextCursor(self, cursor): self.__textItem.setTextCursor(cursor) def textCursor(self): return self.__textItem.textCursor() def setTextInteractionFlags(self, flags): self.__textInteractionFlags = flags def textInteractionFlags(self): return self.__textInteractionFlags def setDefaultStyleSheet(self, stylesheet): self.document().setDefaultStyleSheet(stylesheet) def mouseDoubleClickEvent(self, event): Annotation.mouseDoubleClickEvent(self, event) if event.buttons() == Qt.LeftButton and \ self.__textInteractionFlags & Qt.TextEditable: self.startEdit() def startEdit(self): """Start the annotation text edit process. """ self.__textItem.setTextInteractionFlags(self.__textInteractionFlags) self.__textItem.setFocus(Qt.MouseFocusReason) # Install event filter to find out when the text item loses focus. self.__textItem.installSceneEventFilter(self) self.__textItem.document().contentsChanged.connect( self.textEdited ) def endEdit(self): """End the annotation edit. """ self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction) self.__textItem.removeSceneEventFilter(self) self.__textItem.document().contentsChanged.disconnect( self.textEdited ) self.editingFinished.emit() def __onDocumentSizeChanged(self, size): # The size of the text document has changed. Expand the text # control rect's height if the text no longer fits inside. try: rect = self.geometry() _, top, _, bottom = self.textMargins() if rect.height() < (size.height() + bottom + top): rect.setHeight(size.height() + bottom + top) self.setGeometry(rect) except Exception: log.error("error in __onDocumentSizeChanged", exc_info=True) def __updateFrame(self): rect = self.geometry() rect.moveTo(0, 0) path = QPainterPath() path.addRect(rect) self.__framePathItem.setPath(path) def resizeEvent(self, event): width = event.newSize().width() left, _, right, _ = self.textMargins() self.__textItem.setTextWidth(max(width - left - right, 0)) self.__updateFrame() QGraphicsWidget.resizeEvent(self, event) def sceneEventFilter(self, obj, event): if obj is self.__textItem and event.type() == QEvent.FocusOut: self.__textItem.focusOutEvent(event) self.endEdit() return True return Annotation.sceneEventFilter(self, obj, event) def itemChange(self, change, value): if change == QGraphicsItem.ItemSelectedHasChanged: if self.isSelected(): self.setFramePen(QPen(Qt.DashDotLine)) else: self.setFramePen(QPen(Qt.NoPen)) return Annotation.itemChange(self, change, value) def changeEvent(self, event): if event.type() == QEvent.FontChange: self.__textItem.setFont(self.font()) Annotation.changeEvent(self, event)
def setPath(self, path): self.__shape = None QGraphicsPathItem.setPath(self, path)
class AxisScene(QGraphicsScene): def __init__(self, parent = None): super(AxisScene, self).__init__(parent) self.guidePen = QPen(QColor("blue"),1) self.dot = QGraphicsEllipseItem(-10, -10, 20, 20) self.dot.setPos(QPointF(0,0)) self.dot.setPen(QPen(QColor("red"), 4)) self.dot.setBrush(QColor("black")) self.lastPos = {} self.lastPos['x'] = 0 self.lastPos['y'] = 0 self.grid = False self.gridPen = QPen(QColor("blue"), 2) self.pathItem = QGraphicsPathItem() self.pathItem.setPen(QPen(QColor("red"), 1, Qt.DotLine)) self.path = None self.xAxis = "Select Axis..." self.yAxis = self.xAxis self.addItem(self.dot) def setXAxisName(self, x): self.xAxis = "Axis " + str(x) self.invalidate() def setYAxisName(self, y): self.yAxis = "Axis " + str(y) self.invalidate() def pathToggled(self, toggled): if toggled: self.path = QPainterPath() self.path.moveTo(0,0) self.pathItem.setPath(self.path) self.addItem(self.pathItem) else: if self.path != None: self.removeItem(self.pathItem) self.path = None self.invalidate() def gridToggled(self, toggled): self.grid = toggled self.invalidate() def updateDotX(self, x): self.lastPos['x'] = x * (self.sceneRect().width() / 2) self.update(self.lastPos['x'], self.lastPos['y']) def updateDotY(self, y): self.lastPos['y'] = y * (self.sceneRect().height() / 2) self.update(self.lastPos['x'], self.lastPos['y']) def update(self, x, y): if self.path != None: self.path.lineTo(x, y) self.pathItem.setPath(self.path) self.dot.setPos(self.lastPos['x'], self.lastPos['y']) self.invalidate() def drawBackground(self, painter, rect): if self.grid: painter.setClipRect(rect) painter.setPen(self.gridPen) def drawForeground(self, painter, rect): painter.setClipRect(rect) painter.setPen(self.gridPen) r = self.sceneRect() if self.grid: painter.drawLine(r.center().x(), r.top(), r.center().x(), r.bottom()) painter.drawLine(r.left(), r.center().y(), r.right(), r.center().y()) painter.setPen(QPen(QColor("red"), 1)) painter.drawText(QRectF(r.left(), r.center().y(), 80, 80), self.xAxis) painter.drawText(QRectF(r.center().x()+5, r.top(), 80, 80), self.yAxis) if self.path != None: painter.setPen(QPen(QColor("red"), 1)) painter.drawLine(QPointF(self.lastPos['x'], r.top()), QPointF(self.lastPos['x'], r.bottom())) painter.drawLine(QPointF(r.left(), self.lastPos['y']), QPointF(r.right(), self.lastPos['y']))