Beispiel #1
0
class RectZoomMoveView(QChartView):
    """
    Filter data to be displayed in rectangular body
    """

    rangeSig = pyqtSignal(list)

    def __init__(self, parent=None):
        super(RectZoomMoveView, self).__init__(parent)
        self.setChart(QChart())
        self.chart().setMargins(QMargins(5, 5, 5, 5))
        self.chart().setContentsMargins(-10, -10, -10, -10)
        self.chart().setTitle(" ")
        self.relationState = True

        # Define two rectangles for background and drawing respectively
        self.parentRect = QGraphicsRectItem(self.chart())

        self.parentRect.setFlag(QGraphicsItem.ItemClipsChildrenToShape, True)
        self.parentRect.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.RangeItem = RectRangeItem(parent=self.parentRect)
        self.RangeItem.setZValue(998)
        pen = QPen(Qt.gray)
        pen.setWidth(1)
        self.parentRect.setPen(pen)
        self.parentRect.setZValue(997)

        self.scene().addItem(self.parentRect)
        self.scene().addItem(self.RangeItem)

        self.RangeItem.hide()
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.dataLength = 0

        self.RangeItem.selectedChange.connect(self.changeFromRectItem)

        self.BtnsWidget = ViewButtonsWidget(self)
        self.BtnsWidget.refreshBtn.clicked.connect(self.updateView)
        self.BtnsWidget.RelationSig.connect(self.setRelationState)
        self.BtnsWidget.dateRangeEdit.dateRangeSig.connect(self.changDateRect)

    def changDateRect(self, daterange):
        if self.chartTypes == "Bar":
            v = 3
        else:
            v = 2
        l = len(self.RangeItem.rangePoints)
        if l > 2:
            try:
                num = self.mintimeData.date().daysTo(daterange[0])
                left = self.RangeItem.rangePoints[num]
                num = self.mintimeData.date().daysTo(daterange[1])
                right = self.RangeItem.rangePoints[num]
                rect = self.chart().plotArea()
                rect.setLeft(left)
                rect.setRight(right)
            except:
                rect = self.chart().plotArea()
            self.RangeItem.setRect(rect)
            self.RangeItem.updateHandlesPos()
        else:
            try:
                num = self.mintimeData.date().daysTo(daterange[0])
                left = self.RangeItem.rangePoints[num]
                num = self.mintimeData.date().daysTo(daterange[0])
                right = self.RangeItem.rangePoints[num]
                rect = self.chart().plotArea()
                rect.setLeft(left)
                rect.setRight(right)
            except:
                rect = self.chart().plotArea()
            self.RangeItem.setRect(rect)
            self.RangeItem.updateHandlesPos()

    def lineSpace(self, start, end, num):
        res = []
        if self.chartTypes == "Bar":
            step = (end - start) / (num)
            for i in range(num + 2):
                res.append(start + i * step)
        else:
            step = (end - start) / (num - 1)
            for i in range(num + 1):
                res.append(start + i * step)
        return res

    def getRangePoints(self):
        count = self.zoomSeries.count()
        rect = self.chart().plotArea()
        left = rect.left()
        right = rect.right()
        if count == 0:
            self.RangeItem.rangePoints = [left, right]
        else:
            # Get coordinate position for each node
            self.RangeItem.rangePoints = self.lineSpace(left, right, count)

    def setRangeColor(self, color):
        self.RangeItem.setRangeColor(color)

    def setRelationState(self, state):
        self.relationState = state

    def initSeries(self, chartTypes="Bar"):
        self.chartTypes = chartTypes
        axisX = QDateTimeAxis()
        axisX.setFormat("yyyy-MM-dd")
        self.zoomSeries = QLineSeries(self.chart())
        self.chart().addSeries(self.zoomSeries)
        self.chart().setAxisY(QValueAxis(), self.zoomSeries)
        self.chart().setAxisX(axisX, self.zoomSeries)
        self.initView()

    def clearAll(self):
        # Clear all series and axes
        self.chart().removeAllSeries()
        axess = self.chart().axes()
        for axes in axess:
            self.chart().removeAxis(axes)

    def setData(self, timeData, valueData, chartTypes="Bar"):
        axisX = QDateTimeAxis()
        axisX.setFormat("yyyy-MM-dd")

        if self.chartTypes == "Bar":
            # Clear all series
            self.clearAll()
            self.zoomSeries = QLineSeries(self.chart())
            barSeries = QBarSeries(self.chart())
            barset = QBarSet("data")
            barSeries.setBarWidth(0.8)
            barSeries.append(barset)
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
            barset.append(valueData)
            self.zoomSeries.hide()
            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(barSeries)
            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes == "Scatter":
            # Clear all series
            self.clearAll()
            self.zoomSeries = QLineSeries(self.chart())
            scattSeries = QScatterSeries(self.chart())
            scattSeries.setMarkerSize(8)

            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
                scattSeries.append(td.toMSecsSinceEpoch(), vd)
            self.zoomSeries.hide()
            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(scattSeries)
            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes in ["Line", "PLine"]:
            self.clearAll()
            if self.chartTypes == "Line":
                self.zoomSeries = QLineSeries(self.chart())
            else:
                self.zoomSeries = QSplineSeries(self.chart())
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)
            self.chart().addSeries(self.zoomSeries)

            self.chart().setAxisY(QValueAxis(), self.zoomSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, self.zoomSeries)
        elif self.chartTypes == "Area":

            self.clearAll()
            self.zoomSeries = QLineSeries()
            self.zoomSeries.setColor(QColor("#666666"))
            for td, vd in zip(timeData, valueData):
                self.zoomSeries.append(td.toMSecsSinceEpoch(), vd)

            areaSeries = QAreaSeries(self.zoomSeries, None)

            self.chart().addSeries(self.zoomSeries)
            self.chart().addSeries(areaSeries)
            self.chart().setAxisY(QValueAxis(), areaSeries)
            axisX.setRange(min(timeData), max(timeData))
            self.chart().setAxisX(axisX, areaSeries)
            self.zoomSeries.hide()
        self.mintimeData = min(timeData)
        self.maxtimeData = max(timeData)
        self.BtnsWidget.dateRangeEdit.setDateRange([
            self.mintimeData.toString("yyyy-MM-dd"),
            self.maxtimeData.toString("yyyy-MM-dd"),
        ])
        self.updateView()

    def resetView(self):

        rect = self.chart().plotArea()
        self.parentRect.setRect(rect)
        topRight = self.chart().plotArea().topRight()
        x = int(topRight.x())
        y = int(topRight.y())
        self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23))
        self.RangeItem.setRect(rect)
        self.RangeItem.show()
        self.save_current_rubber_band()
        self.RangeItem.updateHandlesPos()
        self.apply_nice_numbers()
        self.getRangePoints()
        self.sendRang()

    def initView(self):
        self.RangeItem.hide()
        # Hide y-axis
        if self.chart().axisY():
            self.chart().axisY().setVisible(False)
        if self.chart().axisX():
            self.chart().axisX().setGridLineVisible(False)
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.getRangePoints()

    def updateView(self):
        self.RangeItem.hide()
        # Hide y-axis
        if self.chart().axisY():
            self.chart().axisY().setVisible(False)
        if self.chart().axisX():
            self.chart().axisX().setGridLineVisible(False)
        self.m_chartRectF = QRectF()
        self.m_rubberBandOrigin = QPointF(0, 0)
        self.resetView()

    # Map points to chart
    def point_to_chart(self, pnt):
        scene_point = self.mapToScene(pnt)
        chart_point = self.chart().mapToValue(scene_point)
        return chart_point

    # Map chart to points
    def chart_to_view_point(self, char_coord):
        scene_point = self.chart().mapToPosition(char_coord)
        view_point = self.mapFromScene(scene_point)
        return view_point

    # Save positions of rectangles
    def save_current_rubber_band(self):
        rect = self.RangeItem.rect()

        chart_top_left = self.point_to_chart(rect.topLeft().toPoint())
        self.m_chartRectF.setTopLeft(chart_top_left)

        chart_bottom_right = self.point_to_chart(rect.bottomRight().toPoint())
        self.m_chartRectF.setBottomRight(chart_bottom_right)

    # Respond to change in positions of rectangles
    def changeFromRectItem(self, rectIndex):
        self.save_current_rubber_band()
        self.sendRang(rectIndex)

    def sendRang(self, rectIndex=[]):

        if self.RangeItem.rect() != self.parentRect.rect():
            self.BtnsWidget.setPalActive()
        else:
            self.BtnsWidget.setPalDisActive()
        if self.chartTypes == "Bar":
            v = 3
        else:
            v = 2
        if rectIndex == []:
            maxData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(len(self.RangeItem.rangePoints) - v).x())
            minData = QDateTime.fromMSecsSinceEpoch(self.zoomSeries.at(0).x())
        else:
            minData = max(rectIndex[0], 0)
            maxData = min(rectIndex[1], len(self.RangeItem.rangePoints) - v)
            minData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(minData).x())
            maxData = QDateTime.fromMSecsSinceEpoch(
                self.zoomSeries.at(maxData).x())

        if minData > maxData:
            if self.RangeItem.handleSelected is None:
                self.resetView()
        else:
            self.BtnsWidget.dateRangeEdit.setDate([
                minData.toString("yyyy-MM-dd"),
                maxData.toString("yyyy-MM-dd")
            ])
            if self.relationState:
                self.rangeSig.emit([
                    minData.toString("yyyy-MM-dd HH:mm:ss"),
                    maxData.toString("yyyy-MM-dd HH:mm:ss"),
                ])

    # Change positions of rectangles in scaling
    def resizeEvent(self, event):
        super().resizeEvent(event)
        rect = self.chart().plotArea()
        self.parentRect.setRect(rect)
        self.getRangePoints()
        topRight = self.chart().plotArea().topRight()
        x = int(topRight.x())
        y = int(topRight.y())
        self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23))
        if self.RangeItem.isVisible():
            self.restore_rubber_band()
            self.save_current_rubber_band()
            self.RangeItem.updateHandlesPos()
        else:
            self.RangeItem.setRect(self.parentRect.rect())
            self.RangeItem.show()
            self.RangeItem.setRect(self.parentRect.rect())
            self.save_current_rubber_band()
            self.RangeItem.updateHandlesPos()
        self.apply_nice_numbers()

    # Restore to original positions of rectangles
    def restore_rubber_band(self):
        view_top_left = self.chart_to_view_point(self.m_chartRectF.topLeft())
        view_bottom_right = self.chart_to_view_point(
            self.m_chartRectF.bottomRight())

        self.m_rubberBandOrigin = view_top_left
        height = self.chart().plotArea().height()
        rect = QRectF()
        rect.setTopLeft(view_top_left)
        rect.setBottomRight(view_bottom_right)
        rect.setHeight(height)
        self.RangeItem.setRect(rect)

    # Adjust display coordinates of axes automatically
    def apply_nice_numbers(self):
        axes_list = self.chart().axes()
        for value_axis in axes_list:
            if value_axis:
                pass
