def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis, ): bar_set = QBarSet(self.name) tmp_dict = dict(zip(self.x_list, self.y_list)) for k in _idx2x: try: bar_set.append(tmp_dict[k]) except KeyError: bar_set.append(0) if self.color is not None: bar_set.setColor(self.color) bar_series = QBarSeries() bar_series.append(bar_set) _chart.addSeries(bar_series) _chart.setAxisX(_axis_x, bar_series) _chart.setAxisY(_axis_y, bar_series) if self.show_value: self.createShow()
def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Demo12_1, QChart 基本绘图") self.resize(580, 420) chart = QChart() chart.setTitle("简单函数曲线") chartView = QChartView(self) chartView.setChart(chart) self.setCentralWidget(chartView) series0 = QLineSeries() series1 = QLineSeries() series0.setName("sin曲线") series1.setName("cos曲线") chart.addSeries(series0) chart.addSeries(series1) t = 0 intv = 0.1 pointCount = 100 for i in range(pointCount): y1 = math.cos(t) series0.append(t, y1) y2 = 1.5 * math.sin(t + 20) series1.append(t, y2) t = t + intv axisX = QValueAxis() axisX.setRange(0, 10) axisX.setTitleText("time(secs)") axisY = QValueAxis() axisY.setRange(-2, 2) axisY.setTitleText("value") chart.setAxisX(axisX, series0) chart.setAxisY(axisY, series0) chart.setAxisX(axisX, series1) chart.setAxisY(axisY, series1)
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis, ): series = QBoxPlotSeries() series.setName(self.name) if self.color is not None: series.setBrush(self.color) tmp_dict = dict(zip(self.x_list, self.y_list)) for k in _idx2x: try: series.append(QBoxSet(*tmp_dict[k])) except KeyError: series.append(QBoxSet()) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
def createLineChart(self): chart = QChart() chart.setTitle("像素分布直方图") seriesArray = [] # for i, data_list in enumerate(self.m_dataTable): # series = QLineSeries() # for value, _ in data_list: # series.append(value) # series.setName("Series " + str(i)) # seriesArray.append(series) # chart.addSeries(series) axisX = QValueAxis() axisY = QValueAxis() axisX.setRange(0, 255) axisY.setRange(0, 50000) chart.setAxisX(axisX) chart.setAxisY(axisY) # for i in seriesArray: # chart.removeSeries(i) return chart
def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(400, 300) # 抗锯齿 self.setRenderHint(QPainter.Antialiasing) # 图表 chart = QChart() self.setChart(chart) # 设置标题 chart.setTitle('Simple horizontal barchart example') # 开启动画效果 chart.setAnimationOptions(QChart.SeriesAnimations) # 添加Series series = self.getSeries() chart.addSeries(series) # 分类 categories = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] # 分类x轴 axis = QBarCategoryAxis() axis.append(categories) # 创建默认轴线 chart.createDefaultAxes() # 替换默认y轴 chart.setAxisY(axis, series) # 显示图例 chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom)
def __init__(self, series: QLineSeries, title: str, xTitle: str, yTitle: str, minimumSize=QSize(400, 400), *args): super().__init__(*args) chart = QChart() chart.setTitle(title) axisX = QValueAxis(chart) axisX.setTitleText(xTitle) chart.setAxisX(axisX) axisY = QValueAxis(chart) axisY.setTitleText(yTitle) chart.setAxisY(axisY) chart.legend().show() chart.legend().setAlignment(Qt.AlignBottom) self.setChart(chart) self.set_series(series) self.setMinimumSize(minimumSize) self.setRenderHint(QPainter.Antialiasing) self.pan = Pan(self)
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis, ): series = QCandlestickSeries() series.setName(self.name) for x, y in zip(self.x_list, self.y_list): series.append(QCandlestickSet(*y, _x2idx[x])) if self.inc_color is not None: series.setIncreasingColor(self.inc_color) else: series.setIncreasingColor(QColor("#c41919")) if self.dec_color is not None: series.setDecreasingColor(self.dec_color) else: series.setDecreasingColor(QColor("#009f9f")) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
def createBar(self): min_num, max_num = 0, 100 linked_bag_list = [] try: df = self.linked['Beam Diff'].dropna() linked_bag_list = df.values.tolist() min_num = int(min(linked_bag_list)) if min_num > 0: # check if greater than 0, set to 0 min_num = 0 max_num = int(max(linked_bag_list)) except AttributeError: self.statusbar.showMessage('Data not ready') count = [0] * (max_num + 1) # choose the largest num as length of count for num in linked_bag_list: count[int(num)] += 1 # update every number's count max_count = max(count) setBar = QBarSet('Beam Difference Occurrence') setBar.append(count) brush = QBrush(QColor(0x57B1FD)) pen = QPen(QColor(0x57B1FD)) pen.setWidth(2) setBar.setPen(pen) setBar.setBrush(brush) series = QBarSeries() series.append(setBar) chart = QChart() chart.setTheme(QChart.ChartThemeBlueIcy) font = QFont() font.setPixelSize(18) chart.setTitleFont(font) chart.setTitle('Linked Bins Histogram') chart.addSeries(series) chart.setAnimationOptions(QChart.SeriesAnimations) axisX = QValueAxis() axisX.setTitleText("Attenuation Window") axisX.setRange(min_num, max_num+20) chart.setAxisX(axisX, series) axisY = QValueAxis() axisY.setTitleText("Frequency") axisY.setRange(0, max_count+20) chart.setAxisY(axisY, series) chart.legend().hide() chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) return chartView
def load_glycation(self, filename: Optional[str] = None) -> None: """ Load glycation data from a CSV file and display it in the corresponding chart view. :param str filename: directly load this file :return: nothing, sets self.se_glycation :rtype: None """ # load and clean glycation data if filename is None: filename, self.last_path = get_filename( self, "open", self.tr("Load glycation data ..."), self.last_path, FileTypes(["csv"])) if filename is None: return logging.info( self.tr("Loading glycation data in '{}'").format(filename)) try: self.glycation = read_clean_datasets(filename) except (OSError, ValueError) as e: logging.error(str(e)) QMessageBox.critical(self, self.tr("Error"), str(e)) return # extract x- and y-values from series x_values = [str(i) for i in self.glycation.index] y_values = [a.nominal_value for a in self.glycation] # assemble the chart bar_set = QBarSet("glycation abundance") bar_set.append(y_values) bar_set.setColor(QColor("#a1dab4")) bar_set.hovered.connect(self.update_glycation_label) bar_series = QBarSeries() bar_series.append(bar_set) x_axis = QBarCategoryAxis() x_axis.append(x_values) x_axis.setTitleText(self.tr("count")) y_axis = QValueAxis() y_axis.setRange(0, 100) y_axis.setTitleText(self.tr("abundance")) y_axis.setLabelFormat("%d") chart = QChart() chart.addSeries(bar_series) chart.setAxisX(x_axis, bar_series) chart.setAxisY(y_axis, bar_series) chart.legend().setVisible(False) chart.setBackgroundRoundness(0) chart.layout().setContentsMargins(0, 0, 0, 0) chart.setMargins(QMargins(5, 5, 5, 5)) self.cvGlycation.setChart(chart)
def plot_candlechart(ohlc_data): app = ParaMakerApplication([]) #app.setStyleSheet("background-color:black;") series = QCandlestickSeries() series.setBodyOutlineVisible(False) series.setDecreasingColor(Qt.red) series.setIncreasingColor(Qt.green) rsi = qc.QLineSeries() # 5-days average data line rsi.append(QPointF(ohlc_data[300].timestamp, ohlc_data[300].closed)) rsi.append(QPointF(ohlc_data[700].timestamp, ohlc_data[700].closed)) #rsi.append(QPointF(ohlc_data[150].timestamp, ohlc_data[100].closed)) tm = [] # stores str type data # in a loop, series and rsi append corresponding data for candle in ohlc_data: series.append( QCandlestickSet(candle.opened, candle.high, candle.low, candle.closed)) #rsi.append(QPointF(num, m)) tm.append(str(candle.timestamp)) #rsi.append(str(candle.timestamp)) #rsi_values = calculate_rsi(14, ohlc_data) chart = QChart() chart.setBackgroundVisible(False) chart.setPlotAreaBackgroundVisible(False) chart.addSeries(series) # candle chart.addSeries(rsi) # rsi line #chart.axisX(rsi).setRange(ohlc_data[0].timestamp, ohlc_data[-1].timestamp) chart.createDefaultAxes() axisXRSI = QValueAxis() axisYRSI = QValueAxis() axisXRSI.setRange(ohlc_data[0].timestamp, ohlc_data[-1].timestamp) axisYRSI.setRange(ohlc_data[0].closed, ohlc_data[-1].closed) axisXRSI.setGridLineVisible(False) axisYRSI.setGridLineVisible(False) chart.setAxisX(axisXRSI, rsi) chart.setAxisY(axisYRSI, rsi) chart.legend().hide() chart.axisX(series).setCategories(tm) #chart.axisX(series).setGridLineVisible(False) #chart.axisY(series).setGridLineVisible(False) ###chart.axisX(rsi).setVisible(False) chartview = QChartView(chart) chartview.setRenderHint(QPainter.Antialiasing) ui = ParaMakerWindow() ui.setCentralWidget(chartview) sys.exit(app.exec_())
def beforeDelay(self): print("in before delay bar") min_num, max_num = 0, 100 max_count = 0 total_stopped_time = [] try: total_stopped_time = self.tm.total_stopped_time max_num = max(total_stopped_time) except AttributeError: self.statusbar.showMessage('Data not ready') count = total_stopped_time count = [0] * (int(max_num) + 1 ) # choose the largest num as length of count for num in total_stopped_time: count[int(num)] += 1 # update every number's count max_count = max(count) print(len(total_stopped_time), max_count) setBar = QBarSet('stop time') setBar.append(count) brush = QBrush(QColor(0x57B1FD)) pen = QPen(QColor(0x57B1FD)) pen.setWidth(2) setBar.setPen(pen) setBar.setBrush(brush) series = QBarSeries() series.append(setBar) chart = QChart() font = QFont() font.setPixelSize(18) chart.setTitleFont(font) chart.setTitle('Stop time Histogram (before)') chart.addSeries(series) chart.setAnimationOptions(QChart.SeriesAnimations) axisX = QValueAxis() axisX.setRange(min_num, max_num + 20) chart.setAxisX(axisX, series) axisY = QValueAxis() axisY.setRange(0, max_count + 20) chart.setAxisY(axisY, series) chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom) chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) # MainWindow.setCentralWidget(chartView) return chartView
def afterDelay(self): # print("in after delay bar") min_num, max_num = 0, 100 max_count = 0 total_stopped_after_delay = [] count = [0] * (int(max_num) + 1) # choose the largest num as length of count try: total_stopped_after_delay = self.tm.total_stopped_after_delay max_num = max(total_stopped_after_delay) count = [0] * (int(max_num) + 1) # choose the largest num as length of count for num in total_stopped_after_delay: count[int(num)] += 1 # update every number's count max_count = max(count) except (AttributeError, ValueError): self.statusbar.showMessage('Data not ready') setBar = QBarSet('Stop Time Occurrence') setBar.append(count) brush = QBrush(QColor(0xA6E22E)) # Green pen = QPen(QColor(0xA6E22E)) # Green pen.setWidth(2) setBar.setPen(pen) setBar.setBrush(brush) series = QBarSeries() series.append(setBar) chart = QChart() font = QFont() font.setPixelSize(18) chart.setTitleFont(font) chart.setTitle('Stop time Occurrence (after)') chart.addSeries(series) chart.setAnimationOptions(QChart.SeriesAnimations) axisX = QValueAxis() axisX.setRange(min_num, max_num+20) chart.setAxisX(axisX, series) axisY = QValueAxis() axisY.setRange(0, max_count+20) chart.setAxisY(axisY, series) chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom) chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) # MainWindow.setCentralWidget(chartView) return chartView
def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Demo12_1, QChart基本绘图") self.resize(580, 420) #创建chart和chartView chart = QChart() #创建 Chart chart.setTitle("简单函数曲线") chartView = QChartView(self) #创建 ChartView chartView.setChart(chart) #Chart添加到ChartView self.setCentralWidget(chartView) #创建曲线序列 series0 = QLineSeries() series1 = QLineSeries() series0.setName("Sin曲线") series1.setName("Cos曲线") chart.addSeries(series0) #序列添加到图表 chart.addSeries(series1) #序列添加数值 t = 0 intv = 0.1 pointCount = 100 for i in range(pointCount): y1 = math.cos(t) series0.append(t, y1) y2 = 1.5 * math.sin(t + 20) series1.append(t, y2) t = t + intv ##创建坐标轴 axisX = QValueAxis() #X 轴 axisX.setRange(0, 10) #设置坐标轴范围 axisX.setTitleText("time(secs)") #标题 ## axisX.setLabelFormat("%.1f") #标签格式 ## axisX.setTickCount(11) #主分隔个数 ## axisX.setMinorTickCount(4) ## axisX.setGridLineVisible(false) axisY = QValueAxis() #Y 轴 axisY.setRange(-2, 2) axisY.setTitleText("value") ## axisY.setTickCount(5) ## axisY.setMinorTickCount(4) ## axisY.setLabelFormat("%.2f") #标签格式 ## axisY.setGridLineVisible(false) #为序列设置坐标轴 chart.setAxisX(axisX, series0) #为序列设置坐标轴 chart.setAxisY(axisY, series0) chart.setAxisX(axisX, series1) #为序列设置坐标轴 chart.setAxisY(axisY, series1)
class AudioRecPlot(QWidget): def __init__(self): super().__init__() self.m_chart = QChart() chart_view = QChartView(self.m_chart) chart_view.setMinimumSize(800, 600) self.m_series = QLineSeries() self.m_chart.addSeries(self.m_series) axis_x = QValueAxis() axis_x.setRange(0, 2000) axis_x.setLabelFormat("%g") axis_x.setTitleText("Samples") axis_y = QValueAxis() axis_y.setRange(-1, 1) axis_y.setTitleText("Audio level") self.m_chart.setAxisX(axis_x, self.m_series) self.m_chart.setAxisY(axis_y, self.m_series) self.m_chart.setTitle("Data from the microphone") main_layout = QVBoxLayout() main_layout.addWidget(chart_view) self.setLayout(main_layout) format_audio = QAudioFormat() format_audio.setSampleRate(48000) format_audio.setChannelCount(1) format_audio.setSampleSize(8) format_audio.setCodec("audio/pcm") format_audio.setByteOrder(QAudioFormat.LittleEndian) format_audio.setSampleType(QAudioFormat.UnSignedInt) input_devices = QAudioDeviceInfo.defaultInputDevice() self.m_audio_input = QAudioInput(input_devices, format_audio) self.m_device = XYSeriesIODevice(self.m_series) self.m_device.open(QIODevice.WriteOnly) self.m_audio_input.start(self.m_device) self.init_ui() def init_ui(self): self.show() def __exit__(self, exc_type, exc_val, exc_tb): self.m_audio_input.stop() self.m_device.close()
def agg_glycoforms(self) -> None: """ Display glycoform data in the corresponding chart view. :return: nothing :rtype: None """ # aggregate "other" abundances if self.cbAggGlycoforms.isChecked(): agg_abundance = ( self.glycoforms.iloc[self.sbAggGlycoforms.value():].sum()) self.glycoforms_agg = ( self.glycoforms.iloc[:self.sbAggGlycoforms.value()].append( pd.Series(agg_abundance, index=[self.tr("other")]))) else: self.glycoforms_agg = self.glycoforms # extract x- and y-values from series x_values = [str(i) for i in self.glycoforms_agg.index] y_values = [a.nominal_value for a in self.glycoforms_agg] # assemble the chart bar_set = QBarSet("glycoform abundance") bar_set.append(y_values) bar_set.setColor(QColor("#2c7fb8")) bar_set.hovered.connect(self.update_glycoform_label) bar_series = QBarSeries() bar_series.append(bar_set) x_axis = QBarCategoryAxis() x_axis.append(x_values) x_axis.setTitleVisible(False) x_axis.setLabelsAngle(270) range_max = max(self.glycoforms_agg).nominal_value range_max = math.ceil(range_max / 20) * 20 tick_count = range_max // 20 + 1 y_axis = QValueAxis() y_axis.setRange(0, range_max) y_axis.setTickCount(tick_count) y_axis.setTitleText(self.tr("abundance")) y_axis.setLabelFormat("%d") chart = QChart() chart.addSeries(bar_series) chart.setAxisX(x_axis, bar_series) chart.setAxisY(y_axis, bar_series) chart.legend().setVisible(False) chart.setBackgroundRoundness(0) chart.layout().setContentsMargins(0, 0, 0, 0) chart.setMargins(QMargins(5, 5, 5, 5)) self.cvGlycoforms.setChart(chart)
class ChartTab(QChartView): def __init__(self): QChartView.__init__(self) self.chart = QChart() self.candleSeries = QCandlestickSeries(self) self.candleSeries.setIncreasingColor(Qt.blue) self.candleSeries.setBodyOutlineVisible(False) self.candleSeries.setDecreasingColor(Qt.red) self.candleSeries.setMaximumColumnWidth(20) self.candleSeries.clicked.connect(lambda set: print(set.high())) self.xAxis = QDateTimeAxis() self.xAxis.setTickCount(10) self.xAxis.setFormat("h:mm") self.yAxis = QValueAxis() for candle in data: self.addCandle( self.get_integer_price(candle[0]), self.get_integer_price(candle[1]), self.get_integer_price(candle[2]), self.get_integer_price(candle[3]), datetime.strptime(candle[4], '%Y%m%d%H%M%S').timestamp() * 1000) self.chart.addSeries(self.candleSeries) self.setChart(self.chart) self.chart.setAxisX(self.xAxis, self.candleSeries) self.chart.setAxisY(self.yAxis, self.candleSeries) self.chart.legend().setVisible(False) def mouseMoveEvent(self, QMouseEvent): chartValues = self.chart.mapToValue(QMouseEvent.pos()) price = chartValues.y() print(price) def addCandle(self, open, close, high, low, timestamp): candlestickSet = QCandlestickSet() candlestickSet.setOpen(open) candlestickSet.setClose(close) candlestickSet.setHigh(high) candlestickSet.setLow(low) candlestickSet.setTimestamp(timestamp) pen = QPen() candlestickSet.setPen(pen) self.candleSeries.append(candlestickSet) def get_integer_price(self, str_price): return int(str_price.strip()[1:])
def beforeDelayDistribution(self): min_num, max_num = 0, 100 max_count = 0 total_stopped_time = [] count = [0] try: total_stopped_time = self.tm.total_stopped_time max_num = len(total_stopped_time) # change from max() to len() 2/12 11:11 count = total_stopped_time max_count = max(count) except (AttributeError, ValueError): self.statusbar.showMessage('Data not ready') setBar = QBarSet('stop time') setBar.append(count) brush = QBrush(QColor(0x57B1FD)) pen = QPen(QColor(0x57B1FD)) pen.setWidth(2) setBar.setPen(pen) setBar.setBrush(brush) series = QBarSeries() series.append(setBar) chart = QChart() font = QFont() font.setPixelSize(18) chart.setTitleFont(font) chart.setTitle('Stop time Distribution (before)') chart.addSeries(series) chart.setAnimationOptions(QChart.SeriesAnimations) axisX = QValueAxis() axisX.setRange(min_num, max_num) chart.setAxisX(axisX, series) axisY = QValueAxis() axisY.setRange(0, max_count+20) chart.setAxisY(axisY, series) chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom) chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) # MainWindow.setCentralWidget(chartView) return chartView
def crearGraficoBarras(self): paises = [ "EEUU", "China", "Japon", "Alemania", "Reino Unido", "Resto del mundo" ] valores = [24.32, 14.85, 8.91, 12.54, 7.85, 31.53] colores = [ Qt.blue, Qt.red, Qt.darkYellow, Qt.gray, Qt.black, Qt.darkCyan ] grafico = QChart() grafico.setMargins(QMargins(30, 30, 30, 30)) grafico.setTheme(QChart.ChartThemeLight) grafico.setTitle("% Distribución del PIB global") grafico.setAnimationOptions(QChart.SeriesAnimations) for i in range(len(paises)): series = QBarSeries() barSet = QBarSet(paises[i]) barSet.setColor(colores[i]) barSet.setLabelColor(Qt.yellow) barSet.append(valores[i]) series.append(barSet) series.setLabelsVisible(True) series.setLabelsAngle(-90) # series.setLabelsPrecision(2) series.setLabelsFormat("@value %") series.setLabelsPosition(QAbstractBarSeries.LabelsCenter) grafico.addSeries(series) axisX = QBarCategoryAxis() axisX.append(paises) axisY = QValueAxis() axisY.setRange(0, 31.53) axisY.setTickCount(10) axisY.setLabelFormat("%.2f %") grafico.createDefaultAxes() grafico.setAxisX(axisX, None) grafico.setAxisY(axisY, None) grafico.legend().setVisible(True) grafico.legend().setAlignment(Qt.AlignBottom) return grafico
def addSeries(self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis): series = QScatterSeries() series.setName(self.name) for x, y in zip(self.x_list, self.y_list): series.append(_x2idx[x], y) if self.color is not None: series.setColor(self.color) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis ): series = QLineSeries() series.setName(self.name) for x, y in zip(self.x_list, self.y_list): series.append(_x2idx[x], y) if self.color is not None: series.setColor(self.color) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
class QtBarChart(QChartView): def __init__(self, spec): super().__init__(None) self.spec = spec self.chart = QChart() # self.chart.setTitle(str(self.spec.variables)) self.chart.legend().hide() self.mainset = QBarSet("") self.mainset.append([0 for i in range(len(spec.variables))]) self.mainset.setColor( QColor(spec.color[0], spec.color[1], spec.color[2])) self.series = QBarSeries() self.series.append(self.mainset) self.setMinimumWidth(400) self.setMinimumHeight(230) self.axis_x = QBarCategoryAxis() self.axis_y = QValueAxis() self.axis_x.append(spec.variables) self.chart.addSeries(self.series) self.chart.setAxisX(self.axis_x, self.series) self.chart.setAxisY(self.axis_y, self.series) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) self._updates_per_second = 10 self._dataset = [] def clear(self): self._dataset = [] def update_data(self, dataset): data = [] for d in dataset: data.append(d) self._dataset = data def redraw(self): if len(self._dataset) > 0: for i in range(len(self._dataset)): self.mainset.replace(i, self._dataset[i]) self.axis_y.setRange(0, max(self._dataset))
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis ): bar_set = QBarSet(self.name) tmp_dict = dict(zip(self.x_list, self.y_list)) for k in _idx2x: if k in tmp_dict.keys(): bar_set.append(tmp_dict[k]) else: bar_set.append(0) if self.color is not None: bar_set.setColor(self.color) bar_series = QBarSeries() bar_series.append(bar_set) _chart.addSeries(bar_series) _chart.setAxisX(_axis_x, bar_series) _chart.setAxisY(_axis_y, bar_series) if self.show_value: self.createShow()
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis ): series = QCandlestickSeries() series.setName(self.name) for x, y in zip(self.x_list, self.y_list): series.append(QCandlestickSet(*y, _x2idx[x])) if self.inc_color is not None: series.setIncreasingColor(self.inc_color) else: series.setIncreasingColor(QColor('#c41919')) if self.dec_color is not None: series.setDecreasingColor(self.dec_color) else: series.setDecreasingColor(QColor('#009f9f')) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
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 PlotterPane(QChartView): """ This plotter widget makes viewing sensor data easy! This widget represents a chart that will look for tuple data from the MicroPython REPL, Python 3 REPL or Python 3 code runner and will auto-generate a graph. """ data_flood = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) # Holds the raw input to be checked for actionable data to display. self.input_buffer = [] # Holds the raw actionable data detected while plotting. self.raw_data = [] self.setObjectName('plotterpane') self.max_x = 100 # Maximum value along x axis self.max_y = 1000 # Maximum value +/- along y axis self.flooded = False # Flag to indicate if data flooding is happening. # Holds deques for each slot of incoming data (assumes 1 to start with) self.data = [deque([0] * self.max_x), ] # Holds line series for each slot of incoming data (assumes 1 to start # with). self.series = [QLineSeries(), ] # Ranges used for the Y axis (up to 1000, after which we just double # the range). self.y_ranges = [1, 5, 10, 25, 50, 100, 250, 500, 1000] # Set up the chart with sensible defaults. self.chart = QChart() self.chart.legend().hide() self.chart.addSeries(self.series[0]) self.axis_x = QValueAxis() self.axis_y = QValueAxis() self.axis_x.setRange(0, self.max_x) self.axis_y.setRange(-self.max_y, self.max_y) self.axis_x.setLabelFormat("time") self.axis_y.setLabelFormat("%d") self.chart.setAxisX(self.axis_x, self.series[0]) self.chart.setAxisY(self.axis_y, self.series[0]) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) def process_bytes(self, data): """ Takes raw bytes and, if a valid tuple is detected, adds the data to the plotter. The the length of the bytes data > 1024 then a data_flood signal is emitted to ensure Mu can take action to remain responsive. """ # Data flooding guards. if self.flooded: return if len(data) > 1024: self.flooded = True self.data_flood.emit() return data = data.replace(b'\r\n', b'\n') self.input_buffer.append(data) # Check if the data contains a Python tuple, containing numbers, on a # single line (i.e. ends with \n). input_bytes = b''.join(self.input_buffer) lines = input_bytes.split(b'\n') for line in lines: if line.startswith(b'(') and line.endswith(b')'): # Candidate tuple. Extract the raw bytes into a numeric tuple. raw_values = [val.strip() for val in line[1:-1].split(b',')] numeric_values = [] for raw in raw_values: try: numeric_values.append(int(raw)) # It worked, so move onto the next value. continue except ValueError: # Try again as a float. pass try: numeric_values.append(float(raw)) except ValueError: # Not an int or float, so ignore this value. continue if numeric_values: # There were numeric values in the tuple, so use them! self.add_data(tuple(numeric_values)) # Reset the input buffer. self.input_buffer = [] if lines[-1]: # Append any bytes that are not yet at the end of a line, for # processing next time we read data from self.serial. self.input_buffer.append(lines[-1]) def add_data(self, values): """ Given a tuple of values, ensures there are the required number of line series, add the data to the line series, update the range of the chart so the chart displays nicely. """ # Store incoming data to dump as CSV at the end of the session. self.raw_data.append(values) # Check the number of incoming values. if len(values) != len(self.series): # Adjust the number of line series. value_len = len(values) series_len = len(self.series) if value_len > series_len: # Add new line series. for i in range(value_len - series_len): new_series = QLineSeries() self.chart.addSeries(new_series) self.chart.setAxisX(self.axis_x, new_series) self.chart.setAxisY(self.axis_y, new_series) self.series.append(new_series) self.data.append(deque([0] * self.max_x)) else: # Remove old line series. for old_series in self.series[value_len:]: self.chart.removeSeries(old_series) self.series = self.series[:value_len] self.data = self.data[:value_len] # Add the incoming values to the data to be displayed, and compute # max range. max_ranges = [] for i, value in enumerate(values): self.data[i].appendleft(value) max_ranges.append(max([max(self.data[i]), abs(min(self.data[i]))])) if len(self.data[i]) > self.max_x: self.data[i].pop() # Re-scale y-axis. max_y_range = max(max_ranges) y_range = bisect.bisect_left(self.y_ranges, max_y_range) if y_range < len(self.y_ranges): self.max_y = self.y_ranges[y_range] elif max_y_range > self.max_y: self.max_y += self.max_y elif max_y_range < self.max_y / 2: self.max_y = self.max_y / 2 self.axis_y.setRange(-self.max_y, self.max_y) # Ensure floats are used to label y axis if the range is small. if self.max_y <= 5: self.axis_y.setLabelFormat("%2.2f") else: self.axis_y.setLabelFormat("%d") # Update the line series with the data. for i, line_series in enumerate(self.series): line_series.clear() xy_vals = [] for j in range(self.max_x): val = self.data[i][self.max_x - 1 - j] xy_vals.append((j, val)) for point in xy_vals: line_series.append(*point) def set_theme(self, theme): """ Sets the theme / look for the plotter pane. """ if theme == 'day': self.chart.setTheme(QChart.ChartThemeLight) elif theme == 'night': self.chart.setTheme(QChart.ChartThemeDark) else: self.chart.setTheme(QChart.ChartThemeHighContrast)
class QtHistogram(QChartView): def __init__(self, spec): super().__init__(None) self.spec = spec self.chart = QChart() self.chart.setTitle(self.spec.variable) self.chart.legend().hide() self.mainset = QBarSet("") self.mainset.append([0] * len(spec.bins)) self.mainset.setColor( QColor(spec.color[0], spec.color[1], spec.color[2])) self.series = QBarSeries() self.series.append(self.mainset) self.setMinimumWidth(400) self.setMinimumHeight(230) self.y_ranges = [0, 1, 5, 10, 25, 50, 100, 250, 500, 1000] self.max_y = 1000 self.max_y_range = 1000 self.lookback = 30 self.recent_max_y = deque([self.max_y_range] * self.lookback) font = QtGui.QFont() font.setPixelSize(10) self.axis_x = QBarCategoryAxis() self.axis_x.setLabelsAngle(-90) self.axis_x.setLabelsFont(font) self.axis_y = QValueAxis() self.axis_y.setRange(0, self.max_y) self.axis_x.append(map(str, spec.bins)) self.chart.addSeries(self.series) self.chart.setAxisX(self.axis_x, self.series) self.chart.setAxisY(self.axis_y, self.series) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) self._updates_per_second = 10 self._dataset = [] def clear(self): self._dataset = [] def update_data(self, dataset): data = [] for d in dataset: data.append(d) self._dataset = data def redraw(self): if len(self._dataset) > 0: for i in range(len(self._dataset)): self.mainset.replace(i, self._dataset[i]) # Calculate max of current values max_y_range = max(self._dataset) # Store max value self.recent_max_y.appendleft(max_y_range) if len(self.recent_max_y) > self.lookback: self.recent_max_y.pop() # Set max based on the last 30 max values, # to avoid flickering self.max_y_range = max(self.recent_max_y) y_range = bisect.bisect_left(self.y_ranges, self.max_y_range) if y_range < len(self.y_ranges): self.max_y = self.y_ranges[y_range] elif max_y_range > self.max_y: self.max_y += self.max_y elif max_y_range < self.max_y / 2: self.max_y = self.max_y / 2 self.axis_y.setRange(0, self.max_y)
def agg_results(self) -> None: """ Display results in the corresponding chart view. :return: nothing :rtype: None """ # aggregate "other" abundances if self.cbAggResults.isChecked(): agg_abundance = ( self.results.iloc[self.sbAggResults.value():].sum()) agg_abundance["glycoform"] = self.tr("other") self.results_agg = ( self.results.iloc[:self.sbAggResults.value()].append( agg_abundance, ignore_index=True)) else: self.results_agg = self.results # extract x- and y-values from series x_values = list(self.results_agg["glycoform"].str.split(" or").str[0]) y_values_obs = list(self.results_agg["abundance"]) y_values_cor = list(self.results_agg["corr_abundance"]) # assemble the chart bar_set_obs = QBarSet(self.tr("observed")) bar_set_obs.append(y_values_obs) bar_set_obs.setColor(QColor("#225ea8")) bar_set_obs.hovered.connect(self.update_results_label) bar_set_cor = QBarSet(self.tr("corrected")) bar_set_cor.append(y_values_cor) bar_set_cor.setColor(QColor("#41b6c4")) bar_set_cor.hovered.connect(self.update_results_label) bar_series = QBarSeries() bar_series.append([bar_set_obs, bar_set_cor]) x_axis = QBarCategoryAxis() x_axis.append(x_values) x_axis.setTitleVisible(False) x_axis.setLabelsAngle(270) range_min = min( self.results_agg[["abundance", "corr_abundance"]].min().min(), 0) range_min = math.floor(range_min / 20) * 20 range_max = (self.results_agg[["abundance", "corr_abundance"]].max().max()) range_max = math.ceil(range_max / 20) * 20 tick_count = (range_max - range_min) // 20 + 1 y_axis = QValueAxis() y_axis.setRange(range_min, range_max) y_axis.setTickCount(tick_count) y_axis.setTitleText(self.tr("abundance")) y_axis.setLabelFormat("%d") chart = QChart() chart.addSeries(bar_series) chart.setAxisX(x_axis, bar_series) chart.setAxisY(y_axis, bar_series) chart.legend().setVisible(False) chart.setBackgroundRoundness(0) chart.layout().setContentsMargins(0, 0, 0, 0) chart.setMargins(QMargins(5, 5, 5, 5)) self.cvResults.setChart(chart)
class MainInterface(QMainWindow): '''实现 GUI 以及其连接整个程序的功能 @属性说明: @方法说明: @注意: ''' def __init__(self, parent=None): super().__init__(parent) # 父类初始化 self.ui = Ui_main_interface() # 创建UI类 self.ui.setupUi(self) self.showMaximized() # 最大化界面 self.setWindowTitle("疲劳检测") # 界面标题 self.time = QTimer() # 创建定时器 self._connect_slot() # 初始化槽函数连接 self.eye_data_chart_init() # 初始化眼睛闭合数据折线图 self._t = 0 # 用来计数 self._perclos_threshold = 0.3 # 设置初始化阈值 def _connect_slot(self): '''初始化信号与槽的连接 @参数说明: 无 @返回值: 无 @注意: 无 ''' self.ui.btn_start.clicked.connect(self._display) self.time.timeout.connect(self.test) def paintEvent(self, evevt): """绘图软件背景图 Qt里面默认事件处理函数,在界面需要重新绘制时触发 此方法主要是绘制软件的背景图 @参数说明: evevt:Qt默认事件 @返回值: 无 @注意: 无 """ temp_painter = QPainter(self) # 创建背景图QPixmap()对象 soft_background_image = QPixmap("resources/groud.jpg") # 绘制背景图 temp_painter.drawPixmap(0, 0, self.width(), self.height(), soft_background_image) # 执行父类的paintEvent()函数,以便父类执行其内建的一些操作 super().paintEvent(evevt) def eye_data_chart_init(self): '''初始化左右眼闭合程度曲线图表 @参数说明: 无 @返回值: 无 @注意: 无 ''' # 创建 chart 和 chartview self._chart = QChart() self._chart.setTitle("眼睛闭合程度值") # 设置图表标题 self._chartView = QChartView(self) self._chartView.setChart(self._chart) # chart 添加到 chartview # 完成布局 self.ui.horizontalLayout_2.addWidget(self._chartView) ## 创建曲线系列 self._series0 = QLineSeries() self._series1 = QLineSeries() self._series0.setName("左眼曲线") # 设置曲线名 self._series1.setName("右眼曲线") self._chart.addSeries(self._series0) # 序列添加到图表 self._chart.addSeries(self._series1) # 创建坐标轴 self._axis_x = QValueAxis() # x 轴 self._axis_x.setRange(0, 60) # 设置 x 轴坐标范围 self._axis_x.setTitleText("time(secs)") # x 轴标题 self._axis_y = QValueAxis() # y 轴 self._axis_y.setRange(0, 0.5) # 设置 y 轴坐标范围 self._axis_y.setTitleText("value") # y 轴标题 # 为序列设置坐标轴 self._chart.setAxisX(self._axis_x, self._series0) self._chart.setAxisY(self._axis_y, self._series0) self._chart.setAxisX(self._axis_x, self._series1) self._chart.setAxisY(self._axis_y, self._series1) @pyqtSlot(bool) def _display(self, checked): ''' @参数说明: @返回值: @注意: ''' if (checked == False): # 当按键为 False 时,停止检查 self.ui.le_eye_threshold.setEnabled(True) self.ui.btn_start.setText("启动") self.ui.lb_fatigue_detection.setText("检测停止") self.time.stop() else: threshold_str = self.ui.le_eye_threshold.text() # 获得睁闭眼阈值 threshold_str = re.match(r"\d\.\d\d$", threshold_str) # 对睁闭眼阈值做限定 if (threshold_str == None): message_title = "阈值格式错误" message_text = "请输入正确的阈值格式,格式为 x.xx (x 为数字)" QMessageBox.critical(self, message_title, message_text) else: self.ui.btn_start.setText("停止") self.ui.le_eye_threshold.setEnabled(False) model_path = r"E:\make_data\facial" # 人脸关键模型路径 opencv_facial_path = r"E:\Fatigue_Detection\model_data\facial_model\haarcascade_frontalface_default.xml" # 人脸检测模型路径 cap_index = eval( self.ui.cmb_cap_index.currentText()) # 从 combabox 获取设想头索引 # cap_file = r"C:\Users\LWL\Pictures\Camera Roll\WIN_20200503_07_51_19_Pro.mp4" self.facial_data = GetFacialData( tf_model=model_path, facial_model_file=opencv_facial_path, cap_index=cap_index) # 创建 GetFacialData 类 self.time.start(1000) # 设置每次检测的间隔时间 self.ui.lb_fatigue_detection.setText("检测中") self._series0.clear() self._series1.clear() self._t = 0 # 重新开始计数 self._perclos_threshold = eval(threshold_str.group()) def test(self): ret, frame = self.facial_data.get_frame() if (ret == -1): message_title = "摄像头打开失败" message_text = "摄像头打开失败,请检测摄像头索引是否正确" self.time.stop() QMessageBox.critical(self, message_title, message_text) if (ret == -2): message_title = "获取帧失败" message_text = "从摄像头获取帧失败,请重启软件" self.time.stop() QMessageBox.critical(self, message_title, message_text) else: frame = cv2.medianBlur(frame, 5) ret, rect = self.facial_data.get_facial(frame) h, w = frame.shape[:2] if (ret == -1): frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) temp_q_image = QImage(frame, w, h, QImage.Format_RGB888) # 在 lb_display 中显示图片 self.ui.lb_display.setPixmap(QPixmap.fromImage(temp_q_image)) self.ui.lb_facial_number.setText(str(rect)) # 显示当前检测人脸数 else: self.ui.lb_facial_number.setText("1") # 显示当前检测人脸数 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) facial = frame[rect[2]:rect[3], rect[0]:rect[1]] image = cv2.cvtColor(facial, cv2.COLOR_RGB2GRAY) image_h, image_w = image.shape[:2] image = cv2.resize(image, (150, 150)) image = np.reshape(image, [1, 150, 150, 1]) image = image / 255. facial_keypoints = self.facial_data.get_result(image) facial_keypoints = (facial_keypoints[0] + 1) / 2 facial_keypoints[:: 2] = facial_keypoints[::2] * image_w + rect[0] facial_keypoints[ 1::2] = facial_keypoints[1::2] * image_h + rect[2] # 圈出人脸范围 facial = cv2.rectangle(frame, (rect[0], rect[2]), (rect[1], rect[3]), (255, 0, 0), 1) # 将人脸多特征点标记到图片上 for i in range(12): facial = cv2.circle(frame, (int(facial_keypoints[2 * i]), int(facial_keypoints[2 * i + 1])), 2, (255, 0, 0), -1) # 进行打点 # 获得左右眼的闭合程度 eye_process_data = result_process.eyes_process( facial_keypoints) # 添加点到图表上 self._series0.append(self._t, eye_process_data[0]) self._series1.append(self._t, eye_process_data[1]) # 在label上显示左右眼计算值 self.ui.lb_left_eye_figure.setText(str( eye_process_data[0])) # 显示左眼的计算值 self.ui.lb_right_eye_figure.setText(str( eye_process_data[1])) # 显示右眼的计算值 temp_q_image = QImage(facial.data, w, h, QImage.Format_RGB888) # 在 lb_display 中显示图片 self.ui.lb_display.setPixmap(QPixmap.fromImage(temp_q_image)) self._t += 1 # 每个 1s 绘制点 if (self._t > 60): # 获取 series0 以及 series1 中所有的数据 left_eye_point = self._series0.pointsVector() right_eye_point = self._series1.pointsVector() # 使用正则表达式提取其中的计算数据 left_eye_data = np.array( re.findall(r"\d+\.\d{2,5}", str(left_eye_point))) right_eye_data = np.array( re.findall(r"\d+\.\d{2,5}", str(right_eye_point))) perclos_judge_result = result_process.perclos_judge( left_eye_data, self._perclos_threshold) # 对 perclos_judge 的结果进行输出 if (perclos_judge_result == -2): self.ui.lb_fatigue_detection.setText("过度疲劳") message_title = "过度疲劳警告提醒" message_text = "为了你的人身安全,请停下手中工作,休息一段时间!" QMessageBox.critical(self, message_title, message_text) # 过度疲劳提醒 elif (perclos_judge_result == -1): self.ui.lb_fatigue_detection.setText("疲劳状态") else: self.ui.lb_fatigue_detection.setText("状态良好") # 清除所有的 series0 以及 series1 数据,重新绘图 self._series0.clear() self._series1.clear() self._t = 0 # 重新开始计数
class MainWindow(QMainWindow, Ui_MainWindow): """ Main application window """ WIDTH = 150 HEIGHT = 50 MARGIN = 5 max_ping = 0 max_loss = 0 def __init__(self, host, history, history_size, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.host = host self.history = history self.history_size = history_size self.setupUi(self) self.setWindowFlag(Qt.WindowStaysOnTopHint) self.position_to_dock() self.series_delay = QLineSeries() self.series_loss = QLineSeries() self.axis_X = QDateTimeAxis() # pylint: disable=invalid-name self.axis_X.setTickCount(3) self.axis_X.setFormat("HH:mm") self.axis_X.setTitleText("Time") self.chart = QChart() self.chart.addSeries(self.series_delay) self.chart.addSeries(self.series_loss) self.chart.setTitle(f"Connection to {self.host}") self.init_series(self.series_delay, "Delay ms") self.init_series(self.series_loss, "Loss %") self.chart.legend().setVisible(False) self.chart.legend().setAlignment(Qt.AlignBottom) self.chart.layout().setContentsMargins(0, 0, 0, 0) self.chart.setBackgroundRoundness(0) self.chart.setMargins(QMargins(0, 0, 0, 0)) self.chartWidget.setChart(self.chart) self.chartWidget.setRenderHint(QPainter.Antialiasing) def init_series(self, series, label): """ Series settings """ self.chart.setAxisX(self.axis_X, series) axis_Y = QValueAxis() # pylint: disable=invalid-name axis_Y.setLabelFormat("%i") axis_Y.setTitleText(label) axis_Y.setRange(0, 100) self.chart.addAxis(axis_Y, Qt.AlignLeft) self.chart.setAxisY(axis_Y, series) def add_series(self, ping, loss): """ Append series data """ self.max_ping = max(ping or 0, self.max_ping) self.max_loss = max(loss, self.max_loss) if self.series_delay.count() > self.history_size: self.series_delay.remove(0) self.series_delay.append( QDateTime.currentDateTime().toMSecsSinceEpoch(), ping or 0) if self.series_loss.count() > self.history_size: self.series_loss.remove(0) self.series_loss.append( QDateTime.currentDateTime().toMSecsSinceEpoch(), loss) self.axis_X.setRange( QDateTime.currentDateTime().addSecs(-self.history), QDateTime.currentDateTime()) self.chart.axisY().setRange(0, self.max_ping + self.MARGIN) def position_to_dock(self): """ Adjust main window position according to it's size and desktop """ desktop_geometry = QDesktopWidget().availableGeometry() self.setGeometry( desktop_geometry.width() - self.width() - self.MARGIN, desktop_geometry.height() - self.height() - self.MARGIN, self.width(), self.height()) def set_labels(self, mean_=None, curr=None, loss=None): """ Update window text """ mean_text = curr_text = loss_text = "No connection" if mean_ is not None: mean_text = f"Mean ping: {mean_}ms" if curr is not None: curr_text = f"Last ping: {curr}ms" if loss is not None: loss_text = f"Ping loss: {loss}%" self.meanLabel.setText(mean_text) self.currLabel.setText(curr_text) self.lossLabel.setText(loss_text) def toggle(self, reason): """ Toggle window visibility """ if reason == QSystemTrayIcon.ActivationReason.DoubleClick: # pylint: disable=no-member self.setVisible(not self.isVisible()) if self.isVisible(): self.activateWindow()
class barChartView(QChartView): def __init__(self, xAxis=[], *args, **kwargs): super(barChartView, self).__init__(*args, **kwargs) self.initChart(xAxis) # line 宽度需要调整 self.lineItem = QGraphicsLineItem(self._chart) pen = QPen(Qt.gray) self.lineItem.setPen(pen) self.lineItem.setZValue(998) self.lineItem.hide() self.cal() # 一些固定计算,减少mouseMoveEvent中的计算量 def cal(self): # 提示widget self.toolTipWidget = GraphicsProxyWidget(self._chart) # 获取x和y轴的最小最大值 axisX, axisY = self._chart.axisX(), self._chart.axisY() self.category_len = len(axisX.categories()) self.min_x, self.max_x = -0.5, self.category_len - 0.5 self.min_y, self.max_y = axisY.min(), axisY.max() # 坐标系中左上角顶点 self.point_top = self._chart.mapToPosition( QPointF(self.min_x, self.max_y)) def setCat(self, data): self.categories = data #初始化 def initChart(self, xAxis): self._chart = QChart() # 调整边距 self._chart.layout().setContentsMargins(0, 0, 0, 0) # 外界 self._chart.setMargins(QMargins(3, 0, 3, 0)) # 内界 self._chart.setBackgroundRoundness(0) self._chart.setBackgroundVisible(False) # 设置主题 self._chart.setTheme(QChart.ChartThemeBlueIcy) # 抗锯齿 self.setRenderHint(QPainter.Antialiasing) # 开启动画效果 self._chart.setAnimationOptions(QChart.SeriesAnimations) self.categories = xAxis self._series = QBarSeries(self._chart) self._chart.addSeries(self._series) self._chart.createDefaultAxes() # 创建默认的轴 self._axis_x = QBarCategoryAxis(self._chart) self._axis_x.append(self.categories) self._axis_y = QValueAxis(self._chart) self._axis_y.setTitleText("任务数") self._axis_y.setRange(0, 10) self._chart.setAxisX(self._axis_x, self._series) self._chart.setAxisY(self._axis_y, self._series) # chart的图例 legend = self._chart.legend() legend.setVisible(True) self.setChart(self._chart) def mouseMoveEvent(self, event): super(barChartView, self).mouseMoveEvent(event) pos = event.pos() # 把鼠标位置所在点转换为对应的xy值 x = self._chart.mapToValue(pos).x() y = self._chart.mapToValue(pos).y() index = round(x) # 得到在坐标系中的所有bar的类型和点 serie = self._chart.series()[0] bars = [ (bar, bar.at(index)) for bar in serie.barSets() if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y ] # print(bars) if bars: right_top = self._chart.mapToPosition( QPointF(self.max_x, self.max_y)) # 等分距离比例 step_x = round( (right_top.x() - self.point_top.x()) / self.category_len) posx = self._chart.mapToPosition(QPointF(x, self.min_y)) self.lineItem.setLine(posx.x(), self.point_top.y(), posx.x(), posx.y()) self.lineItem.show() try: title = self.categories[index] except: title = "" t_width = self.toolTipWidget.width() t_height = self.toolTipWidget.height() # 如果鼠标位置离右侧的距离小于tip宽度 x = pos.x() - t_width if self.width() - \ pos.x() - 20 < t_width else pos.x() # 如果鼠标位置离底部的高度小于tip高度 y = pos.y() - t_height if self.height() - \ pos.y() - 20 < t_height else pos.y() self.toolTipWidget.show(title, bars, QPoint(x, y)) else: self.toolTipWidget.hide() self.lineItem.hide()
def main(): import sys from PyQt5.QtChart import QChart, QChartView from PyQt5.QtCore import Qt from PyQt5.QtGui import QPainter from PyQt5.QtWidgets import QApplication, QMainWindow import numpy as np @pyqtSlot(QPointF, bool) def help(point, state): print('help') app = QApplication(sys.argv) size = 50 bdr = 2 opc = 0.3 special = False markers = [ XMarkerCircle(), XMarkerPlus(), XMarkerDash(), XMarkerSquare(), XMarkerDiamond(), XMarkerCross(), XMarkerTriangle() ] # Chart Setup chart = QChart() chart.axisX = QValueAxis() chart.axisY = QValueAxis() chart.axisX.setTickCount(11) chart.axisY.setTickCount(11) chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom) chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) class scatser(QScatterSeries): def __init__(self, parent=None): super(scatser, self).__init__(parent) self.hovered.connect(self.onHovered) self.pen = QPen(Qt.black) @pyqtSlot(QPointF, bool) def onHovered(self, point, state): if state: spoint = self.chart().mapToPosition(point) - QPointF( 0, size / 2) self.ttip = XToolTipLabel('Hello from:\n x: %.1f, y: %.1f' % (point.x(), point.y()), colour=self.color()) self.ttip_proxy = chart.scene().addWidget(self.ttip) w = self.ttip.width() h = self.ttip.height() self.ttip_proxy.setPos(spoint.x() - w / 2.0, spoint.y() - h) self.ttip.updateGeometry() else: self.ttip_proxy.deleteLater() mcount = 0 nm = len(markers) pos = [0.1, 0.3, 0.5, 0.7, 0.9] for i in pos: for j in pos: if mcount == nm: mcount = 0 #print(mcount) m = markers[mcount] m.setBrush(size, size, border=bdr, opacity=opc) ser = scatser() ser.append(i, j) if special: ser.setBorderColor(QColor(1, 1, 1, 1)) ser.setMarkerSize(size) #ser.setMarkerShape(1) ser.setBrush(m) else: xtypemarker(ser, size=size, width=bdr, fillalpha=50) chart.addSeries(ser) chart.setAxisX(chart.axisX, ser) chart.setAxisY(chart.axisY, ser) mcount += 1 chart.axisX.setMin(0) chart.axisY.setMin(0) chart.axisX.setMax(1) chart.axisY.setMax(1) window = QMainWindow() window.setCentralWidget(chartView) window.resize(800, 800) window.show() sys.exit(app.exec_())
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 PlotterPane(QChartView): """ This plotter widget makes viewing sensor data easy! This widget represents a chart that will look for tuple data from the MicroPython REPL, Python 3 REPL or Python 3 code runner and will auto-generate a graph. """ data_flood = pyqtSignal() def __init__(self, theme='day', parent=None): super().__init__(parent) # Holds the raw input to be checked for actionable data to display. self.input_buffer = [] # Holds the raw actionable data detected while plotting. self.raw_data = [] self.setObjectName('plotterpane') self.max_x = 100 # Maximum value along x axis self.max_y = 1000 # Maximum value +/- along y axis self.flooded = False # Flag to indicate if data flooding is happening. # Holds deques for each slot of incoming data (assumes 1 to start with) self.data = [ deque([0] * self.max_x), ] # Holds line series for each slot of incoming data (assumes 1 to start # with). self.series = [ QLineSeries(), ] # Ranges used for the Y axis (up to 1000, after which we just double # the range). self.y_ranges = [1, 5, 10, 25, 50, 100, 250, 500, 1000] # Set up the chart with sensible defaults. self.chart = QChart() self.chart.legend().hide() self.chart.addSeries(self.series[0]) self.axis_x = QValueAxis() self.axis_y = QValueAxis() self.axis_x.setRange(0, self.max_x) self.axis_y.setRange(-self.max_y, self.max_y) self.axis_x.setLabelFormat("time") self.axis_y.setLabelFormat("%d") self.chart.setAxisX(self.axis_x, self.series[0]) self.chart.setAxisY(self.axis_y, self.series[0]) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) def process_bytes(self, data): """ Takes raw bytes and, if a valid tuple is detected, adds the data to the plotter. The the length of the bytes data > 1024 then a data_flood signal is emitted to ensure Mu can take action to remain responsive. """ # Data flooding guards. if self.flooded: return if len(data) > 1024: self.flooded = True self.data_flood.emit() return data = data.replace(b'\r\n', b'\n') self.input_buffer.append(data) # Check if the data contains a Python tuple, containing numbers, on a # single line (i.e. ends with \n). input_bytes = b''.join(self.input_buffer) lines = input_bytes.split(b'\n') for line in lines: if line.startswith(b'(') and line.endswith(b')'): # Candidate tuple. Extract the raw bytes into a numeric tuple. raw_values = [val.strip() for val in line[1:-1].split(b',')] numeric_values = [] for raw in raw_values: try: numeric_values.append(int(raw)) # It worked, so move onto the next value. continue except ValueError: # Try again as a float. pass try: numeric_values.append(float(raw)) except ValueError: # Not an int or float, so ignore this value. continue if numeric_values: # There were numeric values in the tuple, so use them! self.add_data(tuple(numeric_values)) # Reset the input buffer. self.input_buffer = [] if lines[-1]: # Append any bytes that are not yet at the end of a line, for # processing next time we read data from self.serial. self.input_buffer.append(lines[-1]) def add_data(self, values): """ Given a tuple of values, ensures there are the required number of line series, add the data to the line series, update the range of the chart so the chart displays nicely. """ # Store incoming data to dump as CSV at the end of the session. self.raw_data.append(values) # Check the number of incoming values. if len(values) != len(self.series): # Adjust the number of line series. value_len = len(values) series_len = len(self.series) if value_len > series_len: # Add new line series. for i in range(value_len - series_len): new_series = QLineSeries() self.chart.addSeries(new_series) self.chart.setAxisX(self.axis_x, new_series) self.chart.setAxisY(self.axis_y, new_series) self.series.append(new_series) self.data.append(deque([0] * self.max_x)) else: # Remove old line series. for old_series in self.series[value_len:]: self.chart.removeSeries(old_series) self.series = self.series[:value_len] self.data = self.data[:value_len] # Add the incoming values to the data to be displayed, and compute # max range. max_ranges = [] for i, value in enumerate(values): self.data[i].appendleft(value) max_ranges.append(max([max(self.data[i]), abs(min(self.data[i]))])) if len(self.data[i]) > self.max_x: self.data[i].pop() # Re-scale y-axis. max_y_range = max(max_ranges) y_range = bisect.bisect_left(self.y_ranges, max_y_range) if y_range < len(self.y_ranges): self.max_y = self.y_ranges[y_range] elif max_y_range > self.max_y: self.max_y += self.max_y elif max_y_range < self.max_y / 2: self.max_y = self.max_y / 2 self.axis_y.setRange(-self.max_y, self.max_y) # Ensure floats are used to label y axis if the range is small. if self.max_y <= 5: self.axis_y.setLabelFormat("%2.2f") else: self.axis_y.setLabelFormat("%d") # Update the line series with the data. for i, line_series in enumerate(self.series): line_series.clear() xy_vals = [] for j in range(self.max_x): val = self.data[i][self.max_x - 1 - j] xy_vals.append((j, val)) for point in xy_vals: line_series.append(*point) def set_theme(self, theme): """ Sets the theme / look for the plotter pane. """ if theme == 'day': self.chart.setTheme(QChart.ChartThemeLight) elif theme == 'night': self.chart.setTheme(QChart.ChartThemeDark) else: self.chart.setTheme(QChart.ChartThemeHighContrast)
class Chart(QWidget): def __init__(self, ch0Name='ch0', ch1Name='ch1', ch2Name='ch2', ch3Name='ch3'): super(Chart, self).__init__() self.ch0Name = ch0Name self.ch1Name = ch1Name self.ch2Name = ch2Name self.ch3Name = ch3Name self.data = [] self.initUI() def initUI(self): vbox = QVBoxLayout() vbox.addWidget(self.chartUI()) vbox.addWidget(self.controlUI()) self.setLayout(vbox) def chartUI(self): self.chart1 = QLineSeries() self.chart1.setName(self.ch0Name) self.chart1.setPen(QPen(Qt.red)) self.chart2 = QLineSeries() self.chart2.setName(self.ch1Name) self.chart2.setPen(QPen(Qt.darkYellow)) self.chart3 = QLineSeries() self.chart3.setName(self.ch2Name) self.chart3.setPen(QPen(Qt.green)) self.chart4 = QLineSeries() self.chart4.setName(self.ch3Name) self.chart4.setPen(QPen(Qt.blue)) self.chart = QChart() self.chart.addSeries(self.chart1) self.chart.addSeries(self.chart2) self.chart.addSeries(self.chart3) self.chart.addSeries(self.chart4) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setTitle("laser data") self.axis_x = QValueAxis() self.axis_y = QValueAxis() self.axis_x.setTickCount(10) self.axis_y.setTickCount(10) self.axis_x.setLabelFormat('%d') self.axis_y.setLabelFormat('%d') self.axis_x.setRange(0, 1000) self.axis_y.setRange(100, 300) self.chart.setAxisX(self.axis_x, self.chart1) self.chart.setAxisY(self.axis_y, self.chart1) self.chart.setAxisX(self.axis_x, self.chart2) self.chart.setAxisY(self.axis_y, self.chart2) self.chart.setAxisX(self.axis_x, self.chart3) self.chart.setAxisY(self.axis_y, self.chart3) self.chart.setAxisX(self.axis_x, self.chart4) self.chart.setAxisY(self.axis_y, self.chart4) self.chartView = QChartView() self.chartView.setChart(self.chart) self.chartView.setRubberBand(QChartView.RectangleRubberBand) self.chartView.setRenderHint(QPainter.Antialiasing) return self.chartView def controlUI(self): self.autoRefreshCb = QCheckBox('自动刷新') self.autoRefreshCb.setChecked(True) self.ch0Enable = QCheckBox(self.ch0Name) self.ch1Enable = QCheckBox(self.ch1Name) self.ch2Enable = QCheckBox(self.ch2Name) self.ch3Enable = QCheckBox(self.ch3Name) self.ch0Enable.setChecked(True) self.ch1Enable.setChecked(True) self.ch2Enable.setChecked(True) self.ch3Enable.setChecked(True) hbox1 = QHBoxLayout() hbox1.addWidget(self.autoRefreshCb) hbox1.addWidget(self.ch0Enable) hbox1.addWidget(self.ch1Enable) hbox1.addWidget(self.ch2Enable) hbox1.addWidget(self.ch3Enable) self.xDataMinLabel = QLabel('x min:') self.xDataMaxLabel = QLabel('x max:') self.yDataMinLabel = QLabel('y min:') self.yDataMaxLabel = QLabel('y max:') self.xDataMinLine = QLineEdit() self.xDataMaxLine = QLineEdit() self.yDataMinLine = QLineEdit() self.yDataMaxLine = QLineEdit() self.setBtn = QPushButton('设置') hbox = QHBoxLayout() hbox.addWidget(self.xDataMinLabel) hbox.addWidget(self.xDataMinLine) hbox.addWidget(self.xDataMaxLabel) hbox.addWidget(self.xDataMaxLine) hbox.addWidget(self.yDataMinLabel) hbox.addWidget(self.yDataMinLine) hbox.addWidget(self.yDataMaxLabel) hbox.addWidget(self.yDataMaxLine) hbox.addWidget(self.setBtn) mainLayout = QVBoxLayout() mainLayout.addLayout(hbox1) mainLayout.addLayout(hbox) frame = QFrame() frame.setLayout(mainLayout) self.setBtn.clicked.connect(self.setAxisRange) self.ch0Enable.clicked.connect(self.changeCh) self.ch1Enable.clicked.connect(self.changeCh) self.ch2Enable.clicked.connect(self.changeCh) self.ch3Enable.clicked.connect(self.changeCh) return frame # @timethis def update(self): x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() try: for i in range(0, len(x0Data)): if self.ch0Enable.isChecked(): self.chart1.append(QPoint(x0Data[i], y0Data[i])) for i in range(0, len(x1Data)): if self.ch1Enable.isChecked(): self.chart2.append(QPoint(x1Data[i], y1Data[i])) for i in range(0, len(x2Data)): if self.ch2Enable.isChecked(): self.chart3.append(QPoint(x2Data[i], y2Data[i])) for i in range(0, len(x3Data)): if self.ch3Enable.isChecked(): self.chart4.append(QPoint(x3Data[i], y3Data[i])) except: logging.debug('y0Data is %s' % y0Data) logging.debug('y1Data is %s' % y1Data) logging.debug('y2Data is %s' % y2Data) logging.debug('y3Data is %s' % y3Data) self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() # self.chartView.update() if self.autoRefreshCb.isChecked(): self.fillAxisRange() self.setAxisRange() def fillAxisRange(self): x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data tmp = [min(x0Data), min(x1Data), min(x2Data), min(x3Data)] xDataMin = min(tmp) tmp = [max(x0Data), max(x1Data), max(x2Data), max(x3Data)] xDataMax = max(tmp) tmp = [min(y0Data), min(y1Data), min(y2Data), min(y3Data)] yDataMin = min(tmp) tmp = [max(y0Data), max(y1Data), max(y2Data), max(y3Data)] yDataMax = max(tmp) xDataAvr = (xDataMin + xDataMax) // 2 yDataAvr = (yDataMin + yDataMax) // 2 self.xDataMinLine.setText(str(xDataAvr - xDataAvr*6//5)) self.xDataMaxLine.setText(str(xDataAvr + xDataAvr*6//5)) self.yDataMinLine.setText(str(yDataAvr - yDataAvr*6//5)) self.yDataMaxLine.setText(str(yDataAvr + yDataAvr*6//5)) @pyqtSlot() def setAxisRange(self): if self.xDataMinLine.text() and self.xDataMaxLine.text() and \ self.yDataMinLine.text() and self.yDataMaxLine.text(): self.axis_x.setRange(int(self.xDataMinLine.text()), int(self.xDataMaxLine.text())) self.axis_y.setRange(int(self.yDataMinLine.text()), int(self.yDataMaxLine.text())) else: QMessageBox.warning(self, '警告', '缺少参数') @pyqtSlot() def changeCh(self): self.chart1.clear() self.chart2.clear() self.chart3.clear() self.chart4.clear() x0Data, y0Data, x1Data, y1Data, x2Data, y2Data, x3Data, y3Data = self.data for i in range(0, len(x0Data)): if self.ch0Enable.isChecked(): self.chart1.append(QPoint(x0Data[i], y0Data[i])) for i in range(0, len(x1Data)): if self.ch1Enable.isChecked(): self.chart2.append(QPoint(x1Data[i], y1Data[i])) for i in range(0, len(x2Data)): if self.ch2Enable.isChecked(): self.chart3.append(QPoint(x2Data[i], y2Data[i])) for i in range(0, len(x3Data)): if self.ch3Enable.isChecked(): self.chart4.append(QPoint(x3Data[i], y3Data[i]))