def __updateCurve(self): self.prepareGeometryChange() if self.sourceAnchor and self.sinkAnchor: source_pos = self.sourceAnchor.anchorScenePos() sink_pos = self.sinkAnchor.anchorScenePos() source_pos = self.curveItem.mapFromScene(source_pos) sink_pos = self.curveItem.mapFromScene(sink_pos) # Adaptive offset for the curve control points to avoid a # cusp when the two points have the same y coordinate # and are close together delta = source_pos - sink_pos dist = math.sqrt(delta.x()**2 + delta.y()**2) cp_offset = min(dist / 2.0, 60.0) # TODO: make the curve tangent orthogonal to the anchors path. path = QPainterPath() path.moveTo(source_pos) path.cubicTo(source_pos + QPointF(cp_offset, 0), sink_pos - QPointF(cp_offset, 0), sink_pos) self.curveItem.setPath(path) self.sourceIndicator.setPos(source_pos) self.sinkIndicator.setPos(sink_pos) self.__updateText() else: self.setHoverState(False) self.curveItem.setPath(QPainterPath())
def __updateCurve(self): self.prepareGeometryChange() if self.sourceAnchor and self.sinkAnchor: source_pos = self.sourceAnchor.anchorScenePos() sink_pos = self.sinkAnchor.anchorScenePos() source_pos = self.curveItem.mapFromScene(source_pos) sink_pos = self.curveItem.mapFromScene(sink_pos) # Adaptive offset for the curve control points to avoid a # cusp when the two points have the same y coordinate # and are close together delta = source_pos - sink_pos dist = math.sqrt(delta.x() ** 2 + delta.y() ** 2) cp_offset = min(dist / 2.0, 60.0) # TODO: make the curve tangent orthogonal to the anchors path. path = QPainterPath() path.moveTo(source_pos) path.cubicTo(source_pos + QPointF(cp_offset, 0), sink_pos - QPointF(cp_offset, 0), sink_pos) self.curveItem.setPath(path) self.sourceIndicator.setPos(source_pos) self.sinkIndicator.setPos(sink_pos) self.__updateText() else: self.setHoverState(False) self.curveItem.setPath(QPainterPath())
def __init__(self, edge, modObj): QGraphicsPathItem.__init__(self) self.__edge = edge self.__modObj = modObj startPoint = QPointF(edge.points[0][0], edge.points[0][1]) painterPath = QPainterPath(startPoint) index = 1 while index + 3 <= len(edge.points): painterPath.cubicTo(edge.points[index][0], edge.points[index][1], edge.points[index + 1][0], edge.points[index + 1][1], edge.points[index + 2][0], edge.points[index + 2][1]) index = index + 3 if index + 2 <= len(edge.points): painterPath.quadTo(edge.points[index + 1][0], edge.points[index + 1][1], edge.points[index + 2][0], edge.points[index + 2][1]) index = index + 2 if index + 1 <= len(edge.points): painterPath.lineTo(edge.points[index + 1][0], edge.points[index + 1][1]) self.setPath(painterPath) return
def __init__( self, edge, modObj, connObj ): QGraphicsPathItem.__init__( self ) self.__edge = edge self.__modObj = modObj self.__connObj = connObj startPoint = QPointF( edge.points[ 0 ][ 0 ], edge.points[ 0 ][ 1 ] ) painterPath = QPainterPath( startPoint ) index = 1 while index + 3 <= len( edge.points ): painterPath.cubicTo(edge.points[index][0], edge.points[index][1], edge.points[index+1][0],edge.points[index+1][1], edge.points[index+2][0],edge.points[index+2][1]) index = index + 3 if index + 2 <= len( edge.points ): painterPath.quadTo(edge.points[index+1][0], edge.points[index+1][1], edge.points[index+2][0], edge.points[index+2][1]) index = index + 2 if index + 1 <= len( edge.points ): painterPath.lineTo(edge.points[index+1][0], edge.points[index+1][1]) lastIndex = len( edge.points ) - 1 self.addArrow( painterPath, edge.points[lastIndex-1][0], edge.points[lastIndex-1][1], edge.points[lastIndex][0], edge.points[lastIndex][1] ) self.setPath( painterPath ) return
def __init__(self, edge): QGraphicsPathItem.__init__(self) self.__edge = edge startPoint = QPointF(edge.points[0][0], edge.points[0][1]) painterPath = QPainterPath(startPoint) index = 1 while index + 3 <= len(edge.points): painterPath.cubicTo(edge.points[index][0], edge.points[index][1], edge.points[index + 1][0], edge.points[index + 1][1], edge.points[index + 2][0], edge.points[index + 2][1]) index = index + 3 if index + 2 <= len(edge.points): painterPath.quadTo(edge.points[index + 1][0], edge.points[index + 1][1], edge.points[index + 2][0], edge.points[index + 2][1]) index = index + 2 if index + 1 <= len(edge.points): painterPath.lineTo(edge.points[index + 1][0], edge.points[index + 1][1]) if edge.head != edge.tail: lastIndex = len(edge.points) - 1 self.addArrow(painterPath, edge.points[lastIndex - 1][0], edge.points[lastIndex - 1][1], edge.points[lastIndex][0], edge.points[lastIndex][1]) self.setPath(painterPath) return
def compute_path(self): p1 = self.p1 if self.p1.x() < self.p2.x() else self.p2 p2 = self.p2 if self.p1.x() < self.p2.x() else self.p1 path = QPainterPath() path.moveTo(p1) dx = p2.x() - p1.x() path.cubicTo(QPoint(p1.x() + dx / 3, p1.y()), QPoint(p2.x() - dx / 3, p2.y()), p2) self.__path = path
def _updatePath(self): p0 = self._p0 p1 = self._p1 path = QPainterPath() path.moveTo(p0) dx = p1.x() - p0.x() x0 = p0.x() + 0.7 * dx x1 = p1.x() - 0.7 * dx path.cubicTo(QPointF(x0, p0.y()), QPointF(x1, p1.y()), p1) self.setPath(path)
def rebuildSmooth( self ): """ Rebuilds a smooth path based on the inputed points and set \ parameters for this item. :return <QPainterPath> """ # collect the control points points = self.controlPoints() # create the path path = QPainterPath() if ( len(points) == 3 ): x0, y0 = points[0] x1, y1 = points[1] xN, yN = points[2] path.moveTo(x0, y0) path.quadTo(x1, y1, xN, yN) elif ( len(points) == 4 ): x0, y0 = points[0] x1, y1 = points[1] x2, y2 = points[2] xN, yN = points[3] path.moveTo(x0, y0) path.cubicTo(x1, y1, x2, y2, xN, yN) elif ( len(points) == 6 ): x0, y0 = points[0] x1, y1 = points[1] x2, y2 = points[2] x3, y3 = points[3] x4, y4 = points[4] xN, yN = points[5] xC = (x2+x3) / 2.0 yC = (y2+y3) / 2.0 path.moveTo(x0, y0) path.cubicTo(x1, y1, x2, y2, xC, yC) path.cubicTo(x3, y3, x4, y4, xN, yN) else: x0, y0 = points[0] xN, yN = points[-1] path.moveTo(x0, y0) path.lineTo(xN, yN) return path
def _updatePath(self): p0 = self._startPos p1 = self._endPos if p0 is None or p1 is None: return path = QPainterPath() path.moveTo(p0) dx = p1.x() - p0.x() x0 = p0.x() + 0.7 * dx x1 = p1.x() - 0.7 * dx path.cubicTo(QPointF(x0, p0.y()), QPointF(x1, p1.y()), p1) self.setPath(path)
def qpainterpath_simple_split(path, t): """ Split a QPainterPath defined simple curve. The path must be either empty or composed of a single LineToElement or CurveToElement. Parameters ---------- path : QPainterPath t : float Point where to split specified as a percentage along the path Returns ------- splitpath: Tuple[QPainterPath, QPainterPath] A pair of QPainterPaths """ assert path.elementCount() > 0 el0 = path.elementAt(0) assert el0.type == QPainterPath.MoveToElement if path.elementCount() == 1: p1 = QPainterPath() p1.moveTo(el0.x, el0.y) return p1, QPainterPath(p1) el1 = path.elementAt(1) if el1.type == QPainterPath.LineToElement: pointat = path.pointAtPercent(t) l1 = QLineF(el0.x, el0.y, pointat.x(), pointat.y()) l2 = QLineF(pointat.x(), pointat.y(), el1.x, el1.y) p1 = QPainterPath() p2 = QPainterPath() p1.addLine(l1) p2.addLine(l2) return p1, p2 elif el1.type == QPainterPath.CurveToElement: c0, c1, c2, c3 = el0, el1, path.elementAt(2), path.elementAt(3) assert all(el.type == QPainterPath.CurveToDataElement for el in [c2, c3]) cp = [QPointF(el.x, el.y) for el in [c0, c1, c2, c3]] first, second = bezier_subdivide(cp, t) p1, p2 = QPainterPath(), QPainterPath() p1.moveTo(first[0]) p1.cubicTo(*first[1:]) p2.moveTo(second[0]) p2.cubicTo(*second[1:]) return p1, p2 else: assert False
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 paint(self, painter, option, widget=None): myPen = self.pen() myPen.setColor(self.myColor) painter.setPen(myPen) painter.setBrush(self.myColor) controlPoints = [] endPt = self.endItem.getLinkPointForParameter(self.endIndex) startPt = self.startItem.getLinkPointForOutput(self.startIndex) if isinstance(self.startItem.element, Algorithm): if self.startIndex != -1: controlPoints.append(self.startItem.pos() + startPt) controlPoints.append(self.startItem.pos() + startPt + QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt) pt = QPointF(self.startItem.pos() + startPt + QPointF(-3, -3)) painter.drawEllipse(pt.x(), pt.y(), 6, 6) pt = QPointF(self.endItem.pos() + endPt + QPointF(-3, -3)) painter.drawEllipse(pt.x(), pt.y(), 6, 6) else: # Case where there is a dependency on an algorithm not # on an output controlPoints.append(self.startItem.pos() + startPt) controlPoints.append(self.startItem.pos() + startPt + QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt) else: controlPoints.append(self.startItem.pos()) controlPoints.append(self.startItem.pos() + QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 2, 0)) controlPoints.append(self.endItem.pos() + endPt) pt = QPointF(self.endItem.pos() + endPt + QPointF(-3, -3)) painter.drawEllipse(pt.x(), pt.y(), 6, 6) path = QPainterPath() path.moveTo(controlPoints[0]) path.cubicTo(*controlPoints[1:]) painter.strokePath(path, painter.pen()) self.setPath(path)
def paintEvent(self, QPaintEvent): back = (numpy.ones((100, 200, 300)) * 0).astype(numpy.uint8) back[0:60, 0:60, 0:60] = 255 ol = (numpy.zeros((100, 200, 300))).astype(numpy.uint8) ol[0:99, 0:99, 0:99] = 120 ol[0:99, 120:140, 0:99] = 255 path = QPainterPath() path.addRect(20, 20, 60, 60) path.moveTo(0, 0) path.cubicTo(99, 0, 50, 50, 99, 99) path.cubicTo(0, 99, 50, 50, 0, 0) painter = QPainter(self) painter.fillRect(0, 0, 100, 100, Qt.Qt.red)
def __updateCurve(self): self.prepareGeometryChange() if self.sourceAnchor and self.sinkAnchor: source_pos = self.sourceAnchor.anchorScenePos() sink_pos = self.sinkAnchor.anchorScenePos() source_pos = self.curveItem.mapFromScene(source_pos) sink_pos = self.curveItem.mapFromScene(sink_pos) # TODO: get the orthogonal angle to the anchors path. path = QPainterPath() path.moveTo(source_pos) path.cubicTo(source_pos + QPointF(60, 0), sink_pos - QPointF(60, 0), sink_pos) self.curveItem.setPath(path) self.sourceIndicator.setPos(source_pos) self.sinkIndicator.setPos(sink_pos) self.__updateText() else: self.setHoverState(False) self.curveItem.setPath(QPainterPath())
def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) angle = math.pi / 2 bLine1 = QLineF() bLine1.setP1(startPoint) if startPoint.x() > endPoint.x(): dist = startPoint.x() - endPoint.x() one = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) bLine1.setP1(endPoint) two = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) path.cubicTo(one, two, endPoint) return path, QLineF(one, two)
def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) if startPoint.x() > endPoint.x(): dist = (startPoint.x() - endPoint.x()) * 2 tLine = QLineF((dist / 2), 0.0, -(dist / 2), 0.0).translated(QLineF(startPoint, endPoint).pointAt(0.5)) one = tLine.p1() two = tLine.p2() path.cubicTo(one, two, endPoint) self.__path = path return path, QLineF(one, two)
def updatePath(self): self.endPoints = [] controlPoints = [] endPt = self.endItem.getLinkPointForParameter(self.endIndex) startPt = self.startItem.getLinkPointForOutput(self.startIndex) if isinstance(self.startItem.element, Algorithm): if self.startIndex != -1: controlPoints.append(self.startItem.pos() + startPt) controlPoints.append(self.startItem.pos() + startPt + QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt) pt = QPointF(self.startItem.pos() + startPt + QPointF(-3, -3)) self.endPoints.append(pt) pt = QPointF(self.endItem.pos() + endPt + QPointF(-3, -3)) self.endPoints.append(pt) else: # Case where there is a dependency on an algorithm not # on an output controlPoints.append(self.startItem.pos() + startPt) controlPoints.append(self.startItem.pos() + startPt + QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt) else: controlPoints.append(self.startItem.pos()) controlPoints.append(self.startItem.pos() + QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt - QPointF(ModelerGraphicItem.BOX_WIDTH / 3, 0)) controlPoints.append(self.endItem.pos() + endPt) pt = QPointF(self.endItem.pos() + endPt + QPointF(-3, -3)) self.endPoints.append(pt) path = QPainterPath() path.moveTo(controlPoints[0]) path.cubicTo(*controlPoints[1:]) self.setPath(path)
def polygonToCurvedPath(polygon, radius): path = QPainterPath() for i, pt in enumerate(polygon): # TODO: if two points are too close to draw the desired radius, either remove those points or draw at smaller radius px, py = polygon[i - 1] if i > 0 else polygon[-1] nx, ny = polygon[i + 1] if i < len(polygon) - 1 else polygon[0] x, y = pt if px == x: dy = y - py r = radius if dy < 0 else -radius p1 = QPointF(x, y + r) else: dx = x - px r = radius if dx < 0 else -radius p1 = QPointF(x + r, y) if x == nx: dy = y - ny r = radius if dy < 0 else -radius p2 = QPointF(x, y + r) else: dx = x - nx r = radius if dx < 0 else -radius p2 = QPointF(x + r, y) if i == 0: path.moveTo(p1) else: path.lineTo(p1) path.cubicTo(pt, pt, p2) path.closeSubpath() return path
def polygonToCurvedPath(polygon, radius): path = QPainterPath() for i, pt in enumerate(polygon): # TODO: if two points are too close to draw the desired radius, either remove those points or draw at smaller radius px, py = polygon[i-1] if i > 0 else polygon[-1] nx, ny = polygon[i+1] if i < len(polygon) - 1 else polygon[0] x, y = pt if px == x: dy = y - py r = radius if dy < 0 else -radius p1 = QPointF(x, y + r) else: dx = x - px r = radius if dx < 0 else -radius p1 = QPointF(x + r, y) if x == nx: dy = y - ny r = radius if dy < 0 else -radius p2 = QPointF(x, y + r) else: dx = x - nx r = radius if dx < 0 else -radius p2 = QPointF(x + r, y) if i == 0: path.moveTo(p1) else: path.lineTo(p1) path.cubicTo(pt, pt, p2) path.closeSubpath() return path
def paintEvent(self, event): option = QStyleOption() option.initFrom(self) contents_rect = self.style().subElementRect(QStyle.SE_FrameContents, option, self) or self.contentsRect() # the SE_FrameContents rect is Null unless the stylesheet defines decorations if self.graphStyle == self.BarStyle: graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width()) / self.horizontalPixelsPerUnit)) else: graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width() - 1) / self.horizontalPixelsPerUnit) + 1) max_value = self.__dict__['max_value'] = max(chain([0], *(islice(reversed(graph.data), graph_width) for graph in self.graphs if graph.enabled))) if self.graphHeight == self.AutomaticHeight or self.graphHeight < 0: graph_height = self.__dict__['graph_height'] = max(self.scaler.get_height(max_value), self.minHeight) else: graph_height = self.__dict__['graph_height'] = max(self.graphHeight, self.minHeight) if self.graphStyle == self.BarStyle: height_scaling = float(contents_rect.height()) / graph_height else: height_scaling = float(contents_rect.height() - self.lineThickness) / graph_height painter = QStylePainter(self) painter.drawPrimitive(QStyle.PE_Widget, option) painter.setClipRect(contents_rect) painter.save() painter.translate(contents_rect.x() + contents_rect.width() - 1, contents_rect.y() + contents_rect.height() - 1) painter.scale(-1, -1) painter.setRenderHint(QStylePainter.Antialiasing, self.graphStyle != self.BarStyle) for graph in (graph for graph in self.graphs if graph.enabled and graph.data): if self.boundary is not None and 0 < self.boundary < graph_height: boundary_width = min(5.0/height_scaling, self.boundary-0, graph_height-self.boundary) pen_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling) pen_color.setColorAt(0, graph.color) pen_color.setColorAt(1, graph.over_boundary_color) brush_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling) brush_color.setColorAt(0, self.color_with_alpha(graph.color, self.fillTransparency)) brush_color.setColorAt(1, self.color_with_alpha(graph.over_boundary_color, self.fillTransparency)) else: pen_color = graph.color brush_color = self.color_with_alpha(graph.color, self.fillTransparency) dataset = islice(reversed(graph.data), graph_width) if self.graphStyle == self.BarStyle: lines = [QLine(x*self.horizontalPixelsPerUnit, 0, x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)] painter.setPen(QPen(pen_color, self.lineThickness)) painter.drawLines(lines) else: painter.translate(0, +self.lineThickness/2 - 1) if self.smoothEnvelope and self.smoothFactor > 0: min_value = 0 max_value = graph_height * height_scaling cx_offset = self.horizontalPixelsPerUnit / 3.0 smoothness = self.smoothFactor last_values = deque(3*[dataset.next() * height_scaling], maxlen=3) # last 3 values: 0 last, 1 previous, 2 previous previous envelope = QPainterPath() envelope.moveTo(0, last_values[0]) for x, y in enumerate(dataset, 1): x = x * self.horizontalPixelsPerUnit y = y * height_scaling * (1 - smoothness) + last_values[0] * smoothness last_values.appendleft(y) c1x = x - cx_offset * 2 c2x = x - cx_offset c1y = limit((1 + smoothness) * last_values[1] - smoothness * last_values[2], min_value, max_value) # same gradient as previous previous value to previous value c2y = limit((1 - smoothness) * last_values[0] + smoothness * last_values[1], min_value, max_value) # same gradient as previous value to last value envelope.cubicTo(c1x, c1y, c2x, c2y, x, y) else: envelope = QPainterPath() envelope.addPolygon(QPolygonF([QPointF(x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)])) if self.fillEnvelope or graph.fill_envelope: first_element = envelope.elementAt(0) last_element = envelope.elementAt(envelope.elementCount() - 1) fill_path = QPainterPath() fill_path.moveTo(last_element.x, last_element.y) fill_path.lineTo(last_element.x + 1, last_element.y) fill_path.lineTo(last_element.x + 1, -self.lineThickness) fill_path.lineTo(-self.lineThickness, -self.lineThickness) fill_path.lineTo(-self.lineThickness, first_element.y) fill_path.connectPath(envelope) painter.fillPath(fill_path, brush_color) painter.strokePath(envelope, QPen(pen_color, self.lineThickness, join=Qt.RoundJoin)) painter.translate(0, -self.lineThickness/2 + 1) if self.boundary is not None and self.boundaryColor: painter.setRenderHint(QStylePainter.Antialiasing, False) painter.setPen(QPen(self.boundaryColor, 1.0)) painter.drawLine(0, self.boundary*height_scaling, contents_rect.width(), self.boundary*height_scaling) painter.restore() # queue the 'updated' signal to be emited after returning to the main loop QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
def paint(self, painter, rect, widget_size, draw_highlight): GraphXYView.paint(self, painter, rect, widget_size, draw_highlight) smooth = 2.5 # this is invert smoothing, increase it to sharpen graph if not self.model(): return option = self.viewOptions() background = option.palette.base() foreground = QPen(option.palette.color(QPalette.Foreground)) # Handle step by step size increment step_width = floor(widget_size.width() / RESIZE_INCREMENT) * RESIZE_INCREMENT step_height = floor(widget_size.height() / RESIZE_INCREMENT) * RESIZE_INCREMENT if self.model().rowCount(self.rootIndex()) != 0: value_max = self.getValueMaxAll() else: value_max = 0 # If there is no data yet, or the max is at 0, use a max of 10 to dispaly an axe if self.fetcher.fragment.type == 'LoadStream': if value_max < 100: value_max = 100 else: if value_max == 0: value_max = 10 if len(self.data) != 0: xmin = self.getValueMin(0) xmax = self.getValueMax(0) else: return if xmin == xmax: return # avoid division by 0 painter.save() # Offset to cerrectly center the graph after the resizing due to the step by step increment painter.translate((widget_size.width() - step_width) / 2.0, (widget_size.height() - step_height) / 2.0) painter.setPen(foreground) # Draw lines fm = QFontMetrics(painter.font()) margin_size = fm.width("0") if self.fetcher.fragment.type == 'TrafficStream': x_axe_off = fm.width(unicode(value_max * 2000)) else: x_axe_off = fm.width(unicode(value_max * 200)) # Order them by max mean value means = {} for col in xrange(1, len(self.data[0])): means[col] = self.getMeanValue(col) def mean_sorter(x, y): return cmp(y[1], x[1]) means_sorted = means.items() means_sorted.sort(mean_sorter) def slope_by_index(points, index, sens): if index >= len(points): return 0 if index == 0: return points[index].y() + (points[index+1].y()-points[index].y())/smooth if index == (len(points) - 1): return points[index].y() - (points[index].y()-points[index-1].y())/smooth vpoints = [ points[index-1].y(), points[index].y(), points[index+1].y()] if points[index].y() == max(vpoints): return points[index].y() if points[index].y() == min(vpoints): return points[index].y() if sens == 0: return points[index].y() + (points[index+1].y()-points[index].y())/smooth #return points[index].y() + (points[index+1].y() - points[index-1].y()) / (points[index+1].x()-points[index-1].x()) * (points[index+1].x() - points[index].x()) / smooth else: return points[index].y() - (points[index].y()-points[index-1].y())/smooth #return points[index].y() + (points[index+1].y() - points[index-1].y()) / (points[index+1].x()-points[index-1].x()) * (points[index-1].x() - points[index].x()) / smooth colors = odict() for _col in means_sorted: col = _col[0] path = QPainterPath() path.setFillRule(Qt.WindingFill) last_point = None height_max = 0.0 width_max = step_width - 2 * margin_size - x_axe_off height_max = (step_height * (1.0 - TITLE_AREA)) - 2 * margin_size points = [] for row in xrange(len(self.data)): index = self.model().index(row, col, self.rootIndex()) value = index.data().toInt()[0] x_value = int(self.data[row][0]) #print "x=", x_value, "y=", value if value >= 0.0: height = height_max * value/value_max x = (float(x_value - xmin) / float(xmax - xmin)) * width_max point = QPointF(x + margin_size + x_axe_off, height_max - height + margin_size) points.append(point) for index, point in enumerate(points): # draw simple point painter.setBrush(QBrush(QColor(self.colours[col]).dark(200))) painter.drawEllipse(QRectF(point.x() - 2, point.y() - 2, 4, 4)) # init drawing if index == 0: path.moveTo(point) continue px = points[index-1].x() + (points[index].x() - points[index-1].x()) / smooth py = slope_by_index(points, index-1, 0) c1 = QPointF(px, py) px = points[index].x() - ( points[index].x() - points[index-1].x() ) / smooth py = slope_by_index(points, index, 1) c2 = QPointF(px, py) path.cubicTo(c1, c2, point) last_point = points[len(points)-1] if last_point: txt = self.model().headerData(col, Qt.Horizontal).toString() txt_width = fm.width(txt) txt_height = fm.height() colors[txt] = QColor(self.colours[col]) path.lineTo(QPointF(x + margin_size + x_axe_off, height_max + margin_size)) path.lineTo(QPointF(margin_size + x_axe_off, height_max + margin_size)) color = QColor(self.colours[col]) color.setAlpha(200) ## Create the gradient effect grad = QLinearGradient(QPointF(0.0, 0.0), QPointF(0.0, height_max)) grad.setColorAt(1.0, color.dark(150)) grad.setColorAt(0.95, color) grad.setColorAt(0.05, color) grad.setColorAt(0.0, Qt.white) painter.setBrush(QBrush(grad)) painter.drawPath(path) # Graduations nbr_grad = xmax - xmin dgrad = 1 while nbr_grad > 10: nbr_grad = floor(nbr_grad / 10) dgrad = dgrad * 10 if nbr_grad <= 2: dgrad = dgrad / 10 nbr_grad = 10 # Prevent for infinite loops. if dgrad < 1: dgrad = 1 dx = (float(dgrad) / float(xmax-xmin)) * width_max text_dy = fm.height() i = 0 while (i * dgrad) <= xmax - xmin: if self.fetcher.fragment.type != 'TrafficStream' or (self.fetcher.fragment.type == 'TrafficStream' and i % 4 == 0): grad_width = fm.width("0") painter.drawLine(margin_size + x_axe_off + (i*dx), height_max + margin_size, margin_size + x_axe_off + (i*dx), height_max + margin_size + grad_width) text = unicode(int(dgrad * i)) # Legend drawing: painter.translate(margin_size + x_axe_off + (i*dx), height_max + margin_size + 2*grad_width) painter.rotate(-45.0) int_time = (i * dgrad) + xmin text = QString('%ds' % (xmax - int_time)) txt_width = fm.width(text) painter.drawText(QRect(-txt_width, -dx, txt_width, 2*dx), Qt.AlignRight|Qt.AlignVCenter, text) painter.rotate(45.0) painter.translate(-(margin_size + x_axe_off + (i*dx)), -(height_max + margin_size + 2*grad_width)) i = i + 1 interval = 0 height = height_max + margin_size + txt_width * sin(45) + 30 for k, v in colors.iteritems(): painter.setPen(v) legendRect = QRect(interval, height, 10, 10) painter.drawRect(legendRect) painter.fillRect(legendRect, QBrush(v)) painter.setPen(foreground) txt_width = fm.width(k) txt_height = fm.height() painter.drawText(QRect(interval + 10, height, txt_width, txt_height), Qt.AlignRight|Qt.AlignVCenter, k) interval += 20 + txt_width painter.translate((step_width - widget_size.width()) / 2.0, (step_height - widget_size.height()) / 2.0) painter.restore()
# from lazyflow.operators import OpCompressedCache from PyQt4 import QtCore, uic from PyQt4.QtGui import QApplication, QPainter, QPainterPath from PyQt4 import QtGui from PyQt4 import Qt app = QtGui.QApplication([]) scene = QtGui.QGraphicsScene() scene.addText("Hello World!") back = (numpy.ones((100, 200, 300)) * 0).astype(numpy.uint8) back[0:60, 0:60, 0:60] = 255 ol = (numpy.zeros((100, 200, 300))).astype(numpy.uint8) ol[0:99, 0:99, 0:99] = 120 ol[0:99, 120:140, 0:99] = 255 path = QPainterPath() path.addRect(20, 20, 60, 60) path.moveTo(0, 0) path.cubicTo(99, 0, 50, 50, 99, 99) path.cubicTo(0, 99, 50, 50, 0, 0) scene.addPath(path) view = QtGui.QGraphicsView(scene) view.show() app.exec_()
def render(o): path = QPainterPath() # unit_x gives offset and direction of the x base vector. Start and end should be the grid points. # move the endpoints inwards an unnoticable bit, so that the intersection detector # won't trip on the common endpoint. u_x = QLineF(o.unit_x.pointAt(0.0001), o.unit_x.pointAt(0.9999)) path.moveTo(u_x.p1()) if o.is_straight: path.lineTo(u_x.p2()) return path if o.flipped: u_x = QLineF(u_x.p2(), u_x.p1()) u_y = u_x.normalVector() # move y unit to start at (0,0). u_y.translate(-u_y.p1()) scaling = o.length_base / u_x.length() * o.size_correction if o.basewidth * scaling > 0.8: # Plug is too large for the edge length. Make it smaller. scaling = 0.8 / o.basewidth # some magic numbers here... carefully fine-tuned, better leave them as they are. ends_ctldist = 0.4 #base_lcdist = 0.1 * scaling base_ucdist = 0.05 * scaling knob_lcdist = 0.6 * o.knobsize * scaling knob_ucdist = 0.8 * o.knobsize * scaling # set up piece -- here is where the really interesting stuff happens. # We will work from the ends inwards, so that symmetry counterparts are adjacent. # The QLine.pointAt function is used to transform everything into the coordinate # space defined by the us. # -- end points r1y = ends_ctldist * o.basepos * dsin(o.startangle) q6y = ends_ctldist * (1. - o.basepos) * dsin(o.endangle) p1 = u_x.p1() p6 = u_x.p2() r1 = u_x.pointAt( ends_ctldist * o.basepos * dcos(o.startangle)) + u_y.pointAt(r1y) q6 = u_x.pointAt(1. - ends_ctldist * (1. - o.basepos) * dcos(o.endangle)) + u_y.pointAt(q6y) # -- base points p2x = o.basepos - 0.5 * o.basewidth * scaling p5x = o.basepos + 0.5 * o.basewidth * scaling if p2x < 0.1 or p5x > 0.9: # knob to large. center knob on the edge. (o.basewidth * scaling < 0.8 -- see above) p2x = 0.5 - 0.5 * o.basewidth * scaling p5x = 0.5 + 0.5 * o.basewidth * scaling #base_y = r1y > q6y ? r1y : q6y #base_y = 0.5*(r1y + q6y) base_y = -o.baseroundness * ends_ctldist * min(p2x, 1. - p5x) if base_y > 0: base_y = 0 base_lcy = base_y * 2.0 base_y += base_ucdist / 2 base_lcy -= base_ucdist / 2 #base_lcy = r1y #if (q6y < r1y): base_lcy = q6y # at least -base_ucdist from base_y #if (base_lcy > base_y - base_ucdist): base_lcy = base_y-base_ucdist q2 = u_x.pointAt(p2x) + u_y.pointAt(base_lcy) r5 = u_x.pointAt(p5x) + u_y.pointAt(base_lcy) p2 = u_x.pointAt(p2x) + u_y.pointAt(base_y) p5 = u_x.pointAt(p5x) + u_y.pointAt(base_y) r2 = u_x.pointAt(p2x) + u_y.pointAt(base_y + base_ucdist) q5 = u_x.pointAt(p5x) + u_y.pointAt(base_y + base_ucdist) if o._is_plugless: if not o.flipped: path.cubicTo(r1, q2, p2) path.cubicTo(r2, q5, p5) path.cubicTo(r5, q6, p6) else: path.cubicTo(q6, r5, p5) path.cubicTo(q5, r2, p2) path.cubicTo(q2, r1, p1) return path # -- knob points p3x = p2x - o.knobsize * scaling * dsin(o.knobangle - o.knobtilt) p4x = p5x + o.knobsize * scaling * dsin(o.knobangle + o.knobtilt) # for the y coordinate, knobtilt sign was swapped. Knobs look better this way... # like x offset from base points y, but that is 0. p3y = o.knobsize * scaling * dcos(o.knobangle + o.knobtilt) + base_y p4y = o.knobsize * scaling * dcos(o.knobangle - o.knobtilt) + base_y q3 = u_x.pointAt(p3x) + u_y.pointAt(p3y - knob_lcdist) r4 = u_x.pointAt(p4x) + u_y.pointAt(p4y - knob_lcdist) p3 = u_x.pointAt(p3x) + u_y.pointAt(p3y) p4 = u_x.pointAt(p4x) + u_y.pointAt(p4y) r3 = u_x.pointAt(p3x) + u_y.pointAt(p3y + knob_ucdist) q4 = u_x.pointAt(p4x) + u_y.pointAt(p4y + knob_ucdist) # done setting up. construct path. # if flipped, add points in reverse. if not o.flipped: path.cubicTo(r1, q2, p2) path.cubicTo(r2, q3, p3) path.cubicTo(r3, q4, p4) path.cubicTo(r4, q5, p5) path.cubicTo(r5, q6, p6) else: path.cubicTo(q6, r5, p5) path.cubicTo(q5, r4, p4) path.cubicTo(q4, r3, p3) path.cubicTo(q3, r2, p2) path.cubicTo(q2, r1, p1) return path