Beispiel #2
0
class Graph(QChartView):
	def __init__(self, parent=None):
		super().__init__(parent=parent)

		self.setpoint_temperature = None

		self.chart = QChart()
		self.chart.legend().hide()
		self.setChart( self.chart )
		self.setRenderHint(QPainter.Antialiasing)
		self.chart.setPlotAreaBackgroundBrush( QBrush(Qt.black) )
		self.chart.setPlotAreaBackgroundVisible( True )

		self.setpointTemperatureSeries = QLineSeries( self.chart )
		pen = self.setpointTemperatureSeries.pen()
		pen.setWidthF(2.)
		pen.setColor( Qt.green )
		self.setpointTemperatureSeries.setPen( pen )
		#self.setpointTemperatureSeries.setUseOpenGL( True )
		self.chart.addSeries( self.setpointTemperatureSeries )

		self.temperatureSeries = QLineSeries( self.chart )
		pen = self.temperatureSeries.pen()
		pen.setWidthF(2.)
		pen.setColor( Qt.red )
		self.temperatureSeries.setPen( pen )
		#self.temperatureSeries.setUseOpenGL( True )
		self.chart.addSeries( self.temperatureSeries )

		self.number_of_samples_to_keep = 2 * 5 * 60

		self.xMin = QDateTime.currentDateTime().toMSecsSinceEpoch()
		self.xMax = QDateTime.currentDateTime().toMSecsSinceEpoch()
		self.yMin = 400
		self.yMax = 0

		#self.chart.createDefaultAxes()
		#x_axis = QValueAxis()
		x_axis = QDateTimeAxis()
		x_axis.setTitleText( "Time" )
		x_axis.setFormat("HH:mm:ss")
		self.chart.addAxis( x_axis, Qt.AlignBottom )
		self.temperatureSeries.attachAxis( x_axis )
		self.setpointTemperatureSeries.attachAxis( x_axis )
		startDate = QDateTime.currentDateTime().addSecs( -5 * 60 )
		endDate = QDateTime.currentDateTime().addSecs( 5 * 60 )
		#startDate = QDateTime(QDate(2017, 1, 9), QTime(17, 25, 0))
		#endDate = QDateTime(QDate(2017, 1, 9), QTime(17, 50, 0))
		#self.chart.axisX().setRange( startDate, endDate )
		#self.chart.axisX().setRange( 0, 100 )

		y_axis = QValueAxis()
		y_axis.setTitleText( "Temperature (K)" )
		self.chart.addAxis( y_axis, Qt.AlignLeft )
		self.temperatureSeries.attachAxis( y_axis )
		self.setpointTemperatureSeries.attachAxis( y_axis )
		self.chart.axisY().setRange( 0, 400 )
		#self.chart.axisY().setRange( 260., 290. )

		self.temperatureSeries.pointAdded.connect( self.Rescale_Axes )
		#self.setpointTemperatureSeries.pointAdded.connect( self.Rescale_Axes )

		self.setRubberBand( QChartView.HorizontalRubberBand )

		# Customize chart title
		font = QFont()
		font.setPixelSize(24);
		self.chart.setTitleFont(font);
		self.chart.setTitleBrush(QBrush(Qt.white));

		## Customize chart background
		#backgroundGradient = QLinearGradient()
		#backgroundGradient.setStart(QPointF(0, 0));
		#backgroundGradient.setFinalStop(QPointF(0, 1));
		#backgroundGradient.setColorAt(0.0, QColor(0x000147));
		#backgroundGradient.setColorAt(1.0, QColor(0x000117));
		#backgroundGradient.setCoordinateMode(QGradient.ObjectBoundingMode);
		#self.chart.setBackgroundBrush(backgroundGradient);
		transparent_background = QBrush(QColor(0,0,0,0))
		self.chart.setBackgroundBrush( transparent_background )

		# Customize axis label font
		labelsFont = QFont()
		labelsFont.setPixelSize(16);
		x_axis.setLabelsFont(labelsFont)
		y_axis.setLabelsFont(labelsFont)
		x_axis.setTitleFont(labelsFont)
		y_axis.setTitleFont(labelsFont)

		# Customize axis colors
		axisPen = QPen(QColor(0xd18952))
		axisPen.setWidth(2)
		x_axis.setLinePen(axisPen)
		y_axis.setLinePen(axisPen)

		# Customize axis label colors
		axisBrush = QBrush(Qt.white)
		x_axis.setLabelsBrush(axisBrush)
		y_axis.setLabelsBrush(axisBrush)
		x_axis.setTitleBrush(axisBrush)
		y_axis.setTitleBrush(axisBrush)

	def set_title(self, title):
		self.chart.setTitle(title)

	def add_new_data_point( self, x, y ):
		x_as_millisecs = x.toMSecsSinceEpoch()
		self.temperatureSeries.append( x_as_millisecs, y )
		if( self.setpoint_temperature ):
			self.setpointTemperatureSeries.append( x_as_millisecs, self.setpoint_temperature )

		num_of_datapoints = self.temperatureSeries.count()
		#if( num_of_datapoints > self.number_of_samples_to_keep ):
		#	self.number_of_samples_to_keep.
		#print( x_as_millisecs, y )
		#self.chart.scroll( x_as_millisecs - 5 * 60 * 1000, x_as_millisecs )
		#self.temperatureSeries.append( x, float(y) )
		#self.repaint()

	def Rescale_Axes( self, index ):
		x = self.temperatureSeries.at( index ).x()
		x_rescaled = False
		if( x < self.xMin ):
			self.xMin = x
			x_rescaled = True
		if( x > self.xMax ):
			self.xMax = x
			x_rescaled = True
		if( x_rescaled ):
			full_range = min( self.xMax - self.xMin, 5 * 60 * 1000 )
			margin = full_range * 0.05

			self.chart.axisX().setRange( QDateTime.fromMSecsSinceEpoch(self.xMax - full_range - margin), QDateTime.fromMSecsSinceEpoch(self.xMax + margin) )
			
		y = self.temperatureSeries.at( index ).y()
		y_rescaled = False
		if( y < self.yMin ):
			self.yMin = y
			y_rescaled = True
		if( y > self.yMax ):
			self.yMax = y
			y_rescaled = True
		if( y_rescaled ):
			full_range = self.yMax - self.yMin
			margin = full_range * 0.05
			self.chart.axisY().setRange( self.yMin - margin, self.yMax + margin )