def __init__(self): super(SpeedFigure, self).__init__() self.layout = QVBoxLayout() self.chart_view = [] self.line_series = [[], []] self.y_axis = [] self.default_max_y_value = 3000 self.colors = [Qt.red, Qt.blue, Qt.green, Qt.magenta] for i in range(2): cv = QChartView() for j in range(4): ls = QLineSeries() p = ls.pen() p.setColor(self.colors[j]) ls.setPen(p) self.line_series[i].append(ls) cv.chart().addSeries(ls) cv.chart().legend().hide() cv.chart().layout().setContentsMargins(0, 0, 0, 0) cv.setRenderHint(QPainter.Antialiasing) self.chart_view.append(cv) self.layout.addWidget(cv) self.last_timestamp = None self.setLayout(self.layout)
class DemoWindow(QMainWindow): def __init__(self, parent=None): super(DemoWindow, self).__init__(parent=parent) self.plotChart = QChart() self.plotChart.legend().hide() self.plotView = QChartView(self.plotChart) self.setCentralWidget(self.plotView) self.plotCurve = QLineSeries() self.plotCurve.setUseOpenGL(True) self.plotCurve.pen().setColor(Qt.red) self.plotChart.addSeries(self.plotCurve) self.plotChart.createDefaultAxes() self.plotChart.axisX().setLabelFormat('%d') self.RecvData = array.array('f') # 存储接收到的传感器数据 self.RecvIndx = 0 self.tmrData = QTimer() # 模拟传感器传送过来数据 self.tmrData.setInterval(3) self.tmrData.timeout.connect(self.on_tmrData_timeout) self.tmrData.start() self.tmrPlot = QTimer() self.tmrPlot.setInterval(100) self.tmrPlot.timeout.connect(self.on_tmrPlot_timeout) self.tmrPlot.start() def on_tmrData_timeout(self): val = math.sin(2 * 3.14 / 500 * self.RecvIndx) self.RecvData.append(val) self.RecvIndx += 1 def on_tmrPlot_timeout(self): self.RecvData = self.RecvData[-1000:] plotData = [] for i, val in enumerate(self.RecvData): plotData.append(QPointF(i, val)) self.plotCurve.replace(plotData) self.plotChart.axisX().setMax(len(plotData)) self.plotChart.axisY().setRange(min(self.RecvData), max(self.RecvData))
def add_data(self, xdata, ydata, color): curve = QLineSeries() pen = curve.pen() 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 add_tab(self): if self.count() >0: self.setTabsClosable(True) else: self.setTabsClosable(False) model = ItemModelLineChart(self.parent) self.models.append(model) w_table_view = WTableLineChart(self.parent) w_table_view.table.name = self.default_name w_table_view.table.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) w_table_view.table.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) w_table_view.table.setModel(model) w_table_view.create_connections() self.tables.append(w_table_view.table) line_series = QLineSeries() line_series.setName(w_table_view.table.name) self.series.append(line_series) mapper = QVXYModelMapper(self) mapper.setXColumn(0) mapper.setYColumn(1) mapper.setSeries(line_series) mapper.setModel(model) self.chart.addSeries(line_series) seriesColorHex = line_series.pen().color().name() model.add_mapping(seriesColorHex, QRect(0, 0, 2, model.rowCount())) model.signal_update_models.connect(self.update_axes) self.addTab(w_table_view,w_table_view.table.name)
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()
def setupChart(self): """Set up the GUI's graph series type, chart instance, chart axes, and chart view widget.""" random.seed(50) # Create seed for random numbers # Create the model instance and set the headers self.model = QStandardItemModel() self.model.setColumnCount(3) self.model.setHorizontalHeaderLabels(["Year", "Social Exp. %GDP", "Country"]) # Collect x and y data values and labels from the CSV file xy_data_and_labels = self.loadCSVFile() # Create the individual lists for x, y and labels values x_values, y_values, labels = [], [], [] # Append items to the corresponding lists for item in range(len(xy_data_and_labels)): x_values.append(xy_data_and_labels[item][0]) y_values.append(xy_data_and_labels[item][1]) labels.append(xy_data_and_labels[item][2]) # Remove all duplicates from the labels list using list comprehension. # This list will be used to create the labels in the chart's legend. set_of_labels = [] [set_of_labels.append(x) for x in labels if x not in set_of_labels] # Create chart object self.chart = QChart() self.chart.setTitle("Public Social Spending as a Share of GDP, 1880 to 2016") self.chart.legend().hide() # Hide legend at the start # Specify parameters for the x and y axes self.axis_x = QValueAxis() self.axis_x.setLabelFormat("%i") self.axis_x.setTickCount(10) self.axis_x.setRange(1880, 2016) self.chart.addAxis(self.axis_x, Qt.AlignBottom) self.axis_y = QValueAxis() self.axis_y.setLabelFormat("%i" + "%") self.axis_y.setRange(0, 40) self.chart.addAxis(self.axis_y, Qt.AlignLeft) # Create a Python dict to associate the labels with the individual line series series_dict = {} for label in set_of_labels: # Create labels from data and add them to a Python dictionary series_label = 'series_{}'.format(label) series_dict[series_label] = label # Create label value for each line series # For each of the keys in the dict, create a line series for keys in series_dict.keys(): # Use get() to access the corresponding value for a key label = series_dict.get(keys) # Create line series instance and set its name and color values line_series = QLineSeries() line_series.setName(label) line_series.setColor(QColor(random.randint(10, 254), random.randint(10, 254), random.randint(10, 254))) # Append x and y coordinates to the series for value in range(len(xy_data_and_labels)): if line_series.name() == xy_data_and_labels[value][2]: line_series.append(x_values[value], y_values[value]) # Create and add items to the model (for displaying the table) items = [QStandardItem(str(item)) for item in xy_data_and_labels[value]] color = line_series.pen().color() for item in items: item.setBackground(color) self.model.insertRow(value, items) self.chart.addSeries(line_series) line_series.attachAxis(self.axis_x) line_series.attachAxis(self.axis_y) # Create QChartView object for displaying the chart self.chart_view = ChartView(self.chart) self.setCentralWidget(self.chart_view)
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 GraphicsScene(QGraphicsScene): def __init__(self): super(GraphicsScene, self).__init__() self.line_series = QLineSeries() self.chart = QChart() self.chart_view = QChartView(self.chart) self.chart_view.setMinimumSize(640, 480) self.model = ItemModel() self.model.signal_update_models.connect(self.update_axes) self.table_view = TableView() self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_view.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setAnimationDuration(2000) self.line_series.setName("Line 1") self.mapper = QVXYModelMapper(self) self.mapper.setXColumn(0) self.mapper.setYColumn(1) self.mapper.setSeries(self.line_series) self.mapper.setModel(self.model) self.chart.addSeries(self.line_series) seriesColorHex = self.line_series.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(0, 0, 2, self.model.rowCount())) self.line_series2 = QLineSeries() self.line_series2.setName("Line 2") self.mapper2 = QVXYModelMapper(self) self.mapper2.setXColumn(2) self.mapper2.setYColumn(3) self.mapper2.setSeries(self.line_series2) self.mapper2.setModel(self.model) self.chart.addSeries(self.line_series2) seriesColorHex = self.line_series2.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())) self.chart.createDefaultAxes() self.chart_view.setRenderHint(QPainter.Antialiasing) self.chart.resize(500, 400) self.chart.setFlag(QGraphicsItem.ItemIsMovable) self.chart.setFlag(QGraphicsItem.ItemIsSelectable) self.addItem(self.chart) @pyqtSlot() def update_axes(self): self.chart.removeSeries(self.line_series) self.chart.removeSeries(self.line_series2) self.chart.addSeries(self.line_series) self.chart.addSeries(self.line_series2) self.chart.createDefaultAxes()
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 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))
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.init_ui() def init_ui(self): self.line_series = QLineSeries() self.chart = QChart() self.chart_view = QChartView(self.chart) self.chart_view.setMinimumSize(640,480) self.model = ItemModel() self.model.signal_update_models.connect(self.update_axes) self.table_view = TableView() self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setAnimationDuration(2000) self.line_series.setName("Line 1") self.mapper = QVXYModelMapper(self) self.mapper.setXColumn(0) self.mapper.setYColumn(1) self.mapper.setSeries(self.line_series) self.mapper.setModel(self.model) self.chart.addSeries(self.line_series) seriesColorHex = self.line_series.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(0,0,2, self.model.rowCount())) self.line_series2 = QLineSeries() self.line_series2.setName("Line 2") self.mapper2 = QVXYModelMapper(self) self.mapper2.setXColumn(2) self.mapper2.setYColumn(3) self.mapper2.setSeries(self.line_series2) self.mapper2.setModel(self.model) self.chart.addSeries(self.line_series2) seriesColorHex = self.line_series2.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())) self.chart.createDefaultAxes() self.grid = QGridLayout() self.grid.addWidget(self.table_view,0,0) self.grid.addWidget(self.chart_view,0,1) self.chart_view.setRenderHint(QPainter.Antialiasing) self.cw = QWidget() self.cw.setLayout(self.grid) self.setCentralWidget(self.cw) self.resize(400,300) @pyqtSlot() def update_axes(self): self.chart.removeSeries(self.line_series) self.chart.removeSeries(self.line_series2) self.chart.addSeries(self.line_series) self.chart.addSeries(self.line_series2) self.chart.createDefaultAxes()
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()