def add_data(self, xdata, ydata, color=None): curve = QLineSeries() pen = curve.pen() if color is not None: pen.setColor(color) pen.setWidthF(.1) curve.setPen(pen) curve.setUseOpenGL(True) curve.append(series_to_polyline(xdata, ydata)) self.chart.addSeries(curve) self.chart.createDefaultAxes() self.ncurves += 1
def add_data(self, xdata, ydata, color=None, legend_text=None): curve = QLineSeries() pen = curve.pen() if color is not None: pen.setColor(color) pen.setWidthF(1.5) curve.setPen(pen) # curve.setPointsVisible(True) # curve.setUseOpenGL(True) self.total_samples = max(self.total_samples, len(xdata)) # Decimate xdecimated, ydecimated = self.decimate(xdata, ydata) # Data must be in ms since epoch # curve.append(self.series_to_polyline(xdecimated * 1000.0, ydecimated)) # self.reftime = datetime.datetime.fromtimestamp(xdecimated[0]) # if len(xdecimated) > 0: # xdecimated = xdecimated - xdecimated[0] xdecimated *= 1000 # No decimal expected points = [] for i, _ in enumerate(xdecimated): # TODO hack # curve.append(QPointF(xdecimated[i], ydecimated[i])) points.append(QPointF(xdecimated[i], ydecimated[i])) curve.replace(points) points.clear() if legend_text is not None: curve.setName(legend_text) # Needed for mouse events on series self.chart.setAcceptHoverEvents(True) self.xvalues[self.ncurves] = np.array(xdecimated) # connect signals / slots # curve.clicked.connect(self.lineseries_clicked) # curve.hovered.connect(self.lineseries_hovered) # Add series self.chart.addSeries(curve) self.ncurves += 1 self.update_axes()
def add_data(self, data, chart, color=None): curve = QLineSeries(chart) curve.setName("latency") pen = curve.pen() if color is not None: pen.setColor(color) pen.setWidthF(1) curve.setPen(pen) curve.setUseOpenGL(True) for x in data: curve.append(x[0], x[1]) # curve.append(series_to_polyline(xdata, ydata)) chart.addSeries(curve) chart.createDefaultAxes() return curve
def __drawBode(self): self.chart.removeAllSeries() #删除所有序列 ## 创建序列 pen = QPen(Qt.red) pen.setWidth(2) seriesMag = QLineSeries() #幅频曲线序列 seriesMag.setName("幅频曲线") seriesMag.setPen(pen) seriesMag.setPointsVisible(False) seriesMag.hovered.connect(self.do_seriesMag_hovered) seriesPhase = QLineSeries() #相频曲线序列 pen.setColor(Qt.blue) seriesPhase.setName("相频曲线") seriesPhase.setPen(pen) seriesPhase.setPointsVisible(True) seriesPhase.hovered.connect(self.do_seriesPhase_hovered) ## 为序列添加数据点 count = len(self.__vectW) #数据点数 for i in range(count): seriesMag.append(self.__vectW[i], self.__vectMag[i]) seriesPhase.append(self.__vectW[i], self.__VectPhase[i]) ##设置坐标轴范围 minMag = min(self.__vectMag) maxMag = max(self.__vectMag) minPh = min(self.__VectPhase) maxPh = max(self.__VectPhase) self.__axisMag.setRange(minMag, maxMag) self.__axisPhase.setRange(minPh, maxPh) ##序列添加到chart,并指定坐标轴 self.chart.addSeries(seriesMag) seriesMag.attachAxis(self.__axisFreq) seriesMag.attachAxis(self.__axisMag) self.chart.addSeries(seriesPhase) seriesPhase.attachAxis(self.__axisFreq) seriesPhase.attachAxis(self.__axisPhase) for marker in self.chart.legend().markers(): #QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked)
class PeersCountGraphView(BaseTimedGraph): peersCountFetched = AsyncSignal(int) def __init__(self, parent=None): super(PeersCountGraphView, self).__init__(parent=parent) self.setObjectName('PeersCountGraph') self.peersCountFetched.connectTo(self.onPeersCount) self.axisY.setTitleText(iPeers()) pen = QPen(QColor('#60cccf')) pen.setWidth(2) self.seriesPeers = QLineSeries() self.seriesPeers.setName('Peers') self.seriesPeers.setPen(pen) self.chart.addSeries(self.seriesPeers) self.seriesPeers.attachAxis(self.axisX) self.seriesPeers.attachAxis(self.axisY) self.setChart(self.chart) async def onPeersCount(self, count): dtNow = QDateTime.currentDateTime() dtMsecs = dtNow.toMSecsSinceEpoch() delta = 120 * 1000 if not self.seriesPurgedT or (dtMsecs - self.seriesPurgedT) > delta: self.removeOldSeries(self.seriesPeers, dtMsecs - delta) self.seriesPurgedT = dtMsecs peersVector = self.seriesPeers.pointsVector() values = [p.y() for p in peersVector] if values: self.axisY.setMax(max(values) + 10) self.axisY.setMin(min(values) - 10) dateMin = QDateTime.fromMSecsSinceEpoch(dtMsecs - (30 * 1000)) dateMax = QDateTime.fromMSecsSinceEpoch(dtMsecs + 2000) self.seriesPeers.append(dtMsecs, count) self.axisX.setRange(dateMin, dateMax)
def do_redrawWave(self): self.chart.removeAllSeries() # 删除所有序列 pen=QPen(self.__colorLine) # 曲线颜色 pen.setWidth(2) seriesWave = QLineSeries() seriesWave.setUseOpenGL(True) seriesWave.setPen(pen) vx=0 intv=0.001 #1000Hz采样 pointCount=len(self.__vectData) for i in range(pointCount): value=self.__vectData[i] seriesWave.append(vx,value) vx =vx+ intv self.__axisX.setRange(0,vx) self.chart.addSeries(seriesWave) seriesWave.attachAxis(self.__axisX) seriesWave.attachAxis(self.__axisY)
def add_data(self, xdata, ydata, color=None, legend_text=None): curve = QLineSeries() pen = curve.pen() if color is not None: pen.setColor(color) pen.setWidthF(1.5) curve.setPen(pen) #curve.setUseOpenGL(True) # Decimate xdecimated, ydecimated = self.decimate(xdata, ydata) # Data must be in ms since epoch # curve.append(self.series_to_polyline(xdecimated * 1000.0, ydecimated)) for i in range(len(xdecimated)): # TODO hack x = xdecimated[i] - xdecimated[0] curve.append(QPointF(x, ydecimated[i])) self.reftime = datetime.datetime.fromtimestamp(xdecimated[0]) if legend_text is not None: curve.setName(legend_text) # Needed for mouse events on series self.chart.setAcceptHoverEvents(True) # connect signals / slots # curve.clicked.connect(self.lineseries_clicked) # curve.hovered.connect(self.lineseries_hovered) # Add series self.chart.addSeries(curve) self.ncurves += 1 self.update_axes()
class Display(QWidget): def __init__(self, trainer='MLP', debug=False): # QWidget Setup QWidget.__init__(self, flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint) self.setWindowTitle("NeuroSky GUI") self.resize(1400, 1000) # Linker Params self._linker = Linker(debug=debug, trainer=trainer) self.TRAINER_FORWARD = self._linker.trainer.add_identifier('forward') self.TRAINER_BACKWARD = self._linker.trainer.add_identifier('backward') self.TRAINER_IDLE = self._linker.trainer.add_identifier('idle') # Indicators self._raw_data_indicator = self._create_indicator('Raw Data:') self._poor_level_indicator = self._create_indicator( 'Poor Level Signal:') self._sample_rate_indicator = self._create_indicator('Sample Rate:') self._prediction_indicator = self._create_indicator('Prediction:') self._training_status_indicator = self._create_indicator( 'Training Status:') self._forward_counter_indicator = self._create_indicator( 'Current Forward Count:') self._backward_counter_indicator = self._create_indicator( 'Current Backward Count:') self._idle_counter_indicator = self._create_indicator( 'Current Idle Count:') # Initializing layout self.main_page() # Series self._x_axis = 0 self._connect_data() def main_page(self): # type: (Display) -> None # Top Layout top_left_layout = QVBoxLayout() top_left_layout.addLayout(self._raw_data_indicator['layout']) top_left_layout.addLayout(self._poor_level_indicator['layout']) top_left_layout.addLayout(self._sample_rate_indicator['layout']) top_right_layout = QVBoxLayout() top_right_layout.addWidget(self._get_connector_chart(), alignment=Qt.AlignCenter) # top_right_layout.setStretchFactor(self._get_connector_chart(), 1) top_layout = QHBoxLayout() top_layout.addLayout(top_left_layout) top_layout.addLayout(top_right_layout) # Bottom Layout bottom_left_layout = QVBoxLayout() bottom_left_layout.addLayout(self._prediction_indicator['layout']) bottom_left_layout.addLayout(self._training_status_indicator['layout']) bottom_left_layout.addLayout(self._idle_counter_indicator['layout']) bottom_left_layout.addLayout(self._forward_counter_indicator['layout']) bottom_left_layout.addLayout( self._backward_counter_indicator['layout']) bottom_right_layout = QVBoxLayout() bottom_right_layout.addWidget(self._get_processor_chart(), alignment=Qt.AlignCenter) bottom_layout = QHBoxLayout() bottom_layout.addLayout(bottom_left_layout) bottom_layout.addLayout(bottom_right_layout) # Outer Layout outer_layout = QVBoxLayout() outer_layout.addLayout(top_layout) outer_layout.addLayout(bottom_layout) # Set Layout self.setLayout(outer_layout) def _get_connector_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.blue) pen.setWidthF(1) # Series self._connector_series = QLineSeries() self._connector_series.setPen(pen) self._connector_series.useOpenGL() # Chart self._connector_chart = QChart() self._connector_chart.legend().hide() self._connector_chart.addSeries(self._connector_series) self._connector_chart.createDefaultAxes() self._connector_chart.axisX().setMax(100) self._connector_chart.axisX().setMin(0) self._connector_chart.axisY().setMax(500) self._connector_chart.axisY().setMin(-500) # Chart View view = QChartView(self._connector_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view def _get_processor_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.red) pen.setWidthF(1) # Series self._processor_series = QLineSeries() self._processor_series.setPen(pen) self._processor_series.useOpenGL() # Chart self._processor_chart = QChart() self._processor_chart.legend().hide() self._processor_chart.addSeries(self._processor_series) self._processor_chart.createDefaultAxes() self._processor_chart.axisX().setMax(100) self._processor_chart.axisX().setMin(0) self._processor_chart.axisY().setMax(5000) self._processor_chart.axisY().setMin(0) self._processor_x_axis = QValueAxis() self._processor_x_axis.setLabelFormat('%i') self._processor_chart.setAxisX(self._processor_x_axis, self._processor_series) self._processor_y_axis = QLogValueAxis() self._processor_y_axis.setLabelFormat('%g') self._processor_y_axis.setBase(8) # Chart View view = QChartView(self._processor_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view def _connect_data(self): # type: (Display) -> None self._linker.raw.connect(self._add_connector_data) self._linker.poor_signal_level.connect( lambda level: self._poor_level_indicator['label'].setText( str(level))) self._linker.sampling_rate.connect( lambda rate: self._sample_rate_indicator['label'].setText(str(rate) )) self._linker.fft.connect(self._add_processor_data) self._linker.prediction.connect( lambda prediction: self._prediction_indicator['label'].setText( str(prediction))) self._linker.training_status.connect( lambda status: self._training_status_indicator['label'].setText( str(status))) self._linker.identifiers.connect(self._connect_identifiers) def keyPressEvent(self, event): # type: (Display, {key}) -> None key = event.key() if key == Qt.Key_Escape: self._linker.close() self.close() elif key == Qt.Key_W: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_FORWARD) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_FORWARD) # ) self._linker.trainer.train(self.TRAINER_FORWARD) elif key == Qt.Key_S: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_BACKWARD) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_BACKWARD) # ) self._linker.trainer.train(self.TRAINER_BACKWARD) elif key == Qt.Key_Space: # self._linker.connector.record( # './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_IDLE) # ) # self._linker.processor.record( # './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_IDLE) # ) self._linker.trainer.train(self.TRAINER_IDLE) else: print(key) @staticmethod def _create_indicator( label): # type: (Any) -> Dict[str, Union[QHBoxLayout, QLabel]] layout = QHBoxLayout() display_widget = QLabel(label) layout.addWidget(display_widget, alignment=Qt.AlignCenter) label_widget = QLabel('Initializing...') layout.addWidget(label_widget, alignment=Qt.AlignCenter) return { 'layout': layout, 'display': display_widget, 'label': label_widget } @pyqtSlot(int) def _add_connector_data(self, data): # type: (Display, Any) -> Optional[Any] self._raw_data_indicator['label'].setText(str(data)) self._connector_series.append(self._x_axis, data) if self._connector_series.count() >= 100: self._connector_series.clear() self._x_axis = 0 else: self._x_axis += 1 @pyqtSlot(np.ndarray) def _add_processor_data( self, data): # type: (Display, {__getitem__}) -> Optional[Any] self._processor_series.clear() x_axis = data[0] y_axis = data[1] for i in range(len(x_axis)): self._processor_series.append(x_axis[i], y_axis[i]) @pyqtSlot(list) def _connect_identifiers(self, identifiers): for identifier in identifiers: if identifier['name'] == self.TRAINER_IDLE: self._idle_counter_indicator['label'].setText( str(identifier['training_count'])) elif identifier['name'] == self.TRAINER_FORWARD: self._forward_counter_indicator['label'].setText( str(identifier['training_count'])) elif identifier['name'] == self.TRAINER_BACKWARD: self._backward_counter_indicator['label'].setText( str(identifier['training_count']))
class Chart(QWidget): def __init__(self, ch0Name='ch0', ch1Name='ch1', ch2Name='ch2', ch3Name='ch3'): super(Chart, self).__init__() self.ch0Name = ch0Name self.ch1Name = ch1Name self.ch2Name = ch2Name self.ch3Name = ch3Name self.data = [] self.initUI() def initUI(self): vbox = QVBoxLayout() vbox.addWidget(self.chartUI()) vbox.addWidget(self.controlUI()) self.setLayout(vbox) def chartUI(self): self.chart1 = QLineSeries() self.chart1.setName(self.ch0Name) self.chart1.setPen(QPen(Qt.red)) self.chart2 = QLineSeries() self.chart2.setName(self.ch1Name) self.chart2.setPen(QPen(Qt.darkYellow)) self.chart3 = QLineSeries() self.chart3.setName(self.ch2Name) self.chart3.setPen(QPen(Qt.green)) self.chart4 = QLineSeries() self.chart4.setName(self.ch3Name) self.chart4.setPen(QPen(Qt.blue)) self.chart = QChart() self.chart.addSeries(self.chart1) self.chart.addSeries(self.chart2) self.chart.addSeries(self.chart3) self.chart.addSeries(self.chart4) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setTitle("laser data") self.axis_x = QValueAxis() self.axis_y = QValueAxis() self.axis_x.setTickCount(10) self.axis_y.setTickCount(10) self.axis_x.setLabelFormat('%d') self.axis_y.setLabelFormat('%d') self.axis_x.setRange(0, 1000) self.axis_y.setRange(100, 300) self.chart.setAxisX(self.axis_x, self.chart1) self.chart.setAxisY(self.axis_y, self.chart1) self.chart.setAxisX(self.axis_x, self.chart2) self.chart.setAxisY(self.axis_y, self.chart2) self.chart.setAxisX(self.axis_x, self.chart3) self.chart.setAxisY(self.axis_y, self.chart3) self.chart.setAxisX(self.axis_x, self.chart4) self.chart.setAxisY(self.axis_y, self.chart4) self.chartView = QChartView() self.chartView.setChart(self.chart) self.chartView.setRubberBand(QChartView.RectangleRubberBand) self.chartView.setRenderHint(QPainter.Antialiasing) return self.chartView def controlUI(self): self.autoRefreshCb = QCheckBox('自动刷新') self.autoRefreshCb.setChecked(True) self.ch0Enable = QCheckBox(self.ch0Name) self.ch1Enable = QCheckBox(self.ch1Name) self.ch2Enable = QCheckBox(self.ch2Name) self.ch3Enable = QCheckBox(self.ch3Name) self.ch0Enable.setChecked(True) self.ch1Enable.setChecked(True) self.ch2Enable.setChecked(True) self.ch3Enable.setChecked(True) hbox1 = QHBoxLayout() hbox1.addWidget(self.autoRefreshCb) hbox1.addWidget(self.ch0Enable) hbox1.addWidget(self.ch1Enable) hbox1.addWidget(self.ch2Enable) hbox1.addWidget(self.ch3Enable) self.xDataMinLabel = QLabel('x min:') self.xDataMaxLabel = QLabel('x max:') self.yDataMinLabel = QLabel('y min:') self.yDataMaxLabel = QLabel('y max:') self.xDataMinLine = QLineEdit() self.xDataMaxLine = QLineEdit() self.yDataMinLine = QLineEdit() self.yDataMaxLine = QLineEdit() self.setBtn = QPushButton('设置') hbox = QHBoxLayout() hbox.addWidget(self.xDataMinLabel) hbox.addWidget(self.xDataMinLine) hbox.addWidget(self.xDataMaxLabel) hbox.addWidget(self.xDataMaxLine) hbox.addWidget(self.yDataMinLabel) hbox.addWidget(self.yDataMinLine) hbox.addWidget(self.yDataMaxLabel) hbox.addWidget(self.yDataMaxLine) hbox.addWidget(self.setBtn) mainLayout = QVBoxLayout() mainLayout.addLayout(hbox1) mainLayout.addLayout(hbox) frame = QFrame() frame.setLayout(mainLayout) self.setBtn.clicked.connect(self.setAxisRange) self.ch0Enable.clicked.connect(self.changeCh) self.ch1Enable.clicked.connect(self.changeCh) self.ch2Enable.clicked.connect(self.changeCh) self.ch3Enable.clicked.connect(self.changeCh) return frame # @timethis def update(self): x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() try: for i in range(0, len(x0Data)): if self.ch0Enable.isChecked(): self.chart1.append(QPoint(x0Data[i], y0Data[i])) for i in range(0, len(x1Data)): if self.ch1Enable.isChecked(): self.chart2.append(QPoint(x1Data[i], y1Data[i])) for i in range(0, len(x2Data)): if self.ch2Enable.isChecked(): self.chart3.append(QPoint(x2Data[i], y2Data[i])) for i in range(0, len(x3Data)): if self.ch3Enable.isChecked(): self.chart4.append(QPoint(x3Data[i], y3Data[i])) except: logging.debug('y0Data is %s' % y0Data) logging.debug('y1Data is %s' % y1Data) logging.debug('y2Data is %s' % y2Data) logging.debug('y3Data is %s' % y3Data) self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() # self.chartView.update() if self.autoRefreshCb.isChecked(): self.fillAxisRange() self.setAxisRange() def fillAxisRange(self): x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data tmp = [min(x0Data), min(x1Data), min(x2Data), min(x3Data)] xDataMin = min(tmp) tmp = [max(x0Data), max(x1Data), max(x2Data), max(x3Data)] xDataMax = max(tmp) tmp = [min(y0Data), min(y1Data), min(y2Data), min(y3Data)] yDataMin = min(tmp) tmp = [max(y0Data), max(y1Data), max(y2Data), max(y3Data)] yDataMax = max(tmp) xDataAvr = (xDataMin + xDataMax) // 2 yDataAvr = (yDataMin + yDataMax) // 2 self.xDataMinLine.setText(str(xDataAvr - xDataAvr*6//5)) self.xDataMaxLine.setText(str(xDataAvr + xDataAvr*6//5)) self.yDataMinLine.setText(str(yDataAvr - yDataAvr*6//5)) self.yDataMaxLine.setText(str(yDataAvr + yDataAvr*6//5)) @pyqtSlot() def setAxisRange(self): if self.xDataMinLine.text() and self.xDataMaxLine.text() and \ self.yDataMinLine.text() and self.yDataMaxLine.text(): self.axis_x.setRange(int(self.xDataMinLine.text()), int(self.xDataMaxLine.text())) self.axis_y.setRange(int(self.yDataMinLine.text()), int(self.yDataMaxLine.text())) else: QMessageBox.warning(self, '警告', '缺少参数') @pyqtSlot() def changeCh(self): self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data for i in range(0, len(x0Data)): if self.ch0Enable.isChecked(): self.chart1.append(QPoint(x0Data[i], y0Data[i])) for i in range(0, len(x1Data)): if self.ch1Enable.isChecked(): self.chart2.append(QPoint(x1Data[i], y1Data[i])) for i in range(0, len(x2Data)): if self.ch2Enable.isChecked(): self.chart3.append(QPoint(x2Data[i], y2Data[i])) for i in range(0, len(x3Data)): if self.ch3Enable.isChecked(): self.chart4.append(QPoint(x3Data[i], y3Data[i]))
def initChart(self): series = QLineSeries() data = [ QPoint(0, 4), QPoint(3, 2), QPoint(7, 7), QPoint(9, 10), QPoint(12, 17), QPoint(17, 9), QPoint(20, 22), QPoint(22, 2), QPoint(28, 13) ] series.append(data) # creating chart object chart = QChart() chart.legend().hide() chart.addSeries(series) pen = QPen(QColor(0, 0, 128)) pen.setWidth(3) series.setPen(pen) font = QFont("Open Sans") font.setPixelSize(40) font.setBold(True) chart.setTitleFont(font) chart.setTitleBrush(QBrush(Qt.yellow)) chart.setTitle("Custom Chart Demo") backgroundGradient = QLinearGradient() backgroundGradient.setStart(QPoint(0, 0)) backgroundGradient.setFinalStop(QPoint(0, 1)) backgroundGradient.setColorAt(0.0, QColor(175, 201, 182)) backgroundGradient.setColorAt(1.0, QColor(51, 105, 66)) backgroundGradient.setCoordinateMode(QGradient.ObjectBoundingMode) chart.setBackgroundBrush(backgroundGradient) plotAreaGraident = QLinearGradient() plotAreaGraident.setStart(QPoint(0, 1)) plotAreaGraident.setFinalStop(QPoint(1, 0)) plotAreaGraident.setColorAt(0.0, QColor(222, 222, 222)) plotAreaGraident.setColorAt(1.0, QColor(51, 105, 66)) plotAreaGraident.setCoordinateMode(QGradient.ObjectBoundingMode) chart.setPlotAreaBackgroundBrush(plotAreaGraident) chart.setPlotAreaBackgroundVisible(True) # customize axis axisX = QCategoryAxis() axisY = QCategoryAxis() labelFont = QFont("Open Sans") labelFont.setPixelSize(25) axisX.setLabelsFont(labelFont) axisY.setLabelsFont(labelFont) axisPen = QPen(Qt.white) axisPen.setWidth(2) axisX.setLinePen(axisPen) axisY.setLinePen(axisPen) axisBrush = QBrush(Qt.white) axisX.setLabelsBrush(axisBrush) axisY.setLabelsBrush(axisBrush) axisX.setRange(0, 30) axisX.append("low", 10) axisX.append("medium", 20) axisX.append("high", 30) axisY.setRange(0, 30) axisY.append("slow", 10) axisY.append("average", 20) axisY.append("fast", 30) axisX.setGridLineVisible(False) axisY.setGridLineVisible(False) chart.addAxis(axisX, Qt.AlignBottom) chart.addAxis(axisY, Qt.AlignLeft) series.attachAxis(axisX) series.attachAxis(axisY) self.chartView = QChartView(chart) self.chartView.setRenderHint(QPainter.Antialiasing)
def __createChart(self): ##创建图表 chart = QChart() #创建 Chart ## chart.setTitle("简单函数曲线") chart.legend().setVisible(True) self.chartView.setChart(chart) #Chart添加到chartView pen=QPen() pen.setWidth(2) ##========LineSeries折线 和 ScatterSeries散点 seriesLine = QLineSeries() seriesLine.setName("LineSeries折线") seriesLine.setPointsVisible(False) #数据点不可见 pen.setColor(Qt.red) seriesLine.setPen(pen) seriesLine.hovered.connect(self.do_series_hovered) #信号 hovered seriesLine.clicked.connect(self.do_series_clicked) #信号 clicked chart.addSeries(seriesLine) #添加到chart seriesLinePoint = QScatterSeries() #散点序列 seriesLinePoint.setName("ScatterSeries散点") shape=QScatterSeries.MarkerShapeCircle #MarkerShapeRectangle seriesLinePoint.setMarkerShape(shape) #散点形状,只有2种 seriesLinePoint.setBorderColor(Qt.yellow) seriesLinePoint.setBrush(QBrush(Qt.red)) seriesLinePoint.setMarkerSize(10) #散点大小 seriesLinePoint.hovered.connect(self.do_series_hovered) #信号 hovered seriesLinePoint.clicked.connect(self.do_series_clicked) #信号 clicked chart.addSeries(seriesLinePoint) #添加到chart ##======== SplineSeries 曲线和 QScatterSeries 散点 seriesSpLine = QSplineSeries() seriesSpLine.setName("SplineSeries曲线") seriesSpLine.setPointsVisible(False) #数据点不可见 pen.setColor(Qt.blue) seriesSpLine.setPen(pen) seriesSpLine.hovered.connect(self.do_series_hovered) #信号 hovered seriesSpLine.clicked.connect(self.do_series_clicked) #信号 clicked seriesSpPoint = QScatterSeries() #散点序列 seriesSpPoint.setName("QScatterSeries") shape=QScatterSeries.MarkerShapeRectangle #MarkerShapeCircle seriesSpPoint.setMarkerShape(shape) #散点形状,只有2种 seriesSpPoint.setBorderColor(Qt.green) seriesSpPoint.setBrush(QBrush(Qt.blue)) seriesSpPoint.setMarkerSize(10) #散点大小 seriesSpPoint.hovered.connect(self.do_series_hovered) #信号 hovered seriesSpPoint.clicked.connect(self.do_series_clicked) #信号 clicked chart.addSeries(seriesSpLine) chart.addSeries(seriesSpPoint) ## 创建缺省坐标轴 chart.createDefaultAxes() #创建缺省坐标轴并与序列关联 chart.axisX().setTitleText("time(secs)") chart.axisX().setRange(0,10) chart.axisX().applyNiceNumbers() chart.axisY().setTitleText("value") chart.axisY().setRange(-2,2) chart.axisY().applyNiceNumbers() for marker in chart.legend().markers(): #QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked)
class Chart(QChart): MIN_X = 0 MAX_X = 750 MIN_Y = -1 MAX_Y = 1 TICKS = 5 PENCOLOR = Qt.red PENWIDTH = 1 def __init__(self, parent=None): super(Chart, self).__init__(parent) self.parent = parent # we will draw lines self.series = QLineSeries(parent) # color and pen-width self.series.setPen(QPen(self.PENCOLOR, self.PENWIDTH)) self.addSeries(self.series) self.legend().hide() self.__construct_axises() def setRange_X_axis(self, min_X, max_X): self.MIN_X = min_X self.MAX_X = max_X self.axisX().setRange(self.MIN_X, self.MAX_X) def setRange_Y_axis(self, min_Y, max_Y): self.MIN_Y = min_Y self.MAX_Y = max_Y self.axisY().setRange(self.MIN_Y, self.MAX_Y) def add_point(self, x, y): self.series.append(x, y) def get_series(self) -> list: return self.series.pointsVector() def remove_point(self, index): self.series.remove(index) def remove_points(self, index, count): self.series.removePoints(index, count) def replace_point(self, index, x, y): self.series.replace(index, x, y) def replace_series(self, lst): self.series.replace(lst) def get_series_count(self): return self.series.count() def __construct_axises(self): self.createDefaultAxes() # X-Axis x_axis = self.axisX() x_axis.hide() x_axis.setRange(self.MIN_X, self.MAX_X) # Y-axis y_axis = self.axisY() y_axis.setRange(self.MIN_Y, self.MAX_Y) y_axis.setTickCount(self.TICKS)
def run_evolution(): range_a = float(str(form.input_a.text())) range_b = float(str(form.input_b.text())) precision = int(str(form.input_d.text())) particles_number = int(str(form.input_particles.text())) iterations = int(str(form.input_iterations.text())) c1_weight = float(str(form.input_c1.text())) c2_weight = float(str(form.input_c2.text())) c3_weight = float(str(form.input_c3.text())) neighborhood_distance = float(str(form.input_neighborhood.text())) app.setOverrideCursor(QtCore.Qt.WaitCursor) best_real, best_fx, best_fxs, avg_fxs, min_fxs, particles = evolution( range_a, range_b, precision, particles_number, iterations, c1_weight, c2_weight, c3_weight, neighborhood_distance) chart = QChart() bests = QLineSeries() avg = QLineSeries() mins = QLineSeries() pen_best = bests.pen() pen_best.setWidth(1) pen_best.setBrush(QtGui.QColor("red")) pen_avg = avg.pen() pen_avg.setWidth(1) pen_avg.setBrush(QtGui.QColor("green")) pen_min = mins.pen() pen_min.setWidth(1) pen_min.setBrush(QtGui.QColor("blue")) bests.setPen(pen_best) avg.setPen(pen_avg) mins.setPen(pen_min) form.best_table.item(1, 0).setText(str(best_real)) form.best_table.item(1, 1).setText(str(best_fx)) for i in range(len(best_fxs)): bests.append(i + 1, best_fxs[i]) avg.append(i + 1, avg_fxs[i]) mins.append(i + 1, min_fxs[i]) chart.addSeries(bests) chart.addSeries(avg) chart.addSeries(mins) chart.setBackgroundBrush(QtGui.QColor(41, 43, 47)) chart.createDefaultAxes() chart.legend().hide() chart.setContentsMargins(-10, -10, -10, -10) chart.layout().setContentsMargins(0, 0, 0, 0) chart.axisX().setTickCount(11) chart.axisX().setLabelsColor(QtGui.QColor("white")) chart.axisX().setGridLineColor(QtGui.QColor("grey")) chart.axisX().setLabelFormat("%i") chart.axisY().setRange(-2, 2) chart.axisY().setLabelsColor(QtGui.QColor("white")) chart.axisY().setGridLineColor(QtGui.QColor("grey")) form.widget.setChart(chart) draw_thread.particles_list = particles draw_thread.start() app.restoreOverrideCursor()
class TelemetryDialog(QDialog): resized = QtCore.pyqtSignal() visibility = QtCore.pyqtSignal(bool) def __init__(self, winTitle="Network Telemetry", parent=None): super(TelemetryDialog, self).__init__(parent) self.visibility.connect(self.onVisibilityChanged) self.winTitle = winTitle self.updateLock = Lock() # Used to detect network change self.lastNetKey = "" self.lastSeen = None self.maxPoints = 20 self.maxRowPoints = 60 self.paused = False self.streamingSave = False self.streamingFile = None self.linesBeforeFlush = 10 self.currentLine = 0 # OK and Cancel buttons #buttons = QDialogButtonBox(QDialogButtonBox.Ok,Qt.Horizontal, self) #buttons.accepted.connect(self.accept) #buttons.move(170, 280) desktopSize = QApplication.desktop().screenGeometry() #self.mainWidth=1024 #self.mainHeight=768 #self.mainWidth = desktopSize.width() * 3 / 4 #self.mainHeight = desktopSize.height() * 3 / 4 self.setGeometry(self.geometry().x(), self.geometry().y(), desktopSize.width() / 2, desktopSize.height() / 2) self.setWindowTitle(winTitle) self.radar = RadarWidget(self) self.radar.setGeometry(self.geometry().width() / 2, 10, self.geometry().width() / 2 - 20, self.geometry().width() / 2 - 20) self.createTable() self.btnExport = QPushButton("Export Table", self) self.btnExport.clicked[bool].connect(self.onExportClicked) self.btnExport.setStyleSheet("background-color: rgba(2,128,192,255);") self.btnPause = QPushButton("Pause Table", self) self.btnPause.setCheckable(True) self.btnPause.clicked[bool].connect(self.onPauseClicked) self.btnPause.setStyleSheet("background-color: rgba(2,128,192,255);") self.btnStream = QPushButton("Streaming Save", self) self.btnStream.setCheckable(True) self.btnStream.clicked[bool].connect(self.onStreamClicked) self.btnStream.setStyleSheet("background-color: rgba(2,128,192,255);") self.createChart() self.setBlackoutColors() self.setMinimumWidth(600) self.setMinimumHeight(600) self.center() def createTable(self): # Set up location table self.locationTable = QTableWidget(self) self.locationTable.setColumnCount(8) self.locationTable.setGeometry(10, 10, self.geometry().width() / 2 - 20, self.geometry().height() / 2) self.locationTable.setShowGrid(True) self.locationTable.setHorizontalHeaderLabels([ 'macAddr', 'SSID', 'Strength', 'Timestamp', 'GPS', 'Latitude', 'Longitude', 'Altitude' ]) self.locationTable.resizeColumnsToContents() self.locationTable.setRowCount(0) self.locationTable.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.ntRightClickMenu = QMenu(self) newAct = QAction('Copy', self) newAct.setStatusTip('Copy data to clipboard') newAct.triggered.connect(self.onCopy) self.ntRightClickMenu.addAction(newAct) self.locationTable.setContextMenuPolicy(Qt.CustomContextMenu) self.locationTable.customContextMenuRequested.connect( self.showNTContextMenu) def setBlackoutColors(self): self.locationTable.setStyleSheet( "QTableView {background-color: black;gridline-color: white;color: white} QTableCornerButton::section{background-color: white;}" ) headerStyle = "QHeaderView::section{background-color: white;border: 1px solid black;color: black;} QHeaderView::down-arrow,QHeaderView::up-arrow {background: none;}" self.locationTable.horizontalHeader().setStyleSheet(headerStyle) self.locationTable.verticalHeader().setStyleSheet(headerStyle) mainTitleBrush = QBrush(Qt.red) self.timeChart.setTitleBrush(mainTitleBrush) self.timeChart.setBackgroundBrush(QBrush(Qt.black)) self.timeChart.axisX().setLabelsColor(Qt.white) self.timeChart.axisY().setLabelsColor(Qt.white) titleBrush = QBrush(Qt.white) self.timeChart.axisX().setTitleBrush(titleBrush) self.timeChart.axisY().setTitleBrush(titleBrush) def resizeEvent(self, event): wDim = self.geometry().width() / 2 - 20 hDim = self.geometry().height() / 2 smallerDim = wDim if hDim < smallerDim: smallerDim = hDim # Radar self.radar.setGeometry(self.geometry().width() - smallerDim - 10, 10, smallerDim, smallerDim) # chart self.timePlot.setGeometry(10, 10, self.geometry().width() - smallerDim - 30, smallerDim) # Buttons self.btnPause.setGeometry(10, self.geometry().height() / 2 + 18, 110, 25) self.btnExport.setGeometry(150, self.geometry().height() / 2 + 18, 110, 25) self.btnStream.setGeometry(290, self.geometry().height() / 2 + 18, 110, 25) # Table self.locationTable.setGeometry(10, self.geometry().height() / 2 + 50, self.geometry().width() - 20, self.geometry().height() / 2 - 60) def center(self): # Get our geometry qr = self.frameGeometry() # Find the desktop center point cp = QDesktopWidget().availableGeometry().center() # Move our center point to the desktop center point qr.moveCenter(cp) # Move the top-left point of the application window to the top-left point of the qr rectangle, # basically centering the window self.move(qr.topLeft()) def showNTContextMenu(self, pos): curRow = self.locationTable.currentRow() if curRow == -1: return self.ntRightClickMenu.exec_(self.locationTable.mapToGlobal(pos)) def onCopy(self): self.updateLock.acquire() curRow = self.locationTable.currentRow() curCol = self.locationTable.currentColumn() if curRow == -1 or curCol == -1: self.updateLock.release() return curText = self.locationTable.item(curRow, curCol).text() clipboard = QApplication.clipboard() clipboard.setText(curText) self.updateLock.release() def onVisibilityChanged(self, visible): if not visible: self.paused = True self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);") # We're coming out of streaming self.streamingSave = False self.btnStream.setStyleSheet( "background-color: rgba(2,128,192,255);") self.btnStream.setChecked(False) if (self.streamingFile): self.streamingFile.close() self.streamingFile = None return else: self.paused = False self.btnPause.setStyleSheet( "background-color: rgba(2,128,192,255);") if self.locationTable.rowCount() > 1: self.locationTable.scrollToItem(self.locationTable.item(0, 0)) def hideEvent(self, event): self.visibility.emit(False) def showEvent(self, event): self.visibility.emit(True) def onPauseClicked(self, pressed): if self.btnPause.isChecked(): self.paused = True self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);") else: self.paused = False self.btnPause.setStyleSheet( "background-color: rgba(2,128,192,255);") def onStreamClicked(self, pressed): if not self.btnStream.isChecked(): # We're coming out of streaming self.streamingSave = False self.btnStream.setStyleSheet( "background-color: rgba(2,128,192,255);") if (self.streamingFile): self.streamingFile.close() self.streamingFile = None return self.btnStream.setStyleSheet("background-color: rgba(255,0,0,255);") self.streamingSave = True fileName = self.saveFileDialog() if not fileName: self.btnStream.setStyleSheet( "background-color: rgba(2,128,192,255);") self.btnStream.setChecked(False) return try: self.streamingFile = open( fileName, 'w', 1 ) # 1 says use line buffering, otherwise it fully buffers and doesn't write except: QMessageBox.question(self, 'Error', "Unable to write to " + fileName, QMessageBox.Ok) self.streamingFile = None self.streamingSave = False self.btnStream.setStyleSheet( "background-color: rgba(2,128,192,255);") self.btnStream.setChecked(False) return self.streamingFile.write( 'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n' ) def onExportClicked(self): fileName = self.saveFileDialog() if not fileName: return try: outputFile = open(fileName, 'w') except: QMessageBox.question(self, 'Error', "Unable to write to " + fileName, QMessageBox.Ok) return outputFile.write( 'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n' ) numItems = self.locationTable.rowCount() if numItems == 0: outputFile.close() return self.updateLock.acquire() for i in range(0, numItems): outputFile.write( self.locationTable.item(i, 0).text() + ',"' + self.locationTable.item(i, 1).text() + '",' + self.locationTable.item(i, 2).text() + ',' + self.locationTable.item(i, 3).text()) outputFile.write(',' + self.locationTable.item(i, 4).text() + ',' + self.locationTable.item(i, 5).text() + ',' + self.locationTable.item(i, 6).text() + ',' + self.locationTable.item(i, 7).text() + '\n') self.updateLock.release() outputFile.close() def saveFileDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName( self, "QFileDialog.getSaveFileName()", "", "CSV Files (*.csv);;All Files (*)", options=options) if fileName: return fileName else: return None def createChart(self): self.timeChart = QChart() titleFont = QFont() titleFont.setPixelSize(18) titleBrush = QBrush(QColor(0, 0, 255)) self.timeChart.setTitleFont(titleFont) self.timeChart.setTitleBrush(titleBrush) self.timeChart.setTitle('Signal (Past ' + str(self.maxPoints) + ' Samples)') # self.timeChart.addSeries(testseries) # self.timeChart.createDefaultAxes() self.timeChart.legend().hide() # Axis examples: https://doc.qt.io/qt-5/qtcharts-multiaxis-example.html newAxis = QValueAxis() newAxis.setMin(0) newAxis.setMax(self.maxPoints) newAxis.setTickCount(11) newAxis.setLabelFormat("%d") newAxis.setTitleText("Sample") self.timeChart.addAxis(newAxis, Qt.AlignBottom) newAxis = QValueAxis() newAxis.setMin(-100) newAxis.setMax(-10) newAxis.setTickCount(9) newAxis.setLabelFormat("%d") newAxis.setTitleText("dBm") self.timeChart.addAxis(newAxis, Qt.AlignLeft) chartBorder = Qt.darkGray self.timePlot = QChartView(self.timeChart, self) self.timePlot.setBackgroundBrush(chartBorder) self.timePlot.setRenderHint(QPainter.Antialiasing) self.timeSeries = QLineSeries() pen = QPen(Qt.yellow) pen.setWidth(2) self.timeSeries.setPen(pen) self.timeChart.addSeries(self.timeSeries) self.timeSeries.attachAxis(self.timeChart.axisX()) self.timeSeries.attachAxis(self.timeChart.axisY()) def updateNetworkData(self, curNet): if not self.isVisible(): return # Signal is -NN dBm. Need to make it positive for the plot self.radar.updateData(curNet.signal * -1) if self.winTitle == "Client Telemetry": self.setWindowTitle(self.winTitle + " - [" + curNet.macAddr + "] " + curNet.ssid) else: self.setWindowTitle(self.winTitle + " - " + curNet.ssid) self.radar.draw() # Network changed. Clear our table and time data updateChartAndTable = False self.updateLock.acquire() if (curNet.getKey() != self.lastNetKey): self.lastNetKey = curNet.getKey() self.locationTable.setRowCount(0) self.timeSeries.clear() updateChartAndTable = True ssidTitle = curNet.ssid if len(ssidTitle) > 28: ssidTitle = ssidTitle[:28] ssidTitle = ssidTitle + '...' self.timeChart.setTitle(ssidTitle + ' Signal (Past ' + str(self.maxPoints) + ' Samples)') else: if self.lastSeen != curNet.lastSeen: updateChartAndTable = True if updateChartAndTable: # Update chart numPoints = len(self.timeSeries.pointsVector()) if numPoints >= self.maxPoints: self.timeSeries.remove(0) # Now we need to reset the x data to pull the series back counter = 0 for curPoint in self.timeSeries.pointsVector(): self.timeSeries.replace(counter, counter, curPoint.y()) counter += 1 if curNet.signal >= -100: self.timeSeries.append(numPoints, curNet.signal) else: self.timeSeries.append(numPoints, -100) # Update Table self.addTableData(curNet) # Limit points in each if self.locationTable.rowCount() > self.maxRowPoints: self.locationTable.setRowCount(self.maxRowPoints) self.updateLock.release() def addTableData(self, curNet): if self.paused: return # rowPosition = self.locationTable.rowCount() # Always insert at row(0) rowPosition = 0 self.locationTable.insertRow(rowPosition) #if (addedFirstRow): # self.locationTable.setRowCount(1) # ['macAddr','SSID', 'Strength', 'Timestamp','GPS', 'Latitude', 'Longitude', 'Altitude'] self.locationTable.setItem(rowPosition, 0, QTableWidgetItem(curNet.macAddr)) tmpssid = curNet.ssid if (len(tmpssid) == 0): tmpssid = '<Unknown>' newSSID = QTableWidgetItem(tmpssid) self.locationTable.setItem(rowPosition, 1, newSSID) self.locationTable.setItem(rowPosition, 2, IntTableWidgetItem(str(curNet.signal))) self.locationTable.setItem( rowPosition, 3, DateTableWidgetItem(curNet.lastSeen.strftime("%m/%d/%Y %H:%M:%S"))) if curNet.gps.isValid: self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('Yes')) else: self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('No')) self.locationTable.setItem( rowPosition, 5, FloatTableWidgetItem(str(curNet.gps.latitude))) self.locationTable.setItem( rowPosition, 6, FloatTableWidgetItem(str(curNet.gps.longitude))) self.locationTable.setItem( rowPosition, 7, FloatTableWidgetItem(str(curNet.gps.altitude))) #order = Qt.DescendingOrder #self.locationTable.sortItems(3, order ) # If we're in streaming mode, write the data out to disk as well if self.streamingFile: self.streamingFile.write( self.locationTable.item(rowPosition, 0).text() + ',"' + self.locationTable.item(rowPosition, 1).text() + '",' + self.locationTable.item(rowPosition, 2).text() + ',' + self.locationTable.item(rowPosition, 3).text() + ',' + self.locationTable.item(rowPosition, 4).text() + ',' + self.locationTable.item(rowPosition, 5).text() + ',' + self.locationTable.item(rowPosition, 6).text() + ',' + self.locationTable.item(rowPosition, 7).text() + '\n') if (self.currentLine > self.linesBeforeFlush): self.streamingFile.flush() self.currentLine += 1 numRows = self.locationTable.rowCount() if numRows > 1: self.locationTable.scrollToItem(self.locationTable.item(0, 0)) def onTableHeadingClicked(self, logical_index): header = self.locationTable.horizontalHeader() order = Qt.DescendingOrder # order = Qt.DescendingOrder if not header.isSortIndicatorShown(): header.setSortIndicatorShown(True) elif header.sortIndicatorSection() == logical_index: # apparently, the sort order on the header is already switched # when the section was clicked, so there is no need to reverse it order = header.sortIndicatorOrder() header.setSortIndicator(logical_index, order) self.locationTable.sortItems(logical_index, order) def updateData(self, newRadius): self.radar.updateData(newRadius) def showTelemetry(parent=None): dialog = TelemetryDialog(parent) result = dialog.exec_() return (result == QDialog.Accepted)
def __drawChart(self): ##绘制图表 self.chart.removeAllSeries() #删除所有序列 self.chart.setTitle("股票日线图--" + self.ui.tabWidget.tabText(0)) ## 1. 创建蜡烛图 seriesCandle = QCandlestickSeries() seriesCandle.setName("蜡烛图") seriesCandle.setIncreasingColor(Qt.red) #暴涨 seriesCandle.setDecreasingColor(Qt.darkGreen) #暴跌 visible = self.ui.chkBox_Outline.isChecked() seriesCandle.setBodyOutlineVisible(visible) seriesCandle.setCapsVisible(self.ui.chkBox_Caps.isChecked()) self.chart.addSeries(seriesCandle) seriesCandle.attachAxis(self.__axisX) seriesCandle.attachAxis(self.__axisY) seriesCandle.clicked.connect(self.do_candleClicked) seriesCandle.hovered.connect(self.do_candleHovered) ## 2. 创建MA曲线 pen = QPen() pen.setWidth(2) seriesMA1 = QLineSeries() #不能使用QSplineSeries seriesMA1.setName("MA5") pen.setColor(Qt.magenta) seriesMA1.setPen(pen) self.chart.addSeries(seriesMA1) seriesMA1.attachAxis(self.__axisX) seriesMA1.attachAxis(self.__axisY) seriesMA2 = QLineSeries() seriesMA2.setName("MA10") pen.setColor(Qt.yellow) seriesMA2.setPen(pen) self.chart.addSeries(seriesMA2) seriesMA2.attachAxis(self.__axisX) seriesMA2.attachAxis(self.__axisY) seriesMA3 = QLineSeries() seriesMA3.setName("MA20") pen.setColor(Qt.cyan) seriesMA3.setPen(pen) self.chart.addSeries(seriesMA3) seriesMA3.attachAxis(self.__axisX) seriesMA3.attachAxis(self.__axisY) seriesMA4 = QLineSeries() seriesMA4.setName("MA60") pen.setColor(Qt.green) #green seriesMA4.setPen(pen) self.chart.addSeries(seriesMA4) seriesMA4.attachAxis(self.__axisX) seriesMA4.attachAxis(self.__axisY) ## 3. 填充数据到序列 dataRowCount = self.itemModel.rowCount() #数据点个数 for i in range(dataRowCount): dateStr = self.itemModel.item(i, 0).text() #日期字符串,如"2017/02/03" dateValue = QDate.fromString(dateStr, "yyyy/MM/dd") #QDate dtValue = QDateTime(dateValue) #日期时间 QDateTime timeStamp = dtValue.toMSecsSinceEpoch() #毫秒数 oneCandle = QCandlestickSet() #QCandlestickSet oneCandle.setOpen(float(self.itemModel.item(i, 1).text())) #开盘 oneCandle.setHigh(float(self.itemModel.item(i, 2).text())) #最高 oneCandle.setLow(float(self.itemModel.item(i, 3).text())) #最低 oneCandle.setClose(float(self.itemModel.item(i, 4).text())) #收盘 oneCandle.setTimestamp(timeStamp) #时间戳 seriesCandle.append(oneCandle) #添加到序列 M1 = float(self.itemModel.item(i, 5).text()) M2 = float(self.itemModel.item(i, 6).text()) M3 = float(self.itemModel.item(i, 7).text()) M4 = float(self.itemModel.item(i, 8).text()) seriesMA1.append(timeStamp, M1) seriesMA2.append(timeStamp, M2) seriesMA3.append(timeStamp, M3) seriesMA4.append(timeStamp, M4) ## 4. 设置坐标轴范围 minDateStr = self.itemModel.item(0, 0).text() #日期字符串,如"2017/02/03" minDate = QDate.fromString(minDateStr, "yyyy/MM/dd") #QDate minDateTime = QDateTime(minDate) #最小日期时间,QDateTime maxDateStr = self.itemModel.item(dataRowCount - 1, 0).text() #日期字符串,如"2017/05/03" maxDate = QDate.fromString(maxDateStr, "yyyy/MM/dd") maxDateTime = QDateTime(maxDate) #最大日期时间 self.__axisX.setRange(minDateTime, maxDateTime) #日期时间范围 dateFormat = self.ui.comboDateFormat.currentText() #格式,如"MM-dd" self.__axisX.setFormat(dateFormat) #标签格式 self.__axisY.applyNiceNumbers() #自动 for marker in self.chart.legend().markers(): #QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked)
class ContentView(QWidget): def __init__(self): super().__init__() self.m_chart_1 = QChart() self.m_chart_2 = QChart() self.m_chart_3 = QChart() self.m_chart_4 = QChart() self.m_series_1 = QLineSeries() self.m_series_2 = QLineSeries() self.m_series_3 = QLineSeries() self.m_series_4 = QLineSeries() self.y_original = [] self.x_data = [] self.y_processed = [] self.sampling_rate = 0 self.pathForVocalMute = "" self.select_action_drop = QComboBox() self.echo_shift = 0.4 self.echo_alpha = 0.5 self.init_ui() def init_ui(self): main_layout = QVBoxLayout() # Drag&Drop area drag_drop = DragDropArea(parent=self) main_layout.addWidget(drag_drop) # Chart layout chart_layout_1 = QHBoxLayout() chart_layout_2 = QHBoxLayout() # Chart 1 chart_view_1 = QChartView(self.m_chart_1) chart_view_1.setMinimumSize(400, 300) self.m_chart_1.addSeries(self.m_series_1) pen = self.m_series_1.pen() pen.setColor(Qt.red) pen.setWidthF(.1) self.m_series_1.setPen(pen) self.m_series_1.setUseOpenGL(True) axis_x = QValueAxis() axis_x.setRange(0, 100) axis_x.setLabelFormat("%g") axis_x.setTitleText("Samples") axis_y = QValueAxis() axis_y.setRange(-10, 10) axis_y.setTitleText("Audio level") self.m_chart_1.setAxisX(axis_x, self.m_series_1) self.m_chart_1.setAxisY(axis_y, self.m_series_1) self.m_chart_1.setTitle("Original signal time domain") chart_layout_1.addWidget(chart_view_1) # Chart 2 chart_view_2 = QChartView(self.m_chart_2) chart_view_2.setMinimumSize(400, 300) self.m_chart_2.setTitle("Original signal frequency domain") pen = self.m_series_2.pen() pen.setColor(Qt.blue) pen.setWidthF(.1) self.m_series_2.setPen(pen) self.m_series_2.setUseOpenGL(True) self.m_chart_2.addSeries(self.m_series_2) chart_layout_1.addWidget(chart_view_2) # Chart 3 chart_view_3 = QChartView(self.m_chart_3) chart_view_3.setMinimumSize(400, 300) self.m_chart_3.addSeries(self.m_series_3) pen = self.m_series_3.pen() pen.setColor(Qt.green) pen.setWidthF(.1) self.m_series_3.setPen(pen) self.m_series_3.setUseOpenGL(True) axis_x = QValueAxis() axis_x.setRange(0, 100) axis_x.setLabelFormat("%g") axis_x.setTitleText("Samples") axis_y = QValueAxis() axis_y.setRange(-10, 10) axis_y.setTitleText("Audio level") self.m_chart_3.setAxisX(axis_x, self.m_series_3) self.m_chart_3.setAxisY(axis_y, self.m_series_3) self.m_chart_3.setTitle("Processed signal time domain") chart_layout_2.addWidget(chart_view_3) # Chart 4 chart_view_4 = QChartView(self.m_chart_4) chart_view_4.setMinimumSize(400, 300) self.m_chart_4.setTitle("Processed signal frequency domain") pen = self.m_series_4.pen() pen.setColor(Qt.magenta) pen.setWidthF(.1) self.m_series_4.setPen(pen) self.m_series_4.setUseOpenGL(True) self.m_chart_4.addSeries(self.m_series_4) chart_layout_2.addWidget(chart_view_4) main_layout.addLayout(chart_layout_1) main_layout.addLayout(chart_layout_2) # Action buttons player_layout = QHBoxLayout() self.select_action_drop.addItems([ "Add noise", "Filter", "Mute equipment", "Mute vocal", "Add echo", "Filter echo" ]) player_layout.addWidget(self.select_action_drop) noise_jc = QIcon('rate_ic.png') noise_btn = QPushButton('Process') noise_btn.setIcon(noise_jc) noise_btn.clicked.connect(self.on_action) player_layout.addWidget(noise_btn) play_jc = QIcon('play_ic.png') play_orig_btn = QPushButton('Play Original') play_orig_btn.setIcon(play_jc) play_orig_btn.clicked.connect(self.on_play_orig) player_layout.addWidget(play_orig_btn) play_jc = QIcon('play_ic.png') play_btn = QPushButton('Play Processed') play_btn.setIcon(play_jc) play_btn.clicked.connect(self.on_play) player_layout.addWidget(play_btn) stop_jc = QIcon('stop_ic.png') stop_btn = QPushButton('Stop') stop_btn.setIcon(stop_jc) stop_btn.clicked.connect(self.on_stop) player_layout.addWidget(stop_btn) main_layout.addLayout(player_layout) self.setLayout(main_layout) '''' Toolbar actions ''' def browse_file(self): path1 = QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'), '*.wav') print(path1[0]) rate, data = wavfile.read(path1[0]) self.sampling_rate = rate self.y_original = data[:, 0] self.show_original_data() def on_file_upload(self, file_url): print(file_url[7:]) self.pathForVocalMute = file_url[7:] rate, data = wavfile.read(file_url[7:]) self.sampling_rate = rate self.y_original = data[:, 0] self.show_original_data() def on_save(self): print("on_save") if len(self.y_processed) > 0: path = QFileDialog.getSaveFileName(self, 'Save File', os.getenv('HOME'), 'audio/wav') if path[0] != '': data2 = np.asarray([self.y_processed, self.y_processed]).transpose() wavfile.write(path[0], self.sampling_rate, data2) else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("No path") msg.setInformativeText("You should define path to save file") msg.setWindowTitle("Error") msg.exec_() else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("No data") msg.setInformativeText( "No data to save, you should upload and process sound file") msg.setWindowTitle("Error") msg.exec_() '''' Action selection ''' def on_action(self): if self.select_action_drop.currentText() == "Add noise": self.on_add_noise() elif self.select_action_drop.currentText() == "Filter": self.on_filter() elif self.select_action_drop.currentText() == "Mute equipment": self.on_mute_equipment() elif self.select_action_drop.currentText() == "Mute vocal": self.on_mute_voice() elif self.select_action_drop.currentText() == "Add echo": self.on_add_echo() elif self.select_action_drop.currentText() == "Filter echo": self.on_filter_echo() ''' Noise addition ''' def on_add_noise(self): if len(self.y_original) == 0: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Upload sound file") msg.setInformativeText( "First you should add sound file to process") msg.setWindowTitle("Error") msg.exec_() return noise = np.random.normal(0, self.y_original.max() / 30, len(self.y_original)) arr1 = np.array(self.y_original) self.y_processed = arr1 + noise self.show_processed_data() def on_filter(self): print("on_filter") if len(self.y_original) == 0: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Upload sound file") msg.setInformativeText( "First you should add sound file to process") msg.setWindowTitle("Error") msg.exec_() return filter1, filter2, limit1, limit2, extra, max_ripple, min_attenuation, ok = FilterSelectionDialog.show_dialog( parent=self) print(filter1, filter2, limit1, limit2, extra, max_ripple, min_attenuation, ok) if ok: if filter1 == "FIR filter": self.on_fir_filter(filter2, limit1, limit2, extra) elif filter1 == "IIR filter": self.on_iir_filter(filter2, limit1, limit2, extra, max_ripple, min_attenuation) def on_mute_equipment(self): print("on_mute_equipment") check_piano, check_organ, check_flute, check_french_horn, check_trumpet, check_violin, \ check_guitar_acoustic, check_guitar_bass, check_clarinet, \ check_saxophone, ok = MuteInstrumentsDialog.show_dialog(parent=self) print(check_piano, check_organ, check_flute, check_french_horn, check_trumpet, check_violin, check_guitar_acoustic, check_guitar_bass, check_clarinet, check_saxophone, ok) ''' Piano A0 (28 Hz) to C8 (4,186 Hz or 4.1 KHz) Organ C0 (16 Hz) to A9 (7,040 KHz) Concert Flute C4 (262 Hz) to B6 (1,976 Hz) French Horn A2 (110 Hz) to A5 (880 Hz) Trumpet E3 (165 Hz) to B5 (988 Hz) Violin G3 (196 Hz) - G7 (3,136 Hz) (G-D-E-A) (or C8 (4,186 Hz?) Guitar (Acoustic) E2 (82 Hz) to F6 (1,397 Hz) Guitar (Bass) 4 string E1 (41 Hz) to C4 (262 Hz) Clarinet E3 (165 Hz) to G6 (1,568 Hz) Saxaphone Eb 138-830 (880) ''' if ok: print(check_piano) limit1 = 0.1 limit2 = 0.2 if check_piano: pass elif check_organ: pass elif check_flute: limit1 = 262 / self.sampling_rate limit2 = 1976 / self.sampling_rate pass elif check_french_horn: limit1 = 110 / self.sampling_rate limit2 = 880 / self.sampling_rate pass elif check_trumpet: limit1 = 165 / self.sampling_rate limit2 = 988 / self.sampling_rate pass elif check_violin: limit1 = 196 / self.sampling_rate limit2 = 3136 / self.sampling_rate pass elif check_guitar_acoustic: limit1 = 82 / self.sampling_rate limit2 = 1397 / self.sampling_rate pass elif check_guitar_bass: limit1 = 41 / self.sampling_rate limit2 = 262 / self.sampling_rate pass elif check_clarinet: limit1 = 165 / self.sampling_rate limit2 = 1568 / self.sampling_rate pass elif check_saxophone: limit1 = 138 / self.sampling_rate limit2 = 880 / self.sampling_rate pass print(limit1, limit2) print([ 0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001, 0.9991, 1.0 ], [0, 1, 1, 0, 0, 1, 1, 0]) design_filter = signal.firwin2(1000000, [ 0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001, 0.9991, 1.0 ], [0, 1, 1, 0, 0, 1, 1, 0]) self.y_processed = signal.convolve(self.y_original, design_filter, mode='same') w1, h1 = signal.freqz(design_filter) result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1) if result: self.show_processed_data() def on_mute_voice(self): y, sr = librosa.load(self.pathForVocalMute, sr=self.sampling_rate) S_full, phase = librosa.magphase(librosa.stft(y)) S_filter = librosa.decompose.nn_filter( S_full, aggregate=np.median, metric='cosine', width=int(librosa.time_to_frames(2, sr=sr))) S_filter = np.minimum(S_full, S_filter) margin_i, margin_v = 2, 10 power = 2 mask_i = librosa.util.softmask(S_filter, margin_i * (S_full - S_filter), power=power) mask_v = librosa.util.softmask(S_full - S_filter, margin_v * S_filter, power=power) S_foreground = mask_v * S_full S_background = mask_i * S_full self.y_processed = librosa.istft(S_background) self.show_processed_data() def on_add_echo(self): if len(self.y_original) == 0: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Upload sound file") msg.setInformativeText( "First you should add sound file to process") msg.setWindowTitle("Error") msg.exec_() return num_shift = int(self.sampling_rate * self.echo_shift) zeros = np.zeros(num_shift) original = np.append(self.y_original, zeros) echo = np.append(zeros, self.y_original) * self.echo_alpha self.y_processed = original + echo np.delete( self.y_processed, np.arange( len(self.y_processed) - len(zeros), len(self.y_processed))) self.show_processed_data() def on_filter_echo(self): ceps = cepstrum.real_cepstrum(np.array(self.y_original)) index, result = CepstrumDialog.show_dialog(self, ceps) if result: print(index) b = np.array([1]) a = np.zeros(index + 1) a[0] = 1 a[len(a) - 1] = self.echo_alpha zi = signal.lfilter_zi(b, a) self.y_processed, _ = signal.lfilter(b, a, self.y_original, axis=0, zi=zi * self.y_original[0]) w1, h1 = signal.freqz(b, a) result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1) if result: self.show_processed_data() ''' Filters ''' def on_fir_filter(self, filter_type, limit1, limit2, extra): if filter_type == "Low-pass": design_filter = signal.firwin(41, limit1, window=extra) elif filter_type == "High-pass": temp = np.zeros(41) temp[20] = 1 design_filter = temp - np.array( signal.firwin(41, limit1, window=extra)) elif filter_type == "Band-pass": temp = np.zeros(41) temp[20] = 1 design_filter = temp - np.array( signal.firwin(41, [limit1, limit2], window=extra)) elif filter_type == "Band-reject": design_filter = signal.firwin(41, [limit1, limit2], window=extra) self.y_processed = signal.convolve(self.y_original, design_filter, mode='same') w1, h1 = signal.freqz(design_filter) result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1) if result: self.show_processed_data() def on_iir_filter(self, filter_type, limit1, limit2, extra, max_ripple, min_attenuation): if filter_type == "Low-pass": b, a = signal.iirfilter(4, limit1, rp=int(max_ripple), rs=int(min_attenuation), btype='lowpass', ftype=extra) elif filter_type == "High-pass": b, a = signal.iirfilter(4, limit1, rp=int(max_ripple), rs=int(min_attenuation), btype='highpass', ftype=extra) elif filter_type == "Band-pass": b, a = signal.iirfilter(4, [limit1, limit2], rp=int(max_ripple), rs=int(min_attenuation), btype='bandpass', ftype=extra) elif filter_type == "Band-reject": b, a = signal.iirfilter(4, [limit1, limit2], rp=int(max_ripple), rs=int(min_attenuation), btype='bandstop', ftype=extra) self.y_processed = signal.lfilter(b, a, self.y_original) w1, h1 = signal.freqz(b, a) result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1) if result: self.show_processed_data() ''' Audio controls ''' def on_play(self): print("on_play") if len(self.y_processed) > 0: data2 = np.asarray(self.y_processed) sd.play(data2, self.sampling_rate) else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Upload sound file") msg.setInformativeText( "First you should upload and process sound file to play") msg.setWindowTitle("Error") msg.exec_() def on_stop(self): sd.stop() def on_play_orig(self): print("on_play_orig") if len(self.y_original) > 0: data = np.asarray(self.y_original) sd.play(data, self.sampling_rate) else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Upload sound file") msg.setInformativeText("First you should add sound file to play") msg.setWindowTitle("Error") msg.exec_() ''' Signal plots ''' def show_original_data(self): # Time domain y_data_scaled = np.interp( self.y_original, (self.y_original.min(), self.y_original.max()), (-10, +10)) sample_size = len(self.y_original) self.x_data = np.linspace(0., 100., sample_size) points_1 = [] for k in range(len(y_data_scaled)): points_1.append(QPointF(self.x_data[k], y_data_scaled[k])) self.m_series_1.replace(points_1) # Frequency domain y_freq_data = np.abs(fftpack.fft(self.y_original)) y_freq_data = np.interp(y_freq_data, (y_freq_data.min(), y_freq_data.max()), (0, +10)) x_freq_data = fftpack.fftfreq(len( self.y_original)) * self.sampling_rate axis_x = QValueAxis() axis_x.setRange(0, self.sampling_rate / 2) axis_x.setLabelFormat("%g") axis_x.setTitleText("Frequency [Hz]") axis_y = QValueAxis() axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data)) axis_y.setTitleText("Magnitude") self.m_chart_2.setAxisX(axis_x, self.m_series_2) self.m_chart_2.setAxisY(axis_y, self.m_series_2) points_2 = [] for k in range(len(y_freq_data)): points_2.append(QPointF(x_freq_data[k], y_freq_data[k])) self.m_series_2.replace(points_2) self.m_series_3.clear() self.m_series_4.clear() def show_processed_data(self): # Time domain y_data_scaled = np.interp( self.y_processed, (self.y_processed.min(), self.y_processed.max()), (-10, +10)) points_3 = [] sample_size = len(self.y_processed) x_data = np.linspace(0., 100., sample_size) for k in range(len(y_data_scaled)): points_3.append(QPointF(x_data[k], y_data_scaled[k])) self.m_series_3.replace(points_3) # Frequency domain y_freq_data = np.abs(fftpack.fft(self.y_processed)) y_freq_data = np.interp(y_freq_data, (y_freq_data.min(), y_freq_data.max()), (0, +10)) x_freq_data = fftpack.fftfreq(len( self.y_processed)) * self.sampling_rate axis_x = QValueAxis() axis_x.setRange(0, self.sampling_rate / 2) axis_x.setLabelFormat("%g") axis_x.setTitleText("Frequency [Hz]") axis_y = QValueAxis() axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data)) axis_y.setTitleText("Magnitude") self.m_chart_4.setAxisX(axis_x, self.m_series_4) self.m_chart_4.setAxisY(axis_y, self.m_series_4) points_4 = [] for k in range(len(y_freq_data)): points_4.append(QPointF(x_freq_data[k], y_freq_data[k])) self.m_series_4.replace(points_4)
class RowingMonitorMainWindow(QtWidgets.QMainWindow): COLOR_RED = QColor('#E03A3E') COLOR_BLUE = QColor('#009DDC') DISABLE_LOGGING = False PLOT_VISIBLE_SAMPLES = 200 PLOT_MIN_Y = -1 PLOT_MAX_Y = 55 PLOT_TIME_WINDOW_SECONDS = 7 PLOT_WIDTH_INCHES = 2 PLOT_HEIGHT_INCHES = 1 PLOT_DPI = 300 PLOT_FAST_DRAWING = False WORK_PLOT_VISIBLE_STROKES = 64 WORK_PLOT_MIN_Y = 0 WORK_PLOT_MAX_Y = 350 BOAT_SPEED_PLOT_VISIBLE_STROKES = 64 BOAT_SPEED_PLOT_MIN_Y = 0 BOAT_SPEED_PLOT_MAX_Y = 10 GUI_FONT = QtGui.QFont('Nunito SemiBold', 12) GUI_FONT_LARGE = QtGui.QFont('Nunito', 24) GUI_FONT_MEDIUM = QtGui.QFont('Nunito', 16) def __init__(self, config, data_source, *args, **kwargs): super(RowingMonitorMainWindow, self).__init__(*args, **kwargs) self.setWindowTitle('Rowing Monitor') self.config = config self.log_folder_path = config.log_folder_path self.workout = wo.WorkoutMetricsTracker( config=config, data_source=data_source ) # Connect workut emitter to UI update self.workout_qt_emitter = SignalEmitter() self.workout_qt_emitter.updated.connect(self.ui_callback) # Setup main window layout self.main_widget = QtWidgets.QWidget() self.main_widget.setFocus() self.setCentralWidget(self.main_widget) self.app_layout = QtWidgets.QVBoxLayout(self.main_widget) self.app_layout.setContentsMargins(0, 0, 0, 0) #(left, top, right, bottom) # Build button bar self.button_bar_background_widget = QtWidgets.QWidget(self.main_widget) self.button_bar_background_widget.setObjectName('ButtonBarBackground') self.button_bar_background_widget.setStyleSheet('QWidget#ButtonBarBackground {background-color: #F1F1F1;}') self.button_bar_layout = QtWidgets.QHBoxLayout(self.button_bar_background_widget) self.start_button = QtWidgets.QPushButton('Start') self.start_button.setFlat(True) # Start button style palette = self.start_button.palette() palette.setColor(palette.Button, QColor('#E03A3E')) palette.setColor(palette.ButtonText, QColor('white')) self.start_button.setAutoFillBackground(True) self.start_button.setPalette(palette) self.start_button.update() self.start_button.setFont(self.GUI_FONT) self.start_button.setMinimumSize(97, 60) self.start_button.setMaximumSize(97, 60) # Add to main window self.button_bar_layout.addWidget(self.start_button) #self.button_bar_layout.addWidget(self.button_bar_background_widget) self.button_bar_layout.setAlignment(QtCore.Qt.AlignLeft) self.button_bar_layout.setContentsMargins(0, 0, 0, 0) #(left, top, right, bottom) self.app_layout.addWidget(self.button_bar_background_widget)#.addLayout(self.button_bar_layout) self.stats_layout = QtWidgets.QHBoxLayout() self.stats_layout.setContentsMargins(0, 0, 0, 0) self.stats_layout.setSpacing(0) self.app_layout.addLayout(self.stats_layout) # Build workout stats bar self.metrics_panel_layout = QtWidgets.QVBoxLayout() self.charts_panel_layout = QtWidgets.QVBoxLayout() self.workout_totals_layout = QtWidgets.QVBoxLayout() self.time_label = QtWidgets.QLabel(self._format_total_workout_time(0)) self.distance_label = QtWidgets.QLabel(self._format_total_workout_distance(0)) self.time_label.setAlignment(QtCore.Qt.AlignCenter) self.distance_label.setAlignment(QtCore.Qt.AlignCenter) self.time_label.setFixedHeight(40) self.distance_label.setFixedHeight(30) self.workout_totals_layout.addWidget(self.time_label) self.workout_totals_layout.addWidget(self.distance_label) #self.workout_totals_layout.setSpacing(0) self.workout_totals_layout.setContentsMargins(0, 0, 0, 30) self.metrics_panel_layout.addLayout(self.workout_totals_layout) self.stroke_stats_layout = QtWidgets.QVBoxLayout() self.spm_label = QtWidgets.QLabel(self._format_strokes_per_minute(99)) self.stroke_ratio_label = QtWidgets.QLabel(self._format_stroke_ratio(1)) self.spm_label.setAlignment(QtCore.Qt.AlignCenter) self.stroke_ratio_label.setAlignment(QtCore.Qt.AlignCenter) self.spm_label.setFixedHeight(40) self.stroke_ratio_label.setFixedHeight(30) self.stroke_stats_layout.addWidget(self.spm_label) self.stroke_stats_layout.addWidget(self.stroke_ratio_label) #self.stroke_stats_layout.setSpacing(0) self.stroke_stats_layout.setContentsMargins(0, 30, 0, 30) self.metrics_panel_layout.addLayout(self.stroke_stats_layout) self.boat_stats_layout = QtWidgets.QVBoxLayout() self.boat_speed_label = QtWidgets.QLabel(self._format_boat_speed(0)) self.split_time_label = QtWidgets.QLabel(self._format_boat_pace(0)) self.boat_speed_label.setAlignment(QtCore.Qt.AlignCenter) self.split_time_label.setAlignment(QtCore.Qt.AlignCenter) self.boat_speed_label.setFixedHeight(40) self.split_time_label.setFixedHeight(30) self.boat_stats_layout.addWidget(self.boat_speed_label) self.boat_stats_layout.addWidget(self.split_time_label) #self.boat_stats_layout.setSpacing(0) self.boat_stats_layout.setContentsMargins(0, 30, 0, 0) self.metrics_panel_layout.addLayout(self.boat_stats_layout) # Appearance self.time_label.setFont(self.GUI_FONT_LARGE) self.distance_label.setFont(self.GUI_FONT_MEDIUM) self.spm_label.setFont(self.GUI_FONT_LARGE) self.stroke_ratio_label.setFont(self.GUI_FONT_MEDIUM) self.boat_speed_label.setFont(self.GUI_FONT_LARGE) self.split_time_label.setFont(self.GUI_FONT_MEDIUM) # Add to main window self.metrics_panel_layout.setSpacing(0) self.metrics_panel_layout.setContentsMargins(60, 30, 30, 30) #(left, top, right, bottom) self.charts_panel_layout.setSpacing(30) self.charts_panel_layout.setContentsMargins(30, 30, 60, 60)#(30, 30, 60, 60) #(left, top, right, bottom) self.stats_layout.addLayout(self.metrics_panel_layout) self.stats_layout.addLayout(self.charts_panel_layout) self.xdata = [0.0 for i in range(self.PLOT_VISIBLE_SAMPLES)] self.ydata = [0.0 for i in range(self.PLOT_VISIBLE_SAMPLES)] self.work_per_stroke_data = [0.0 for i in range(self.WORK_PLOT_VISIBLE_STROKES)] self.boat_speed_data = [0.0 for i in range(self.WORK_PLOT_VISIBLE_STROKES)] self.seen_strokes = 0 ############################################ # Add torque chart self.torque_plot = QChart() self.torque_plot.setContentsMargins(-26, -26, -26, -26) #self.torque_plot.setAnimationOptions(QChart.GridAxisAnimations) self.torque_plot.legend().setVisible(False) self.torque_plot_horizontal_axis = QValueAxis() self.torque_plot_vertical_axis = QValueAxis() self.torque_plot.addAxis(self.torque_plot_vertical_axis, QtCore.Qt.AlignLeft) self.torque_plot.addAxis(self.torque_plot_horizontal_axis, QtCore.Qt.AlignBottom) # Line series self.torque_plot_series = QLineSeries(self) for i in range(self.PLOT_VISIBLE_SAMPLES): self.torque_plot_series.append(0, 0) #self.torque_plot_series.setColor(QColor('#009DDC')) pen = self.torque_plot_series.pen() pen.setWidth(3) pen.setColor(self.COLOR_BLUE) pen.setJoinStyle(QtCore.Qt.RoundJoin) pen.setCapStyle(QtCore.Qt.RoundCap) self.torque_plot_series.setPen(pen) # Area series self.torque_plot_area_series = QAreaSeries() self.torque_plot_area_series.setUpperSeries(self.torque_plot_series) self.torque_plot_area_series.setLowerSeries(QLineSeries(self)) for i in range(self.PLOT_VISIBLE_SAMPLES): self.torque_plot_area_series.lowerSeries().append(0, 0) self.torque_plot_area_series.setColor(self.COLOR_BLUE) # Compose plot # self.torque_plot.addSeries(self.torque_plot_area_series) # self.torque_plot_area_series.attachAxis(self.torque_plot_horizontal_axis) # self.torque_plot_area_series.attachAxis(self.torque_plot_vertical_axis) self.torque_plot.addSeries(self.torque_plot_series) self.torque_plot_series.attachAxis(self.torque_plot_horizontal_axis) self.torque_plot_series.attachAxis(self.torque_plot_vertical_axis) # Set axes range self.torque_plot_vertical_axis.setRange(self.PLOT_MIN_Y, self.PLOT_MAX_Y) #self.torque_plot_vertical_axis.setTickCount(10) self.torque_plot_vertical_axis.setVisible(False) self.torque_plot_horizontal_axis.setRange(-self.PLOT_TIME_WINDOW_SECONDS, 0) self.torque_plot_horizontal_axis.setVisible(False) # Add plot view to GUI self.torque_plot_chartview = QChartView(self.torque_plot) self.torque_plot_chartview.setRenderHint(QPainter.Antialiasing) #self.torque_plot_chartview.setMinimumHeight(250) #self.torque_plot_chartview.resize(250, 250) self.torque_plot_box = QtWidgets.QGroupBox("Force") self.torque_plot_box.setFont(self.GUI_FONT) self.torque_plot_box.setAlignment(QtCore.Qt.AlignLeft) self.torque_plot_box_layout = QtWidgets.QVBoxLayout() self.torque_plot_box_layout.addWidget(self.torque_plot_chartview) self.torque_plot_box.setLayout(self.torque_plot_box_layout) self.charts_panel_layout.addWidget(self.torque_plot_box) ############################################ ############################################ # Add work chart self.work_plot = QChart() self.work_plot.setContentsMargins(-26, -26, -26, -26) self.work_plot.legend().setVisible(False) self.work_plot_horizontal_axis = QBarCategoryAxis() self.work_plot_vertical_axis = QValueAxis() self.work_plot.addAxis(self.work_plot_vertical_axis, QtCore.Qt.AlignLeft) self.work_plot.addAxis(self.work_plot_horizontal_axis, QtCore.Qt.AlignBottom) # Define series self.work_plot_series = QBarSeries() self.work_plot_bar_set_list = [QBarSet(str(i)) for i in range(self.WORK_PLOT_VISIBLE_STROKES)] self.work_plot_series.append(self.work_plot_bar_set_list) for bar_set in self.work_plot_bar_set_list: bar_set.append(0) self.work_plot_series.setBarWidth(1.0) # Compose plot self.work_plot.addSeries(self.work_plot_series) self.work_plot_series.attachAxis(self.work_plot_horizontal_axis) self.work_plot_series.attachAxis(self.work_plot_vertical_axis) # Set axes range self.work_plot_vertical_axis.setRange(self.WORK_PLOT_MIN_Y, self.WORK_PLOT_MAX_Y) self.work_plot_vertical_axis.setTickCount(8) self.work_plot_vertical_axis.setVisible(False) self.work_plot_horizontal_axis.append("1") self.work_plot_horizontal_axis.setVisible(False) # Add plot view to GUI self.work_plot_chartview = QChartView(self.work_plot) self.work_plot_chartview.setRenderHint(QPainter.Antialiasing) #self.work_plot_chartview.setMinimumHeight(250) #self.work_plot_chartview.resize(250, 250) self.work_plot_box = QtWidgets.QGroupBox("Work per stroke") self.work_plot_box.setFont(self.GUI_FONT) self.work_plot_box.setAlignment(QtCore.Qt.AlignLeft) self.work_plot_box_layout = QtWidgets.QVBoxLayout() self.work_plot_box_layout.addWidget(self.work_plot_chartview) self.work_plot_box.setLayout(self.work_plot_box_layout) self.charts_panel_layout.addWidget(self.work_plot_box) ############################################ ############################################ # Add boat speed chart self.boat_speed_plot = QChart() self.boat_speed_plot.setContentsMargins(-26, -26, -26, -26) #self.boat_speed_plot.setBackgroundRoundness(0) self.boat_speed_plot.legend().setVisible(False) self.boat_speed_plot_horizontal_axis = QBarCategoryAxis() self.boat_speed_plot_vertical_axis = QValueAxis() self.boat_speed_plot.addAxis(self.boat_speed_plot_vertical_axis, QtCore.Qt.AlignLeft) self.boat_speed_plot.addAxis(self.boat_speed_plot_horizontal_axis, QtCore.Qt.AlignBottom) # Define series self.boat_speed_plot_series = QBarSeries() self.boat_speed_plot_bar_set_list = [QBarSet(str(i)) for i in range(self.BOAT_SPEED_PLOT_VISIBLE_STROKES)] self.boat_speed_plot_series.append(self.boat_speed_plot_bar_set_list) for bar_set in self.boat_speed_plot_bar_set_list: bar_set.append(0) self.boat_speed_plot_series.setBarWidth(1.0) # Compose plot self.boat_speed_plot.addSeries(self.boat_speed_plot_series) self.boat_speed_plot_series.attachAxis(self.boat_speed_plot_horizontal_axis) self.boat_speed_plot_series.attachAxis(self.boat_speed_plot_vertical_axis) # Set axes range self.boat_speed_plot_vertical_axis.setRange(self.BOAT_SPEED_PLOT_MIN_Y, self.BOAT_SPEED_PLOT_MAX_Y) self.boat_speed_plot_vertical_axis.setTickCount(8) self.boat_speed_plot_vertical_axis.setVisible(False) self.boat_speed_plot_horizontal_axis.append("1") self.boat_speed_plot_horizontal_axis.setVisible(False) # Add plot view to GUI self.boat_speed_plot_chartview = QChartView(self.boat_speed_plot) self.boat_speed_plot_chartview.setRenderHint(QPainter.Antialiasing) #self.boat_speed_plot_chartview.setContentsMargins(0, 0, 0, 0) self.boat_speed_plot_box = QtWidgets.QGroupBox("Boat speed") self.boat_speed_plot_box.setFont(self.GUI_FONT) #self.boat_speed_plot_box.setFlat(True) #self.boat_speed_plot_box.setContentsMargins(0, 0, 0, 0) #self.boat_speed_plot_box.setObjectName("BoatSpeedGB") # Changed here... #self.boat_speed_plot_box.setStyleSheet('QGroupBox {background-color: white;}') #self.main_widget.setStyleSheet('QGroupBox::title { background-color: blue }') self.boat_speed_plot_box.setAlignment(QtCore.Qt.AlignLeft) self.boat_speed_plot_box_layout = QtWidgets.QVBoxLayout() self.boat_speed_plot_box_layout.addWidget(self.boat_speed_plot_chartview) self.boat_speed_plot_box.setLayout(self.boat_speed_plot_box_layout) self.charts_panel_layout.addWidget(self.boat_speed_plot_box) ############################################ # Set interaction behavior self.start_button.clicked.connect(self.start) # Update workout duration every second self.timer = QtCore.QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self.timer_tick) self.start_timestamp = None self.started = False self.show() def update_torque_plot(self): self.torque_plot_series.append(self.xdata[-1], self.ydata[-1]) self.torque_plot_series.remove(0) self.torque_plot_area_series.lowerSeries().append(self.xdata[-1], 0) self.torque_plot_area_series.lowerSeries().remove(0) self.torque_plot_horizontal_axis.setRange(self.xdata[-1] - self.PLOT_TIME_WINDOW_SECONDS, self.xdata[-1]) def update_work_plot(self): # Create new bar set new_bar_set = QBarSet(str(self.seen_strokes)) value = self.work_per_stroke_data[-1] value_rel = int(value * 255 / self.WORK_PLOT_MAX_Y) new_bar_set.append(value) new_bar_set.setColor(self.COLOR_BLUE) # QColor(value_rel, value_rel, value_rel)) # Append new set, and remove oldest self.work_plot_series.append(new_bar_set) self.work_plot_series.remove(self.work_plot_series.barSets()[0]) def update_boat_speed_plot(self): # Create new bar set new_bar_set = QBarSet(str(self.seen_strokes)) value = self.boat_speed_data[-1] value_rel = int(value * 255 / self.BOAT_SPEED_PLOT_MAX_Y) new_bar_set.append(value) new_bar_set.setColor(self.COLOR_BLUE) # QColor(value_rel, value_rel, value_rel)) # Append new set, and remove oldest self.boat_speed_plot_series.append(new_bar_set) self.boat_speed_plot_series.remove(self.boat_speed_plot_series.barSets()[0]) def start(self): if not self.started: self.start_workout() self.start_button.setText('Stop') self.started = True else: self.stop_workout() self.start_button.setText('Start') self.started = False def start_workout(self): self.timer.start() self.workout.start(qt_signal_emitter=self.workout_qt_emitter) def stop_workout(self): self.timer.stop() self.workout.stop() if not self.DISABLE_LOGGING and not DEV_MODE: self.workout.save(output_folder_path=self.log_folder_path) def _format_total_workout_time(self, value_seconds): minutes = value_seconds // 60 seconds = value_seconds % 60 return '%d:%02d' % (minutes, seconds) def _format_total_workout_distance(self, value): return f'{int(value):,} m' def _format_strokes_per_minute(self, value): return '%.1f spm' % value def _format_stroke_ratio(self, value): return '1:%.1f ratio' % value def _format_boat_speed(self, value): return '%0.2f m/s' % value def _format_boat_pace(self, value_seconds): return '%s /500m' % (self._format_total_workout_time(value_seconds)) def ui_callback(self): # If this is the first pulse, capture the current time if self.start_timestamp is None: self.start_timestamp = QtCore.QTime.currentTime() # Update distance distance = self.workout.boat.position.values[-1] self.distance_label.setText(self._format_total_workout_distance(distance)) if len(self.workout.person.torque) > 0: self.ydata = self.ydata[1:] + [self.workout.person.torque.values[-1]] self.xdata = self.xdata[1:] + [self.workout.person.torque.timestamps[-1]] self.update_torque_plot() # Update SPM new_stroke_info_available = len(self.workout.person.strokes) > self.seen_strokes if new_stroke_info_available: # SPM indicator spm = 60 / self.workout.person.strokes.values[-1].duration ratio = self.workout.person.strokes.values[-1].drive_to_recovery_ratio self.spm_label.setText(self._format_strokes_per_minute(spm)) self.stroke_ratio_label.setText(self._format_stroke_ratio(ratio)) # Work plot self.work_per_stroke_data = self.work_per_stroke_data[1:] + \ [self.workout.person.strokes.values[-1].work_done_by_person] self.update_work_plot() self.seen_strokes += 1 # Boat speed plot average_boat_speed = self.workout.boat.speed.get_average_value( start_time=self.workout.person.strokes.values[-1].start_time, end_time=self.workout.person.strokes.values[-1].end_time ) self.boat_speed_data = self.boat_speed_data[1:] + [average_boat_speed] self.boat_speed_label.setText(self._format_boat_speed(average_boat_speed)) split_time_seconds = 500.0 / average_boat_speed self.split_time_label.setText(self._format_boat_pace(split_time_seconds)) self.update_boat_speed_plot() def timer_tick(self): # Do nothing if we haven't received an encoder pulse yet. if self.start_timestamp is None: return # Update workout time label time_since_start = self.start_timestamp.secsTo(QtCore.QTime.currentTime()) self.time_label.setText(self._format_total_workout_time(time_since_start))
def do_redrawFill(self): self.chart.removeAllSeries() #删除所有序列 pen=QPen(self.__colorLine) #线条颜色 pen.setWidth(2) seriesFullWave = QLineSeries() #全波形 seriesFullWave.setUseOpenGL(True) seriesFullWave.setPen(pen) seriesPositive = QLineSeries() #正半部分曲线 seriesPositive.setUseOpenGL(True) seriesPositive.setVisible(False) #不显示 seriesNegative = QLineSeries() #负半部分曲线 seriesNegative.setUseOpenGL(True) seriesNegative.setVisible(False) #不显示即可 seriesZero = QLineSeries() #零均值线 seriesZero.setUseOpenGL(True) seriesZero.setVisible(False) #不显示即可 ## 填充数据 vx=0 intv=0.001 #1000Hz采样,数据点间隔时间 pointCount=len(self.__vectData) for i in range(pointCount): value=self.__vectData[i] seriesFullWave.append(vx,value) #完整波形 seriesZero.append(vx,0) #零值线 if value>0: seriesPositive.append(vx,value) #正半部分波形 seriesNegative.append(vx,0) else: seriesPositive.append(vx,0) seriesNegative.append(vx,value) #负半部分波形 vx =vx+intv self.__axisX.setRange(0,vx) ## 创建QAreaSeries序列,设置上、下界的QLineSeries对象 pen.setStyle(Qt.NoPen) #无线条,隐藏填充区域的边线 if self.ui.radioFill_Pos.isChecked(): #positive fill series = QAreaSeries(seriesPositive, seriesZero) #QAreaSeries series.setColor(self.__colorFill) #填充色 series.setPen(pen) #不显示线条 self.chart.addSeries(series) series.attachAxis(self.__axisX) series.attachAxis(self.__axisY) elif self.ui.radioFill_Neg.isChecked(): #negative fill series = QAreaSeries(seriesZero,seriesNegative) series.setColor(self.__colorFill) series.setPen(pen) #不显示线条 self.chart.addSeries(series) series.attachAxis(self.__axisX) series.attachAxis(self.__axisY) elif self.ui.radioFill_Both.isChecked(): #both fill series = QAreaSeries(seriesZero,seriesFullWave) series.setColor(self.__colorFill) series.setPen(pen) #不显示线条 self.chart.addSeries(series) series.attachAxis(self.__axisX) series.attachAxis(self.__axisY) series.clicked.connect(self.do_area_clicked) #关联槽函数 ## 构建QAreaSeries的两个QLineSeries序列必须添加到chart里,否则程序崩溃 self.chart.addSeries(seriesZero) #隐藏 self.chart.addSeries(seriesPositive) #隐藏 self.chart.addSeries(seriesNegative) #隐藏 self.chart.addSeries(seriesFullWave) #全波形曲线,显示 seriesPositive.attachAxis(self.__axisX) seriesPositive.attachAxis(self.__axisY) seriesNegative.attachAxis(self.__axisX) seriesNegative.attachAxis(self.__axisY) seriesZero.attachAxis(self.__axisX) seriesZero.attachAxis(self.__axisY) seriesFullWave.attachAxis(self.__axisX) seriesFullWave.attachAxis(self.__axisY)
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 )
class BandwidthGraphView(BaseTimedGraph): bwStatsFetched = AsyncSignal(dict) def __init__(self, parent=None): super(BandwidthGraphView, self).__init__(parent=parent) self.setObjectName('BandwidthGraph') self.chart.setTitle(iBandwidthUsage()) self.axisY.setTitleText(iRateKbPerSecond()) self.bwStatsFetched.connectTo(self.onBwStats) penIn = QPen(QColor('red')) penIn.setWidth(2) penOut = QPen(QColor('blue')) penOut.setWidth(2) self.seriesKbIn = QLineSeries() self.seriesKbIn.setName(iRateInput()) self.seriesKbIn.setPen(penIn) self.chart.addSeries(self.seriesKbIn) self.seriesKbIn.attachAxis(self.axisX) self.seriesKbIn.attachAxis(self.axisY) self.seriesKbOut = QLineSeries() self.seriesKbOut.setName(iRateOutput()) self.seriesKbOut.setPen(penOut) self.chart.addSeries(self.seriesKbOut) self.seriesKbOut.attachAxis(self.axisX) self.seriesKbOut.attachAxis(self.axisY) self.setChart(self.chart) async def onBwStats(self, stats): dtNow = QDateTime.currentDateTime() dtMsecs = dtNow.toMSecsSinceEpoch() delta = 120 * 1000 if not self.seriesPurgedT or (dtMsecs - self.seriesPurgedT) > delta: self.removeOldSeries(self.seriesKbIn, dtMsecs - delta) self.removeOldSeries(self.seriesKbOut, dtMsecs - delta) self.seriesPurgedT = dtMsecs rateIn = stats.get('RateIn', 0) rateOut = stats.get('RateOut', 0) rateInKb = int(rateIn / 1024) rateOutKb = int(rateOut / 1024) inVector = self.seriesKbIn.pointsVector() outVector = self.seriesKbIn.pointsVector() inValues = [p.y() for p in inVector] outValues = [p.y() for p in outVector] if inValues or outValues: self.axisY.setMax(max(max(inValues), max(outValues))) dateMin = QDateTime.fromMSecsSinceEpoch(dtMsecs - (30 * 1000)) dateMax = QDateTime.fromMSecsSinceEpoch(dtMsecs + 2000) self.seriesKbIn.append(dtMsecs, rateInKb) self.seriesKbOut.append(dtMsecs, rateOutKb) self.axisX.setRange(dateMin, dateMax)
def run_evolution(): range_a = float(str(form.input_a.text())) range_b = float(str(form.input_b.text())) precision = int(str(form.input_d.text())) generations_number = int(str(form.input_t.text())) app.setOverrideCursor(QtCore.Qt.WaitCursor) best_reals, best_binary, best_fxs, local_fxs, _, _ = evolution(range_a, range_b, precision, generations_number, form.checkBox.isChecked()) form.best_table.item(1,0).setText(str(best_reals[len(local_fxs)-1])) form.best_table.item(1,1).setText(''.join(map(str, best_binary[len(local_fxs)-1]))) form.best_table.item(1,2).setText(str(best_fxs[len(local_fxs)-1])) chart = QChart() bests = QLineSeries() pen_best = bests.pen() pen_best.setWidth(1) pen_best.setBrush(QtGui.QColor("red")) bests.setPen(pen_best) for i in range(0, len(local_fxs)): if len(local_fxs[i]) - 1 == 0: fxs = QScatterSeries() fxs.append(i + 0.99, local_fxs[i][0]) pen = fxs.pen() color = QtGui.QColor(random.randint(50,255), random.randint(50,255), random.randint(50,255)) fxs.setColor(color) pen.setColor(color) fxs.setPen(pen) fxs.setMarkerSize(5) else: fxs = QLineSeries() tick = 1 / (len(local_fxs[i]) - 1) for j in range(len(local_fxs[i])): fxs.append(i + j * tick, local_fxs[i][j]) pen = fxs.pen() pen.setWidth(1) pen.setBrush(QtGui.QColor(random.randint(50,255), random.randint(50,255), random.randint(50,255))) fxs.setPen(pen) bests.append(i+1, best_fxs[i]) chart.addSeries(fxs) chart.addSeries(bests) chart.setBackgroundBrush(QtGui.QColor(41, 43, 47)) chart.createDefaultAxes() chart.legend().hide() chart.setContentsMargins(-10, -10, -10, -10) chart.layout().setContentsMargins(0, 0, 0, 0) chart.axisX().setTickCount(11) chart.axisX().setLabelsColor(QtGui.QColor("white")) chart.axisX().setGridLineColor(QtGui.QColor("grey")) chart.axisX().setLabelFormat("%i") chart.axisY().setRange(-2,2) chart.axisY().setLabelsColor(QtGui.QColor("white")) chart.axisY().setGridLineColor(QtGui.QColor("grey")) form.widget.setChart(chart) with open('best_history.csv', 'w', newline='', encoding='utf8') as history_csvfile: history_writer = csv.writer( history_csvfile, delimiter=';', dialect=csv.excel) history_writer.writerow(['Parametry']) history_writer.writerow(['Precyzja: 10^-%d' % precision]) history_writer.writerow(['Iteracje: %d' % generations_number]) history_writer.writerow(['', 'real', 'bin', 'f(real)']) for index, generation in enumerate(range(generations_number)): history_writer.writerow([index, best_reals[generation], best_binary[generation], best_fxs[generation]]) app.restoreOverrideCursor()