class Chart(QWidget): def __init__(self, chartKey, data, frame, parent=None): super(Chart, self).__init__(parent) self.frame = frame self.data = data self.create_chart(chartKey) def create_chart(self, chartKey): self.series = QPieSeries() self.series.setHoleSize(0.35) self.chart = QChart() #Add series to the chart self.addSeries(chartKey) # for the background and title self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("Code Size Visualizer") self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignRight) self.chart.setTheme(QChart.ChartThemeBlueCerulean) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) #each section of the pie chart def addSeries(self, key): self.chart.removeAllSeries() self.series = QPieSeries() self.series.setHoleSize(0.35) #Show chartview only if the content length is less than 6. Otherwise show a table view if len(self.data[key]) < 6: #print('length',self.data, key) for key, value in self.data[key].items(): print('key, value', key, value) slice_ = QPieSlice(str(key), value) self.series.append(slice_) self.series.setLabelsVisible() self.series.setLabelsPosition(QPieSlice.LabelInsideHorizontal) for slice in self.series.slices(): #slice.setLabel(slice.label()) slice.setLabel(slice.label() + ' - ' + str(slice.value()) + ' B ') self.chart.addSeries(self.series) self.frame.frame.hide() self.chart.show() else: self.table = TableView(self.data[key], len(self.data[key]), 1) if self.frame.ly.count() > 0: self.frame.ly.itemAt(0).widget().setParent(None) self.frame.ly.addWidget(self.table) self.frame.frame.show() self.chart.hide()
class ErrorLineChart(QFrame): def __init__(self, nseries=1, series_names=None): super().__init__() if nseries < 1: raise ValueError( 'The number of serieses must be larger than zero.') self.nseries = nseries self.series_names = series_names layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setMinimumHeight(110) self.setMinimumWidth(400) self.serieses = [QLineSeries() for _ in range(self.nseries)] self.chart = QChart() if self.series_names is None: self.chart.legend().hide() for idx, series in enumerate(self.serieses): self.chart.addSeries(series) if self.series_names is not None: series.setName(self.series_names[idx]) self.chart.createDefaultAxes() self.chart.layout().setContentsMargins(0, 0, 0, 0) # self.chart.setTheme(QChart.ChartThemeDark) self.chart.axisY().setTickCount(3) chart_view = QChartView(self.chart) chart_view.setRenderHint(QPainter.Antialiasing) layout.addWidget(chart_view) self.x_max = 2 self.y_pts = list() def append_point(self, x, y, series_idx=0): self.serieses[series_idx].append(x, y) self.x_max = max(x, self.x_max) self.y_pts.append(y) if self.x_max > 100: self.chart.axisX().setRange(self.x_max - 100, self.x_max) y_max = max(self.y_pts[-100:]) self.serieses[series_idx].remove(self.x_max - 100, self.y_pts[self.x_max - 101]) else: self.chart.axisX().setRange(1, self.x_max) y_max = max(self.y_pts) self.chart.axisY().setRange(0, y_max + y_max / 5) def clear(self): self.chart.removeAllSeries() self.serieses = [QLineSeries() for _ in range(self.nseries)] for idx, series in enumerate(self.serieses): self.chart.addSeries(series) if self.series_names is not None: series.setName(self.series_names[idx]) self.chart.createDefaultAxes() self.chart.axisY().setTickCount(3) self.x_max = 2 self.y_pts = list()
class Chart(QWidget): def __init__(self, chartKey, parent=None): super(Chart, self).__init__(parent) self.create_chart(chartKey) def create_chart(self, chartKey): self.series = QPieSeries() self.series.setHoleSize(0.35) self.chart = QChart() #Add series to the chart self.addSeries(chartKey) # for the background and title self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("DonutChart Example") self.chart.setTheme(QChart.ChartThemeBlueCerulean) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) def addSeries(self, key): self.chart.removeAllSeries() self.series = QPieSeries() self.series.setHoleSize(0.35) for key, value in sampleData[key].items(): print("adding series", str(key), value) slice_ = QPieSlice(str(key), value) self.series.append(slice_) self.chart.addSeries(self.series) self.series.doubleClicked.connect(self.handle_double_clicked) #Show the update chart with the distribution of the selected slice def handle_double_clicked(self, slice): slice.setExploded() slice.setLabelVisible() if slice.label() in sampleData.keys(): print("slice",slice.label()); self.addSeries(slice.label())
class Chart(QWidget): def __init__(self, chartKey, parent=None): super(Chart, self).__init__(parent) self.create_chart(chartKey, 0) def create_chart(self, chartKey, replace): self.series = QPieSeries() self.series.setHoleSize(0.35) self.chart = QChart() #Add series to the chart self.addSeries(chartKey) # for the background and title self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("DonutChart Example") self.chart.setTheme(QChart.ChartThemeBlueCerulean) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) def addSeries(self, key): self.chart.removeAllSeries() self.series = QPieSeries() self.series.setHoleSize(0.35) print('chart',key) for key, value in sampleData[key].items(): #print("adding series", str(key), value) slice_ = QPieSlice(str(key), value) self.series.append(slice_) self.chart.addSeries(self.series)
class VentanaBenchmark(QtWidgets.QMainWindow): def __init__(self, lista_algoritmos, ajustes, entorno, controlador): super().__init__() self.setWindowIcon(QtGui.QIcon('icon-crop.png')) uic.loadUi('ventana_benchmark.ui', self) self.lista_algoritmos = lista_algoritmos self.entorno = entorno self.controlador = controlador tupla_algoritmos = tuple(lista_algoritmos) eje_x = QBarCategoryAxis() eje_x.append(tupla_algoritmos) self.eje_y = QLogValueAxis() self.eje_y.setRange(0, 100) pen = QtGui.QPen() pen.setStyle(Qt.DashLine) self.eje_y.setGridLinePen(pen) self.eje_y.setMinorTickCount(10) self.eje_y.setBase(10) self.eje_y.setLabelFormat("%g") self.eje_y.setTitleText("Número de episodios") self.grafico = QChart() #self.grafico.addSeries(series) self.grafico.setAnimationOptions(QChart.NoAnimation) self.grafico.addAxis(eje_x, Qt.AlignBottom) self.grafico.addAxis(self.eje_y, Qt.AlignLeft) # TODO no se muestra self.set_ajustes(ajustes, False) self.grafico.legend().setVisible(True) self.grafico.legend().setAlignment(Qt.AlignTop) self.__init_datos() def set_ajustes(self, ajustes, actualizar_grafico=True): n_ejecuciones = ajustes[utils.AJUSTES_PARAM_N_EJECUCIONES] self.formatear_titulo_gafico(n_ejecuciones) self.modo = ajustes[utils.AJUSTES_PARAM_MODO_BENCHMARK] if actualizar_grafico: self.actualizar_grafico() def init_grafico(self): self.vista_grafico.setChart(self.grafico) def actualizar_grafico(self, algoritmo=None, nuevo_dato=None, clear=True): """Añade a la barra de algoritmo el nuevo dato""" if algoritmo is not None and nuevo_dato is not None: self.datos[algoritmo].append(nuevo_dato) if clear: self.grafico.removeAllSeries() if self.modo == utils.AJUSTES_BENCHMARK_MODO_BARRAS: self.__actualizar_grafico_barras() else: self.__actualizar_grafico_cajas() def __actualizar_grafico_barras(self): self.grafico.legend().setVisible(True) medias = [ math.floor(np.mean(datos)) if len(datos) > 0 else 0 for datos in self.datos.values() ] mejores = [ np.min(datos) if len(datos) > 0 else 0 for datos in self.datos.values() ] peores = [ np.max(datos) if len(datos) > 0 else 0 for datos in self.datos.values() ] self.eje_y.setRange(1, max(max(medias), max(peores))) barset_media = QBarSet('Media') barset_media.append(medias) barset_mejor = QBarSet('Mejor') barset_mejor.append(mejores) barset_peor = QBarSet('Peor') barset_peor.append(peores) series = QBarSeries() series.append(barset_media) series.append(barset_mejor) series.append(barset_peor) series.setLabelsVisible(True) self.grafico.addSeries(series) series.attachAxis(self.eje_y) self.init_grafico() def __actualizar_grafico_cajas(self): self.grafico.legend().setVisible(False) series = QBoxPlotSeries() maximo = 0 minimo = np.inf for alg in self.lista_algoritmos: eg = QBoxSet() if len(self.datos[alg]) > 0: ma = np.max(self.datos[alg]) mi = np.min(self.datos[alg]) q1 = np.quantile(self.datos[alg], 0.25) q3 = np.quantile(self.datos[alg], 0.75) iqr = q3 - q1 low = max(q1 - 1.5 * iqr, mi) high = min(q3 + 1.5 * iqr, ma) if high >= maximo: maximo = high if low <= minimo: minimo = low eg.setValue(QBoxSet.LowerExtreme, low) eg.setValue(QBoxSet.UpperExtreme, high) eg.setValue(QBoxSet.Median, np.median(self.datos[alg])) eg.setValue(QBoxSet.LowerQuartile, q3) eg.setValue(QBoxSet.UpperQuartile, q1) else: eg.setValue(QBoxSet.LowerExtreme, 1) eg.setValue(QBoxSet.UpperExtreme, 1) eg.setValue(QBoxSet.Median, 1) eg.setValue(QBoxSet.LowerQuartile, 1) eg.setValue(QBoxSet.UpperQuartile, 1) series.append(eg) self.eje_y.setRange(max(1, minimo), maximo) self.grafico.addSeries(series) series.attachAxis(self.eje_y) self.init_grafico() def limpiar_grafico(self): self.grafico.removeAllSeries() self.init_grafico() self.__init_datos() def __init_datos(self): self.datos = dict([]) for alg in self.lista_algoritmos: self.datos[alg] = [] def closeEvent(self, event: QtGui.QCloseEvent) -> None: self.controlador.deshabilitar_todo( False ) # Antes de cerrar la ventana habilitamos los botones de ventana princ self.controlador.cerrar_benchmark() event.accept() def formatear_titulo_gafico(self, n_ejecuciones): self.grafico.setTitle("Episodios hasta el fin del entrenamiento (" + str(n_ejecuciones) + " ejecuciones)")
class Chart(QtWidgets.QWidget): def __init__(self,chartKey, frame, parent=None): super(Chart, self).__init__(parent, QtCore.Qt.Window) self.frame = frame self.create_chart(chartKey) @QtCore.pyqtSlot() def create_chart(self, chartKey): self.series = QPieSeries() self.series.setHoleSize(0.35) self.chart = QChart() print('inside chart',self.frame) #Add series to the chart self.addSeries(chartKey) # for the background and title self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("DonutChart Example") self.chart.setTheme(QChart.ChartThemeBlueCerulean) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) def addSeries(self, key): self.chart.removeAllSeries() self.series = QPieSeries() print(self.series) self.series.setHoleSize(0.35) print('chart',key) if len(sampleData[key]) == 2: for key, value in sampleData[key].items(): #print("adding series", str(key), value) slice_ = QPieSlice(str(key), value) self.series.append(slice_) self.chart.addSeries(self.series) #self.frame.frame.hide() #self.frame.frame.removeWidget(self.table) self.frame.frame.hide() self.chart.show() else: print('hi') self.table = TableView(data, 5, 4) if self.frame.ly.count() == 0: self.frame.ly.addWidget(self.table) self.frame.frame.show() self.chart.hide() #print(frame) print('parent', self.parent())
class Interface(QMainWindow): def __init__(self, *args, **kwargs): super(Interface, self).__init__() self.__dataGenerator = None self.__wid = QWidget(self) self.setCentralWidget(self.__wid) self.__layout = QGridLayout() self.__layout.setSpacing(5) self.__axisx = QValueAxis() self.__axisx.setRange(0.0, 100.0) self.__axisy = QValueAxis() self.__values = list() self.__counter = 0 self.__data_iterator = None self.time_ms = 0 self.timer = QTimer(self) self.timerInterval = 1000 self.timer.setInterval(self.timerInterval) self.timer.timeout.connect(self.run_simulation) self.initUI() def init_values(self): self.__counter = 0 self.__data_iterator = self.__dataGenerator.get_values(100) self.time_ms = 0 def on_tick(self): try: values = next(self.__data_iterator) self.__values.append(values) except StopIteration: self.timer.stop() self.__writeLog() self.__drawParetoChart() self.__drawComparisonChart() def __setWindowProperties(self, parent): self.setWindowTitle("Title") self.setGeometry(100, 60, 1000, 600) def __createOptimisationChartGroupBox(self): groupBox = QGroupBox("Множество Парето") layout = QGridLayout() layout.setSpacing(0) self.__pareto_chart = QChart() self.__pareto_chart_series = [] view = QChartView(self.__pareto_chart) layout.addWidget(view) groupBox.setLayout(layout) return groupBox def __createButtonsGroupBox(self): groupBox = QGroupBox("Кнопки") layout = QGridLayout() layout.setSpacing(5) self.__btn_start = QPushButton("Запуск", self) self.__btn_stop = QPushButton("Остановка", self) layout.addWidget(self.__btn_start, 1, 1, 1, 3) layout.addWidget(self.__btn_stop, 1, 4, 1, 3) groupBox.setLayout(layout) return groupBox def __createQueryParametersGroupBox(self): groupBox = QGroupBox("Параметры запросов") layout = QGridLayout() layout.setSpacing(5) label_query_count = QLabel("Количество запросов: ") self.spinbox_query_count = QSpinBox() self.spinbox_query_count.setRange(100, 1000) self.spinbox_query_count.setSingleStep(100) label_update_frequency = QLabel("Частота обновления (мсек): ") self.spinbox_update_frequency = QSpinBox() self.spinbox_update_frequency.setRange(100, 300) self.spinbox_update_frequency.setSingleStep(100) layout.addWidget(label_query_count, 1, 1, 1, 1) layout.addWidget(self.spinbox_query_count, 1, 2, 1, 3) layout.addWidget(label_update_frequency, 2, 1, 1, 1) layout.addWidget(self.spinbox_update_frequency, 2, 2, 1, 3) groupBox.setLayout(layout) return groupBox def __createLogGroupBox(self): groupBox = QGroupBox("Замеры времени") self.__plainTextEdit_time_logs = QPlainTextEdit("") vbox = QVBoxLayout() vbox.addWidget(self.__plainTextEdit_time_logs) vbox.addStretch(1) groupBox.setLayout(vbox) return groupBox def __createComparisonChartGroupBox(self): groupBox = QGroupBox("Сравнительный график") layout = QGridLayout() layout.setSpacing(0) self.__comparison_chart = QChart() self.__comparison_chart_series = [] self.__comparison_view = QChartView(self.__comparison_chart) layout.addWidget(self.__comparison_view) groupBox.setLayout(layout) return groupBox def __start_btn_clicked(self): self.__drawParetoChart() self.interval = int(self.spinbox_query_count.value()) self.timerInterval = int(self.spinbox_update_frequency.value()) self.__dataGenerator = DataGenerator(self.timerInterval * 10) self.init_values() self.timer.start(self.timerInterval) def run_simulation(self): self.time_ms += self.timerInterval self.on_tick() def __stop_btn_clicked(self): self.timer.stop() def __drawParetoChart(self): def make_noise(value, noise_size): return value + (noise_size / -2 + noise_size * random.random()) self.__pareto_chart.removeAllSeries() series1 = QScatterSeries() series1.setMarkerShape(QScatterSeries.MarkerShapeCircle) series1.setMarkerSize(5) series1.append(make_noise(23, 2), make_noise(25, 2)) series1.setBrush(QColor(Qt.red)) self.__pareto_chart.addSeries(series1) self.__axisy.setRange(0.0, 100.0) series3 = QScatterSeries() series3.setName("Точка утопии") series3.setMarkerShape(QScatterSeries.MarkerShapeCircle) series3.setMarkerSize(10) series3.append(make_noise(2, 0.5), make_noise(23, 2)) self.__pareto_chart.addSeries(series3) series2 = QScatterSeries() series2.setName("Оптимальный") series2.setMarkerShape(QScatterSeries.MarkerShapeCircle) series2.setMarkerSize(7) series2.append(make_noise(2, 0.5), make_noise(45, 4)) self.__pareto_chart.addSeries(series2) self.__pareto_chart.setAxisX(self.__axisx, series1) self.__pareto_chart.setAxisY(self.__axisy, series1) self.__pareto_chart.setAxisX(self.__axisx, series2) self.__pareto_chart.setAxisY(self.__axisy, series2) self.__pareto_chart.setAxisX(self.__axisx, series3) self.__pareto_chart.setAxisY(self.__axisy, series3) def __writeLog(self): self.__counter += 1 self.__plainTextEdit_time_logs.moveCursor(QTextCursor.End) time_string = ("[%d:%d]" % (self.time_ms / 1000, self.time_ms % 1000 / 100)) try: optimal = self.__values[-1][2] - self.__values[-2][2] other = self.__values[-1][1] - self.__values[-2][1] except IndexError: optimal = 0 other = 0 for i in range(self.__counter): self.__plainTextEdit_time_logs.insertPlainText( '{0} {1:20} {2:1.4} \n'.format(time_string, 'Оптимальный:', float(optimal))) self.__plainTextEdit_time_logs.insertPlainText( '{0} {1:20} {2:1.4} \n'.format(time_string, 'Другой:', float(other))) self.__plainTextEdit_time_logs.moveCursor(QTextCursor.End) def __drawComparisonChart(self): self.__comparison_chart.removeAllSeries() series1 = QLineSeries(self) series2 = QLineSeries(self) series1.setName("Оптимальный") series2.setName("Другой") [(series1.append(i[0], i[1]), series2.append(i[0], i[2])) for i in self.__values] self.__comparison_chart.addSeries(series1) self.__comparison_chart.addSeries(series2) self.__comparison_chart.createDefaultAxes() def initUI(self): self.__layout.addWidget(self.__createOptimisationChartGroupBox(), 1, 1, 8, 5) self.__layout.addWidget(self.__createLogGroupBox(), 9, 1, 2, 5) self.__layout.addWidget(self.__createButtonsGroupBox(), 1, 6, 1, 5) self.__layout.addWidget(self.__createQueryParametersGroupBox(), 2, 6, 2, 5) self.__layout.addWidget(self.__createComparisonChartGroupBox(), 4, 6, 7, 5) self.__wid.setLayout(self.__layout) self.__btn_start.clicked.connect(self.__start_btn_clicked) self.__btn_stop.clicked.connect(self.__stop_btn_clicked) self.__setWindowProperties(self) self.show() def closeEvent(self, event): # событие закрытия окна reply = QMessageBox.question(self, 'Выход', "Вы уверены, что хотите выйти?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() def showWarning(self, message): q = QMessageBox() q.setIcon(QMessageBox.Warning) q.setText(message) q.setWindowTitle("Ошибка") q.setStandardButtons(QMessageBox.Ok) q.exec_()
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.resopt = ResOperator() self.chart = QChart() self.chart.setTheme(QChart.ChartThemeQt) self.chart.setTitle("文件类型统计") self.chartView.setChart(self.chart) self.progressBar.hide() self.collectSrcThread = None self.calDestThread = None self.copyThread = None self.collectSrcTask = None self.calDestTask = None self.copyTask = None @pyqtSlot() def show(self): super().show() print('show') # 在线程中已完成了文件的收集,在这里更新UI @pyqtSlot() def on_collect_finished(self): # 输出后缀统计扇形图 suffix_list = self.resopt.get_suffix_list(5) all = self.resopt.count_all() self.chart.removeAllSeries() series = QPieSeries() for (suffix, count) in suffix_list: series.append(suffix, count) all -= count if all > 0: series.append('others', all) series.setLabelsVisible(True) self.chart.addSeries(series) # 设置按键和进度条 self.collectPushButton.setEnabled(True) self.progressBar.hide() @pyqtSlot() def on_copy_finished(self): self.progressLabel.setText("完成复制") @pyqtSlot() def on_make_dest_finished(self): self.processPushButton.setEnabled(True) # 正在生成目标文件路径 @pyqtSlot(int, str) def on_make_dest_running(self, count, path): self.progressBar.setValue(count) self.progressLabel.setText("计算目标路径:" + path) # 正在复制文件 def on_copy_running(self, count, path): self.progressBar.setValue(count) self.progressLabel.setText("复制文件:" + path) # 选择源路径 @pyqtSlot() def on_srcPushButton_clicked(self): dialog = QFileDialog() dialog.setFileMode(QFileDialog.DirectoryOnly) dialog.setViewMode(QFileDialog.Detail) if dialog.exec_(): self.srcEdit.setText(dialog.selectedFiles()[0]) # 选择目标路径 @pyqtSlot() def on_destPushButton_clicked(self): dialog = QFileDialog() dialog.setFileMode(QFileDialog.DirectoryOnly) dialog.setViewMode(QFileDialog.Detail) if dialog.exec_(): self.destEdit.setText(dialog.selectedFiles()[0]) # 开始收集源路径中的文件 @pyqtSlot() def on_collectPushButton_clicked(self): # 设置UI self.progressBar.setMinimum(0) self.progressBar.setMaximum(0) self.progressBar.show() self.collectPushButton.setDisabled(True) # 创建任务 self.collectSrcTask = CollectSourceTask(self.srcEdit.text()) # 将任务移入线程 self.collectSrcThread = QThread() self.collectSrcTask.moveToThread(self.collectSrcThread) # 线程的started信号接入任务的doWork槽 self.collectSrcThread.started.connect(self.collectSrcTask.doWork) # 任务完成信号(done)接入线程的quit槽 self.collectSrcTask.done.connect(self.collectSrcThread.quit) # 线程完成后,更新ui self.collectSrcThread.finished.connect(self.on_collect_finished) # 启动 self.collectSrcThread.start() # 根据收集的结果,开始处理文件 @pyqtSlot() def on_processPushButton_clicked(self): count = self.resopt.count_all_unread() self.progressBar.setMinimum(0) self.progressBar.setMaximum(count) self.progressBar.show() self.processPushButton.setDisabled(True) if self.destEdit.text() is not '': self.calDestTask = CalculateDestinationTask(self.destEdit.text()) self.calDestThread = QThread() self.calDestTask.moveToThread(self.calDestThread) self.calDestThread.started.connect(self.calDestTask.doWork) self.calDestTask.done.connect(self.calDestThread.quit) self.calDestTask.update.connect(self.on_make_dest_running) self.calDestThread.finished.connect(self.on_make_dest_finished) self.calDestThread.start() # 开始复制文件 @pyqtSlot() def on_copyPushButton_clicked(self): count = self.resopt.count_all_ready() if count: self.progressBar.show() self.progressBar.setValue(0) self.progressBar.setMinimum(0) self.progressBar.setMaximum(count) self.copyTask = CopyTask() self.copyThread = QThread() self.copyTask.moveToThread(self.copyThread) self.copyThread.started.connect(self.copyTask.doWork) self.copyTask.update.connect(self.on_copy_running) self.copyTask.done.connect(self.copyThread.quit) self.copyThread.finished.connect(self.on_copy_finished) self.copyThread.start()
class DistributionPieChart(QChartView): """ Pie chart that shows the distribution of capital according to several criteria """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Chart self.chart = QChart() self.chart.setTheme(QChart.ChartThemeDark) self.chart.legend().hide() self.chart.createDefaultAxes() self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setBackgroundVisible(False) self.chart.setTitle(" ") self.chart.setTitleBrush(QBrush(QColor('white'))) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) self.setStyleSheet("border: 0px; background-color: rgba(0,0,0,0)") self.setupSeries() # Initialize to all mode def setupSeries(self, mode="all"): """ Chart gets updated displaying the new data. Modes: - all : distribution between all accounts - accs : distribution between portfolio accounts - cryptoaccs : distribution between crypto accounts - strategies : distribution between strategies """ # Series self.chart.removeAllSeries() # Remove any previous series self.series = QPieSeries() # Get data if mode == "all": data = balances.get_all_accounts( ) + cbalances.get_all_accounts_with_amount_fiat() elif mode == "accounts": data = balances.get_all_accounts() elif mode == "crypto": data = cbalances.get_all_accounts_with_amount_fiat() elif mode == "currency": data = [(confighandler.get_fiat_currency().upper(), balances.get_total_balance_all_accounts( )), ("BTC", cbalances.get_total_balance_all_accounts_fiat())] data.sort(key=lambda x: x[1]) # Sort # Set Chart Title self.total = sum([i[1] for i in data]) self.setDefaultTitle() # Add to series for d in data: self.series.append(d[0], d[1]) # Hide little slices' labels self.series.setLabelsVisible(True) for slc in self.series.slices(): if slc.angleSpan() < 5: slc.setLabelVisible(False) slc.setLabelArmLengthFactor(0.05) self.chart.addSeries(self.series) # Signals and functionality self.series.hovered.connect(self.selectSlice) def selectSlice(self, _slice, state): """ Highlight selected slice """ font = ChartTitleFont() if state: font.setPointSize(20) _slice.setLabelVisible(True) self.chart.setTitle( f"{int(_slice.value())} {confighandler.get_fiat_currency().upper()} {round(_slice.percentage()*100,1)}%") else: font.setBold(False) if _slice.angleSpan() < 5: _slice.setLabelVisible(False) _slice.setExploded(False) self.setDefaultTitle() _slice.setLabelFont(font) def setDefaultTitle(self): """ Sets title as total balance from all pie slices """ self.chart.setTitle( f"{int(self.total)} {confighandler.get_fiat_currency().upper()}") font = ChartTitleFont(fontsize=20) self.chart.setTitleFont(font)
class Ui(mainwindow.Ui_MainWindow): def __init__(self, MainWindow): #super(Ui, self).__init__(M) super(Ui, self).setupUi(MainWindow) #uic.loadUi('UI/mainwindow.ui', self) self.MainWindow = MainWindow self.initialize() def close(self): self.MainWindow.close() def style(self): return self.MainWindow.style() def initialize(self): self.tabWidget.setCurrentIndex(0) self.actionExit.triggered.connect(self.close) self.action_Plot.setEnabled(False) self.actionNext.setIcon( self.style().standardIcon( QtWidgets.QStyle.SP_ArrowForward)) self.actionPrevious.setIcon( self.style().standardIcon( QtWidgets.QStyle.SP_ArrowBack)) self.action_Open.setIcon( self.style().standardIcon( QtWidgets.QStyle.SP_DialogOpenButton)) self.actionSave.setIcon( self.style().standardIcon( QtWidgets.QStyle.SP_DriveFDIcon)) self.actionSave.triggered.connect(self.save) self.action_Open.triggered.connect(self.getOpenFilename) self.actionNext.triggered.connect(self.nextPacket) self.actionPrevious.triggered.connect(self.previousPacket) self.actionAbout.triggered.connect(self.about) self.actionPrevious.setEnabled(False) self.actionNext.setEnabled(False) self.actionSave.setEnabled(False) self.action_Plot.setEnabled(False) self.actionPaste.triggered.connect(self.onPasteTriggered) # self.actionLog.triggered.connect(self.dockWidget_2.show) self.actionSet_IDB.triggered.connect(self.onSetIDBClicked) self.plotButton.clicked.connect(self.onPlotButtonClicked) self.exportButton.clicked.connect(self.onExportButtonClicked) self.action_Plot.triggered.connect(self.onPlotActionClicked) self.actionLoad_mongodb.triggered.connect(self.onLoadMongoDBTriggered) self.mdb=None self.current_row = 0 self.data=[] self.x=[] self.y=[] self.xlabel='x' self.ylabel='y' self.chart = QChart() self.chart.layout().setContentsMargins(0,0,0,0) self.chart.setBackgroundRoundness(0) self.savePlotButton.clicked.connect(self.savePlot) self.chartView = QChartView(self.chart) self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15) # IDB location self.settings = QtCore.QSettings('FHNW', 'stix_parser') def onExportButtonClicked(self): if self.y: filename = str(QtWidgets.QFileDialog.getSaveFileName( None, "Save file", "", "*.csv")[0]) if filename: with open(filename,'w') as f: f.write('{},{}\n'.format(self.xlabel,self.ylabel)) for xx,yy in zip(self.x,self.y): f.write('{},{}\n'.format(xx,yy)) self.showMessage('The data has been written to {}'.format(filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('Plot first!') msgBox.setWindowTitle("Warning") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def savePlot(self): #if self.figure.get_axes(): if self.chart: filename = str(QtWidgets.QFileDialog.getSaveFileName( None, "Save file", "", "*.png *.jpg")[0]) if filename: if not filename.endswith(('.png','.jpg')): filename+='.png' #self.figure.savefig(filename) p=self.chartView.grab() p.save(filename) self.showMessage(('Saved to %s.' % filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('The canvas is empty!') msgBox.setWindowTitle("STIX DATA VIEWER") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def onPasteTriggered(self): pass def showMessageBox(self, message, content): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Critical) msg.setText("Error") msg.setInformativeText(message) msg.setWindowTitle("Error") msg.setDetailedText(content) msg.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) retval = msg.exec_() def showMessage(self, msg): # if destination != 1: self.statusbar.showMessage(msg) # if destination !=0 : # self.listWidget_2.addItem(msg) def onSetIDBClicked(self): pass def save(self): pass def setListViewSelected(self, row): #index = self.model.createIndex(row, 0); # if index.isValid(): # self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select) pass def about(self): msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("STIX raw data parser and viewer, [email protected]") msgBox.setWindowTitle("Stix data viewer") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def nextPacket(self): self.current_row += 1 length=len(self.data) if self.current_row>=length: self.current_row=length-1 self.showMessage('No more packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def previousPacket(self): self.current_row -= 1 if self.current_row <0: self.current_row=0 self.showMessage('Reach the first packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def getOpenFilename(self): pass def openFile(self, filename): pass def onDataLoaded(self, data,clear=True): if not clear: self.data.append(data) else: self.data = data self.displayPackets(clear) if self.data: self.actionPrevious.setEnabled(True) self.actionNext.setEnabled(True) self.actionSave.setEnabled(True) self.action_Plot.setEnabled(True) def displayPackets(self,clear=True): if clear: self.packetTreeWidget.clear() t0=0 for p in self.data: if type(p) is not dict: continue header = p['header'] root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget) if t0==0: t0=header['time'] root.setText(0, '{:.2f}'.format(header['time']-t0)) root.setText(1, ('TM({},{}) - {}').format(header['service_type'], header['service_subtype'], header['DESCR'])) self.total_packets = len(self.data) self.showMessage((('%d packets loaded') % (self.total_packets))) self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected) self.showPacket(0) def onLoadMongoDBTriggered(self): diag=QtWidgets.QDialog() diag_ui=mongo_dialog.Ui_Dialog() diag_ui.setupUi(diag) diag_ui.pushButton.setFocus(True) #self.settings = QtCore.QSettings('FHNW', 'stix_parser') self.mongo_server= self.settings.value('mongo_server', [], str) self.mongo_port= self.settings.value('mongo_port', [], str) self.mongo_user= self.settings.value('mongo_user', [], str) self.mongo_pwd= self.settings.value('mongo_pwd', [], str) if self.mongo_server: diag_ui.serverLineEdit.setText(self.mongo_server) if self.mongo_port: diag_ui.portLineEdit.setText(self.mongo_port) if self.mongo_user: diag_ui.userLineEdit.setText(self.mongo_user) if self.mongo_pwd: diag_ui.pwdLineEdit.setText(self.mongo_pwd) diag_ui.pushButton.clicked.connect(partial(self.loadRunsFromMongoDB,diag_ui)) diag_ui.buttonBox.accepted.connect(partial(self.loadDataFromMongoDB,diag_ui,diag)) diag.exec_() def loadRunsFromMongoDB(self,dui): server=dui.serverLineEdit.text() port=dui.portLineEdit.text() user=dui.userLineEdit.text() pwd=dui.pwdLineEdit.text() self.showMessage('saving setting...') if self.mongo_server!=server: self.settings.setValue('mongo_server', server) if self.mongo_port!=port: self.settings.setValue('mongo_port', port) if self.mongo_user!=user: self.settings.setValue('mongo_user', user) if self.mongo_pwd!=pwd: self.settings.setValue('mongo_pwd', pwd) self.showMessage('connecting Mongo database ...') self.mdb=mgdb.MongoDB(server,int(port),user,pwd) dui.treeWidget.clear() self.showMessage('Fetching data...') for run in self.mdb.get_runs(): root = QtWidgets.QTreeWidgetItem(dui.treeWidget) root.setText(0, str(run['_id'])) root.setText(1, run['file']) root.setText(2, run['date']) root.setText(3, str(run['start'])) root.setText(4, str(run['end'])) self.showMessage('Runs loaded!') def loadDataFromMongoDB(self,dui,diag): selected_runs=[] for item in dui.treeWidget.selectedItems(): selected_runs.append(item.text(0)) if not selected_runs: self.showMessage('Run not selected!') if selected_runs: diag.done(0) self.showMessage('Loading data ...!') data=self.mdb.get_packets(selected_runs[0]) if data: self.onDataLoaded(data,clear=True) else: self.showMessage('No packets found!') #close def onPacketSelected(self, cur, pre): self.current_row = self.packetTreeWidget.currentIndex().row() self.showMessage((('Packet #%d selected') % self.current_row)) self.showPacket(self.current_row) def showPacket(self, row): if not self.data: return header = self.data[row]['header'] self.showMessage( (('Packet %d / %d %s ') % (row, self.total_packets, header['DESCR']))) self.paramTreeWidget.clear() header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) header_root.setText(0, "Header") rows = len(header) for key, val in header.items(): root = QtWidgets.QTreeWidgetItem(header_root) root.setText(0, key) root.setText(1, str(val)) params = self.data[row]['parameters'] param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) param_root.setText(0, "Parameters") self.showParameterTree(params, param_root) self.paramTreeWidget.expandItem(param_root) self.paramTreeWidget.expandItem(header_root) def showParameterTree(self, params, parent): for p in params: root = QtWidgets.QTreeWidgetItem(parent) if not p: continue try: param_name=p['name'] desc='' scos_desc='' try: desc=param_desc.PCF[param_name] scos_desc=param_desc.SW[param_name] except KeyError: pass root.setToolTip(1,scos_desc) root.setText(0, param_name) root.setText(1, desc) root.setText(2, str(p['raw'])) root.setText(3, str(p['value'])) if 'child' in p: if p['child']: self.showParameterTree(p['child'], root) except KeyError: self.showMessage( ('[Error ]: keyError occurred when adding parameter')) self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked) def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0): if not params: return timestamp = header['time'] #parameters=[p for p in params if p['name'] == name] for p in params: if type(p) is not dict: continue #for p in parameters: if name == p['name']: values = None #print('data type:{}'.format(data_type)) if data_type == 0: values = p['raw'] else: values = p['value'] try: yvalue = None if (type(values) is tuple) or (type(values) is list): yvalue = float(values[0]) else: yvalue = float(values) ret_y.append(yvalue) if xaxis == 1: ret_x.append(timestamp) else: self.showMessage((('Can not plot %s ') % str(yvalue))) except Exception as e: self.showMessage((('%s ') % str(e))) if 'child' in p: if p['child']: self.walk( name, p['child'], header, ret_x, ret_y, xaxis, data_type) def onPlotButtonClicked(self): if self.chart: self.chart.removeAllSeries() if not self.data: return self.showMessage('Preparing plot ...') name = self.paramNameEdit.text() packet_selection = self.comboBox.currentIndex() xaxis_type = self.xaxisComboBox.currentIndex() data_type = self.dataTypeComboBox.currentIndex() timestamp = [] self.y = [] packet_id = self.current_row params = self.data[packet_id]['parameters'] header = self.data[packet_id]['header'] current_spid=header['SPID'] if packet_selection == 0: self.walk( name, params, header, timestamp, self.y, xaxis_type, data_type) elif packet_selection == 1: for packet in self.data: header = packet['header'] if packet['header']['SPID'] != current_spid: continue #only look for parameters in the packets of the same type params = packet['parameters'] self.walk( name, params, header, timestamp, self.y, xaxis_type, data_type) self.x = [] if not self.y: self.showMessage('No data points') elif self.y: style = self.styleEdit.text() if not style: style = '-' title = '%s' % str(name) desc = self.descLabel.text() if desc: title += '- %s' % desc self.chart.setTitle(title) ylabel = 'Raw value' xlabel = name if data_type == 1: ylabel = 'Engineering value' if xaxis_type == 0: xlabel = "Packet #" self.x = range(0, len(self.y)) if xaxis_type == 1: self.x = [t - timestamp[0] for t in timestamp] xlabel = 'Time -T0 (s)' #if xaxis_type != 2: if True: series = QLineSeries() series2 = None # print(y) # print(x) for xx, yy in zip(self.x, self.y): series.append(xx, yy) if 'o' in style: series2 = QScatterSeries() for xx, yy in zip(self.x, self.y): series2.append(xx, yy) self.chart.addSeries(series2) self.chart.addSeries(series) self.showMessage('plotted!') #self.chart.createDefaultAxes() axisX = QValueAxis() axisX.setTitleText(xlabel) axisY = QValueAxis() axisY.setTitleText(ylabel) self.chart.setAxisX(axisX) self.chart.setAxisY(axisY) series.attachAxis(axisX) series.attachAxis(axisY) # histogram #else: # nbins = len(set(self.y)) # ycounts, xedges = np.histogram(self.y, bins=nbins) # series = QLineSeries() # for i in range(0, nbins): # meanx = (xedges[i] + xedges[i + 1]) / 2. # series.append(meanx, ycounts[i]) # # series.append(dataset) # self.chart.addSeries(series) # #self.chart.createDefaultAxes() # self.showMessage('Histogram plotted!') # axisX = QValueAxis() # axisX.setTitleText(name) # axisY = QValueAxis() # axisY.setTitleText("Counts") # self.chart.setAxisY(axisY) # self.chart.setAxisX(axisX) ## series.attachAxis(axisX) # series.attachAxis(axisY) # self.widget.setChart(self.chart) self.xlabel=xlabel self.ylabel=ylabel self.chartView.setRubberBand(QChartView.RectangleRubberBand) self.chartView.setRenderHint(QtGui.QPainter.Antialiasing) def plotParameter(self, name=None, desc=None): self.tabWidget.setCurrentIndex(1) if name: self.paramNameEdit.setText(name) if desc: self.descLabel.setText(desc) def onPlotActionClicked(self): self.tabWidget.setCurrentIndex(1) self.plotParameter() def onTreeItemClicked(self, it, col): #print(it, col, it.text(0)) self.plotParameter(it.text(0), it.text(1)) def error(self, msg, description=''): self.showMessage((('Error: %s - %s') % (msg, description))) def warning(self, msg, description=''): self.showMessage((('Warning: %s - %s') % (msg, description))) def info(self, msg, description=''): self.showMessage((('Info: %s - %s') % (msg, description)))
class widgetIDChart(QtWidgets.QWidget, qdesignFDChart.Ui_Form): actionRequestFromTable = pyqtSignal() def __init__(self, parent=None): super(widgetIDChart, self).__init__(parent) self.setupUi(self) tribchartmenustyle(self) # Default Settings self.nbins = 10 # Extra Menu Items # Distribution Type Selection self.comboBoxDistr = XComboBoxDict(self) self.comboBoxDistr.setMinimumSize(QtCore.QSize(100, 30)) self.knowndistr = distr._distrnames() self.comboBoxDistr.addItem({'None': 'None'}) self.comboBoxDistr.addItems(self.knowndistr) self.comboBoxDistr.setObjectName("comboBoxDistr") self.horizontalLayout.insertWidget(3, self.comboBoxDistr) self.comboBoxDistr.currentTextChanged.connect( self.onComboBoxDistrChanged) self.activeDist = str( self.distrfromname(self.comboBoxDistr.currentText())) # Spinbox Label self.spinBoxLab = QtWidgets.QLabel(self) self.spinBoxLab.setText(' Bins: ') self.horizontalLayout.insertWidget(4, self.spinBoxLab) # Histogram N columns quick select spin box self.spinBoxDistr = QtWidgets.QSpinBox(self) self.spinBoxDistr.setMinimumSize(QtCore.QSize(50, 30)) self.spinBoxDistr.setRange(2, 100) self.spinBoxDistr.setSingleStep(1) self.spinBoxDistr.setValue(self.nbins) self.spinBoxDistr.setObjectName("spinBoxDistr") self.horizontalLayout.insertWidget(5, self.spinBoxDistr) self.spinBoxDistr.valueChanged.connect(self.onSpinBoxChanged) # SetUp for Chart to Display Distribution curves and inputs. self.chart = QChart() self.chart.legend().setVisible(False) # SetUp Visible Chart Axes self.chart.axisX = QValueAxis() self.chart.axisY = QValueAxis() self.chart.axisX.setTickCount(10) self.chart.axisY.setTickCount(2) self.chart.axisX.setTitleText("Value") self.chart.axisY.setTitleText("Probability") # HistogramAxis self.chart.axisHist = QValueAxis() self.chart.addAxis(self.chart.axisHist, Qt.AlignRight) self.chart.axisHist.setTickCount(10) self.chart.axisHist.setTitleText("Count") self.chart.axisBins = QValueAxis() self.chart.addAxis(self.chart.axisBins, Qt.AlignBottom) self.chart.axisBins.setVisible(False) # Add Chart to Chartview and Chartview to Widget self.chartview = QChartView(self.chart) self.verticalLayout.addWidget(self.chartview) self.chartview.setRenderHint(QPainter.Antialiasing) def axesMinMax(self): # returns a length 4 list of the axes min and max values [x1,x2,y1,y2] return [ self.chart.axisX.min(), self.chart.axisX.max(), self.chart.axisY.min(), self.chart.axisY.max() ] def setAxes(self, series): # assigns a series to the chart default axes self.chart.setAxisX(self.chart.axisX, series) self.chart.setAxisY(self.chart.axisY, series) def setAxesMinMax(self, x1, x2, y1, y2): # sets the min max values in X and Y self.chart.axisX.setMin(x1) self.chart.axisX.setMax(x2) self.chart.axisY.setMin(y1) self.chart.axisY.setMax(y2) def setTitle(self, title): self.chart.setTitle(title) def setRawData(self, datar): self.datar = datar self.ndata = len(self.datar) def addDistrLine(self, n, kstats): self.kstats = kstats data = distr.distrpdf(self.activeDist, n, **kstats) xmin = min(data['X']) xmax = max(data['X']) ymin = min(data['Y']) ymax = max(data['Y']) xscal = 0.1 * (xmax - xmin) yscal = 0.1 * (ymax - 0) self.chart.axisY.setRange(0, ymax + yscal) self.lineDist = XLineSeries(data, xkey='X')[0] def addHistLine(self): # fits a distribution to the histogram and draws a line self.kstats = distr.distrfit(self.activeDist, self.datar) #hist[0]) self.addDistrLine(1000, self.kstats) def addHistogram(self, nbins): # accepts a data array datar and int nbins to calculate a histogram self.nbins = nbins self.spinBoxDistr.setValue(nbins) try: self.hist = np.histogram(self.datar, bins=nbins) except: pass # create a function which displays a msg in the middle of the chart by raising a data error of sorts self.histseries = XDictSet({'Hist': self.hist[0]}) # return barsets self.histsets = self.histseries.findChildren(QBarSet) def updateChart(self): self.chart.removeAllSeries() hmin = self.hist[1][0] hmax = self.hist[1][-1] cmax = max(self.hist[0]) + 1 binwidth = self.hist[1][1] - self.hist[1][0] binscale = 1 / binwidth if self.activeDist == 'None': self.chart.axisY.setVisible(False) self.chart.axisX.setMin(hmin) self.chart.axisX.setMax(hmax) else: self.chart.axisY.setVisible(True) try: # Add histogram bars self.chart.axisBins.setRange(-1, self.nbins) self.chart.axisHist.setRange(0, cmax) self.chart.addSeries(self.histseries) self.histseries.setBarWidth(1) # Set Colours self.histsets[0].setColor(tribColours.tribBlue) # Update Axes self.chart.setAxisX(self.chart.axisBins, self.histseries) self.chart.setAxisY(self.chart.axisHist, self.histseries) except NameError: pass if self.activeDist != 'None': try: # Add distribution line self.addHistLine() # Fit Line Formatting linepen = QPen() linepen.setWidth(2.5) linepen.setColor(tribColours.tribCoral) self.lineDist.setPen(linepen) self.chart.addSeries(self.lineDist) self.setAxes(self.lineDist) self.chart.axisX.setRange(hmin - binwidth, hmax + binwidth) except AttributeError: pass @pyqtSlot(int) def onSpinBoxChanged(self, n): self.nbins = n self.addHistogram(self.nbins) self.updateChart() def distrfromname(self, search): for key, name in self.knowndistr.items(): if name == search: return key @pyqtSlot(str) def onComboBoxDistrChanged(self, name): self.activeDist = self.comboBoxDistr.currentKey() self.addHistogram(self.nbins) self.updateChart() @pyqtSlot(dict) def receiveFromTable(self, datadict): self.setRawData(datadict['Value']) self.addHistogram(self.nbins) self.updateChart()
class MainView(QWidget, Ui_Dialog): def __init__(self): super().__init__() Ui_Dialog.setupUi(self, self) self.pushButton_3.clicked.connect(self.showRecords) self.pushButton.clicked.connect(self.start) self.recive = False self.s = socket.socket() # Create a socket object self.c = socket.socket() # Create a socket object host = "192.168.1.40" # Get local machine name port = 12345 # Reserve a port for your serv host = "" # Get local machine nameice. self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.pushButton_3.setDisabled(True) self.pushButton.setText("Stop") try: self.s.bind(("", port)) # Bind to the port except: print("error") # self.s.listen(5) # Now wait for client connection. def __del__(self): self.s.close() def showConfiguration(self): self.hide() self.conf = configureView.configureView(self) self.conf.setMain(self) self.conf.show() def showRecords(self): self.w = QWidget() self.w.show() self.hide() self.gridLayout = QtWidgets.QVBoxLayout(self.w) self.text = QtWidgets.QLabel(self.w) self.chart = QChart() self.chart2 = QChart() self.chart3 = QChart() self.text.setText("none") self.backButton = QtWidgets.QPushButton(self.w) self.chartView = QChartView(self.chart) self.chartView.setRenderHint(QtGui.QPainter.Antialiasing) # self.chartView2.setRenderHint(QtGui.QPainter.Antialiasing) # self.chartView3.setRenderHint(QtGui.QPainter.Antialiasing) self.gridLayout.addWidget(self.chartView) # self.gridLayout.addWidget(self.chartView3) self.backButton.setText("Back") self.gridLayout.addWidget(self.backButton) self.backButton.clicked.connect(self.back) self.recive = True # self.series2 = QLineSeries(self.chart2) # self.series3 = QLineSeries(self.chart3) self.series = QLineSeries(self.chart) self.series2 = QLineSeries(self.chart) self.series3 = QLineSeries(self.chart) # self.series2.setUseOpenGL(True) # self.series3.setUseOpenGL(True) self.series.setUseOpenGL(True) self.series2.setUseOpenGL(True) self.series3.setUseOpenGL(True) # self.chart.addSeries(self.series) self.startServer() def createLineChart(self, dataTable): self.chart.setTitle("Sensor1") series = QLineSeries(self.chart) series2 = QLineSeries(self.chart) series3 = QLineSeries(self.chart) # series2 = QLineSeries(self.chart) # series3 = QLineSeries(self.chart) series.setUseOpenGL(True) series2.setUseOpenGL(True) series3.setUseOpenGL(True) # series2.setUseOpenGL(True) # series3.setUseOpenGL(True) series.replace(self.series.pointsVector()) series2.replace(self.series2.pointsVector()) series3.replace(self.series3.pointsVector()) # series2.replace(self.series2.pointsVector()) # series3.replace(self.series2.pointsVector()) self.chart.removeAllSeries() self.chart.addSeries(series2) self.chart.addSeries(series) self.chart.addSeries(series3) # self.chart2.removeAllSeries() # self.chart2.addSeries(series2) # self.chart3.removeAllSeries() # self.chart3.addSeries(series3) # self.chart.scroll(1,2) def startServer(self): # Establish connection with client. a = [] QApplication.processEvents() self.c.connect(("192.168.1.41", 12346)) self.c.send(b'RecordView True') print("connected") index = 0 while self.recive: QApplication.processEvents() # c, addr = self.s.accept() message, adre = self.s.recvfrom(1024) # print(message) values = message.decode("utf-8").split("-") value1 = int(values[0]) value2 = int(values[1]) value3 = int(values[2]) self.series.append(index, value1) self.series2.append(index, value2) self.series3.append(index, value3) # self.series2.append(index, int(message.decode("utf-8"))) # self.series3.append(index, int(message.decode("utf-8"))) if self.series.count() > 100: self.series.removePoints(0, 1) self.series2.removePoints(0, 1) self.series3.removePoints(0, 1) # self.series2.removePoints(0,1) # self.series3.removePoints(0,1) index += 1 a.append(message.decode("utf-8")) self.createLineChart(a) self.c.connect(("192.168.1.41", 12346)) self.c.send(b'RecordView False') def back(self): self.w.hide() self.show() self.recive = False def configure(self, arguments): print(arguments) self.c.connect(("192.168.1.41", 12346)) self.c.send(b'Sensor ' + arguments) def start(self): self.c.connect(("192.168.1.41", 12346)) if self.pushButton.text() == "Start": text = "Stop" self.pushButton_3.setEnabled(False) self.c.send(b'Record False') else: text = "Start" self.pushButton_3.setEnabled(True) self.c.send(b'Record True') self.recive = self.pushButton.text() == "Start" self.pushButton.setText(text)
class StatisticsController: ''' Class responsible of changing letting the user visualize the data saved in the database through a graph. ''' def __init__(self, pView, pModel): ''' Initializes the chart ''' self.model = pModel self.view = pView self.queries = { 'Products by category': I.PRODUCTS_BY_CATEGORY, 'Sellers by gender': I.SELLERS_BY_GENDER, 'Sellers by age': I.SELLERS_BY_AGE, 'Total sales by gender': I.SALES_BY_GENDER, 'Total sales profit by gender': I.PROFITS_BY_GENDER } # Loads every admin statistic for key in self.queries: self.view.ui.Statistics_StatisticsInput.addItem(key) self.view.ui.Statistics_ShowButton.clicked.connect(self.loadQuery) # Sets up the chart self.chart = QChart() # Embeds the chart in the application layout = QVBoxLayout() chartView = QChartView(self.chart) layout.addWidget(chartView) chartView.show() self.view.ui.Statistics_StatisticsWidget.setLayout(layout) def loadQuery(self): ''' loads a query and its information ''' queryName = self.view.ui.Statistics_StatisticsInput.currentText() query = self.queries[queryName] result = self.model.query(query) self.loadChart(queryName, result) def loadChart(self, pTitle, pData): ''' Loads a chart and embeds it in the application ''' # Creates the chart self.chart.setTitle(pTitle) self.chart.removeAllSeries() # Creates the slices series = QPieSeries(self.chart) for i in range(len(pData)): slice = series.append( '{} | {} | {}%'.format(str(pData[i][0]), str(pData[i][1]), str(pData[i][2])), pData[i][2]) slice.setLabelVisible(True) self.chart.addSeries(series)
class widgetFDChart(QtWidgets.QWidget, qdesignFDChart.Ui_Form): def __init__(self, parent=None): super(widgetFDChart, self).__init__(parent) self.setupUi(self) tribchartmenustyle(self) # SetUp for Chart to Display Distribution curves and inputs. self.chart = QChart() self.chart.legend().setVisible(False) self.chart.axisX = QValueAxis() self.chart.axisY = QValueAxis() self.chart.axisX.setTickCount(10) self.chart.axisY.setTickCount(10) self.chart.axisX.setTitleText("Value") self.chart.axisY.setTitleText("Probability") self.chartview = QChartView(self.chart) self.verticalLayout.addWidget(self.chartview) # self.setAxesMinMax(-3,3,0.01,1.5) self.chartview.setRenderHint(QPainter.Antialiasing) # self.legend().setVisible(True) # self.setAnimationOptions(QChart.SeriesAnimations) # self.legend().setAlignment(Qt.AlignBottom) # Connect Buttons self.pushButtonExportPNG.pressed.connect(self._onActionSavePNG) def axesMinMax(self): # returns a length 4 list of the axes min and max values [x1,x2,y1,y2] return [ self.chart.axisX.min(), self.chart.axisX.max(), self.chart.axisY.min(), self.chart.axisY.max() ] def setAxes(self, series): # assigns a series to the chart default axes self.chart.setAxisX(self.chart.axisX, series) self.chart.setAxisY(self.chart.axisY, series) def setAxesMinMax(self, x1, x2, y1, y2): # sets the min max values in X and Y self.chart.axisX.setMin(x1) self.chart.axisX.setMax(x2) self.chart.axisY.setMin(y1) self.chart.axisY.setMax(y2) def setTitle(self, title): self.chart.setTitle(title) def addDistrLine(self, type, n, kstats): data = distr.distrpdf(type, n, **kstats) xmin = min(data['X']) xmax = max(data['X']) ymin = min(data['Y']) ymax = max(data['Y']) self.lineDist = XLineSeries(data, xkey='X')[0] self.chart.addSeries(self.lineDist) self.setAxes(self.lineDist) xscal = 0.1 * (xmax - xmin) yscal = 0.1 * (ymax - ymin) self.setAxesMinMax(xmin - xscal, xmax + xscal, ymin, ymax + yscal) def updateChart(self, tabledata): self.activeDist = tabledata[0] self.kstats = tabledata[1] self.chart.removeAllSeries() self.addDistrLine(self.activeDist, 100, self.kstats) @pyqtSlot(str) def paintChart(self, filename): #pixmap = QPixmap() pixmap = self.chartview.grab() pixmap.save(filename) def _onActionSavePNG(self): pngfile = QtWidgets.QFileDialog.getSaveFileName( self, caption='Export PNG As', directory='~', filter='*.png') #try: self.paintChart(pngfile[0])
class Ui(mainwindow.Ui_MainWindow): def __init__(self, MainWindow): super(Ui, self).setupUi(MainWindow) self.MainWindow = MainWindow self.stix_tctm_parser = stix_parser.StixTCTMParser() self.initialize() def close(self): self.MainWindow.close() def style(self): return self.MainWindow.style() def initialize(self): self.tabWidget.setCurrentIndex(0) self.actionExit.triggered.connect(self.close) self.actionPlot.setEnabled(False) self.actionNext.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_ArrowForward)) self.actionPrevious.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_ArrowBack)) self.actionOpen.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_DialogOpenButton)) self.actionSave.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_DriveFDIcon)) self.actionSave.triggered.connect(self.save) self.actionOpen.triggered.connect(self.getOpenFilename) self.actionNext.triggered.connect(self.nextPacket) self.actionPrevious.triggered.connect(self.previousPacket) self.actionAbout.triggered.connect(self.about) self.actionPrevious.setEnabled(False) self.actionNext.setEnabled(False) self.actionSave.setEnabled(False) self.actionPlot.setEnabled(False) self.actionCopy.triggered.connect(self.onCopyTriggered) self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected) self.actionCopy.setEnabled(False) self.actionPaste.triggered.connect(self.onPasteTriggered) self.actionLog.triggered.connect(self.dockWidget.show) self.actionSetIDB.triggered.connect(self.onSetIDBClicked) self.plotButton.clicked.connect(self.onPlotButtonClicked) self.exportButton.clicked.connect(self.onExportButtonClicked) self.actionPlot.triggered.connect(self.onPlotActionClicked) self.actionLoadMongodb.triggered.connect(self.onLoadMongoDBTriggered) self.actionConnectTSC.triggered.connect(self.onConnectTSCTriggered) self.actionPacketFilter.triggered.connect(self.onPacketFilterTriggered) self.actionPlugins.triggered.connect(self.onPluginTriggered) self.actionOnlineHelp.triggered.connect(self.onOnlineHelpTriggered) self.actionViewBinary.triggered.connect(self.onViewBinaryTriggered) self.packetTreeWidget.customContextMenuRequested.connect( self.packetTreeContextMenuEvent) self.mdb = None self.current_row = 0 self.data = [] self.x = [] self.y = [] self.xlabel = 'x' self.ylabel = 'y' self.buttons_enabled = False self.chart = QChart() self.chart.layout().setContentsMargins(0, 0, 0, 0) self.chart.setBackgroundRoundness(0) self.savePlotButton.clicked.connect(self.savePlot) self.chartView = QChartView(self.chart) self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15) #self.packetTreeWidget.itemDoubleClicked.connect(self.onPacketTreeItemDoubleClicked) self.selected_services = SELECTED_SERVICES self.selected_SPID = [] # IDB location self.settings = QtCore.QSettings('FHNW', 'stix_parser') self.idb_filename = self.settings.value('idb_filename', [], str) if self.idb_filename: idb._stix_idb.reload(self.idb_filename) if not idb._stix_idb.is_connected(): self.showMessage('IDB has not been set!') else: self.showMessage( 'IDB location: {} '.format(idb._stix_idb.get_idb_filename()), 1) def packetTreeContextMenuEvent(self, pos): menu = QtWidgets.QMenu() rawDataAction = menu.addAction('Show raw data') menu.addSeparator() filterAction = menu.addAction('Filter packets') copyPacketAction = menu.addAction('Copy packet') menu.addSeparator() deleteAllAction = menu.addAction('Delete all packets') self.current_row = self.packetTreeWidget.currentIndex().row() rawDataAction.triggered.connect(self.onViewBinaryTriggered) filterAction.triggered.connect(self.onPacketFilterTriggered) copyPacketAction.triggered.connect(self.onCopyTriggered) deleteAllAction.triggered.connect(self.onDeleteAllTriggered) action = menu.exec_(self.packetTreeWidget.viewport().mapToGlobal(pos)) def onDeleteAllTriggered(self): self.data.clear() self.packetTreeWidget.clear() self.paramTreeWidget.clear() #def onPacketTreeItemDoubleClicked(self): # self.onViewBinaryTriggered() def onViewBinaryTriggered(self): diag = QtWidgets.QDialog() diag_ui = raw_viewer.Ui_Dialog() diag_ui.setupUi(diag) if self.data: try: raw = self.data[self.current_row]['bin'] header = self.data[self.current_row]['header'] diag_ui.setPacketInfo('{}({},{}) {}'.format( header['TMTC'], header['service_type'], header['service_subtype'], header['DESCR'])) diag_ui.displayRaw(raw) except (IndexError, KeyError): diag_ui.setText('Raw data not available.') diag.exec_() def onOnlineHelpTriggered(self): webbrowser.open('https://github.com/i4Ds/STIX-dataviewer', new=2) def onPluginTriggered(self): self.plugin_location = self.settings.value('plugin_location', [], str) diag = QtWidgets.QDialog() diag_ui = plugin.Ui_Dialog() diag_ui.setupUi(diag) if self.plugin_location: diag_ui.setPluginLocation(self.plugin_location) diag_ui.setData(self.data, self.current_row) diag.exec_() location = diag_ui.getPluginLocation() if location != self.plugin_location: self.settings.setValue('plugin_location', location) def onPacketFilterTriggered(self): diag = QtWidgets.QDialog() diag_ui = packet_filter.Ui_Dialog() diag_ui.setupUi(diag) diag_ui.setSelectedServices(self.selected_services) diag_ui.buttonBox.accepted.connect( partial(self.applyServiceFilter, diag_ui)) diag.exec_() def applyServiceFilter(self, diag_ui): self.selected_SPID = diag_ui.getSelectedSPID() self.selected_services = diag_ui.getSelectedServices() self.showMessage('Applying filter...') self.addPacketsToView(self.data, True, show_stat=False) def onExportButtonClicked(self): if self.y: filename = str( QtWidgets.QFileDialog.getSaveFileName(None, "Save data to file", "", "CSV(*.csv)")[0]) if filename: with open(filename, 'w') as f: f.write('{},{}\n'.format(self.xlabel, self.ylabel)) for xx, yy in zip(self.x, self.y): f.write('{},{}\n'.format(xx, yy)) self.showMessage( 'The data has been written to {}'.format(filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('Plot first!') msgBox.setWindowTitle("Warning") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def savePlot(self): # if self.figure.get_axes(): if self.chart: filetypes = "PNG (*.png);;JPEG (*.jpg)" filename = str( QtWidgets.QFileDialog.getSaveFileName(None, "Save plot to file", "", filetypes)[0]) if filename: if not filename.endswith(('.png', '.jpg')): filename += '.png' # self.figure.savefig(filename) p = self.chartView.grab() p.save(filename) self.showMessage(('Saved to %s.' % filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('No figure to save') msgBox.setWindowTitle("STIX raw data viewer") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def onCopyTriggered(self): packet_id = self.current_row try: packet = self.data[packet_id] ss = pprint.pformat(packet) cb = QtWidgets.QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(ss, mode=cb.Clipboard) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) msg.setText( "The data of the selected packet has been copied to the clipboard." ) msg.setWindowTitle("Information") msg.setStandardButtons(QtWidgets.QMessageBox.Ok) retval = msg.exec_() except Exception as e: self.showMessage(str(e), 0) def onPasteTriggered(self): raw_hex = QtWidgets.QApplication.clipboard().text() if len(raw_hex) < 16: self.showMessage('No data in the clipboard.') return data_hex = re.sub(r"\s+", "", raw_hex) try: data_binary = binascii.unhexlify(data_hex) packets = self.stix_tctm_parser.parse_binary(data_binary, 0, store_binary=True) if not packets: return self.showMessage('%d packets read from the clipboard' % len(packets)) self.onDataReady(packets, clear=False, show_stat=False) except Exception as e: self.showMessageBox(str(e), data_hex) def showMessageBox(self, message, content): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Critical) msg.setText("Error") msg.setInformativeText(message) msg.setWindowTitle("Error") msg.setDetailedText(content) msg.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) retval = msg.exec_() def showMessage(self, msg, where=0): if where != 1: self.statusbar.showMessage(msg) if where != 0: self.statusListWidget.addItem(msg) # if destination !=0 : # self.listWidget_2.addItem(msg) def onSetIDBClicked(self): self.idb_filename = QtWidgets.QFileDialog.getOpenFileName( None, 'Select file', '.', 'IDB file(*.db *.sqlite *.sqlite3)')[0] if not self.idb_filename: return idb._stix_idb.reload(self.idb_filename) if idb._stix_idb.is_connected(): #settings = QtCore.QSettings('FHNW', 'stix_parser') self.settings.setValue('idb_filename', self.idb_filename) self.showMessage( 'IDB location: {} '.format(idb._stix_idb.get_idb_filename()), 1) def save(self): filetypes = 'python compressed pickle (*.pklz);; python pickle file (*.pkl);; binary data (*.dat)' self.output_filename = str( QtWidgets.QFileDialog.getSaveFileName(None, "Save packets to", "", filetypes)[0]) if not self.output_filename.endswith(('.pklz', '.pkl', '.dat')): msg = 'unsupported file format !' self.showMessage(msg) return msg = 'Writing data to file %s' % self.output_filename self.showMessage(msg) if self.output_filename.endswith(('.pklz', '.pkl')): stw = stix_writer.StixPickleWriter(self.output_filename) stw.register_run(str(self.input_filename)) stw.write_all(self.data) #stw.done() elif self.output_filename.endswith('.dat'): stw = stix_writer.StixBinaryWriter(self.output_filename) stw.write_all(self.data) num_ok = stw.get_num_sucess() msg = ( 'The binary data of {} packets written to file {}, total packets {}' .format(num_ok, self.output_filename, len(self.data))) self.showMessage(msg) def setListViewSelected(self, row): #index = self.model.createIndex(row, 0); # if index.isValid(): # self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select) pass def about(self): msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("STIX raw data parser and viewer, [email protected]") msgBox.setWindowTitle("Stix data viewer") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def nextPacket(self): self.current_row += 1 length = len(self.data) if self.current_row >= length: self.current_row = length - 1 self.showMessage('No more packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def previousPacket(self): self.current_row -= 1 if self.current_row < 0: self.current_row = 0 self.showMessage('Reach the first packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def getOpenFilename(self): filetypes = ( 'STIX raw data(*.dat *.bin *.binary);; python pickle files (*.pkl *pklz);;' 'ESA xml files (*xml);;' 'ESA ascii files(*.ascii);; CMDVS archive files (*.BDF);; All(*)') self.input_filename = QtWidgets.QFileDialog.getOpenFileName( None, 'Select file', '.', filetypes)[0] if not self.input_filename: return self.openFile(self.input_filename) def openFile(self, filename): self.packetTreeWidget.clear() msg = 'Loading file %s ...' % filename self.showMessage(msg) self.dataReader = StixFileReader(filename) #self.dataReader.dataLoaded.connect(self.onDataReady) self.dataReader.packetArrival.connect(self.onPacketArrival) self.dataReader.error.connect(self.onDataReaderError) self.dataReader.info.connect(self.onDataReaderInfo) self.dataReader.warn.connect(self.onDataReaderWarn) self.dataReader.start() def onDataReaderInfo(self, msg): self.showMessage(msg, 0) def onDataReaderWarn(self, msg): self.showMessage(msg, 1) def onDataReaderError(self, msg): self.showMessage(msg, 1) def onDataReady(self, data, clear=True, show_stat=True): if not clear: self.data.extend(data) else: self.data = data if data: self.addPacketsToView(data, clear=clear, show_stat=show_stat) self.enableButtons() def enableButtons(self): if not self.buttons_enabled: self.actionPrevious.setEnabled(True) self.actionNext.setEnabled(True) self.actionSave.setEnabled(True) self.actionCopy.setEnabled(True) self.actionPlot.setEnabled(True) self.actionViewBinary.setEnabled(True) self.buttons_enabled = True def addPacketsToView(self, data, clear=True, show_stat=True): if clear: self.packetTreeWidget.clear() #t0 = 0 for p in data: if type(p) is not dict: continue header = p['header'] root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget) # if t0 == 0: # t0 = header['time'] timestamp_str = '' try: timestamp_str = header['utc'] except KeyError: timestamp_str = '{:.2f}'.format(header['time']) #- t0) root.setText(0, timestamp_str) root.setText( 1, '{}({},{}) - {}'.format(header['TMTC'], header['service_type'], header['service_subtype'], header['DESCR'])) if not self.selected_SPID: #not set then apply service if header['service_type'] not in self.selected_services: root.setHidden(True) else: if header['SPID'] not in self.selected_SPID: root.setHidden(True) if show_stat: total_packets = len(self.data) self.showMessage(('Total packet(s): %d' % total_packets)) def onConnectTSCTriggered(self): diag = QtWidgets.QDialog() diag_ui = tsc_connection.Ui_Dialog() diag_ui.setupUi(diag) self.tsc_host = self.settings.value('tsc_host', [], str) self.tsc_port = self.settings.value('tsc_port', [], str) if self.tsc_host: diag_ui.serverLineEdit.setText(self.tsc_host) if self.tsc_port: diag_ui.portLineEdit.setText(self.tsc_port) diag_ui.buttonBox.accepted.connect(partial(self.connectToTSC, diag_ui)) diag.exec_() def connectToTSC(self, dui): host = dui.serverLineEdit.text() port = dui.portLineEdit.text() self.showMessage('Connecting to TSC...') self.socketPacketReceiver = StixSocketPacketReceiver(host, int(port)) self.socketPacketReceiver.packetArrival.connect(self.onPacketArrival) self.socketPacketReceiver.error.connect(self.onDataReaderError) self.socketPacketReceiver.info.connect(self.onDataReaderInfo) self.socketPacketReceiver.warn.connect(self.onDataReaderWarn) self.socketPacketReceiver.start() def onPacketArrival(self, packets): if packets: self.onDataReady(packets, clear=False, show_stat=True) def onLoadMongoDBTriggered(self): diag = QtWidgets.QDialog() diag_ui = mongo_dialog.Ui_Dialog() diag_ui.setupUi(diag) #self.settings = QtCore.QSettings('FHNW', 'stix_parser') self.mongo_server = self.settings.value('mongo_server', [], str) self.mongo_port = self.settings.value('mongo_port', [], str) self.mongo_user = self.settings.value('mongo_user', [], str) self.mongo_pwd = self.settings.value('mongo_pwd', [], str) if self.mongo_server: diag_ui.serverLineEdit.setText(self.mongo_server) if self.mongo_port: diag_ui.portLineEdit.setText(self.mongo_port) if self.mongo_user: diag_ui.userLineEdit.setText(self.mongo_user) if self.mongo_pwd: diag_ui.pwdLineEdit.setText(self.mongo_pwd) diag_ui.pushButton.clicked.connect( partial(self.loadRunsFromMongoDB, diag_ui)) diag_ui.buttonBox.accepted.connect( partial(self.loadDataFromMongoDB, diag_ui, diag)) diag.exec_() def loadRunsFromMongoDB(self, dui): server = dui.serverLineEdit.text() port = dui.portLineEdit.text() user = dui.userLineEdit.text() pwd = dui.pwdLineEdit.text() self.showMessage('saving setting...') if self.mongo_server != server: self.settings.setValue('mongo_server', server) if self.mongo_port != port: self.settings.setValue('mongo_port', port) if self.mongo_user != user: self.settings.setValue('mongo_user', user) if self.mongo_pwd != pwd: self.settings.setValue('mongo_pwd', pwd) self.showMessage('connecting Mongo database ...') self.mdb = mgdb.MongoDB(server, int(port), user, pwd) if not self.mdb.is_connected(): return dui.treeWidget.clear() self.showMessage('Fetching data...') for run in self.mdb.get_runs(): root = QtWidgets.QTreeWidgetItem(dui.treeWidget) root.setText(0, str(run['_id'])) root.setText(1, run['filename']) root.setText(2, run['date']) root.setText(3, str(run['start'])) root.setText(4, str(run['end'])) def loadDataFromMongoDB(self, dui, diag): self.showMessage('Loading packets ...') selected_runs = [] for item in dui.treeWidget.selectedItems(): selected_runs.append(item.text(0)) if not selected_runs: self.showMessage('Run not selected!') if selected_runs: diag.done(0) self.showMessage('Loading data ...!') data = self.mdb.get_packets(selected_runs[0]) if data: self.onDataReady(data, clear=True) else: self.showMessage('No packets found!') # close def onPacketSelected(self, cur, pre): self.current_row = self.packetTreeWidget.currentIndex().row() self.showMessage(('Packet #%d selected' % self.current_row)) self.showPacket(self.current_row) def showPacket(self, row): if not self.data: return header = self.data[row]['header'] total_packets = len(self.data) self.showMessage( ('Packet %d / %d %s ' % (row, total_packets, header['DESCR']))) self.paramTreeWidget.clear() header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) header_root.setText(0, "Header") rows = len(header) for key, val in header.items(): root = QtWidgets.QTreeWidgetItem(header_root) root.setText(0, key) root.setText(1, str(val)) params = self.data[row]['parameters'] param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) param_root.setText(0, "Parameters") self.showParameterTree(params, param_root) self.paramTreeWidget.expandItem(param_root) self.paramTreeWidget.expandItem(header_root) self.current_row = row def showParameterTree(self, params, parent): if not params: return for p in params: root = QtWidgets.QTreeWidgetItem(parent) if not p: continue try: param_name = p['name'] desc = '' #description of parameter if 'desc' in p: desc = p['desc'] if not desc: desc = idb._stix_idb.get_PCF_description(param_name) scos_desc = idb._stix_idb.get_scos_description(param_name) if scos_desc: root.setToolTip(1, scos_desc) root.setText(0, param_name) root.setText(1, desc) root.setText(2, str(p['raw'])) try: root.setToolTip(2, hex(p['raw'][0])) except: pass root.setText(3, str(p['eng'])) if 'children' in p: if p['children']: self.showParameterTree(p['children'], root) except KeyError: self.showMessage( '[Error ]: keyError occurred when adding parameter') self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked) def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0): if not params: return timestamp = header['time'] for p in params: if type(p) is not dict: continue if name == p['name']: values = None #print('data type:{}'.format(data_type)) if data_type == 0: values = p['raw'] else: values = p['eng'] try: yvalue = None if (type(values) is tuple) or (type(values) is list): yvalue = float(values[0]) else: yvalue = float(values) ret_y.append(yvalue) if xaxis == 1: ret_x.append(timestamp) else: self.showMessage(('Can not plot %s ' % str(yvalue))) except Exception as e: self.showMessage(('%s ' % str(e))) if 'children' in p: if p['children']: self.walk(name, p['children'], header, ret_x, ret_y, xaxis, data_type) def onPlotButtonClicked(self): if self.chart: self.chart.removeAllSeries() if not self.data: return self.showMessage('Preparing plot ...') name = self.paramNameEdit.text() packet_selection = self.comboBox.currentIndex() xaxis_type = self.xaxisComboBox.currentIndex() data_type = self.dataTypeComboBox.currentIndex() timestamp = [] self.y = [] packet_id = self.current_row params = self.data[packet_id]['parameters'] header = self.data[packet_id]['header'] current_spid = header['SPID'] if packet_selection == 0: self.walk(name, params, header, timestamp, self.y, xaxis_type, data_type) elif packet_selection == 1: for packet in self.data: header = packet['header'] if packet['header']['SPID'] != current_spid: continue params = packet['parameters'] self.walk(name, params, header, timestamp, self.y, xaxis_type, data_type) self.x = [] if not self.y: self.showMessage('No data points') elif self.y: style = self.styleEdit.text() if not style: style = '-' title = '%s' % str(name) desc = self.descLabel.text() if desc: title += '- %s' % desc self.chart.setTitle(title) ylabel = 'Raw value' xlabel = name if data_type == 1: ylabel = 'Engineering value' if xaxis_type == 0: if packet_selection == 1: xlabel = "Packet #" else: xlabel = "Repeat #" self.x = range(0, len(self.y)) if xaxis_type == 1: self.x = [t - timestamp[0] for t in timestamp] xlabel = 'Time -T0 (s)' if xaxis_type != 2: series = QLineSeries() series2 = None for xx, yy in zip(self.x, self.y): series.append(xx, yy) if 'o' in style: series2 = QScatterSeries() for xx, yy in zip(self.x, self.y): series2.append(xx, yy) self.chart.addSeries(series2) self.chart.addSeries(series) axisX = QValueAxis() axisX.setTitleText(xlabel) axisY = QValueAxis() axisY.setTitleText(ylabel) self.chart.setAxisX(axisX) self.chart.setAxisY(axisY) series.attachAxis(axisX) series.attachAxis(axisY) else: nbins = len(set(self.y)) ycounts, xedges = np.histogram(self.y, bins=nbins) series = QLineSeries() for i in range(0, nbins): meanx = (xedges[i] + xedges[i + 1]) / 2. series.append(meanx, ycounts[i]) self.chart.addSeries(series) axisX = QValueAxis() axisX.setTitleText(name) axisY = QValueAxis() axisY.setTitleText("Counts") self.chart.setAxisY(axisY) self.chart.setAxisX(axisX) series.attachAxis(axisX) series.attachAxis(axisY) self.xlabel = xlabel self.ylabel = ylabel self.chartView.setRubberBand(QChartView.RectangleRubberBand) self.chartView.setRenderHint(QtGui.QPainter.Antialiasing) msg = 'Y length: {}, min-Y: {}, max-Y: {}'.format( len(self.y), min(self.y), max(self.y)) self.showMessage(msg, 1) self.showMessage('The canvas updated!') def plotParameter(self, name=None, desc=None): self.tabWidget.setCurrentIndex(1) if name: self.paramNameEdit.setText(name) if desc: self.descLabel.setText(desc) def onPlotActionClicked(self): self.tabWidget.setCurrentIndex(1) self.plotParameter() def onTreeItemClicked(self, it, col): self.plotParameter(it.text(0), it.text(1))
class MainWindow(QMainWindow): BASE_DIR = os.path.dirname(os.path.abspath(__file__)) MAIN_UI_FILE = os.path.join(BASE_DIR, "main.ui") NEW_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_popup.ui") NEW_DISH_MULTI_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_multi_popup.ui") NEW_DISH_DATA_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_data_popup.ui") MODIFY_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "modify_dish_popup.ui") DB_FILE = os.path.join(BASE_DIR, "restaurant.db") def __init__(self): super(MainWindow, self).__init__() # Initialize variable self.db_connection = None self.new_dish_popup = QWidget() self.new_dish_multi_popup = QWidget() self.new_dish_data_popup = QWidget() self.modify_dish_popup = QWidget() self.dish_table_model = QStandardItemModel(0, 6) self.dish_table_proxy = TableFilter() self.dish_data_table_model = QStandardItemModel(0, 6) self.dish_data_table_proxy = TableFilter() self.graph_chart = None self.graph_series = {} # Load UI designs uic.loadUi(self.MAIN_UI_FILE, self) uic.loadUi(self.NEW_DISH_POPUP_UI_FILE, self.new_dish_popup) uic.loadUi(self.NEW_DISH_MULTI_POPUP_UI_FILE, self.new_dish_multi_popup) uic.loadUi(self.NEW_DISH_DATA_POPUP_UI_FILE, self.new_dish_data_popup) uic.loadUi(self.MODIFY_DISH_POPUP_UI_FILE, self.modify_dish_popup) self.init_dish_table() self.init_dish_data_table() self.init_graph() # Connect to database self.init_db_connection() # MainWindow Bind action triggers self.action_new_dish.triggered.connect(self.show_new_dish_popup) self.action_new_dish_multi.triggered.connect( self.show_new_dish_multi_popup) self.action_new_data_multi.triggered.connect( lambda: self.modify_new_dish_data_popup_table(show=True)) self.tabWidget.currentChanged.connect(self.update_graph) # Dish Table filter bind self.dish_lineEdit.textChanged.connect( lambda text, col_idx=1: self.dish_table_proxy.set_col_regex_filter( col_idx, text)) self.lower_price_doubleSpinBox.valueChanged.connect( lambda value, col_idx=2: self.dish_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_price_doubleSpinBox.valueChanged.connect( lambda value, col_idx=2: self.dish_table_proxy. set_col_number_filter(col_idx, -1, value)) self.lower_week_sell_spinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_week_sell_spinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_table_proxy. set_col_number_filter(col_idx, -1, value)) # Dish Data Table filter bind self.lower_data_dateEdit.dateChanged.connect( lambda date, col_idx=1: self.dish_data_table_proxy. set_col_date_filter(col_idx, date, -1)) self.higher_data_dateEdit.dateChanged.connect( lambda date, col_idx=1: self.dish_data_table_proxy. set_col_date_filter(col_idx, -1, date)) self.data_lineEdit.textChanged.connect( lambda text, col_idx=2: self.dish_data_table_proxy. set_col_regex_filter(col_idx, text)) self.lower_data_doubleSpinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_data_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_data_doubleSpinBox.valueChanged.connect( lambda value, col_idx=3: self.dish_data_table_proxy. set_col_number_filter(col_idx, -1, value)) self.lower_data_spinBox.valueChanged.connect( lambda value, col_idx=4: self.dish_data_table_proxy. set_col_number_filter(col_idx, value, -1)) self.higher_data_spinBox.valueChanged.connect( lambda value, col_idx=4: self.dish_data_table_proxy. set_col_number_filter(col_idx, -1, value)) self.data_all_check_checkBox.stateChanged.connect( lambda state, col_idx=5: self.data_table_check_state( state, col_idx)) self.dish_data_table_model.itemChanged.connect(self.update_series) # Popup bind action triggers self.new_dish_popup.create_new_dish_btn.clicked.connect( self.create_new_dish) self.new_dish_multi_popup.pushButton_ok.clicked.connect( self.create_new_dish_multi) self.new_dish_data_popup.dateEdit.dateChanged.connect( self.modify_new_dish_data_popup_table) self.new_dish_data_popup.pushButton_ok.clicked.connect( self.create_new_dish_data) # Get current dishes self.load_dish_table() self.load_dish_data_table() self.new_dish_data_popup.dateEdit.setDate(QtCore.QDate.currentDate()) def init_dish_table(self): self.dish_tableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # Set Header data and stretch for col, col_name in enumerate( ["ID", "菜品", "价格", "近7天总售出", "操作", "备注"]): self.dish_table_model.setHeaderData(col, Qt.Horizontal, col_name, Qt.DisplayRole) self.dish_table_proxy.setSourceModel(self.dish_table_model) self.dish_tableView.setModel(self.dish_table_proxy) self.dish_tableView.setColumnHidden(0, True) for (col, method) in [(1, "Regex"), (2, "Number"), (3, "Number"), (5, "Regex")]: self.dish_table_proxy.filter_method[col] = method def init_dish_data_table(self): self.data_tableView.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) for col, col_name in enumerate( ["Dish_ID", "日期", "菜品", "价格", "售出", "选择"]): self.dish_data_table_model.setHeaderData(col, Qt.Horizontal, col_name, Qt.DisplayRole) self.dish_data_table_proxy.setSourceModel(self.dish_data_table_model) self.data_tableView.setModel(self.dish_data_table_proxy) self.data_tableView.setColumnHidden(0, True) for (col, method) in [(1, "Date"), (2, "Regex"), (3, "Number"), (4, "Number")]: self.dish_data_table_proxy.filter_method[col] = method def init_graph(self): self.graph_chart = QChart(title="售出图") self.graph_chart.legend().setVisible(True) self.graph_chart.setAcceptHoverEvents(True) graph_view = QChartView(self.graph_chart) graph_view.setRenderHint(QPainter.Antialiasing) self.gridLayout_5.addWidget(graph_view) def init_db_connection(self): self.db_connection = sqlite3.connect(self.DB_FILE) cursor = self.db_connection.cursor() # check create table if not exist sql_create_dish_table = """ CREATE TABLE IF NOT EXISTS dish ( id integer PRIMARY KEY, name text NOT NULL, price numeric Not NULL, remarks text, UNIQUE (name, price) ); """ sql_create_dish_data_table = """ CREATE TABLE IF NOT EXISTS dish_data ( dish_id integer NOT NULL REFERENCES dish(id) ON DELETE CASCADE, date date, sell_num integer DEFAULT 0, PRIMARY KEY (dish_id, date), CONSTRAINT dish_fk FOREIGN KEY (dish_id) REFERENCES dish (id) ON DELETE CASCADE ); """ sql_trigger = """ CREATE TRIGGER IF NOT EXISTS place_holder_data AFTER INSERT ON dish BEGIN INSERT INTO dish_data (dish_id, date, sell_num) VALUES(new.id, null, 0); END; """ cursor.execute(sql_create_dish_table) cursor.execute(sql_create_dish_data_table) cursor.execute("PRAGMA FOREIGN_KEYS = on") cursor.execute(sql_trigger) cursor.close() def load_dish_table(self): today = datetime.today() sql_select_query = """ SELECT dish.id, dish.name, dish.price, COALESCE(SUM(dish_data.sell_num), 0), dish.remarks FROM dish LEFT JOIN dish_data ON dish.id = dish_data.dish_id WHERE dish_data.date IS NULL OR dish_data.date BETWEEN date('{}') and date('{}') GROUP BY dish.id ORDER BY dish.name, dish.price;""".format( (today - timedelta(days=7)).strftime("%Y-%m-%d"), today.strftime("%Y-%m-%d")) cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() for row_idx, record in enumerate(records): self.dish_table_model.appendRow(create_dish_table_row(*record)) cursor.close() self.dish_tableView.setItemDelegateForColumn( 4, DishTableDelegateCell(self.show_modify_dish_popup, self.delete_dish, self.dish_tableView)) def load_dish_data_table(self): sql_select_query = """ SELECT dish_data.dish_id, dish_data.date, dish.name, dish.price, dish_data.sell_num FROM dish_data LEFT JOIN dish ON dish_data.dish_id = dish.id WHERE dish_data.date IS NOT NULL ORDER BY dish_data.date DESC, dish.name, dish.price, dish_data.sell_num;""" cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() for row_idx, record in enumerate(records): self.dish_data_table_model.appendRow( create_dish_data_table_row(*record)) cursor.close() self.lower_data_dateEdit.setDate(QDate.currentDate().addDays(-7)) self.higher_data_dateEdit.setDate(QDate.currentDate()) self.data_tableView.setItemDelegateForColumn( 5, DishDataTableDelegateCell(self.data_tableView)) def data_table_check_state(self, state, col): for row in range(self.dish_data_table_proxy.rowCount()): index = self.dish_data_table_proxy.mapToSource( self.dish_data_table_proxy.index(row, col)) if index.isValid(): self.dish_data_table_model.setData(index, str(state), Qt.DisplayRole) def show_new_dish_popup(self): # Move popup to center point = self.rect().center() global_point = self.mapToGlobal(point) self.new_dish_popup.move( global_point - QtCore.QPoint(self.new_dish_popup.width() // 2, self.new_dish_popup.height() // 2)) self.new_dish_popup.show() def show_new_dish_multi_popup(self): file_name = QFileDialog().getOpenFileName(None, "选择文件", "", self.tr("CSV文件 (*.csv)"))[0] self.new_dish_multi_popup.tableWidget.setRowCount(0) if file_name: with open(file_name, "r") as file: csv_reader = csv.reader(file, delimiter=",") for idx, row_data in enumerate(csv_reader): if len(row_data) == 2: name, price = row_data remark = "" elif len(row_data) == 3: name, price, remark = row_data else: QMessageBox.warning( self, "格式错误", self.tr('格式为"菜品 价格"或者"菜品 价格 备注"\n第{}行输入有误'.format( idx))) return self.new_dish_multi_popup.tableWidget.insertRow( self.new_dish_multi_popup.tableWidget.rowCount()) self.new_dish_multi_popup.tableWidget.setItem( idx, 0, QTableWidgetItem(name)) price_type = str_type(price) if price_type == str or (isinstance( price_type, (float, int)) and float(price) < 0): QMessageBox.warning( self, "格式错误", self.tr('第{}行价格输入有误'.format(idx + 1))) return self.new_dish_multi_popup.tableWidget.setItem( idx, 1, QTableWidgetItem("{:.2f}".format(float(price)))) self.new_dish_multi_popup.tableWidget.setItem( idx, 2, QTableWidgetItem(remark)) self.new_dish_multi_popup.show() def modify_new_dish_data_popup_table(self, *args, show=False): sql_select_query = """ SELECT id, name, price, dish_data.sell_num FROM dish LEFT JOIN dish_data ON dish.id=dish_data.dish_id WHERE dish_data.date IS NULL OR dish_data.date = date('{}') GROUP BY id, name, price ORDER BY dish.name, dish.price;""".format( self.new_dish_data_popup.dateEdit.date().toString("yyyy-MM-dd")) cursor = self.db_connection.cursor() cursor.execute(sql_select_query) records = cursor.fetchall() self.new_dish_data_popup.tableWidget.setRowCount(len(records)) self.new_dish_data_popup.tableWidget.setColumnHidden(0, True) for row_idx, record in enumerate(records): dish_id, name, price, sell_num = record self.new_dish_data_popup.tableWidget.setItem( row_idx, 0, QTableWidgetItem(str(dish_id))) self.new_dish_data_popup.tableWidget.setItem( row_idx, 1, QTableWidgetItem(name)) self.new_dish_data_popup.tableWidget.setItem( row_idx, 2, QTableWidgetItem("{:.2f}".format(price))) spin_box = QSpinBox() spin_box.setMaximum(9999) spin_box.setValue(sell_num) self.new_dish_data_popup.tableWidget.setCellWidget( row_idx, 3, spin_box) cursor.close() if show: self.new_dish_data_popup.show() def create_new_dish(self): cursor = self.db_connection.cursor() sql_insert = """ INSERT INTO dish(name, price, remarks) VALUES(?,?,?)""" dish_name = self.new_dish_popup.dish_name.text() dish_price = self.new_dish_popup.dish_price.value() dish_remark = self.new_dish_popup.dish_remark.toPlainText() try: cursor.execute(sql_insert, (dish_name, dish_price, dish_remark)) new_dish_id = cursor.lastrowid cursor.close() self.db_connection.commit() # Update dish table and dish comboBox in UI self.dish_table_model.appendRow( create_dish_table_row(new_dish_id, dish_name, dish_price, 0, dish_remark)) self.new_dish_popup.hide() except sqlite3.Error: cursor.close() QMessageBox.warning(self, "菜品价格重复", self.tr('菜品价格组合重复,请检查')) def create_new_dish_multi(self): cursor = self.db_connection.cursor() sql_insert = """ INSERT INTO dish(name, price, remarks) VALUES (?, ?, ?)""" for row in range(self.new_dish_multi_popup.tableWidget.rowCount()): dish_name = self.new_dish_multi_popup.tableWidget.item(row, 0).text() dish_price = float( self.new_dish_multi_popup.tableWidget.item(row, 1).text()) dish_remark = self.new_dish_multi_popup.tableWidget.item(row, 2).text() try: cursor.execute(sql_insert, (dish_name, dish_price, dish_remark)) new_dish_id = cursor.lastrowid self.dish_table_model.appendRow( create_dish_table_row(new_dish_id, dish_name, dish_price, 0, dish_remark)) except sqlite3.Error: cursor.close() QMessageBox.warning( self, "菜品价格重复", self.tr('前{}行已插入。\n第{}行菜品价格组合重复,请检查'.format(row, row + 1))) return cursor.close() self.db_connection.commit() self.new_dish_multi_popup.hide() def create_new_dish_data(self): current_date = self.new_dish_data_popup.dateEdit.date().toString( "yyyy-MM-dd") table_filter = TableFilter() table_filter.setSourceModel(self.dish_data_table_model) table_filter.set_col_regex_filter(1, current_date) for row in range(table_filter.rowCount()): index = table_filter.mapToSource(table_filter.index(0, 1)) if index.isValid(): self.dish_data_table_model.removeRow(index.row()) del table_filter cursor = self.db_connection.cursor() sql_insert = """ INSERT OR REPLACE INTO dish_data(dish_id, date, sell_num) VALUES (?, ?, ?)""" for row in range(self.new_dish_data_popup.tableWidget.rowCount()): dish_id = int( self.new_dish_data_popup.tableWidget.item(row, 0).text()) name = self.new_dish_data_popup.tableWidget.item(row, 1).text() price = float( self.new_dish_data_popup.tableWidget.item(row, 2).text()) sell_num = self.new_dish_data_popup.tableWidget.cellWidget( row, 3).value() cursor.execute(sql_insert, (dish_id, current_date, sell_num)) self.dish_data_table_model.appendRow( create_dish_data_table_row(dish_id, current_date, name, price, sell_num)) cursor.close() self.db_connection.commit() self.new_dish_data_popup.hide() def delete_dish(self, dish_id): cursor = self.db_connection.cursor() sql_delete = """ DELETE FROM dish WHERE id=?""" cursor.execute(sql_delete, tuple([dish_id])) cursor.close() self.db_connection.commit() # Update dish table and dish comboBox in UI for row in self.dish_data_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_data_table_model.removeRow(index.row()) for row in self.dish_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_table_model.removeRow(index.row()) def show_modify_dish_popup(self, dish_id): point = self.rect().center() global_point = self.mapToGlobal(point) self.modify_dish_popup.move( global_point - QtCore.QPoint(self.modify_dish_popup.width() // 2, self.modify_dish_popup.height() // 2)) # Find the row and get necessary info index = self.dish_table_model.match(self.dish_table_model.index(0, 0), Qt.DisplayRole, str(dish_id)) if index: row_idx = index[0] dish_name = self.dish_table_model.data(row_idx.siblingAtColumn(1)) dish_price = self.dish_table_model.data(row_idx.siblingAtColumn(2)) dish_remark = self.dish_table_model.data( row_idx.siblingAtColumn(5)) self.modify_dish_popup.dish_name.setText(dish_name) self.modify_dish_popup.dish_price.setValue(float(dish_price)) self.modify_dish_popup.dish_remark.setText(dish_remark) try: self.modify_dish_popup.modify_dish_btn.clicked.disconnect() except TypeError: pass self.modify_dish_popup.modify_dish_btn.clicked.connect( lambda: self.modify_dish(row_idx, dish_id)) self.modify_dish_popup.show() def modify_dish(self, row, dish_id): cursor = self.db_connection.cursor() sql_update = """ UPDATE dish SET name = ?, price = ?, remarks = ? WHERE id=?""" dish_name = self.modify_dish_popup.dish_name.text() dish_price = self.modify_dish_popup.dish_price.value() dish_remark = self.modify_dish_popup.dish_remark.toPlainText() cursor.execute(sql_update, (dish_name, dish_price, dish_remark, dish_id)) cursor.close() self.db_connection.commit() self.modify_dish_popup.hide() # Update dish table and dish comboBox in UI old_name = self.dish_table_model.data(row.siblingAtColumn(1)) old_price = self.dish_table_model.data(row.siblingAtColumn(2)) sell_num = self.dish_table_model.data(row.siblingAtColumn(3)) row_idx = row.row() self.dish_table_model.removeRow(row_idx) self.dish_table_model.insertRow( row_idx, create_dish_table_row(dish_id, dish_name, dish_price, sell_num, dish_remark)) for row in self.dish_data_table_model.findItems(str(dish_id)): index = row.index() if index.isValid(): self.dish_data_table_model.setData(index.siblingAtColumn(2), dish_name) self.dish_data_table_model.setData(index.siblingAtColumn(3), "{:.2f}".format(dish_price)) old_key = old_name + '(' + old_price + ')' if old_key in self.graph_line_series: self.graph_line_series[dish_name + '(' + str(dish_price) + ')'] = self.graph_line_series[old_key] del self.graph_line_series[old_key] def update_series(self, item: QStandardItem): if item.column() == 5: # check for checkbox column item_idx = item.index() date = self.dish_data_table_model.data(item_idx.siblingAtColumn(1)) dish_name = self.dish_data_table_model.data( item_idx.siblingAtColumn(2)) dish_price = self.dish_data_table_model.data( item_idx.siblingAtColumn(3)) sell_num = self.dish_data_table_model.data( item_idx.siblingAtColumn(4)) set_name = dish_name + "(" + dish_price + ")" key = str( QDateTime(QDate.fromString(date, "yyyy-MM-dd")).toSecsSinceEpoch()) if key not in self.graph_series: self.graph_series[key] = {} if int(item.text()) == 0: if set_name in self.graph_series[key]: del self.graph_series[key][set_name] if not self.graph_series[key]: del self.graph_series[key] else: self.graph_series[key][set_name] = int(sell_num) def update_graph(self, index): if index == 2: self.graph_chart.removeAllSeries() axis_x = QBarCategoryAxis() axis_x.setTitleText("日期") if self.graph_chart.axisX(): self.graph_chart.removeAxis(self.graph_chart.axisX()) self.graph_chart.addAxis(axis_x, Qt.AlignBottom) axis_y = QValueAxis() axis_y.setLabelFormat("%i") axis_y.setTitleText("售出量") if self.graph_chart.axisY(): self.graph_chart.removeAxis(self.graph_chart.axisY()) self.graph_chart.addAxis(axis_y, Qt.AlignLeft) max_num = 0 total_date = 0 set_dict = {} for key, data in sorted(self.graph_series.items(), key=lambda i: int(i[0])): axis_x.append( QDateTime.fromSecsSinceEpoch( int(key)).toString("yyyy年MM月dd日")) for set_name, value in data.items(): if set_name not in set_dict: set_dict[set_name] = QBarSet(set_name) for _ in range(total_date): set_dict[set_name].append(0) set_dict[set_name].append(value) max_num = max(max_num, value) total_date += 1 for _, bar_set in set_dict.items(): if bar_set.count() < total_date: bar_set.append(0) bar_series = QBarSeries() for _, bar_set in set_dict.items(): bar_series.append(bar_set) bar_series.hovered.connect(self.graph_tooltip) axis_y.setMax(max_num + 1) axis_y.setMin(0) self.graph_chart.addSeries(bar_series) bar_series.attachAxis(axis_x) bar_series.attachAxis(axis_y) def graph_tooltip(self, status, index, bar_set: QBarSet): if status: QToolTip.showText( QCursor.pos(), "{}\n日期: {}\n售出: {}".format(bar_set.label(), self.graph_chart.axisX().at(index), int(bar_set.at(index))))
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setWindowTitle("Demo12_4, 对数坐标轴和多坐标轴") self.__buildStatusBar() self.ui.frameSetup.setEnabled(False) #禁用控制面板 ## 创建QmyChartView对象,并添加到窗口上 self.ui.chartView.setRenderHint(QPainter.Antialiasing) self.ui.chartView.setCursor(Qt.CrossCursor) #设置鼠标指针为十字星 self.__iniChart() # 创建self.chart ## ==============自定义功能函数======================== def __buildStatusBar(self): ##构建状态栏 self.__labMagXY = QLabel("幅频曲线,") self.__labMagXY.setMinimumWidth(250) self.ui.statusBar.addWidget(self.__labMagXY) self.__labPhaseXY = QLabel("相频曲线,") self.__labPhaseXY.setMinimumWidth(250) self.ui.statusBar.addWidget(self.__labPhaseXY) def __iniChart(self): ##图表初始化 self.chart = QChart() #创建 chart self.chart.setTitle("二阶系统频率特性") self.chart.legend().setVisible(True) self.ui.chartView.setChart(self.chart) #chart添加到chartView ##2. 创建坐标轴 ## bottom 轴是 QLogValueAxis self.__axisFreq = QLogValueAxis() self.__axisFreq.setLabelFormat("%.1f") #标签格式 self.__axisFreq.setTitleText("角频率(rad/sec)") self.__axisFreq.setRange(0.1, 100) self.__axisFreq.setMinorTickCount(9) self.chart.addAxis(self.__axisFreq, Qt.AlignBottom) ## left 轴是 QValueAxis self.__axisMag = QValueAxis() self.__axisMag.setTitleText("幅度(dB)") self.__axisMag.setRange(-40, 10) self.__axisMag.setTickCount(6) self.__axisMag.setLabelFormat("%.1f") #标签格式 self.chart.addAxis(self.__axisMag, Qt.AlignLeft) ## right 轴是 QValueAxis self.__axisPhase = QValueAxis() self.__axisPhase.setTitleText("相位(度)") self.__axisPhase.setRange(-200, 0) self.__axisPhase.setTickCount(6) self.__axisPhase.setLabelFormat("%.0f") #标签格式 self.chart.addAxis(self.__axisPhase, Qt.AlignRight) def __loadData(self, allLines): ##从字符串列表读取数据 rowCnt = len(allLines) #文本行数 self.__vectW = [0] * rowCnt self.__vectMag = [0] * rowCnt self.__VectPhase = [0] * rowCnt for i in range(rowCnt): lineText = allLines[i].strip() #一行的文字,必须去掉末尾的\n strList = lineText.split() #分割为字符串列表 self.__vectW[i] = float(strList[0]) #频率 self.__vectMag[i] = float(strList[1]) #幅度 self.__VectPhase[i] = float(strList[2]) #相位 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) ## ==============event处理函数========================== ## ==========由connectSlotsByName()自动连接的槽函数============ @pyqtSlot() ##打开数据 def on_actOpen_triggered(self): curPath = QDir.currentPath() #获取当前路径 filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "频率响应数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return aFile = open(filename, 'r') allLines = aFile.readlines() #读取所有行,list类型,每行末尾带有 \n aFile.close() fileInfo = QFileInfo(filename) QDir.setCurrent(fileInfo.absolutePath()) self.__loadData(allLines) #解析数据 self.__drawBode() #绘制幅频曲线和相频曲线 self.ui.frameSetup.setEnabled(True) @pyqtSlot() ##放大 def on_actZoomIn_triggered(self): self.ui.chartView.chart().zoom(1.2) @pyqtSlot() ##缩小 def on_actZoomOut_triggered(self): self.ui.chartView.chart().zoom(0.8) @pyqtSlot() ##原始大小 def on_actZoomReset_triggered(self): self.ui.chartView.chart().zoomReset() ##图表外观控制 @pyqtSlot(int) ##主题 def on_comboTheme_currentIndexChanged(self, index): self.ui.chartView.chart().setTheme(QChart.ChartTheme(index)) @pyqtSlot(bool) ##显示图例 def on_chkBox_Legend_clicked(self, checked): self.ui.chartView.chart().legend().setVisible(checked) ## 幅频曲线设置 @pyqtSlot() ##设置坐标范围 def on_btnMag_SetRange_clicked(self): self.__axisMag.setRange(self.ui.spinMag_Min.value(), self.ui.spinMag_Max.value()) @pyqtSlot(int) ##分度数 def on_spinMag_Ticks_valueChanged(self, arg1): self.__axisMag.setTickCount(arg1) @pyqtSlot(bool) ##显示数据点 def on_chkBoxMag_Point_clicked(self, checked): seriesMag = self.chart.series()[0] seriesMag.setPointsVisible(checked) ## 相频曲线设置 @pyqtSlot() ##设置坐标范围 def on_btnPh_SetRange_clicked(self): self.__axisPhase.setRange(self.ui.spinPh_Min.value(), self.ui.spinPh_Max.value()) @pyqtSlot(int) ##分度数 def on_spinPh_Ticks_valueChanged(self, arg1): self.__axisPhase.setTickCount(arg1) @pyqtSlot(bool) ##显示数据点 def on_chkBoxPh_Point_clicked(self, checked): seriesPhase = self.chart.series()[1] seriesPhase.setPointsVisible(checked) ## 频率坐标轴 @pyqtSlot() ##设置坐标范围 def on_btnX_SetRange_clicked(self): self.__axisFreq.setRange(self.ui.spinX_Min.value(), self.ui.spinX_Max.value()) @pyqtSlot(int) ##次分度数 def on_spinX_MinorTicks_valueChanged(self, arg1): self.__axisFreq.setMinorTickCount(arg1) ## =============自定义槽函数=============================== def do_LegendMarkerClicked(self): marker = self.sender() #QLegendMarker if (marker.type() != QLegendMarker.LegendMarkerTypeXY): return marker.series().setVisible(not marker.series().isVisible()) marker.setVisible(True) alpha = 1.0 if not marker.series().isVisible(): alpha = 0.5 brush = marker.labelBrush() #QBrush color = brush.color() #QColor color.setAlphaF(alpha) brush.setColor(color) marker.setLabelBrush(brush) brush = marker.brush() color = brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setBrush(brush) pen = marker.pen() #QPen color = pen.color() color.setAlphaF(alpha) pen.setColor(color) marker.setPen(pen) def do_seriesMag_hovered(self, point, state): if state: hint = "幅频曲线:频率=%.1f, 幅度=%.1f dB" % (point.x(), point.y()) self.__labMagXY.setText(hint) ## else: ## self.__labMagXY.setText("幅频曲线") def do_seriesPhase_hovered(self, point, state): if state: hint = "相频曲线:频率=%.1f, 相位=%.1f 度" % (point.x(), point.y()) self.__labPhaseXY.setText(hint)
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setWindowTitle("Demo12_6, 蜡烛图、日期时间坐标轴") self.__buildStatusBar() self.ui.chartView.setRenderHint(QPainter.Antialiasing) self.ui.chartView.setCursor(Qt.CrossCursor) #设置鼠标指针为十字星 ## 初始化Model/View结构 self.itemModel = QStandardItemModel(self) self.ui.tableView.setModel(self.itemModel) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.horizontalHeader().setDefaultSectionSize(80) self.ui.tableView.verticalHeader().setDefaultSectionSize(24) self.__iniChart() # 初始化图表 self.ui.chartView.mouseMove.connect(self.do_chartView_mouseMove) ## ==============自定义功能函数======================== def __buildStatusBar(self): self.__labChartXY = QLabel("Chart Y= ") ##状态栏显示鼠标点的坐标 self.__labChartXY.setMinimumWidth(200) self.ui.statusBar.addWidget(self.__labChartXY) self.__labHoverXY = QLabel("Hovered candle") self.__labHoverXY.setMinimumWidth(200) self.ui.statusBar.addWidget(self.__labHoverXY) self.__labClickXY = QLabel("Clicked candle") ## self.__labClickXY.setMinimumWidth(200) self.ui.statusBar.addPermanentWidget(self.__labClickXY) def __iniChart(self): self.chart = QChart() #创建 Chart self.chart.setTitle("股票日线图") self.chart.setTheme( QChart.ChartThemeBlueCerulean ) #ChartThemeBlueCerulean, ChartThemeQt,ChartThemeBlueNcs,ChartThemeDark self.ui.chartView.setChart(self.chart) #Chart添加到ChartView ## X 轴是QDateTimeAxis self.__axisX = QDateTimeAxis() dateFormat = self.ui.comboDateFormat.currentText() #如"MM-dd" self.__axisX.setFormat(dateFormat) #标签格式 self.__axisX.setTickCount(10) #主分隔个数 self.__axisX.setTitleText("日期") #标题 dateMin = QDateTime.fromString("2018-01-01", "yyyy-MM-dd") self.__axisX.setMin(dateMin) dateMax = dateMin.addDays(150) self.__axisX.setMax(dateMax) self.chart.addAxis(self.__axisX, Qt.AlignBottom) ## Y 轴是 QValueAxis self.__axisY = QValueAxis() self.__axisY.setTitleText("Value") self.__axisY.setRange(0, 20) self.__axisY.setTickCount(5) self.__axisY.setLabelFormat("%.2f") #标签格式 self.chart.addAxis(self.__axisY, Qt.AlignLeft) def __loadData(self, allLines): ##从字符串列表读取数据构建数据模型 rowCount = len(allLines) #文本行数,第1行是标题 self.itemModel.setRowCount(rowCount - 1) #实际数据行数 ## 设置表头 header = allLines[0].strip() #第1行是表头 headerList = header.split() self.itemModel.setHorizontalHeaderLabels(headerList) #设置表头文字 colCount = len(headerList) #列数 self.itemModel.setColumnCount(colCount) #数据列数 ## 设置模型数据 for i in range(rowCount - 1): lineText = allLines[i + 1].strip() #获取 数据区 的一行 tmpList = lineText.split() for j in range(colCount): item = QStandardItem(tmpList[j]) #创建item item.setTextAlignment(Qt.AlignHCenter) self.itemModel.setItem(i, j, item) #为模型的某个行列位置设置Item 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) ## ==============event处理函数========================== ## ==========由connectSlotsByName()自动连接的槽函数============ @pyqtSlot() ##“打开文件”按钮 def on_actOpen_triggered(self): curPath = QDir.currentPath() filename, flt = QFileDialog.getOpenFileName( self, "打开一个文件", curPath, "股票数据文件(*.txt);;所有文件(*.*)") if (filename == ""): return aFile = open(filename, 'r') allLines = aFile.readlines() #读取所有行,list类型,每行末尾带有 \n aFile.close() fileInfo = QFileInfo(filename) QDir.setCurrent(fileInfo.absolutePath()) self.ui.tabWidget.setTabText(0, fileInfo.baseName()) self.__loadData(allLines) # 载入数据到数据模型 self.__drawChart() # 绘制图表 self.ui.tab_Setup.setEnabled(True) @pyqtSlot() def on_actZoomIn_triggered(self): self.ui.chartView.chart().zoom(1.2) @pyqtSlot() def on_actZoomOut_triggered(self): self.ui.chartView.chart().zoom(0.8) @pyqtSlot() def on_actZoomReset_triggered(self): self.ui.chartView.chart().zoomReset() ##图表外观控制 @pyqtSlot(int) ##主题 def on_comboTheme_currentIndexChanged(self, index): self.ui.chartView.chart().setTheme(QChart.ChartTheme(index)) @pyqtSlot(bool) ##显示图例 def on_chkBox_Legend_clicked(self, checked): self.ui.chartView.chart().legend().setVisible(checked) ## 蜡烛图 @pyqtSlot(bool) ##capsVisible def on_chkBox_Caps_clicked(self, checked): seriesCandle = self.chart.series()[0] seriesCandle.setCapsVisible(checked) @pyqtSlot(bool) ##bodyOutlineVisible def on_chkBox_Outline_clicked(self, checked): seriesCandle = self.chart.series()[0] seriesCandle.setBodyOutlineVisible(checked) ## Y轴--QValueAxis @pyqtSlot() ##设置坐标范围 def on_btnY_SetRange_clicked(self): self.__axisY.setRange(self.ui.spinY_Min.value(), self.ui.spinY_Max.value()) @pyqtSlot(int) ##分度数 def on_spinY_Ticks_valueChanged(self, arg1): self.__axisY.setTickCount(arg1) ## X轴--QDateTimeAxis @pyqtSlot(str) ##标签格式 def on_comboDateFormat_currentIndexChanged(self, arg1): self.__axisX.setFormat(arg1) @pyqtSlot(int) ##分度数 def on_btnX_Ticks_valueChanged(self, arg1): self.__axisX.setTickCount(arg1) ## =============自定义槽函数=============================== def do_LegendMarkerClicked(self): marker = self.sender() #QLegendMarker marker.series().setVisible(not marker.series().isVisible()) marker.setVisible(True) alpha = 1.0 if not marker.series().isVisible(): alpha = 0.5 brush = marker.labelBrush() #QBrush color = brush.color() #QColor color.setAlphaF(alpha) brush.setColor(color) marker.setLabelBrush(brush) brush = marker.brush() color = brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setBrush(brush) pen = marker.pen() #QPen color = pen.color() color.setAlphaF(alpha) pen.setColor(color) marker.setPen(pen) if marker.type() == QLegendMarker.LegendMarkerTypeCandlestick: QMessageBox.information(self, "提示", "蜡烛图序列无法隐藏") def do_chartView_mouseMove(self, point): pt = self.chart.mapToValue(point) #QPointF 转换为图表的数值 self.__labChartXY.setText("Chart Y=%.2f" % (pt.y())) #状态栏显示 def do_candleClicked(self, dataSet): valOpen = dataSet.open() valClose = dataSet.close() valHigh = dataSet.high() valLow = dataSet.low() price = "开盘%.2f, 收盘%.2f, 最高%.2f, 最低%.2f" % (valOpen, valClose, valHigh, valLow) timeStamp = dataSet.timestamp() #时间戳数据 dt = QDateTime.fromMSecsSinceEpoch(timeStamp) dateStr = dt.toString("yyyy-MM-dd, ") self.__labClickXY.setText(dateStr + price) def do_candleHovered(self, status, dataSet): if status == False: self.__labHoverXY.setText("Hovered candle") return valOpen = dataSet.open() valClose = dataSet.close() valHigh = dataSet.high() valLow = dataSet.low() price = "开盘%.2f, 收盘%.2f, 最高%.2f, 最低%.2f" % (valOpen, valClose, valHigh, valLow) timeStamp = dataSet.timestamp() #时间戳数据 dt = QDateTime.fromMSecsSinceEpoch(timeStamp) dateStr = dt.toString("yyyy-MM-dd, ") self.__labHoverXY.setText(dateStr + price)
class Gui: def __init__(self): # loading widgets elements from ui file self.window = uic.loadUi("min_function.ui") # Getting widgets elements self.single_run_rb = self.window.findChild(QRadioButton, 'singleRunRadioButton') self.multi_run_rb = self.window.findChild(QRadioButton, 'multiRunRadioButton') self.repetitions_sb = self.window.findChild(QSpinBox, 'repetitionsSpinBox') self.population_sb = self.window.findChild(QSpinBox, 'populationSpinBox') self.crossover_dsb = self.window.findChild(QDoubleSpinBox, 'crossoverDoubleSpinBox') self.mutation_dsb = self.window.findChild(QDoubleSpinBox, 'mutationDoubleSpinBox') self.generation_sb = self.window.findChild(QSpinBox, 'generationSpinBox') self.elitism_cb = self.window.findChild(QCheckBox, 'elitismCheckBox') self.run_pb = self.window.findChild(QPushButton, 'runPushButton') self.x_result_l = self.window.findChild(QLabel, 'xResultLabel') self.fx_l = self.window.findChild(QLabel, 'fxLabel') self.correct_results_l = self.window.findChild(QLabel, 'correctResultsLabel') self.incorrect_results_l = self.window.findChild( QLabel, 'incorrectResultsLabel') self.results_single_run_gb = self.window.findChild( QGroupBox, 'resultsSingleRunGroupBox') self.results_multi_run_gb = self.window.findChild( QGroupBox, 'resultsMultiRunGroupBox') self.icon_result_l = self.window.findChild(QLabel, 'iconResultLabel') self.graph_vbl = self.window.findChild(QVBoxLayout, 'graphVerticalLayout') # Connecting self.run_pb.clicked.connect(self.on_run_pb_clicked) self.multi_run_rb.toggled.connect(self.on_multi_run_rb_toggled) # Graph settings self.chart = QChart() self.chart.setTitle('Chart') self.chart_view = QChartView(self.chart) self.chart_view.setRenderHint(QPainter.Antialiasing) self.graph_vbl.addWidget(self.chart_view) self.repetitions_sb.setEnabled(False) self.results_multi_run_gb.setEnabled(False) # EVEN values ONLY self.population_sb.lineEdit().setEnabled(False) def on_multi_run_rb_toggled(self): if self.multi_run_rb.isChecked(): self.repetitions_sb.setEnabled(True) self.repetitions_sb.setValue(100) self.results_single_run_gb.setEnabled(False) self.results_multi_run_gb.setEnabled(True) self.chart_view.setEnabled(False) else: self.repetitions_sb.setEnabled(False) self.repetitions_sb.setValue(1) self.results_single_run_gb.setEnabled(True) self.results_multi_run_gb.setEnabled(False) self.chart_view.setEnabled(True) def on_run_pb_clicked(self): self.chart.removeAllSeries() min_function = 421.0 ga_answer = 0.0 correct = 0 incorrect = 0 ga = Ga(self.population_sb.value(), self.crossover_dsb.value(), self.mutation_dsb.value(), self.generation_sb.value(), self.elitism_cb.isChecked()) progress_dialog = QProgressDialog('Repetitions...', 'Cancel', 0, self.repetitions_sb.value(), self.window) progress_dialog.setWindowModality(Qt.WindowModal) ga_output = () for i in range(self.repetitions_sb.value()): ga_output = ga.run_generation() ga_answer = ga_output[0] if ga_answer == min_function: correct += 1 else: incorrect += 1 progress_dialog.setValue(i) if progress_dialog.wasCanceled(): break progress_dialog.setValue(self.repetitions_sb.value()) if self.single_run_rb.isChecked(): self.x_result_l.setText(str(ga_answer)) self.fx_l.setText('{0:.2f}'.format(ga.calc_function(ga_answer))) if ga_answer == min_function: self.icon_result_l.setPixmap('correct-icon.png') else: self.icon_result_l.setPixmap('incorrect-icon.png') # Graph series_1 = QLineSeries() series_1.setName('Average Fit') series_2 = QLineSeries() series_2.setName('Best Fit') for i in range(len(ga_output[1])): series_1.append(ga_output[1][i], ga_output[2][i]) series_2.append(ga_output[1][i], ga_output[3][i]) self.chart.addSeries(series_1) self.chart.addSeries(series_2) self.chart.createDefaultAxes() else: self.correct_results_l.setText(str(correct)) self.incorrect_results_l.setText(str(incorrect))
class DiagramForm(QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.db = None self.tool_bar = QToolBar(self) self.action_inout = self.tool_bar.addAction("Доход/расход") self.date_edit = CustomCalendar() self.date_edit.button_up.clicked.connect(self.date_changed) self.date_edit.button_down.clicked.connect(self.date_changed) self.tool_bar.addWidget(self.date_edit) self.action_inout.setIcon(QIcon("icons/consumption.ico")) self.action_inout.triggered.connect(self.change_state_action_inout) self.type_inout = False # #for item in db.get_sum_by_category(): # series.append(item[1], item[0]) # series.append("Еда", 80) # series.append("Хозяйственные товары", 40) # series.append("Развлечения", 40) # series.append("Еда", 80) # series.append("Хозяйственные товары", 40) # series.append("Развлечения", 40) self.chart = QChart() self.chart.setTheme(QChart.ChartThemeQt) self.chart.setAnimationOptions(QChart.AllAnimations) #self.chart.addSeries(series) self.chart.legend().setAlignment(Qt.AlignRight) font = QFont("Segoi UI", 11) self.chart.legend().setFont(font) self.chart.legend().setShowToolTips(True) self.chart.setTitleFont(QFont("Segoi UI", 16)) chart_view = QChartView(self.chart) chart_view.setRenderHint(QPainter.Antialiasing) vbox = QVBoxLayout(self) vbox.addWidget(self.tool_bar) vbox.addWidget(chart_view) #update_diagram() def set_db(self, db): self.db = db def update_diagram(self): year = self.date_edit.get_year() month = self.date_edit.get_month() date_format = f"WHERE strftime(\"%Y\",DATE) = \"{year}\" AND strftime(\"%m\",DATE) = \"{month:02}\"" series = QPieSeries() for item in self.db.get_sum_by_category(date_format, self.type_inout): series.append(item[1], item[0]) for slice in series.slices(): slice.setLabel( slice.label() + ", " + f"{slice.value()}₽" + f" ({round(slice.value() / (series.sum() / 100))}%)") series.clicked.connect(self.pressed) self.chart.removeAllSeries() self.chart.addSeries(series) self.chart.setTitle("Доходы" if self.type_inout else "Расходы") def date_changed(self): self.update_diagram() def change_state_action_inout(self): self.action_inout.setIcon( QIcon("icons/income.ico" if not self.type_inout else "icons/consumption.ico")) self.type_inout = not self.type_inout self.update_diagram() def pressed(self, slice): for sl in slice.series().slices(): sl.setExploded(False) sl.setLabelVisible(False) sl.setPen(QPen(Qt.white, 0)) slice.setExploded(True) slice.setLabelVisible(True) slice.setPen(QPen(Qt.black, 2))
class MainW(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): QtWidgets.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) self.showMaximized() self.imagen.setText("aaaaaaa") myimg = QtGui.QPixmap(plotImg) self.imagen.setPixmap(myimg) self.Juego1.clicked.connect(self.runjuego1) self.Juego2.clicked.connect(self.runjuego2) self.Juego3.clicked.connect(self.runjuego3) self.Juego4.clicked.connect(self.runjuego4) self.Juego5.clicked.connect(self.runjuego5) self.Juego6.clicked.connect(self.runjuego6) self.Juego7.clicked.connect(self.runjuego7) self.Juego8.clicked.connect(self.runjuego8) self.setupgraph() self.updatechart() self._actualizar.clicked.connect(self.updatechart) self._recargar.clicked.connect(self.recargar) def runjuego1(self): self.window = Ruleta.UIWindow() self.window.show() def runjuego2(self): self.window = Altos_o_Bajos_Codificacionado.MainWindow() self.window.show() def runjuego3(self): self.window = LootBoxGame.MyApp() self.window.show() def runjuego4(self): self.window = SuperTragaPerras.UIWindow() self.window.show() def runjuego5(self): self.window = CapsUI.UIWindow() self.window.show() def runjuego6(self): self.window = casino.MyApp() self.window.show() def runjuego7(self): self.window = keno.UIWindow() self.window.show() def runjuego8(self): self.window = Jackpot.UIWindow() self.window.show() def recargar(self): self.window = menu.MyApp() self.window.show() def setupgraph(self): self.chart = QChart() self.chart.createDefaultAxes() self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("Saldo vs Tiempo") self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignBottom) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) self._graphlayout.addWidget(self.chartview) def updatechart(self): self.series = QLineSeries(self) self.datos = bd.getData() self.c = 0 for x in self.datos: self.series.append(self.c, x) self.c += 1 self.chart.removeAllSeries() self.chart.addSeries(self.series) self.chart.createDefaultAxes() def create_linechart(self): self.series = QLineSeries(self) self.datos = bd.getData() self.c = 0 for x in self.datos: self.series.append(self.c, x) self.c += 1 self.chart = QChart() self.chart.addSeries(self.series) self.chart.createDefaultAxes() self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("Saldo vs Tiempo") self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignBottom) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) self._graphlayout.addWidget(self.chartview)
class UDPBitrate(QWidget): def __init__(self): super().__init__() self.mainLayout = QVBoxLayout() self.headerLayout = QGridLayout() self.portLayout = QHBoxLayout() self.axisxLayout = QHBoxLayout() self.axisyLayout = QHBoxLayout() self.smoothLayout = QHBoxLayout() self.btnsLayout = QHBoxLayout() self.lblPort = QLabel("Port: ") self.lblAxisX = QLabel("X-Axis(Time): ") self.lblAxisY = QLabel("Y-Axis(Bitrate): ") self.lblSmooth = QLabel("Smooth: ") self.txtPort = QLineEdit() self.txtAxisX = QLineEdit() self.txtAxisY = QLineEdit() self.txtSmooth = QLineEdit() self.chkMode = QCheckBox("Stack Mode") self.btnStart = QPushButton("Start") self.btnExport = QPushButton("Export") self.btnStart.clicked.connect(self.onStartClick) self.btnExport.clicked.connect(self.onExportClick) self.portLayout.addWidget(self.lblPort) self.portLayout.addWidget(self.txtPort) self.axisxLayout.addWidget(self.lblAxisX) self.axisxLayout.addWidget(self.txtAxisX) self.axisyLayout.addWidget(self.lblAxisY) self.axisyLayout.addWidget(self.txtAxisY) self.smoothLayout.addWidget(self.lblSmooth) self.smoothLayout.addWidget(self.txtSmooth) self.btnsLayout.addWidget(self.chkMode) self.btnsLayout.addWidget(self.btnStart) self.btnsLayout.addWidget(self.btnExport) self.headerLayout.addLayout(self.portLayout, 0, 0, 1, 3) self.headerLayout.addLayout(self.axisxLayout, 0, 3, 1, 2) self.headerLayout.addLayout(self.axisyLayout, 0, 5, 1, 2) self.headerLayout.addLayout(self.smoothLayout, 0, 7, 1, 2) self.headerLayout.addLayout(self.btnsLayout, 0, 9, 1, 2) self.chart = QChart() self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.HighQualityAntialiasing) self.chart.legend().setAlignment(Qt.AlignBottom) self.chart.setTitle("UDP Bitrate") self.mainLayout.addLayout(self.headerLayout) self.mainLayout.addWidget(self.chartview) self.timer = QTimer() self.timer.timeout.connect(self.onTimeOut) self.axis_x_unit_str = ["Sec", "Min", "Hour", "Day"] self.axis_y_unit_str = ["bps", "Kbps", "Mbps", "Gbps"] self.axis_x_unit_scale = [1, 60, 3600, 3600 * 24] self.axis_y_unit_scale = [1, 1e3, 1e6, 1e9] self.axis_x_default_resolution = 1000 self.ports = [] self.udpthreads = [] self.smooth_alpha = 0.0 if os.path.exists("udpbitrate.conf"): with open("udpbitrate.conf", "r") as fp: try: json_data = json.load(fp) self.txtPort.setText(json_data.get("port", "")) self.txtAxisX.setText(json_data.get("x-axis", "1000s")) self.txtAxisY.setText(json_data.get("y-axis", "10m")) self.txtSmooth.setText(json_data.get("smooth", "0")) self.chkMode.setChecked(json_data.get("mode", False)) finally: pass self.setWindowTitle("UDP Bitrate") self.setLayout(self.mainLayout) self.resize(960, 600) self.show() def onStartClick(self): if self.btnStart.text() == "Start": self.btnStart.setText("Stop") self.chkMode.setEnabled(False) self.txtPort.setEnabled(False) self.txtAxisX.setEnabled(False) self.txtAxisY.setEnabled(False) self.txtSmooth.setEnabled(False) self.parse_port() self.parse_axis_x() self.parse_axis_y() self.parse_smooth() self.start_record() json_data = { "port": self.txtPort.text(), "x-axis": self.txtAxisX.text(), "y-axis": self.txtAxisY.text(), "smooth": self.txtSmooth.text(), "mode": self.chkMode.isChecked() } with open("udpbitrate.conf", "w") as fp: json.dump(json_data, fp) else: self.btnStart.setText("Start") self.chkMode.setEnabled(True) self.txtPort.setEnabled(True) self.txtAxisX.setEnabled(True) self.txtAxisY.setEnabled(True) self.txtSmooth.setEnabled(True) self.stop_record() def onExportClick(self): image = QApplication.primaryScreen().grabWindow( self.chartview.winId()).toImage() filename, filetype = QFileDialog.getSaveFileName( self, "Export Image", "./udpbitrate.png", "PNG Files (*.png);;JEPG Files (*.jpg);;All Files (*)") if filename: ext = ".jpg" if ".jpg" in filetype else ".png" filename = filename + ext if ext not in filename else filename image.save(filename) def onTimeOut(self): if self.chkMode.isChecked(): bitrate = 0 for i in range(len(self.udpthreads)): length = float(self.udpthreads[i].get_recv_length()) bitrate += length * 8.0 / self.axis_x_step / self.axis_y_unit_scale[ self.axis_y_unit] self.add_point(bitrate, self.chart.series()[i]) else: total_bitrate = 0 for i in range(len(self.udpthreads)): length = float(self.udpthreads[i].get_recv_length()) bitrate = length * 8.0 / self.axis_x_step / self.axis_y_unit_scale[ self.axis_y_unit] total_bitrate += bitrate self.add_point(bitrate, self.chart.series()[i]) self.add_point(total_bitrate, self.chart.series()[-1]) def add_point(self, val, series): points = series.pointsVector() if len(points) == 0: points.append( QPointF( len(points) * self.axis_x_step / self.axis_x_unit_scale[self.axis_x_unit], val)) elif len(points) <= self.axis_x_resolution: val = self.smooth_alpha * points[-1].y() + ( 1 - self.smooth_alpha) * val points.append( QPointF( len(points) * self.axis_x_step / self.axis_x_unit_scale[self.axis_x_unit], val)) else: val = self.smooth_alpha * points[-1].y() + ( 1 - self.smooth_alpha) * val for i in range(len(points) - 1): points[i] = QPointF( i * self.axis_x_step / self.axis_x_unit_scale[self.axis_x_unit], points[i + 1].y()) points[-1] = QPointF( len(points) * self.axis_x_step / self.axis_x_unit_scale[self.axis_x_unit], val) series.replace(points) def parse_port(self): self.ports = [] s = self.txtPort.text() sl = map(str.strip, s.split(',')) p = re.compile('^(\d+)\s?-\s?(\d+)$|^(\d+)$') for ss in sl: m = p.match(ss) if m: if m.group(3): cur = int(m.group(3)) if len(self.ports) > 16: break if cur > 0: self.ports.append(cur) else: start, end = int(m.group(1)), int(m.group(2)) for cur in range(start, end + 1): if len(self.ports) > 16: break if cur > 0: self.ports.append(cur) def parse_axis_x(self): self.axis_x_val = 0 self.axis_x_unit = 0 s = self.txtAxisX.text().lower() p = re.compile( '^(\d+(?:\.\d+)?)\s?(s(?:ec)?|m(?:in)?|h(?:our)?|d(?:ay)?)?$') m = p.match(s) if m: self.axis_x_val = float(m.group(1)) if m.group(2): if m.group(2) == "s" or m.group(2) == "sec": self.axis_x_unit = 0 elif m.group(2) == "m" or m.group(2) == "min": self.axis_x_unit = 1 elif m.group(2) == "h" or m.group(2) == "hour": self.axis_x_unit = 2 elif m.group(2) == "d" or m.group(2) == "day": self.axis_x_unit = 3 self.axis_x_step = self.axis_x_val * self.axis_x_unit_scale[ self.axis_x_unit] / self.axis_x_default_resolution if self.axis_x_step < 0.1: self.axis_x_resolution = int( 10 * self.axis_x_val * self.axis_x_unit_scale[self.axis_x_unit]) self.axis_x_step = self.axis_x_val * self.axis_x_unit_scale[ self.axis_x_unit] / self.axis_x_resolution else: self.axis_x_resolution = self.axis_x_default_resolution def parse_axis_y(self): self.axis_y_val = 0 self.axis_y_unit = 0 s = self.txtAxisY.text().lower() p = re.compile('^(\d+(?:\.\d+)?)\s?(k|m|g)?$') m = p.match(s) if m: self.axis_y_val = float(m.group(1)) if m.group(2): if m.group(2) == "k": self.axis_y_unit = 1 elif m.group(2) == "m": self.axis_y_unit = 2 elif m.group(2) == "g": self.axis_y_unit = 3 def parse_smooth(self): self.smooth_alpha = 0.0 s = self.txtSmooth.text() p = re.compile('^(\d+(?:\.\d+)?)\s?$') m = p.match(s) if m: self.smooth_alpha = float(m.group(1)) self.smooth_alpha = self.smooth_alpha if self.smooth_alpha < 0.9999 else 0.9999 def start_record(self): self.chart.removeAllSeries() self.series = [] try: for port in self.ports: udp = UdpServer(port) udp.start() self.udpthreads.append(udp) series = QLineSeries() series.setName(str(port)) self.chart.addSeries(series) finally: pass if not self.chkMode.isChecked(): series = QLineSeries() series.setName("Total") self.chart.addSeries(series) self.chart.createDefaultAxes() axis_x = self.chart.axisX() axis_x.setRange(0, self.axis_x_val) axis_x.setLabelFormat("%g") axis_x.setTitleText("Time / " + self.axis_x_unit_str[self.axis_x_unit]) axis_y = self.chart.axisY() axis_y.setRange(0, self.axis_y_val) axis_y.setLabelFormat("%g") axis_y.setTitleText("Bitrate / " + self.axis_y_unit_str[self.axis_y_unit]) self.timer.start(self.axis_x_step * 1000) def stop_record(self): if self.timer.isActive(): self.timer.stop() for udp in self.udpthreads: udp.stop() self.udpthreads = []
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui=Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setWindowTitle("Demo12_7, QAreaSeries绘制填充图") self.__buildStatusBar() self.ui.chartView.setRenderHint(QPainter.Antialiasing) self.ui.chartView.setCursor(Qt.CrossCursor) #设置鼠标指针为十字星 self.ui.chartView.mouseMove.connect(self.do_chartView_mouseMove) self.__colorLine=Qt.darkBlue #曲线颜色,darkBlue self.__colorFill=Qt.darkBlue #填充颜色 gray self.__iniChart() #创建self.chart ## "填充类型"4个RadioButton关联槽函数 self.ui.radioFill_Pos.clicked.connect(self.do_redrawFill) #positive self.ui.radioFill_Neg.clicked.connect(self.do_redrawFill) #negative self.ui.radioFill_Both.clicked.connect(self.do_redrawFill) #both self.ui.radioFill_None.clicked.connect(self.do_redrawWave) #wiggle ## ==============自定义功能函数======================== def __buildStatusBar(self): self.__labFileName = QLabel("数据文件") self.__labFileName.setMinimumWidth(200) self.ui.statusBar.addWidget(self.__labFileName) self.__labChartXY = QLabel("Chart, X=, Y=") self.__labChartXY.setMinimumWidth(200) self.ui.statusBar.addWidget(self.__labChartXY) self.__labAreaXY = QLabel("AreaSeries,X=, Y=") self.__labAreaXY.setMinimumWidth(200) self.ui.statusBar.addWidget(self.__labAreaXY) def __iniChart(self): self.chart = QChart() #创建 chart self.chart.setTitle("地震波形") self.chart.legend().setVisible(False) #不显示图例 self.ui.chartView.setChart(self.chart) #chart添加到chartView ## 创建坐标轴X self.__axisX = QValueAxis() # bottom 轴是 QValueAxis self.__axisX.setTitleText("时间(秒)") self.__axisX.setRange(0, 10) self.__axisX.setTickCount(10) self.__axisX.setLabelFormat("%.2f") #标签格式 self.chart.addAxis(self.__axisX,Qt.AlignBottom) ## 创建坐标轴Y self.__axisY = QValueAxis() # left 轴是 QValueAxis self.__axisY.setTitleText("幅度") self.__axisY.setRange(-5,5) self.__axisY.setTickCount(5) self.__axisY.setLabelFormat("%.2f") #标签格式 self.chart.addAxis(self.__axisY,Qt.AlignLeft) ## ==============event处理函数========================== ## ==========由connectSlotsByName()自动连接的槽函数============ ##=====工具栏 按钮功能 @pyqtSlot() ##“打开文件”按钮 def on_actOpen_triggered(self): curPath=QDir.currentPath() #获取当前路径 filename,flt=QFileDialog.getOpenFileName(self,"打开一个文件",curPath, "地震数据文件(*.txt);;所有文件(*.*)") if (filename==""): return aFile=open(filename,'r') allLines=aFile.readlines() #读取所有行,list类型,每行末尾带有 \n aFile.close() fileInfo=QFileInfo(filename) QDir.setCurrent(fileInfo.absolutePath()) self.__labFileName.setText("数据文件:"+fileInfo.fileName()) rowCnt=len(allLines) #行数,即数据点数 self.__vectData=[0]*rowCnt #列表 for i in range(rowCnt): lineText=allLines[i].strip() #字符串表示的数字 self.__vectData[i]=float(lineText) minV=min(self.__vectData) #最小值 self.ui.spinY_Min.setValue(minV) maxV=max(self.__vectData) #最大值 self.ui.spinY_Max.setValue(maxV) if self.ui.radioFill_None.isChecked(): self.do_redrawWave() #绘制波形曲线 else: self.do_redrawFill() #绘制有填充的波形 self.ui.frameSetup.setEnabled(True) @pyqtSlot() def on_actZoomIn_triggered(self): self.ui.chartView.chart().zoom(1.2) @pyqtSlot() def on_actZoomOut_triggered(self): self.ui.chartView.chart().zoom(0.8) @pyqtSlot() def on_actZoomReset_triggered(self): self.ui.chartView.chart().zoomReset() ## Y轴设置 @pyqtSlot() ##设置坐标范围 def on_btnY_SetRange_clicked(self): self.__axisY.setRange(self.ui.spinY_Min.value(), self.ui.spinY_Max.value()) @pyqtSlot(int) ##分度数 def on_spinY_Ticks_valueChanged(self,arg1): self.__axisY.setTickCount(arg1) @pyqtSlot(bool) ##显示网格线 def on_chkBoxY_GridLine_clicked(self,checked): self.__axisY.setGridLineVisible(checked) ## X轴设置 @pyqtSlot() ##设置坐标范围 def on_btnX_SetRange_clicked(self): self.__axisX.setRange(self.ui.spinX_Min.value(), self.ui.spinX_Max.value()) @pyqtSlot(int) ##分度数 def on_spinX_Ticks_valueChanged(self,arg1): self.__axisX.setTickCount(arg1) @pyqtSlot(bool) ##显示网格线 def on_chkBoxX_GridLine_clicked(self,checked): self.__axisX.setGridLineVisible(checked) ## =============自定义槽函数=============================== @pyqtSlot() ##绘制原始波形曲线 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) @pyqtSlot() ##绘制3种填充曲线 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) def do_chartView_mouseMove(self,point): pt=self.ui.chartView.chart().mapToValue(point) #QPointF 转换为图表的数值 self.__labChartXY.setText("Chart X=%.2f,Y=%.2f"%(pt.x(),pt.y())) #状态栏显示 def do_area_clicked(self,point): self.__labAreaXY.setText("AreaSeries X=%.2f,Y=%.2f" %(point.x(),point.y())) #状态栏显示
class Ui(mainwindow.Ui_MainWindow): def __init__(self, MainWindow): super(Ui, self).setupUi(MainWindow) self.MainWindow = MainWindow self.socketPacketReceiver = None self.timmer_is_on = False self.hexParser = StixHexStringParser() self.socketPacketReceiver = StixSocketPacketReceiver() self.socketPacketServer = StixSocketPacketServer() self.dataReader = StixFileReader() slots = { 'info': self.onDataReaderInfo, 'warning': self.onDataReaderWarning, 'error': self.onDataReaderError, 'critical': self.onDataReaderCritical, 'dataLoaded': self.onDataReady, 'packetArrival': self.onPacketArrival, 'progress': self.onProgressUpdated } self.socketPacketReceiver.connectSignalSlots(slots) self.dataReader.connectSignalSlots(slots) self.hexParser.connectSignalSlots(slots) self.socketPacketServer.connectSignalSlots(slots) self.tabWidget.setCurrentIndex(0) self.actionExit.triggered.connect(self.close) self.actionPlot.setEnabled(False) self.actionNext.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_ArrowForward)) self.actionPrevious.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_ArrowBack)) self.actionOpen.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_DialogOpenButton)) self.actionSave.setIcon(self.style().standardIcon( QtWidgets.QStyle.SP_DriveFDIcon)) self.actionSave.triggered.connect(self.save) self.actionOpen.triggered.connect(self.getOpenFilename) self.filterPattern = None self.actionNext.triggered.connect(self.nextPacket) self.actionPrevious.triggered.connect(self.previousPacket) self.actionAbout.triggered.connect(self.about) self.actionPrevious.setEnabled(False) self.actionNext.setEnabled(False) self.actionSave.setEnabled(False) self.actionPlot.setEnabled(False) self.actionCopy.triggered.connect(self.onCopyTriggered) self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected) self.actionCopy.setEnabled(False) self.actionPaste.triggered.connect(self.onPasteTriggered) self.actionLog.triggered.connect(self.dockWidget.show) self.actionSetIDB.triggered.connect(self.onSetIDBClicked) self.plotButton.clicked.connect( partial(self.onPlotButtonClicked, None)) #self.progressBar = QtWidgets.QProgressBar() #self.statusbar.addPermanentWidget(self.progressBar) self.progressDiag = None #self.progressBar.hide() self.actionPacketServer.triggered.connect(self.startPacketServer) self.exportButton.clicked.connect(self.onExportButtonClicked) self.actionPlot.triggered.connect(self.onPlotActionClicked) self.actionLoadMongodb.triggered.connect(self.onLoadMongoDBTriggered) self.actionConnectTSC.triggered.connect(self.onConnectTSCTriggered) self.actionPacketFilter.triggered.connect(self.filter) self.actionPlugins.triggered.connect(self.onPluginTriggered) self.actionOnlineHelp.triggered.connect(self.onOnlineHelpTriggered) self.actionViewBinary.triggered.connect(self.onViewBinaryTriggered) self.actionTimestampConvertor.triggered.connect(self.onTimestampConvertorTriggered) #self.actionPythonConsole.triggered.connect(self.startPythonConsole) self.autoUpdateButton.clicked.connect( self.onPlotAutoUpdateButtonClicked) self.packetTreeWidget.customContextMenuRequested.connect( self.packetTreeContextMenuEvent) #self.statusListWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) #self.statusListWidget.customContextMenuRequested.connect(self.statusListContextMenuEvent) self.mdb = None self.current_row = 0 self.data = [] self.x = [] self.y = [] self.xlabel = 'x' self.ylabel = 'y' self.buttons_enabled = False self.chart = QChart() self.chart.layout().setContentsMargins(0, 0, 0, 0) self.chart.setBackgroundRoundness(0) self.savePlotButton.clicked.connect(self.savePlot) self.chartView = QChartView(self.chart) self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15) self.selected_services = SELECTED_SERVICES self.selected_SPID = [] self.selected_tmtc = 3 # IDB location self.settings = QtCore.QSettings('FHNW', 'stix_parser') self.idb_filename = self.settings.value('idb_filename', [], str) if self.idb_filename: STIX_IDB.reload(self.idb_filename) if not STIX_IDB.is_connected(): self.showMessage('IDB has not been set!') else: idb_filename = STIX_IDB.get_idb_filename() self.showMessage('IDB loaded from : {} '.format(idb_filename), 1) if idb_filename != self.idb_filename: self.settings.setValue('idb_filename', idb_filename) self.idb_filename = idb_filename #def startPythonConsole(self): # console.start({'packets': self.data}) def close(self): self.MainWindow.close() def style(self): return self.MainWindow.style() def startPacketServer(self): host = 'localhost' port = 9096 self.socketPacketServer.connect(host, port) self.socketPacketServer.setData(self.current_row, self.data) self.socketPacketServer.start() abspath = os.path.dirname(os.path.abspath(__file__)) template = ( "import sys\nsys.path.append('{}')\nimport client_packet_request as req\n" "packets=req.request(query_str='len', host='{}',port={}, verbose_level=1)\n" "#a query_string can be \n" "# - a python slice notation, for example, ':' '0:-1', 3:-1\n" "# - 'len', to get the total number of packets,\n" "# - index , to get a packet of the given index" "#set verbose_level to 0, to suppress print output ").format( abspath, host, port) cb = QtWidgets.QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(template, mode=cb.Clipboard) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) msg.setText( "Packet server started and a template to request packet has been copied to your clipboard!" ) retval = msg.exec_() def onPlotAutoUpdateButtonClicked(self): if not self.timmer_is_on: if not self.data: return num_packets = len(self.data) if num_packets > 200: packets = self.data[-200:-1] else: packets = self.data self.timer = QTimer() self.timer.timeout.connect( partial(self.onPlotButtonClicked, packets)) self.timer.start(2000) self.timmer_is_on = True self.autoUpdateButton.setText('Stop Auto Update') else: if self.timer: self.timer.stop() self.timmer_is_on = False self.autoUpdateButton.setText('Start Auto Update') #def statusListContextMenuEvent(self,pos): # menu = QtWidgets.QMenu() # clearLogAction= menu.addAction('Empty log') # clearLogAction.triggered.connect(self.clearLog) #def clearLog(self): # self.statusListWidget.clear() def packetTreeContextMenuEvent(self, pos): menu = QtWidgets.QMenu() filterAction = menu.addAction('Filter') menu.addSeparator() rawDataAction = menu.addAction('Raw binary data') menu.addSeparator() copyPacketAction = menu.addAction('Copy packet') menu.addSeparator() deleteAllAction = menu.addAction('Delete all packets') self.current_row = self.packetTreeWidget.currentIndex().row() rawDataAction.triggered.connect(self.onViewBinaryTriggered) filterAction.triggered.connect(self.filter) copyPacketAction.triggered.connect(self.onCopyTriggered) deleteAllAction.triggered.connect(self.onDeleteAllTriggered) action = menu.exec_(self.packetTreeWidget.viewport().mapToGlobal(pos)) def filter(self): text, okPressed = QtWidgets.QInputDialog.getText( None, "Packet filtering", "Filtering by SPID or description (! to exclude):", QtWidgets.QLineEdit.Normal, "") if okPressed: self.filterPattern = text self.addPacketsToView(self.data, True, show_stat=False) def onDeleteAllTriggered(self): self.data.clear() self.current_row = 0 self.packetTreeWidget.clear() self.paramTreeWidget.clear() #def onPacketTreeItemDoubleClicked(self): # self.onViewBinaryTriggered() def onViewBinaryTriggered(self): diag = QtWidgets.QDialog() diag_ui = raw_viewer.Ui_Dialog() diag_ui.setupUi(diag) if self.data: try: raw = self.data[self.current_row]['bin'] header = self.data[self.current_row]['header'] diag_ui.setPacketInfo('{}({},{}) {}'.format( header['TMTC'], header['service_type'], header['service_subtype'], header['descr'])) diag_ui.displayRaw(raw) except (IndexError, KeyError): diag_ui.setText('Raw data not available.') diag.exec_() def onOnlineHelpTriggered(self): webbrowser.open( 'https://github.com/i4Ds/STIX-python-data-parser', new=2) def onTimestampConvertorTriggered(self): diag = QtWidgets.QDialog() diag_ui = timestamp_convertor.Ui_Dialog() diag_ui.setupUi(diag) diag.exec_() def onPluginTriggered(self): self.plugin_location = self.settings.value('plugin_location', [], str) diag = QtWidgets.QDialog() diag_ui = plugin.Ui_Dialog() diag_ui.setupUi(diag) if self.plugin_location: diag_ui.setPluginLocation(self.plugin_location) diag_ui.setData(self.data, self.current_row) diag.exec_() location = diag_ui.getPluginLocation() if location != self.plugin_location: self.settings.setValue('plugin_location', location) def onPacketFilterTriggered(self): diag = QtWidgets.QDialog() diag_ui = packet_filter.Ui_Dialog() diag_ui.setupUi(diag) self.filterPattern = '' #empty search string diag_ui.setSelectedServices(self.selected_services) diag_ui.buttonBox.accepted.connect( partial(self.applyServiceFilter, diag_ui)) diag.exec_() def applyServiceFilter(self, diag_ui): self.selected_SPID = diag_ui.getSelectedSPID() self.selected_services = diag_ui.getSelectedServices() self.selected_tmtc = diag_ui.getTMTC() self.showMessage('Applying filter...') self.addPacketsToView(self.data, True, show_stat=False) def onExportButtonClicked(self): if self.y: filename = str( QtWidgets.QFileDialog.getSaveFileName( None, "Save data to file", "", "CSV(*.csv)")[0]) if filename: with open(filename, 'w') as f: f.write('{},{}\n'.format(self.xlabel, self.ylabel)) for xx, yy in zip(self.x, self.y): f.write('{},{}\n'.format(xx, yy)) self.showMessage( 'The data has been written to {}'.format(filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('Plot first!') msgBox.setWindowTitle("Warning") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def savePlot(self): # if self.figure.get_axes(): if self.chart: filetypes = "PNG (*.png);;JPEG (*.jpg)" filename = str( QtWidgets.QFileDialog.getSaveFileName( None, "Save plot to file", "", filetypes)[0]) if filename: if not filename.endswith(('.png', '.jpg')): filename += '.png' # self.figure.savefig(filename) p = self.chartView.grab() p.save(filename) self.showMessage(('Has been saved to %s.' % filename)) else: msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText('No figure to save') msgBox.setWindowTitle("STIX raw data viewer") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def onCopyTriggered(self): packet_id = self.current_row try: packet = self.data[packet_id] ss = pprint.pformat(packet) cb = QtWidgets.QApplication.clipboard() cb.clear(mode=cb.Clipboard) cb.setText(ss, mode=cb.Clipboard) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) msg.setText( "The data of the selected packet has been copied to the clipboard." ) msg.setWindowTitle("Information") msg.setStandardButtons(QtWidgets.QMessageBox.Ok) retval = msg.exec_() except Exception as e: self.showMessage(str(e), 0) def onPasteTriggered(self): raw_hex = QtWidgets.QApplication.clipboard().text() if len(raw_hex) < 16: self.showMessage('No data in the clipboard.') return self.hexParser.setHex(raw_hex) self.hexParser.start() def showMessage(self, msg, where=0): if where != 1: self.statusbar.showMessage(msg) if where != 0: self.statusListWidget.addItem(msg) def onSetIDBClicked(self): self.idb_filename = QtWidgets.QFileDialog.getOpenFileName( None, 'Select file', '.', 'IDB file(*.db *.sqlite *.sqlite3)')[0] if not self.idb_filename: return STIX_IDB.reload(self.idb_filename) if STIX_IDB.is_connected(): #settings = QtCore.QSettings('FHNW', 'stix_parser') self.settings.setValue('idb_filename', self.idb_filename) self.showMessage( 'IDB location: {} '.format(STIX_IDB.get_idb_filename()), 1) def save(self): filetypes = 'python compressed pickle (*.pklz);; python pickle file (*.pkl);; binary data (*.dat)' self.output_filename = str( QtWidgets.QFileDialog.getSaveFileName(None, "Save packets to", "", filetypes)[0]) if not self.output_filename.endswith(('.pklz', '.pkl', '.dat')): msg = 'unsupported file format !' self.showMessage(msg) return msg = 'Writing data to file %s' % self.output_filename self.showMessage(msg) if self.output_filename.endswith(('.pklz', '.pkl')): stw = stix_writer.StixPickleWriter(self.output_filename) stw.register_run(str(self.input_filename)) stw.write_all(self.data) elif self.output_filename.endswith('.dat'): stw = stix_writer.StixBinaryWriter(self.output_filename) stw.write_all(self.data) num_ok = stw.get_num_sucess() msg = ( 'The binary data of {} packets written to file {}, total packets {}' .format(num_ok, self.output_filename, len(self.data))) self.showMessage(msg) msg = 'Packets have been written to %s' % self.output_filename self.showMessage(msg) def setListViewSelected(self, row): #index = self.model.createIndex(row, 0); # if index.isValid(): # self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select) pass def about(self): msgBox = QtWidgets.QMessageBox() msgBox.setIcon(QtWidgets.QMessageBox.Information) msgBox.setText("STIX raw data parser and viewer, [email protected]") msgBox.setWindowTitle("Stix data viewer") msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) msgBox.exec_() def nextPacket(self): self.current_row += 1 length = len(self.data) if self.current_row >= length: self.current_row = length - 1 self.showMessage('No more packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def previousPacket(self): self.current_row -= 1 if self.current_row < 0: self.current_row = 0 self.showMessage('Reach the first packet!') self.showPacket(self.current_row) self.setListViewSelected(self.current_row) def getOpenFilename(self): location = self.settings.value('location', [], str) if not location: location = '.' filetypes = ( 'Supported file (*.dat *.bin *.binary *.pkl *.pklz *.xml *ascii *BDF *txt) ;; All(*)' ) self.input_filename = QtWidgets.QFileDialog.getOpenFileName( None, 'Select file', location, filetypes)[0] if not self.input_filename: return self.settings.setValue('location', os.path.abspath(self.input_filename)) diag = QtWidgets.QDialog() diag_ui = packet_filter.Ui_Dialog() diag_ui.setupUi(diag) diag_ui.setSelectedServices(SELECTED_SERVICES) diag_ui.buttonBox.accepted.connect( partial(self.onOpenFile, self.input_filename, diag_ui)) diag.exec_() def onOpenFile(self, input_filename, diag): self.selected_SPID = diag.getSelectedSPID() self.selected_services = diag.getSelectedServices() self.openFile(input_filename, self.selected_services, self.selected_SPID) def openFile(self, filename, selected_services=None, selected_SPID=None): msg = 'Loading file %s ...' % filename self.progressDiag = QtWidgets.QProgressDialog() #self.showMessage(msg) self.progressDiag.setLabelText(msg) self.progressDiag.setWindowTitle('Loading data') self.progressDiag.setCancelButtonText('Cancel') self.progressDiag.setRange(0, 100) self.progressDiag.setMinimumWidth(300) self.progressDiag.canceled.connect(self.stopParsing) self.filterPattern = '' self.dataReader.setPacketFilter(selected_services, selected_SPID) self.dataReader.setFilename(filename) self.dataReader.start() self.progressDiag.show() def stopParsing(self): if self.dataReader: self.dataReader.stopParsing() self.progressDiag.hide() def onProgressUpdated(self, progress): if not self.progressDiag: return self.progressDiag.setValue(progress) if progress >=99: self.progressDiag.hide() def onDataReaderCritical(self, msg): self.showMessage(msg, 1) def onDataReaderInfo(self, msg): self.showMessage(msg, 0) def onDataReaderWarning(self, msg): self.showMessage(msg, 1) def onDataReaderError(self, msg): self.showMessage(msg, 1) def onDataReady(self, data, clear=True, show_stat=True): #self.progressBar.hide() if not clear: self.data.extend(data) else: self.data = data if data: self.addPacketsToView(data, clear=clear, show_stat=show_stat) self.enableButtons() else: self.showMessage('No packet loaded') def enableButtons(self): if not self.buttons_enabled: self.actionPrevious.setEnabled(True) self.actionNext.setEnabled(True) self.actionSave.setEnabled(True) self.actionCopy.setEnabled(True) self.actionPlot.setEnabled(True) self.actionViewBinary.setEnabled(True) self.buttons_enabled = True def addPacketsToView(self, data, clear=True, show_stat=True): if clear: self.packetTreeWidget.clear() for p in data: if not isinstance(p, dict): continue header = p['header'] root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget) colors = {2: '#FFA500', 1: '#000080', 3: '#FF0000', 4: '#800000'} tc_color = '#78281F' if header['TMTC'] == 'TC': root.setForeground(0, QtGui.QBrush(QtGui.QColor(tc_color))) root.setForeground(1, QtGui.QBrush(QtGui.QColor(tc_color))) else: if header['service_type'] == 5: if header['service_subtype'] in colors.keys(): root.setForeground( 0, QtGui.QBrush( QtGui.QColor( colors[header['service_subtype']]))) root.setForeground( 1, QtGui.QBrush( QtGui.QColor( colors[header['service_subtype']]))) timestamp_str = stix_datetime.format_datetime(header['unix_time']) root.setText(0, timestamp_str) description = '{}({},{}) - {}'.format( header['TMTC'], header['service_type'], header['service_subtype'], header['descr']) root.setText(1, description) hidden = False if self.selected_SPID: if header['TMTC'] == 'TC': hidden = True elif -int(header['SPID']) in self.selected_SPID or int( header['SPID']) not in self.selected_SPID: hidden = True else: if int(header['service_type']) not in self.selected_services: hidden = True TMTC = header['TMTC'] if TMTC == 'TM' and self.selected_tmtc in [2, 0]: hidden = True if TMTC == 'TC' and self.selected_tmtc in [1, 0]: hidden = True if self.filterPattern: to_exclude = False pattern = self.filterPattern.strip() if pattern.startswith('!'): to_exclude = True pattern = pattern[1:] try: spid = int(pattern) hidden = to_exclude == (header['SPID'] == spid) #XNOR operation except (TypeError, ValueError): hidden = to_exclude == (pattern in description) root.setHidden(hidden) if show_stat: total_packets = len(self.data) self.showMessage(('Total packet(s): %d' % total_packets)) def onConnectTSCTriggered(self): diag = QtWidgets.QDialog() diag_ui = tsc_connection.Ui_Dialog() diag_ui.setupUi(diag) self.tsc_host = self.settings.value('tsc_host', [], str) self.tsc_port = self.settings.value('tsc_port', [], str) if self.tsc_host: diag_ui.serverLineEdit.setText(self.tsc_host) if self.tsc_port: diag_ui.portLineEdit.setText(self.tsc_port) diag_ui.buttonBox.accepted.connect(partial(self.connectToTSC, diag_ui)) diag.exec_() def connectToTSC(self, dui): host = dui.serverLineEdit.text() port = dui.portLineEdit.text() self.showMessage('Connecting to TSC...') self.socketPacketReceiver.connect(host, int(port)) self.socketPacketReceiver.start() def onPacketArrival(self, packets): clear = False if packets: if len(self.data) > MAX_NUM_PACKET_IN_BUFFER: clear = True self.onDataReady(packets, clear=clear, show_stat=True) def onLoadMongoDBTriggered(self): diag = QtWidgets.QDialog() diag_ui = mongo_dialog.Ui_Dialog() diag_ui.setupUi(diag) #self.settings = QtCore.QSettings('FHNW', 'stix_parser') self.mongo_server = self.settings.value('mongo_server', [], str) self.mongo_port = self.settings.value('mongo_port', [], str) self.mongo_user = self.settings.value('mongo_user', [], str) self.mongo_pwd = self.settings.value('mongo_pwd', [], str) if self.mongo_server: diag_ui.serverLineEdit.setText(self.mongo_server) if self.mongo_port: diag_ui.portLineEdit.setText(self.mongo_port) if self.mongo_user: diag_ui.userLineEdit.setText(self.mongo_user) if self.mongo_pwd: diag_ui.pwdLineEdit.setText(self.mongo_pwd) diag_ui.pushButton.clicked.connect( partial(self.loadRunsFromMongoDB, diag_ui)) diag_ui.buttonBox.accepted.connect( partial(self.loadDataFromMongoDB, diag_ui, diag)) diag.exec_() def loadRunsFromMongoDB(self, dui): server = dui.serverLineEdit.text() port = dui.portLineEdit.text() user = dui.userLineEdit.text() pwd = dui.pwdLineEdit.text() self.showMessage('saving setting...') if self.mongo_server != server: self.settings.setValue('mongo_server', server) if self.mongo_port != port: self.settings.setValue('mongo_port', port) if self.mongo_user != user: self.settings.setValue('mongo_user', user) if self.mongo_pwd != pwd: self.settings.setValue('mongo_pwd', pwd) self.showMessage('connecting Mongo database ...') self.mdb = mgdb.MongoDB(server, int(port), user, pwd) if not self.mdb.is_connected(): self.showMessage('Failed to connect to MongoDB') return dui.treeWidget.clear() self.showMessage('Fetching data...') for run in self.mdb.select_all_runs(): root = QtWidgets.QTreeWidgetItem(dui.treeWidget) root.setText(0, str(run['_id'])) root.setText(1, run['filename']) root.setText(2, stix_datetime.format_datetime(run['date'])) root.setText(3, stix_datetime.format_datetime(run['data_start_unix_time'])) root.setText(4, stix_datetime.format_datetime(run['data_stop_unix_time'])) def loadDataFromMongoDB(self, dui, diag): self.showMessage('Loading packets ...') selected_runs = [] for item in dui.treeWidget.selectedItems(): selected_runs.append(item.text(0)) if not selected_runs: self.showMessage('Run not selected!') if selected_runs: diag.done(0) self.showMessage('Loading data ...!') data = list(self.mdb.select_packets_by_run(selected_runs[0])) if data: self.onDataReady(data, clear=True) else: self.showMessage('No packets found!') # close def onPacketSelected(self, cur, pre): self.current_row = self.packetTreeWidget.currentIndex().row() self.showMessage(('Packet #%d selected' % self.current_row)) self.showPacket(self.current_row) def showPacket(self, row): if not self.data: return header = self.data[row]['header'] total_packets = len(self.data) self.showMessage( ('Packet %d / %d %s ' % (row, total_packets, header['descr']))) self.paramTreeWidget.clear() header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) header_root.setText(0, "Header") rows = len(header) for key, val in header.items(): root = QtWidgets.QTreeWidgetItem(header_root) root.setText(0, key) root.setText(1, str(val)) params = self.data[row]['parameters'] param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget) param_root.setText(0, "Parameters") self.showParameterTree(params, param_root) self.paramTreeWidget.expandItem(param_root) self.paramTreeWidget.expandItem(header_root) self.current_row = row def showParameterTree(self, params, parent, parent_id=[]): if not params: return for i, p in enumerate(params): root = QtWidgets.QTreeWidgetItem(parent) if not p: continue param = Parameter(p) param_name = param['name'] desc = param['desc'] current_ids = parent_id[:] current_ids.append(i) root.setText(0, param_name) root.setText(1, desc) root.setText(2, str(param['raw'])) tip='parameter'+''.join(['[{}]'.format(x) for x in current_ids]) root.setToolTip(0, tip) long_desc = STIX_IDB.get_scos_description(param_name) if long_desc: root.setToolTip(1, long_desc) try: root.setToolTip(2, hex(param['raw_int'])) except: pass unit=STIX_IDB.get_parameter_unit(param_name) eng=str(param['eng']) root.setText(3, eng) root.setText(4, unit) if 'NIXG' in param_name: root.setHidden(True) #groups should not be shown if param.children: self.showParameterTree(param['children'], root, current_ids) self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked) def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0): if not params: return timestamp = header['unix_time'] for p in params: if not p: continue param = Parameter(p) if name == param.name: values = None if data_type == 0: values = param.raw else: values = param.eng try: yvalue = float(values) ret_y.append(yvalue) if xaxis == 1: ret_x.append(timestamp) else: self.showMessage(('Can not plot %s ' % str(yvalue))) except Exception as e: self.showMessage(('%s ' % str(e))) if param.children: self.walk(name, param.children, header, ret_x, ret_y, xaxis, data_type) def onPlotButtonClicked(self, packets=None): if self.chart: self.chart.removeAllSeries() if packets is None: packets = self.data if not packets: return self.showMessage('Preparing plot ...') name = self.paramNameEdit.text() packet_selection = self.comboBox.currentIndex() xaxis_type = self.xaxisComboBox.currentIndex() data_type = self.dataTypeComboBox.currentIndex() timestamp = [] self.y = [] params = self.paramNameEdit.text() header = packets[0]['header'] current_spid = 0 spid_text = self.spidLineEdit.text() if spid_text: current_spid = int(spid_text) selected_packets=[] if packet_selection == 0: selected_packets=[packets[self.current_row]] elif packet_selection == 1: selected_packets=packets for packet in selected_packets: header = packet['header'] if packet['header']['SPID'] != current_spid: continue params = packet['parameters'] self.walk(name, params, header, timestamp, self.y, xaxis_type, data_type) self.x = [] if not self.y: self.showMessage('No data points') elif self.y: style = self.styleEdit.text() if not style: style = '-' title = '%s' % str(name) desc = self.descLabel.text() if desc: title += '- %s' % desc self.chart.setTitle(title) ylabel = 'Raw value' xlabel = name if data_type == 1: ylabel = 'Engineering / Decompressed value' if xaxis_type == 0: if packet_selection == 1: xlabel = "Packet #" else: xlabel = "Repeat #" self.x = range(0, len(self.y)) if xaxis_type == 1: self.x = [t - timestamp[0] for t in timestamp] xlabel = 'Time -T0 (s)' if xaxis_type != 2: series = QLineSeries() series2 = None for xx, yy in zip(self.x, self.y): series.append(xx, yy) if 'o' in style: series2 = QScatterSeries() for xx, yy in zip(self.x, self.y): series2.append(xx, yy) self.chart.addSeries(series2) self.chart.addSeries(series) axisX = QValueAxis() axisX.setTitleText(xlabel) axisY = QValueAxis() axisY.setTitleText(ylabel) self.chart.setAxisX(axisX) self.chart.setAxisY(axisY) series.attachAxis(axisX) series.attachAxis(axisY) else: nbins = len(set(self.y)) ycounts, xedges = np.histogram(self.y, bins=nbins) series = QLineSeries() for i in range(0, nbins): meanx = (xedges[i] + xedges[i + 1]) / 2. series.append(meanx, ycounts[i]) self.chart.addSeries(series) axisX = QValueAxis() axisX.setTitleText(name) axisY = QValueAxis() axisY.setTitleText("Counts") self.chart.setAxisY(axisY) self.chart.setAxisX(axisX) series.attachAxis(axisX) series.attachAxis(axisY) self.xlabel = xlabel self.ylabel = ylabel self.chartView.setRubberBand(QChartView.RectangleRubberBand) self.chartView.setRenderHint(QtGui.QPainter.Antialiasing) msg = 'Number of data points: {}, Ymin: {}, Ymax: {}'.format( len(self.y), min(self.y), max(self.y)) self.showMessage(msg, 1) self.showMessage('The canvas updated!') def plotParameter(self, SPID=None, pname=None, desc=None): self.tabWidget.setCurrentIndex(1) if pname: self.paramNameEdit.setText(pname) if desc: self.descLabel.setText(desc) if SPID: self.spidLineEdit.setText(str(SPID)) def onPlotActionClicked(self): self.tabWidget.setCurrentIndex(1) self.plotParameter() def onTreeItemClicked(self, it, col): SPID = None try: SPID = self.data[self.current_row]['header']['SPID'] except IndexError: pass self.plotParameter(SPID, it.text(0), it.text(1))
class TestWindow(QMainWindow): def __init__(self, scope, parent=None): super(TestWindow, self).__init__(parent=parent) self.scope = scope self.ncurves = 0 self.chart = QChart() self.chart.legend().hide() self.view = QChartView(self.chart) self.view.setRenderHint(QPainter.Antialiasing) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlWidget = QWidget() controlWidget.setLayout(controlLayout) self.runButton = QPushButton("Get") controlLayout.addWidget(self.runButton) self.channel1 = QCheckBox("fetch 12bit") controlLayout.addWidget(self.channel1) controlLayout.addWidget(QLabel("Delay")) self.delay = QLineEdit("0") controlLayout.addWidget(self.delay) controlLayout.addWidget(QLabel("NumSamples")) self.numSamples = QLineEdit("3000") controlLayout.addWidget(self.numSamples) self.speedsComboBox = LabeledComboBox( label='Timebase', items=[str(x) for x in list(range(8))]) controlLayout.addWidget(self.speedsComboBox) self.layout = QVBoxLayout() self.layout.addWidget(controlWidget) self.layout.addWidget(self.view) self.layoutWidget = QWidget() self.layoutWidget.setLayout(self.layout) self.runButton.clicked.connect(self.on_get) self.setCentralWidget(self.layoutWidget) self.show() @pyqtSlot() def on_get(self): self.chart.removeAllSeries() scope.setSampleSpeed(self.speedsComboBox.getInt()) scope.set12Bits(self.channel1.isChecked()) scope.setDelay(int(str(self.delay.displayText()))) # There is some weird behaviour in 12 bit mode numSamples = int(str(self.numSamples.displayText())) scope.setSamples(min(7 * 1024 + 512, numSamples)) ch1data = scope_getSamples(self.scope) self.add_data(range(len(ch1data)), ch1data, color=Qt.red) self.set_title("Semi live Scope") def set_title(self, title): self.chart.setTitle(title) 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
class PieChart(QtWidgets.QWidget): def __init__(self): QtWidgets.QWidget.__init__(self) self.setObjectName("main") self.setStyleSheet(""" QWidget{ border:1px solid #148CD2; border-radius:10px; } """) self.create_piechart() timer = QTimer(self) timer.timeout.connect(self.redraw) timer.start(5 * 60 * 1000) # update every 5 minutes layout = QHBoxLayout(self) layout.setContentsMargins(5, 5, 50, 5) layout.addWidget(self.chartview) self.setLayout(layout) self.setFixedSize(500, 400) def create_piechart(self): today = datetime.date.today() Day = selectday(today) catogeries = Day['allCategory'] catogeries = dict(sorted(catogeries.items(), key=lambda x: -x[1])[:5]) print(f"--------------------{catogeries}--------") series = QPieSeries() tot_val = 0 for name, value in catogeries.items(): tot_val += value tot_val = max(tot_val, 1) for name, value in catogeries.items(): if value == 0: value = 0.2 _slice = series.append(name, 100 * (value / tot_val)) _slice.setLabelVisible(True) # can be removed if unnecessary self.chart = QChart() self.chart.legend().hide() self.chart.addSeries(series) self.chart.createDefaultAxes() self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("Categories") self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignBottom) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) def redraw(self): # remove pieChart self.chart.removeAllSeries() today = datetime.date.today() Day = selectday(today) catogeries = Day['allCategory'] catogeries = dict(sorted(catogeries.items(), key=lambda x: -x[1])[:5]) print(f"--------------------{catogeries}--------") series = QPieSeries() tot_val = 0 for name, value in catogeries.items(): tot_val += value for name, value in catogeries.items(): _slice = series.append(name, 100 * (value / tot_val)) _slice.setLabelVisible(True) # can be removed if unnecessary self.chart.addSeries(series) self.chartview.setChart((self.chart)) self.chartview.setRenderHint(QPainter.Antialiasing) self.chartview.repaint()
class ProdDetail(QWidget): def __init__(self): super().__init__() hbox=QHBoxLayout() hbox2=QHBoxLayout() hbox3=QHBoxLayout() hbox4=QHBoxLayout() self.prod_combo=QComboBox() self.lineEditProdName=QLineEdit() namelabel=QLabel("스토어팜주소") self.farm_combo=QComboBox() self.li=['https://smartstore.naver.com/heyhannah','https://smartstore.naver.com/monsclub'] self.farm_combo.addItems(self.li) self.shop_title_label=QLabel() self.show_farm_name() self.btn_show_prod_detail=QPushButton('조회') self.btn_show_prod_detail.setIcon(QtGui.QIcon('update.png')) hbox.addWidget(namelabel) hbox.addWidget(self.farm_combo) hbox.addWidget(self.shop_title_label) hbox2.addWidget(QLabel("상품명")) hbox2.addWidget(self.prod_combo) hbox2.addStretch() hbox3.addWidget(QLabel("직접입력")) hbox3.addWidget(self.lineEditProdName) hbox3.addWidget(self.btn_show_prod_detail) hbox3.addStretch() self.init_prod_combo() self.btn_show_prod_detail.clicked.connect(self.get_prod_detail) self.farm_combo.currentTextChanged.connect(self.show_farm_name) self.prod_combo.currentTextChanged.connect(self.input_prod_title) vbox=QVBoxLayout() self.linechart=QChart() self.linechart2=QChart() self.linechart3=QChart() self.chartview = QChartView(self.linechart) self.chartview2 = QChartView(self.linechart2) self.chartview3 = QChartView(self.linechart3) self.tablewidget=QTableWidget() self.chartgroup=QGroupBox() self.chartvbox=QVBoxLayout() self.chartvbox.addWidget(self.chartview) self.chartvbox.addWidget(self.chartview2) self.chartvbox.addWidget(self.chartview3) self.chartgroup.setLayout(self.chartvbox) hbox4.addWidget(self.tablewidget) # hbox4.addWidget(self.chartview) hbox4.addWidget(self.chartgroup) self.updateProdDetail() self.groupbox=QGroupBox() self.groupbox2=QGroupBox() self.groupbox3=QGroupBox() self.groupbox4=QGroupBox() self.groupbox.setLayout(hbox) self.groupbox2.setLayout(hbox2) self.groupbox3.setLayout(hbox3) self.groupbox4.setLayout(hbox4) vbox.addWidget(self.groupbox) vbox.addWidget(self.groupbox2) vbox.addWidget(self.groupbox3) vbox.addWidget(self.groupbox4) self.setLayout(vbox) def init_prod_combo(self): mall_url=self.farm_combo.currentText() conn=sqlite3.connect('emaildb.sqlite') cur=conn.cursor() sql=f"Select distinct title from PROD3 where link like '{mall_url}%'" cur.execute(sql) conn.commit() rows=cur.fetchall() li=[] for row in rows: li.append(row[0]) self.prod_combo.clear() self.prod_combo.addItems(li) cur.close() conn.close() self.lineEditProdName.setText(self.prod_combo.currentText()) def drawChart(self): conn=sqlite3.connect('emaildb.sqlite') cur=conn.cursor() title=self.lineEditProdName.text() mall_url=self.farm_combo.currentText() sql=f"select dt, jjim, sold, review from PROD3 where title='{title}'" cur.execute(sql) conn.commit() rows=cur.fetchall() series=[] # series = QLineSeries(self) series.append(QLineSeries(self)) series.append(QLineSeries(self)) series.append(QLineSeries(self)) tod=datetime.today() nextday=datetime.today()+timedelta(days=1) d=QDate(2020,1,3) dt=QDateTime(d) d2=d.addDays(1) dt2=dt.addDays(1) for i,row in enumerate(rows): for j, serie in enumerate(series): # serie.append((dt.addDays(i)).toMSecsSinceEpoch(),int(row[j+1])) serie.append(i,int(row[j+1])) for serie in series: serie.setPointsVisible(True) self.linechart.removeAllSeries() self.linechart2.removeAllSeries() self.linechart3.removeAllSeries() self.linechart.addSeries(series[0]) self.linechart2.addSeries(series[1]) self.linechart3.addSeries(series[2]) dateAxis=QDateTimeAxis() dateAxis2=QDateTimeAxis() dateAxis3=QDateTimeAxis() self.linechart.addAxis(dateAxis, Qt.AlignBottom) self.linechart2.addAxis(dateAxis2, Qt.AlignBottom) self.linechart3.addAxis(dateAxis3, Qt.AlignBottom) self.linechart.createDefaultAxes() self.linechart2.createDefaultAxes() self.linechart3.createDefaultAxes() self.linechart.setAnimationOptions(QChart.SeriesAnimations) self.linechart.setTitle("찜") self.linechart.legend().setVisible(True) self.linechart2.setAnimationOptions(QChart.SeriesAnimations) self.linechart2.setTitle("구매") self.linechart2.legend().setVisible(True) self.linechart3.setAnimationOptions(QChart.SeriesAnimations) self.linechart3.setTitle("리뷰") self.linechart3.legend().setVisible(True) self.chartview.setRenderHint(QPainter.Antialiasing) self.chartview2.setRenderHint(QPainter.Antialiasing) self.chartview3.setRenderHint(QPainter.Antialiasing) cur.close() conn.close() def updateProdDetail(self): self.tablewidget.clear() self.tablewidget.setRowCount(300) self.tablewidget.setColumnCount(6) self.tablewidget.setItem(0,0,QTableWidgetItem("날짜")) self.tablewidget.setItem(0,1,QTableWidgetItem("찜")) self.tablewidget.setItem(0,2,QTableWidgetItem("구매")) self.tablewidget.setItem(0,3,QTableWidgetItem("리뷰")) conn=sqlite3.connect('emaildb.sqlite') cur=conn.cursor() title=self.lineEditProdName.text() mall_url=self.farm_combo.currentText() sql=f"Select dt, jjim, sold, review from PROD3 where title='{title}' order by dt desc" cur.execute(sql) conn.commit() rows=cur.fetchall() for i,row in enumerate(rows): # print(i, row[0]) for j, elem in enumerate(row): # print(i+1,j,elem) # self.tablewidget.setItem(i+1,j,QTableWidgetItem(elem)) self.tablewidget.setItem(i+1,j,QTableWidgetItem(str(row[j]))) # print(row[1]) # self.tablewidget.setItem(i+1,1,QTableWidgetItem(str(row[1]))) self.tablewidget.resizeColumnToContents(0) cur.close() conn.close() return len(rows) def input_prod_title(self): self.lineEditProdName.setText(self.prod_combo.currentText()) def get_prod_detail(self): url=self.farm_combo.currentText() prod_title=self.lineEditProdName.text() self.tablewidget.clear() self.updateProdDetail() self.drawChart() def setFarm(self,li): self.farmlist=FarmList(self.li) # print(self.li) # self.farm_combo.addItems(self.li) self.farmlist.show() def show_farm_name(self): '''스토어팜 주소를 콤보박스에서 변경시에 검색하여 스토어팜 이름 표시 prod_combo도 변경함 ''' # self.shop_title_label.setText("sssss") url=self.farm_combo.currentText() req=requests.get(url) soup=BeautifulSoup(req.text, 'html.parser') self.shop_title_label.setText(soup.find('title').text.strip()) self.init_prod_combo()
class Chart(QWidget): def __init__(self, chartKey, data, frame, parent=None): super(Chart, self).__init__(parent) self.frame = frame self.data = data self.pt = self.parent() #add the to the main window #self.toolbar = QToolBar("Edit", self) #self.pt.addToolBar(self.toolbar) #ly = QtWidgets.QVBoxLayout() #self.frame = QtWidgets.QFrame() #self.frame.setLayout(ly) #self.layout = QtWidgets.QGridLayout() #print('----------------',self.frame) self.create_chart(chartKey) clicked = QtCore.pyqtSignal(QtCore.QModelIndex) #self.pt.addToolBar(self.navigationBar(data)) def create_chart(self, chartKey): self.series = QPieSeries() self.series.setHoleSize(0.35) self.chart = QChart() #Add series to the chart self.addSeries(chartKey) # for the background and title self.chart.setAnimationOptions(QChart.SeriesAnimations) self.chart.setTitle("DonutChart Example") self.chart.setTheme(QChart.ChartThemeBlueCerulean) self.chartview = QChartView(self.chart) self.chartview.setRenderHint(QPainter.Antialiasing) #navigation = Navigation(classObj, self) #self.addToolBar(navigation.toolbar) #clicked = QtCore.pyqtSignal(QtCore.QModelIndex) def navigationBar(self, data): self.toolbar = QtWidgets.QToolBar() self.toolbar.actionTriggered.connect(self.on_actionTriggered) self.model = QtGui.QStandardItemModel(self) dict_to_model(self.model.invisibleRootItem(), data) it = self.model.item(0, 0) ix = self.model.indexFromItem(it) root_action = self.toolbar.addAction(it.text()) root_action.setData(QtCore.QPersistentModelIndex(ix)) self.listview = QtWidgets.QListView() self.listview.setEditTriggers( QtWidgets.QAbstractItemView.NoEditTriggers) #self.series.doubleClicked.connect(self.on_clicked) self.listview.setModel(self.model) self.listview.setRootIndex(ix) self.a = 10 return self.toolbar #make the listed items clickable #@QtCore.pyqtSlot(QtCore.QModelIndex) def on_clicked(self, index): if not self.model.hasChildren(index): self.clicked.emit(index) return action = self.toolbar.addAction(index.data()) action.setData(QtCore.QPersistentModelIndex(index)) self.listview.setRootIndex(index) print(index.data()) self.chart.addSeries(index.data()) #make the breadcrumbs clickable in order to go back and forth #@QtCore.pyqtSlot(QtWidgets.QAction) def on_actionTriggered(self, action): ix = action.data() self.chart.addSeries(ix.data()) model = ix.model() self.listview.setRootIndex(QtCore.QModelIndex(ix)) self.toolbar.clear() ixs = [] while ix.isValid(): ixs.append(ix) ix = ix.parent() for ix in reversed(ixs): action = self.toolbar.addAction(ix.data()) action.setData(ix) def addSeries(self, key): self.chart.removeAllSeries() self.series = QPieSeries() self.series.setHoleSize(0.35) #Show chartview only if the content length is less than 6. Otherwise show a table view if len(self.data[key]) < 6: for key, value in self.data[key].items(): slice_ = QPieSlice(str(key), value) self.series.append(slice_) for slice in self.series.slices(): slice.setLabel(slice.label()) self.chart.addSeries(self.series) self.frame.frame.hide() self.chart.show() else: for m, item in self.data[key].items(): print(m, item) self.table = TableView(self.data[key], len(self.data[key]), 1) if self.frame.ly.count() > 0: self.frame.ly.itemAt(0).widget().setParent(None) self.frame.ly.addWidget(self.table) self.frame.frame.show() self.chart.hide() self.series.doubleClicked.connect(self.handle_double_clicked) #Show the update chart with the distribution of the selected slice def handle_double_clicked(self, slice): slice.setExploded() slice.setLabelVisible() if slice.label() in self.data.keys(): print("slice", slice.label()) self.addSeries(slice.label())