def setTexts(self, text): for i in self.textItems: i.scene().removeItem(i) self.textItems = [] for t in text: item = TextItem(t) self.textItems.append(item) item.setParentItem(self)
def setData(self, **kwds): self.data = kwds if 'pos' in self.data: for n in range(kwds['pos'].shape[0]): text_item = TextItem(kwds['text'][n]) text_pos = (kwds['pos'][n][0], kwds['pos'][n][1]) text_item.setPos(*kwds['pos'][n]) text_item.setParentItem(self) self.text = kwds.pop('text', []) GraphItem.setData(self, **self.data)
def addPlotAera(self): plotname = 'Plot' + str(len(self.lPlotWindows) + 1) axis = self.TimeAxisItem(orientation='bottom') vb = ViewBox() newdataPlot = PlotWidget(self, viewBox=vb, axisItems={'bottom': axis}, name = plotname) self.dataPlotLayout.addWidget(newdataPlot) self.configPlotArea(newdataPlot) newdataPlot.plotItem.scene().sigMouseClicked.connect(self.mouseClick) newdataPlot.plotItem.scene().sigMouseMoved.connect(self.mouseMove) ## drag and drop # newdataPlot.dragEnterEvent = self.dragEnterEvent # newdataPlot.plotItem.setAcceptDrops(True) # newdataPlot.plotItem.dropEvent = self.dropEvent # set the default plot range newdataPlot.setXRange(self.minTimestamp,self.maxTimestamp,padding=20) newdataPlot.setYRange(-10, 10, padding=20) newdataPlot.plotItem.getAxis('left').setWidth(w=30) newdataPlot.plotItem.hideButtons() newdataPlot.installEventFilter(self) newdataPlot.plotItem.showGrid(True, True, 0.5) vb.scaleBy(y=None) # make it the current selection plot area self.currSelctPlotWgt.setBackground('default') self.currSelctPlotWgt = newdataPlot # set the current selection to plot1 self.currSelctPlotWgt.setBackground(0.95) # link x axis to view box of the first data plot viewBox = self.dataPlot.plotItem.vb # reference to viewbox of the plot 1 axis.linkToView(viewBox) #axis.linkToView(vb) # Link plot 1 X axia to the view box lastplotItem = self.dataPlotLayout.itemAt(self.dataPlotLayout.count()-2).widget() lastplotItem.getViewBox().setXLink(newdataPlot) #lastplotItem.getViewBox().autoRange() txtY_value = TextItem("", fill=(0, 0, 255, 80), anchor=(0, 1), color='w') txtY_value.setParentItem(newdataPlot.plotItem.getViewBox()) self.autoRangeAllWins() self.lPlotWindows.append(plotname)
def setTexts(self, text): """ Generates the text (number) associated with each test point :param text: the numbers of all test points """ for i in self.textItems: try: i.scene().removeItem(i) except Exception as e: pass self.textItems = [] for t in text: item = TextItem(t) item.setColor([255, 255, 255]) self.textItems.append(item) item.setParentItem(self)
def initUI(self): # 添加打开菜单 selFileAction = QAction('&Open', self) # QAction(QIcon('open.png'), '&Open', self) selFileAction.setShortcut('Ctrl+O') selFileAction.setStatusTip('Open new File') selFileAction.triggered.connect(self.openFile) # open data file selFileAction.setIcon(QIcon(self.resource_path('import.png'))) exitAction = QAction('&Exit', self) #QtGui.QAction(QIcon('exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit the application') #exitAction.triggered.connect(QtGui.qApp.quit) exitAction.triggered.connect(self.exitAPP) # exit the application exitAction.setIcon(QIcon(self.resource_path('exit.png'))) clearAction = QAction('Clear', self) # QtGui.QAction(QIcon('Clear.png'), 'Clear', self) clearAction.triggered.connect(self.clearPlotArea) clearAction.setIcon(QIcon(self.resource_path('clear.png'))) addPlotAction = QAction( 'Add a Plot', self) #QtGui.QAction(QIcon('Addplot.png'), 'Add a Plot', self) addPlotAction.triggered.connect(self.addPlotAera) addPlotAction.setIcon(QIcon(self.resource_path('addplot.png'))) removePlotAction = QAction('Remove the Plot', self) # QtGui.QAction(QIcon('Addplot.png'), 'Remove a Plot', self) removePlotAction.triggered.connect(self.removeDataPlotWin) removePlotAction.setIcon(QIcon(self.resource_path('remvplot.png'))) viewAllAction = QAction("View All", self) viewAllAction.triggered.connect(self.autoRangeAllWins) viewAllAction.setIcon(QIcon(self.resource_path('viewall.png'))) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') # add menu File fileMenu.addAction(selFileAction) # link menu bar to openfile action with a menu item fileMenu.addAction(exitAction) # add menu item exit plotMenu = menubar.addMenu("Plot") # add menu Plot plotMenu.addAction(clearAction) # add menu item of 'Clear' plot plotMenu.addAction(addPlotAction) # add menu item of 'Add a Plot' plotMenu.addAction(removePlotAction) # add menu item of 'Add a Plot' helpMenu = menubar.addMenu("Help") # add menu help helpAction = QAction('?', helpMenu) helpAction.triggered.connect(self.helpme) helpMenu.addAction(helpAction) toolBar = self.addToolBar("Open") toolBar.addAction(selFileAction) # link tool bar to openfile action toolBar.addAction(clearAction) toolBar.addAction(addPlotAction) toolBar.addAction(removePlotAction) toolBar.addAction(viewAllAction) # toolBar = self.addToolBar('Exit') # toolBar.addAction(selExitAction) # link menu bar to openfile action # 设置dataPlot class: PlotWidget self.dataPlot.plotItem.showGrid(True, True, 0.5) #self.dataPlot.plotItem.addLegend() self.dataPlot.setAutoVisible(y=True) # 设置treeWidget的相关 class: QTreeWidget self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.treeWidget.customContextMenuRequested.connect(self.showContextMenu) self.treeWidget.treeContextMenu = QMenu(self) self.actionA = self.treeWidget.treeContextMenu.addAction(u'Plot') self.actionA.triggered.connect( lambda: self.plotData(self.currSelctPlotWgt, self.treeWidget.selectedItems())) self.treeWidget.setColumnCount(4) self.treeWidget.setHeaderLabels(['#', 'Parameter', 'Parameter Name', 'Unit']) self.treeWidget.setColumnWidth(0, 10) self.treeWidget.setColumnWidth(1, 50) self.treeWidget.setColumnWidth(2, 100) ### drag and drop self.treeWidget.setDragDropMode(self.treeWidget.DragOnly) # set up context menu of list widget self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.listWidget.customContextMenuRequested.connect(self.showListContextMenu) self.listWidget.listContextMenu = QMenu(self) self.actionB = self.listWidget.listContextMenu.addAction(u'Remove') self.actionB.triggered.connect( lambda: self.removeItemInPlot(self.listWidget.selectedItems())) #################### get the test data from the import window self.winImpData = clsImportData(self.dataparam, self.lTestDATA) # instance of the ImportData window # # x axis for time # xAxis = self.TimeAxisItem("bottom") xAxis = self.dataPlot.plotItem.axes['bottom']['item'] # plotitem and viewbox ## at least one plotitem is used whioch holds its own viewbox and left axis viewBox = self.dataPlot.plotItem.vb # reference to viewbox of the plotitem viewBox.scaleBy(y=None) # # link x axis to view box xAxis.linkToView(viewBox) self.dataPlot.plotItem.scene().sigMouseMoved.connect(self.mouseMove) #self.dataPlot.plotItem.scene().sigMouseClicked.connect(self.mouseClick) # self.dataPlot.HoverEnterEvent = self.hoverEnterEvent ## drag and drop # self.dataPlot.dragEnterEvent = self.dragEnterEvent # self.dataPlot.plotItem.setAcceptDrops(True) # self.dataPlot.plotItem.dropEvent = self.dropEvent vLine = InfiniteLine(angle=90, movable=False, name='vline') hLine = InfiniteLine(angle=0, movable=False, name='hline') self.dataPlot.addItem(vLine, ignoreBounds=True) self.dataPlot.addItem(hLine, ignoreBounds=True) # set the default plot range self.dataPlot.setXRange(self.minTimestamp,self.maxTimestamp,padding=20) self.dataPlot.setYRange(-10, 10, padding=20) self.dataPlot.plotItem.getViewBox().setLimits() self.dataPlot.plotItem.getAxis('left').setWidth(w=30) self.dataPlot.plotItem.hideButtons() #self.dataPlot.plotItem.scene().sigMouseLeave.connect(self.mouseLeave) # ##TODO: cleaning house job self.dataPlot.installEventFilter(self) txtY_value = TextItem("", fill=(0, 0, 255, 80), anchor=(0,1),color='w') txtY_value.setParentItem(viewBox) self.curLabelofYvalue = txtY_value # #self.dataPlot.addItem(self.lableY_value) # labelY_value.setPos(self.minTimestamp,100.0) self.configPlotArea(self.dataPlot) # set current selection plot window background self.currSelctPlotWgt = self.dataPlot self.currSelctPlotWgt.setBackground(0.95)
class verticalScaleBar(GraphicsObject, GraphicsWidgetAnchor): """ Displays a rectangular bar to indicate the relative scale of objects on the view. """ def __init__(self, size, width=5, brush=None, pen=None, suffix='m', offset=None): GraphicsObject.__init__(self) GraphicsWidgetAnchor.__init__(self) self.setFlag(self.ItemHasNoContents) self.setAcceptedMouseButtons(QtCore.Qt.NoButton) if brush is None: brush = getConfigOption('foreground') self.brush = fn.mkBrush(brush) self.pen = fn.mkPen(pen) self._width = width self.size = size if offset == None: offset = (0, 0) self.offset = offset self.bar = QtGui.QGraphicsRectItem() self.bar.setPen(self.pen) self.bar.setBrush(self.brush) self.bar.setParentItem(self) self.text = TextItem(text=fn.siFormat(size, suffix=suffix), anchor=(0.5, 1), angle=90, color=(0, 0, 0)) self.text.setParentItem(self) def parentChanged(self): view = self.parentItem() if view is None: return view.sigRangeChanged.connect(self.updateBar) self.updateBar() def updateBar(self): view = self.parentItem() if view is None: return p1 = view.mapFromViewToItem(self, QtCore.QPointF(0, 0)) p2 = view.mapFromViewToItem(self, QtCore.QPointF(0, self.size)) w = (p2 - p1).y() self.bar.setRect(QtCore.QRectF(0, 0, self._width, w)) self.text.setPos(0, w / 2.) def boundingRect(self): return QtCore.QRectF() def setParentItem(self, p): ret = GraphicsObject.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
class NaturalPlotView(GraphicsView): """Creates a simple about dialog. The about dialog contains general information about the application and shows the copyright notice. That's why the class has no attributes or return values. """ def __init__(self): super().__init__() # settings self.setBackground("#fff") self.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) self.setAntialiasing(True) # create custom view box view_box = ViewBox() view_box.setMouseEnabled(False, False) view_box.setLimits(xMin=0, yMin=0, minXRange=10, minYRange=100) view_box.setRange(xRange=(0, 400), yRange=(0, 5000)) view_box.enableAutoRange() # create natural axis items self.x_axis = NaturalAxis("bottom") self.x_axis.setLabel(QApplication.translate("NaturalPlotView", "Fence length"), "m") self.y_axis = NaturalAxis("left") self.y_axis.setLabel(QApplication.translate("NaturalPlotView", "Number of plants")) # create fence information text self.fenceItem = TextItem(border=pyqtgraph.mkPen(width=2, color="#555"), fill=pyqtgraph.mkBrush((255, 255, 255, 200))) # create tube information text self.tubeItem = TextItem(border=pyqtgraph.mkPen(width=2, color="#555"), fill=pyqtgraph.mkBrush((255, 255, 255, 200)), anchor=(1,1)) # create plot item with custom view box and natural axis items self.plotItem = PlotItem(viewBox=view_box, axisItems={"bottom" : self.x_axis, "left" : self.y_axis}, enableMenu=False) self.plotItem.setContentsMargins(5, 5, 12, 5) self.plotItem.hideButtons() self.plotItem.hide() self.setCentralWidget(self.plotItem) # connect actions view_box.sigResized.connect(self.updateTubeLegendPosition) # translate the plot item self.retranslateUi() def retranslateUi(self): # title label titleStyle = "color: #111; font-size: 15px; font-weight: bold" titleLabel = "<span style='{style}'>{title}</span>".format(style=titleStyle, title="Ergebnis: Funktion(en) der Kostengleichheit") self.plotItem.setTitle(titleLabel) # axis items #self.x_axis.setLabel(QApplication.translate("NaturalPlotView", "Fence length"), "m") #self.y_axis.setLabel(QApplication.translate("NaturalPlotView", "Number of plants")) # fence hint self.fenceItem.setHtml("<p style='margin: 0; color: #555'><b>" + QApplication.translate("NaturalPlotView", "Pfeil über Funktion(en):") + "</b> " + QApplication.translate("NaturalPlotView", "Zaun günstiger") + "</p>") # tube hint self.tubeItem.setHtml("<p style='margin: 0; color: #555'><b>" + QApplication.translate("NaturalPlotView", "Pfeil unter Funktion(en):") + "</b> " + QApplication.translate("NaturalPlotView", "Wuchshülle günstiger") + "</p>") def addPlotItem(self, item, *args, **kwargs): # first show the plot item if not self.plotItem.isVisible(): self.plotItem.show() self.plotItem.addItem(item, *args, **kwargs) def removePlotItem(self, item): self.plotItem.removeItem(item) #TODO: def clear(self): self.plotItem.hide() self.plotItem.clear() def showDescription(self): viewBox = self.plotItem.getViewBox() self.fenceItem.setPos(15, 10) self.fenceItem.setParentItem(viewBox) rect = viewBox.screenGeometry() self.tubeItem.setPos(rect.width() - 15, rect.height() - 10) self.tubeItem.setParentItem(viewBox) def updateTubeLegendPosition(self): rect = self.plotItem.getViewBox().screenGeometry() self.tubeItem.setPos(rect.width() - 15, rect.height() - 10) def export(self, gfxfile): exporter = TestImageExporter(self.plotItem) exporter.parameters()["width"] = 2007.0 # 17 cm / 300 DPI # export the graphics to the selected file exporter.export(gfxfile)
class VariantPlotWidget(QWidget): """Creates a simple about dialog. The about dialog contains general information about the application and shows the copyright notice. That's why the class has no attributes or return values. """ AREA = 0 LINE = 1 curvePlotted = pyqtSignal(QModelIndex) plotReady = pyqtSignal() cleared = pyqtSignal() def __init__(self): super().__init__() # the plot widget is always # disabled at the first start self.setDisabled(True) ### TESTING ### self.model = None self.selectionModel = None self.view = 0 self.calc = False self.plotLength = 0 self.plotCount = 0 self.fenceLine = None self.plantLine = None self.arrowItem = None #self.lengthCoefficient = 1.5 # in model festlegen! #self.transparency = 0.3 ### TESTING ### self.controlWidget = PlotControlWidget() self.plotWidget = NaturalPlotView() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.controlWidget) layout.addWidget(self.plotWidget) self.setLayout(layout) # connect signals self.controlWidget.chartViewChanged.connect(self.updateChartView) self.controlWidget.countEnabled.connect(self.setPlantLineVisible) self.controlWidget.lengthEnabled.connect(self.setFenceLineVisible) def retranslateUi(self): # update the control widget self.controlWidget.retranslateUi() # translate the plot widget self.plotWidget.retranslateUi() def setModel(self, model): self.model = model self.model.dataChanged.connect(self.update) self.model.modelReset.connect(self.update) # das muss optimiert werden, weil dies private Signale sind # es dient dazu, dass gelöschte, oder veränderte (verschobene) Zeilen # nicht mehr ausgewählt werden können (selectionModel) self.model.rowsRemoved.connect(self.modelRemoveAction) self.model.rowsMoved.connect(self.modelRemoveAction) self.model.calculated.connect(self.calculate) def calculate(self): self.calc = True self.paintCalculation() def updateChartView(self, index): self.view = index # update calculation # möglicherweise sollte hier paintEvent() verwendet werden?! # # vorher muss hier noch eine Berechnung stattfinden if self.calc: self.paintCalculation() def setSelectionModel(self, selectionModel): # setup view's selectionModel self.selectionModel = selectionModel def modelRemoveAction(self): # TODO # wird benötigt, da sonst Fehler, wenn mit Enter bestätigt in Zaunlänge self.setDisabled(True) self.clear() def clear(self): # disconnect signals if isinstance(self.plantLine, InfiniteLine): self.plantLine.disconnect() self.plantLine = None if isinstance(self.fenceLine, InfiniteLine): self.fenceLine.disconnect() self.fenceLine = None self.plotWidget.clear() self.cleared.emit() def paintCalculation(self): if not self.calc: return # search for enabeld items # items contains at least one parent and one child # remove parents from children items = self.model.match(self.model.index(0, 0), TreeModel.StatusRole, True, -1, Qt.MatchRecursive) children = [item for item in items if item.parent().isValid()] if self.view == self.AREA: self.plotAreaChart(children) elif self.view == self.LINE: self.plotLineChart(children) def createIntersectionPoint(self): # TODO self.plotLength = self.model.projectData("length") * LENGTH_COEFFICIENT # create the horizontal plant line green = QColor(0, 144, 54) plantPen = pyqtgraph.mkPen(width=2, color=green) # Hochschule für Forstwirtschaft Rottenburg self.plantLine = InfiniteLine(self.model.projectData("count"), 0, plantPen, True) self.plantLine.sigPositionChanged.connect(self.updateCount) self.controlWidget.setCount(self.model.projectData("count")) self.controlWidget.countChanged.connect(self.plantLine.setValue) self.plantLabel = TextItem(html="<b><font color='" + green.name() + "'>Pflanzenzahl</font></b>", anchor=(-0.15, 0.9)) self.plantLabel.setParentItem(self.plantLine) self.plotWidget.addPlotItem(self.plantLine) # create the vertical fence line red = QColor(255, 0, 0) fencePen = pyqtgraph.mkPen(width=2, color=red) self.fenceLine = InfiniteLine(self.model.projectData("length"), 90, fencePen, True) self.fenceLine.sigPositionChanged.connect(self.updateLength) self.fenceLine.sigPositionChangeFinished.connect(self.updatePlotLength) self.controlWidget.setLength(self.model.projectData("length")) self.controlWidget.lengthChanged.connect(self.fenceLine.setValue) self.fenceLabel = TextItem(html="<b><font color='" + red.name() + "'>Zaunlänge</font></b>", anchor=(-2.5, 0.9), angle=-90) self.fenceLabel.setParentItem(self.fenceLine) self.plotWidget.addPlotItem(self.fenceLine) # create an arrow item as point of intersection self.arrowItem = ArrowItem(angle=-45, tipAngle=30, baseAngle=20, headLen=20, tailLen=None, pen={"color" : "#333", "width" : 2}, brush=QColor(255, 123, 0)) self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) self.plotWidget.addPlotItem(self.arrowItem) def plotAreaChart(self, children): # check parents and children # the lists must contain only one item if not len(children) == 1: warning = QMessageBox(self) warning.setWindowModality(Qt.WindowModal) # check for mac only warning.setIcon(QMessageBox.Warning) warning.setStandardButtons(QMessageBox.Ok) warning.setWindowTitle(QApplication.translate("VariantPlotWidget", "Wuchshüllenrechner")) warning.setText("<b>" + QApplication.translate("VariantPlotWidget", "Too many variants are enabled!") + "</b>") warning.setInformativeText(QApplication.translate("VariantPlotWidget", "The area view allows you to set only one variant enabled " "at the same time. Please select the variant manually or " "choose the line view.")) warning.exec() return False (index,) = children # clear the plot widget self.clear() # plot the curve curve = EnhancedCurveItem(index, True) self.plotWidget.addPlotItem(curve) self.curvePlotted.emit(index) # create point of intersection self.createIntersectionPoint() # add the description to the view self.setEnabled(True) self.plotWidget.showDescription() self.plotReady.emit() def plotLineChart(self, children): # check parents and children # the lists must contain only one item if len(children) == 0: print("Fehler") return False # clear the plot widget self.clear() for child in children: # plot the curve curve = EnhancedCurveItem(child) self.plotWidget.addPlotItem(curve) self.curvePlotted.emit(child) # create point of intersection self.createIntersectionPoint() # add the description to the view self.setEnabled(True) self.plotWidget.showDescription() self.plotReady.emit() def updatePlotLength(self): length = self.fenceLine.value() hint = False # update the chart, if necessary if length >= self.plotLength: self.paintCalculation() hint = True elif length < self.plotLength / 5: self.paintCalculation() hint = True if hint: # notice the user about the update notice = QMessageBox(self) notice.setWindowModality(Qt.WindowModal) # check for mac only notice.setIcon(QMessageBox.Information) notice.setStandardButtons(QMessageBox.Ok) notice.setWindowTitle(QApplication.translate("VariantPlotWidget", "Wuchshüllenrechner")) notice.setText("<b>" + QApplication.translate("VariantPlotWidget", "Die Skalierung wurde verändert!") + "</b>") notice.setInformativeText(QApplication.translate("VariantPlotWidget", "Da sich die Zaunlänge geändert hat, wurde die Skalierung " "des Diagramms ebenfalls verändert.")) notice.exec() def updateCount(self, line): # save the new value in the model and # update the control widget count = int(self.plantLine.value()) self.model.setProjectData("count", count) self.controlWidget.setCount(count) # change the arrow item self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) # update the legend self.plotReady.emit() def updateLength(self, line): # save the new value in the model and # update the control widget length = int(self.fenceLine.value()) self.model.setProjectData("length", length) self.controlWidget.setLength(length) # change the arrow item self.arrowItem.setPos(self.model.projectData("length"), self.model.projectData("count")) # update the legend self.plotReady.emit() def setPlantLineVisible(self, state): # check, if plant line is not None to avoid errors if not self.plantLine: return False self.plantLine.setVisible(state) def setFenceLineVisible(self, state): # check, if plant line is not None to avoid errors if not self.fenceLine: return False self.fenceLine.setVisible(state)