def paint(self, p, *args): pen = self.region.lines[0].pen rgn = self.getLevels() if self.orientation == 'horizontal': p1 = self.vb.mapFromViewToItem( self, Point(rgn[0], self.vb.viewRect().center().y())) p2 = self.vb.mapFromViewToItem( self, Point(rgn[1], self.vb.viewRect().center().y())) gradRect = self.gradient.mapRectToParent( self.gradient.gradRect.rect()) for pen in [fn.mkPen('k', width=3), pen]: p.setPen(pen) p.drawLine(p1, gradRect.bottomLeft()) p.drawLine(p2, gradRect.bottomRight()) p.drawLine(gradRect.bottomLeft(), gradRect.topLeft()) p.drawLine(gradRect.bottomRight(), gradRect.topRight()) elif self.orientation == 'vertical': p1 = self.vb.mapFromViewToItem( self, Point(self.vb.viewRect().center().x(), rgn[0])) p2 = self.vb.mapFromViewToItem( self, Point(self.vb.viewRect().center().x(), rgn[1])) gradRect = self.gradient.mapRectToParent( self.gradient.gradRect.rect()) for pen in [fn.mkPen('k', width=3), pen]: p.setPen(pen) p.drawLine(p1, gradRect.bottomLeft()) p.drawLine(p2, gradRect.topLeft()) p.drawLine(gradRect.topLeft(), gradRect.topRight()) p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
def mouseDragEvent(self, ev, axis=None): """Customized mouse dragging, where the right drag is bounding box zoom :param ev: event object containing drag state info :type ev: :py:class:`MouseDragEvent<pyqtgraph:pyqtgraph.GraphicsScene.mouseEvents.MouseDragEvent>` """ if self._customMouse and ev.button() == QtCore.Qt.RightButton: ev.accept() # we accept all buttons # directly copy-pasted from ViewBox for ViewBox.RectMode if ev.isFinish( ): # This is the final move in the drag; change the view scale now # print "finish" pos = ev.pos() self.rbScaleBox.hide() # ax = QtCore.QRectF(Point(self.pressPos), Point(self.mousePos)) ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos)) ax = self.childGroup.mapRectFromParent(ax) self.showAxRect(ax) self.axHistoryPointer += 1 self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax] else: # update shape of scale box self.updateScaleBox(ev.buttonDownPos(), ev.pos()) else: state = None # ctrl reverses mouse operation axis if ev.modifiers() == QtCore.Qt.ControlModifier: state = self.mouseEnabled() self.setMouseEnabled(not state[0], not state[1]) super(SpikeyViewBox, self).mouseDragEvent(ev, axis) if state is not None: self.setMouseEnabled(*state)
def mouseMoveEvent(self, ev): if self.lastMousePos is None: self.lastMousePos = Point(ev.pos()) delta = Point(ev.pos() - self.lastMousePos) self.lastMousePos = Point(ev.pos()) QtGui.QGraphicsView.mouseMoveEvent(self, ev) if not self.mouseEnabled: return self.sigSceneMouseMoved.emit(self.mapToScene(ev.pos())) if self.clickAccepted: ## Ignore event if an item in the scene has already claimed it. return if ev.buttons() == QtCore.Qt.RightButton: delta = Point(np.clip(delta[0], -50, 50), np.clip(-delta[1], -50, 50)) scale = 1.01**delta self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos)) self.sigRangeChanged.emit(self, self.range) elif ev.buttons() in [QtCore.Qt.MidButton, QtCore.Qt.LeftButton ]: ## Allow panning by left or mid button. px = self.pixelSize() tr = -delta * px self.translate(tr[0], tr[1]) self.sigRangeChanged.emit(self, self.range)
def test_selection_line(self): event = Mock() event.button.return_value = Qt.LeftButton event.buttonDownPos.return_value = Point(0, 0) event.pos.return_value = Point(1, 1) event.isFinish.return_value = True # drag a line before data is sent self.widget.graph.view_box.mouseDragEvent(event) self.assertIsNone(self.widget.selection) # drag a line after data is sent self.send_signal(self.widget.Inputs.data, self.data) # set view-dependent click coordinates event.buttonDownPos.return_value = QPointF(2.38, 4.84) event.pos.return_value = QPointF(3.58, 4.76) self.widget.graph.view_box.mouseDragEvent(event) line = self.widget.graph.view_box.selection_line self.assertFalse(line.line().isNull()) # click on the plot resets selection self.assertEqual(len(self.widget.selection), 55) self.widget.graph.view_box.mouseClickEvent(event) self.assertListEqual(self.widget.selection, [])
def pixelSize(self): """Return vector with the length and width of one view pixel in scene coordinates""" p0 = Point(0, 0) p1 = Point(1, 1) tr = self.transform().inverted()[0] p01 = tr.map(p0) p11 = tr.map(p1) return Point(p11 - p01)
def plotVolue(self,xAxis,yAxis): if self.xData: if int(round(xAxis)) <=len(self.xData)-1: xValue =self.xData[int(round(xAxis))] elif int(xAxis)>len(self.xData)-1: xValue=self.xData[len(self.xData)-1] else: xValue = self.xData[int(xAxis)] if (isinstance(xValue, dt.datetime)): xValueText = dt.datetime.strftime(xValue, '%Y-%m-%d %H:%M:%S') elif (isinstance(xValue, (str))): xValueText = xValue elif (isinstance(xValue, (int))): xValueText = xValue else: xValueText = "" else: xValueText=xAxis self.__textDate.setHtml( '<div style="text-align: center">\ <span style="color: yellow; font-size: 20px;">x=%s</span>\ </div>' \ % (xValueText)) self.__textSig.setHtml( '<div style="text-align: right">\ <span style="color: yellow; font-size: 20px;">y=%0.2f</span>\ </div>' \ % (yAxis)) # y,右上角显示 rightAxis = self.__view.getAxis('right') rightAxisWidth = rightAxis.width() rectTextsig = self.__textDate.boundingRect() rectTextsigwidth = rectTextsig.width() topRight = self.__view.vb.mapSceneToView( QtCore.QPointF(self.rects[0].width() - (rightAxisWidth+rectTextsigwidth), self.rects[0].top())) if yAxis<self.rects[0].top(): self.__textSig.anchor=Point((1,1)); else: self.__textSig.anchor = Point((1, 0)); self.__textSig.setPos(topRight.x(), yAxis) # X坐标时间显示 rectTextDate = self.__textDate.boundingRect() rectTextDateHeight = rectTextDate.height() bottomAxis = self.__view.getAxis('bottom') bottomAxisHeight = bottomAxis.height() bottomRight = self.__view.vb.mapSceneToView(QtCore.QPointF(self.rects[0].width(), \ self.rects[0].bottom() - ( bottomAxisHeight + rectTextDateHeight))) # # 修改对称方式防止遮挡 if xAxis >self.rects[0].width(): self.__textDate.anchor = Point((1, 0)) else: self.__textDate.anchor = Point((0, 0)) self.__textDate.setPos(xAxis, bottomRight.y())
def pixelLength(self, direction): """Return the length of one pixel in the direction indicated (in local coordinates)""" dt = self.deviceTransform() if dt is None: return None viewDir = Point(dt.map(direction) - dt.map(Point(0, 0))) norm = viewDir.norm() dti = dt.inverted()[0] return Point(dti.map(norm) - dti.map(Point(0, 0))).length()
def transformAngle(self, relativeItem=None): """Return the rotation produced by this item's transform (this assumes there is no shear in the transform) If relativeItem is given, then the angle is determined relative to that item. """ if relativeItem is None: relativeItem = self.parentItem() tr = self.itemTransform(relativeItem) if isinstance(tr, tuple): ## difference between pyside and pyqt tr = tr[0] vec = tr.map(Point(1, 0)) - tr.map(Point(0, 0)) return Point(vec).angle(Point(1, 0))
def mouseDragEvent(self, ev, axis=None): ## if axis is specified, event will only affect that axis. ev.accept() ## we accept all buttons pos = ev.pos() lastPos = ev.lastPos() dif = pos - lastPos dif = dif * -1 ## Ignore axes if mouse is disabled mask = np.array(self.state['mouseEnabled'], dtype=np.float) if axis is not None: mask[1 - axis] = 0.0 ## Scale or translate based on mouse button if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton): if self.state['mouseMode'] == ViewBox.RectMode: if ev.isFinish( ): ## This is the final move in the drag; change the view scale now #print "finish" self.rbScaleBox.hide() #ax = QtCore.QRectF(Point(self.pressPos), Point(self.mousePos)) ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos)) ax = self.childGroup.mapRectFromParent(ax) self.showAxRect(ax) self.axHistoryPointer += 1 self.axHistory = self.axHistory[:self.axHistoryPointer] + [ ax ] else: ## update shape of scale box self.updateScaleBox(ev.buttonDownPos(), ev.pos()) else: tr = dif * mask tr = self.mapToView(tr) - self.mapToView(Point(0, 0)) self.translateBy(tr) self.sigRangeChangedManually.emit(self.state['mouseEnabled']) elif ev.button() & QtCore.Qt.RightButton: #print "vb.rightDrag" if self.state['aspectLocked'] is not False: mask[0] = 0 dif = ev.screenPos() - ev.lastScreenPos() dif = np.array([dif.x(), dif.y()]) dif[0] *= -1 s = ((mask * 0.02) + 1)**dif center = Point(self.childGroup.transform().inverted()[0].map( ev.buttonDownPos(QtCore.Qt.RightButton))) #center = Point(ev.buttonDownPos(QtCore.Qt.RightButton)) self.scaleBy(s, center) self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
def updateLine(self): start = Point(self.source.connectPoint()) if isinstance(self.target, TerminalGraphicsItem): stop = Point(self.target.connectPoint()) elif isinstance(self.target, QtCore.QPointF): stop = Point(self.target) else: return self.prepareGeometryChange() self.path = self.generatePath(start, stop) self.shapePath = None self.update()
def generatePath(self, start, stop): path = QtGui.QPainterPath() path.moveTo(start) if self.style['shape'] == 'line': path.lineTo(stop) elif self.style['shape'] == 'cubic': path.cubicTo(Point(stop.x(), start.y()), Point(start.x(), stop.y()), Point(stop.x(), stop.y())) else: raise Exception( 'Invalid shape "%s"; options are "line" or "cubic"' % self.style['shape']) return path
def _update_scale_box(self, button_down_pos, current_pos): x, y = current_pos if button_down_pos[0] == x: x += 1 if button_down_pos[1] == y: y += 1 self.updateScaleBox(button_down_pos, Point(x, y))
def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None): """ ============= ================================================================== **Arguments** pos Position of the line. This can be a QPointF or a single value for vertical/horizontal lines. angle Angle of line in degrees. 0 is horizontal, 90 is vertical. pen Pen to use when drawing line. Can be any arguments that are valid for :func:`mkPen <pyqtgraph.mkPen>`. Default pen is transparent yellow. movable If True, the line can be dragged to a new position by the user. bounds Optional [min, max] bounding values. Bounds are only valid if the line is vertical or horizontal. ============= ================================================================== """ UIGraphicsItem.__init__(self) if bounds is None: ## allowed value boundaries for orthogonal lines self.maxRange = [None, None] else: self.maxRange = bounds self.moving = False self.setMovable(movable) self.mouseHovering = False self.p = [0, 0] self.setAngle(angle) if pos is None: pos = Point(0,0) self.setPos(pos) if pen is None: pen = (200, 200, 100) self.setPen(pen) self.currentPen = self.pen
def setPos(self, pos): if type(pos) in [list, tuple]: newPos = pos elif isinstance(pos, QtCore.QPointF): newPos = [pos.x(), pos.y()] else: if self.angle == 90: newPos = [pos, 0] elif self.angle == 0: newPos = [0, pos] else: raise Exception("Must specify 2D coordinate for non-orthogonal lines.") ## check bounds (only works for orthogonal lines) if self.angle == 90: if self.maxRange[0] is not None: newPos[0] = max(newPos[0], self.maxRange[0]) if self.maxRange[1] is not None: newPos[0] = min(newPos[0], self.maxRange[1]) elif self.angle == 0: if self.maxRange[0] is not None: newPos[1] = max(newPos[1], self.maxRange[0]) if self.maxRange[1] is not None: newPos[1] = min(newPos[1], self.maxRange[1]) if self.p != newPos: self.p = newPos UIGraphicsItem.setPos(self, Point(self.p)) self.update() self.sigPositionChanged.emit(self)
def safe_update_scale_box(self, buttonDownPos, currentPos): x, y = currentPos if buttonDownPos[0] == x: x += 1 if buttonDownPos[1] == y: y += 1 self.updateScaleBox(buttonDownPos, Point(x, y))
def wheelEvent(self, ev, axis=None): if axis in (0, 1): mask = [False, False] mask[axis] = self.state['mouseEnabled'][axis] else: mask = self.state['mouseEnabled'][:] s = 1.02**(ev.delta() * self.state['wheelScaleFactor'] ) # actual scaling factor s = [(None if m is False else s) for m in mask] center = Point( fn.invertQTransform(self.childGroup.transform()).map(ev.pos())) # JC added if ev.modifiers( ) == QtCore.Qt.ShiftModifier and s[0] is not None and s[1] is not None: for child in self.childGroup.childItems()[:]: if hasattr(child, 'accept_mousewheel_transformations'): m_old = child.transform() m = QtGui.QTransform() print(1, m_old.m22(), s[1]) m.scale(1, m_old.m22() * s[1]) child.setTransform(m) ev.accept() child_group_transformation = self.childGroup.transform() # self.childGroup.update() # self.autoRange() # self.updateAutoRange() # self.sigTransformChanged.emit(self) ## segfaults here: 1 print(self.viewRange()) print(self.targetRange()) return self._resetTarget() self.scaleBy(s, center) ev.accept() self.sigRangeChangedManually.emit(mask)
def wheelEvent(self, ev, axis=None): mask = np.array(self.state['mouseEnabled'], dtype=np.float) if axis is not None and axis >= 0 and axis < len(mask): mv = mask[axis] mask[:] = 0 mask[axis] = mv angleDelta = ev.angleDelta().y( ) if ev.angleDelta().y() != 0 else ev.angleDelta().x() if isinstance(ev, QWheelEvent): s = ((mask * 0.02) + 1)**(angleDelta * self.state['wheelScaleFactor'] ) # actual scaling factor else: s = ((mask * 0.02) + 1)**(ev.delta() * self.state['wheelScaleFactor'] ) # actual scaling factor center = Point( fn.invertQTransform(self.childGroup.transform()).map(ev.pos())) # center = ev.pos() self._resetTarget() self.scaleBy(s, center) self.sigRangeChangedManually.emit(self.state['mouseEnabled']) ev.accept()
def setRange(self, newRect=None, padding=0.05, lockAspect=None, propagate=True, disableAutoPixel=True): if disableAutoPixel: self.autoPixelRange = False if newRect is None: newRect = self.visibleRange() padding = 0 padding = Point(padding) newRect = QtCore.QRectF(newRect) pw = newRect.width() * padding[0] ph = newRect.height() * padding[1] newRect = newRect.adjusted(-pw, -ph, pw, ph) scaleChanged = False if self.range.width() != newRect.width() or self.range.height( ) != newRect.height(): scaleChanged = True self.range = newRect #print "New Range:", self.range if self.centralWidget is not None: self.centralWidget.setGeometry(self.range) self.updateMatrix(propagate) if scaleChanged: self.sigScaleChanged.emit(self)
def mouseDragEvent(self, ev, axis=None): ev.accept() ## we accept all buttons pos = ev.pos() lastPos = ev.lastPos() dif = pos - lastPos dif = dif * -1 ## Ignore axes if mouse is disabled mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float) mask = mouseEnabled.copy() if axis is not None: mask[1 - axis] = 0.0 if ev.button() == QtCore.Qt.RightButton: ev.ignore() elif ev.button() == QtCore.Qt.LeftButton: pg.ViewBox.mouseDragEvent(self, ev) else: tr = dif * mask tr = self.mapToView(tr) - self.mapToView(Point(0, 0)) x = tr.x() if mask[0] == 1 else None y = tr.y() if mask[1] == 1 else None self._resetTarget() if x is not None or y is not None: self.translateBy(x=x, y=y) self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
def pixelHeight(self): vt = self.deviceTransform() if vt is None: return 0 vt = vt.inverted()[0] return Point( vt.map(QtCore.QPointF(0, 1)) - vt.map(QtCore.QPointF(0, 0))).length()
def updateLine(self): start = Point(self.source.connectPoint()) if isinstance(self.target, TerminalGraphicsItem): stop = Point(self.target.connectPoint()) elif isinstance(self.target, QtCore.QPointF): stop = Point(self.target) else: return self.prepareGeometryChange() self.resetTransform() ang = (stop - start).angle(Point(0, 1)) if ang is None: ang = 0 self.rotate(ang) self.setPos(start) self.length = (start - stop).length() self.update()
def buttonDownScenePos(self, btn=None): """ Return the scene position of the mouse at the time *btn* was pressed. If *btn* is omitted, then the button that initiated the drag is assumed. """ if btn is None: btn = self.button() return Point(self._buttonDownScenePos[int(btn)])
def buttonDownScreenPos(self, btn=None): """ Return the screen position (pixels relative to widget) of the mouse at the time *btn* was pressed. If *btn* is omitted, then the button that initiated the drag is assumed. """ if btn is None: btn = self.button() return Point(self._buttonDownScreenPos[int(btn)])
def generateSpots(self, clear=True): if clear: for spot in self.spots: self.scene().removeItem(spot) self.spots = [] xmn = ymn = xmx = ymx = None ## apply defaults size = self.data['size'].copy() size[size<0] = self.opts['size'] pen = self.data['pen'].copy() pen[pen<0] = self.opts['pen'] ## note pen<0 checks for pen==None brush = self.data['brush'].copy() brush[brush<0] = self.opts['brush'] symbol = self.data['symbol'].copy() symbol[symbol==''] = self.opts['symbol'] for i in xrange(len(self.data)): s = self.data[i] pos = Point(s['x'], s['y']) if self.opts['pxMode']: psize = 0 else: psize = size[i] if self.pointData is None or self.pointData[i] is None: data = self.opts.get('data', None) else: data = self.pointData[i] #if xmn is None: #xmn = pos[0]-psize #xmx = pos[0]+psize #ymn = pos[1]-psize #ymx = pos[1]+psize #else: #xmn = min(xmn, pos[0]-psize) #xmx = max(xmx, pos[0]+psize) #ymn = min(ymn, pos[1]-psize) #ymx = max(ymx, pos[1]+psize) item = self.mkSpot(pos, size[i], self.opts['pxMode'], brush[i], pen[i], data, symbol=symbol[i], index=len(self.spots)) self.spots.append(item) self.data[i]['spot'] = item #if self.optimize: #item.hide() #frag = QtGui.QPainter.PixmapFragment.create(pos, QtCore.QRectF(0, 0, size, size)) #self.optimizeFragments.append(frag) #self.bounds = [[xmn, xmx], [ymn, ymx]] self.spotsValid = True self.sigPlotChanged.emit(self)
def setParentItem(self, p): ret = GraphicsWidget.setParentItem(self, p) if self.offset is not None: offset = Point(self.offset) anchorx = 1 if offset[0] <= 0 else 0 anchory = 1 if offset[1] <= 0 else 0 anchor = (anchorx, anchory) self.anchor(itemPos=anchor, parentPos=anchor, offset=offset) return ret
def mouseMoved(self, evt): pos = Point(evt.x(), evt.y()) if self.zoomedPlot.sceneBoundingRect().contains(pos): mousePoint = self.vb.mapSceneToView(pos) index = float(evt.x()) # if index > 0 : # self.dataLabel.setText("<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y1=%0.1f</span>, <span style='color: green'>y2=%0.1f</span>" % int(index), self.x[index], self.y[index]) self.vLine.setPos(mousePoint.x()) self.hLine.setPos(mousePoint.y())
def buttonDownPos(self, btn=None): """ Return the position of the mouse at the time the drag was initiated in the coordinate system of the item that the event was delivered to. """ if btn is None: btn = self.button() return Point( self.currentItem.mapFromScene(self._buttonDownScenePos[int(btn)]))
def scaleBy(self, s, center=None): """ Scale by *s* around given center point (or center of view). *s* may be a Point or tuple (x, y) """ scale = Point(s) if self.state['aspectLocked'] is not False: scale[0] = self.state['aspectLocked'] * scale[1] vr = self.targetRect() if center is None: center = Point(vr.center()) else: center = Point(center) tl = center + (vr.topLeft() - center) * scale br = center + (vr.bottomRight() - center) * scale self.setRange(QtCore.QRectF(tl, br), padding=0)
def plotInfo(self, xAxis, yAxis): """ 被嵌入的plotWidget在需要的时候通过调用此方法显示K线信息 """ xPos = xAxis xAxis = round(xAxis) if self.datas is None: return try: # 获取数据 value = self.datas[int(xAxis)] except Exception as e: return Time = self.master.xTime[int(xAxis)] sTime = str(Time) title = self.master.gTitle t = parse(str(Time)) if (title[:1] == '年'): timeText = '{0}年'.format(t.year) elif (title[:1] == '季'): quarter = int(t.month / 3 if t.month % 3 == 0 else t.month / 3 + 1) timeText = '{0}年第{1}季度'.format(t.year, quarter) elif (title[:1] == '月'): timeText = '{0}年{1}月'.format(t.year, t.month) else: timeText = '{0}年{1}月{2}日'.format(sTime[0:4], sTime[4:6], sTime[6:]) self.__textInfo.setHtml( '<div style="text-align: right;">\ <span style="color: yellow; font-size: 12px;">\ %s %s %.2f\ </span>\ </div>' \ % (timeText, title, value)) self.__textInfo.setPos(xPos, yAxis) if xAxis > self.master.index: self.__textInfo.anchor = Point((1, 0)) else: self.__textInfo.anchor = Point((0, 0))
def mouseDragEvent(self, ev): if ev.button() == QtCore.Qt.RightButton: ev.ignore() else: pg.ViewBox.mouseDragEvent(self, ev) ev.accept() pos = ev.pos() if ev.button() == QtCore.Qt.RightButton: if ev.isFinish(): self.rbScaleBox.hide() self.ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos)) self.ax = self.childGroup.mapRectFromParent(self.ax) self.Coords = self.ax.getCoords() self.getdataInRect() self.changePointsColors() else: self.updateScaleBox(ev.buttonDownPos(), ev.pos())