def create_piechart(self, series, animation=True):
        if animation:
            animation_type = QChart.AllAnimations
        else:
            animation_type = QChart.NoAnimation

        font_title = QFont()
        font_title.setBold(True)
        font_title.setPointSize(13)

        # define the chart properties
        chart = QChart()
        chart.addSeries(series)
        chart.createDefaultAxes()
        chart.setAnimationOptions(animation_type)
        chart.setBackgroundVisible(False)
        chart.setMargins(QMargins())
        chart.setTitle("Prediction Distribution")
        chart.setTitleFont(font_title)

        font_legend = QFont()
        font_legend.setBold(True)

        # define legend properties
        chart.legend().show()
        chart.legend().setVisible(True)
        chart.legend().setAlignment(Qt.AlignBottom)
        chart.legend().setFont(font_legend)
        self.ui.piechart.setChart(chart)
        self.ui.piechart.setRenderHint(QPainter.Antialiasing)
        QApplication.processEvents()
Exemple #2
0
    def build_plot(self,
                   data,
                   title,
                   is_legend_visible=False,
                   series_name=None):
        axis_x, axis_y = self.make_axis()

        chart = QChart()
        if self.no_margins:
            chart.setMargins(QMargins(0, 0, 0, 0))

        self.clean()

        if data != None:
            self.lineSeries = self.fill_series(data)
            self.lineSeries.setName(series_name)

        chart.addSeries(self.lineSeries)
        chart.legend().setVisible(is_legend_visible)
        chart.setTitle(title)
        chart.addAxis(axis_x, Qt.AlignBottom)
        chart.addAxis(axis_y, Qt.AlignLeft)

        self.lineSeries.attachAxis(axis_x)
        self.lineSeries.attachAxis(axis_y)

        self.setChart(chart)
Exemple #3
0
    def create_barchart(self, series, max_val, animation=True):
        if animation:
            animation_type = QChart.AllAnimations
        else:
            animation_type = QChart.NoAnimation

        chart = QChart()
        chart.addSeries(series)
        chart.setBackgroundVisible(False)
        chart.setMargins(QMargins())
        chart.setAnimationOptions(animation_type)

        labels = ('Human', 'Bot')

        axisX = QBarCategoryAxis()
        axisX.append(labels)

        axisY = QValueAxis()
        axisY.setTitleText("Percentage (%)")
        axisY.setRange(0, max_val)

        chart.addAxis(axisX, Qt.AlignBottom)
        chart.addAxis(axisY, Qt.AlignLeft)

        font = QFont()
        font.setPointSize(9)

        chart.legend().setVisible(True)
        chart.legend().setFont(font)
        chart.legend().setAlignment(Qt.AlignBottom)

        self.ui.barchart.setChart(chart)
        self.ui.barchart.setRenderHint(QPainter.Antialiasing)
Exemple #4
0
    def build_multiple_plot(self, first_data, second_data, title):
        axis_x, axis_y = self.make_axis()

        chart = QChart()
        if self.no_margins:
            chart.setMargins(QMargins(0, 0, 0, 0))

        self.clean()

        first_lineseries = self.fill_series(first_data)
        second_lineseries = self.fill_series(second_data)

        chart.addSeries(first_lineseries)
        chart.addSeries(second_lineseries)
        chart.addAxis(axis_x, Qt.AlignBottom)
        chart.addAxis(axis_y, Qt.AlignLeft)
        chart.legend().setVisible(False)
        chart.setTitle(title)

        first_lineseries.attachAxis(axis_x)
        first_lineseries.attachAxis(axis_y)

        second_lineseries.attachAxis(axis_x)
        second_lineseries.attachAxis(axis_y)

        first_lineseries.setPointsVisible(True)
        second_lineseries.setPointsVisible(True)

        self.setChart(chart)
Exemple #5
0
    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)
Exemple #6
0
class pieChartView(QChartView):
    def __init__(self, *args, **kwargs):
        super(pieChartView, self).__init__(*args, **kwargs)
        self.initChart()
        self.refresh()

    def initChart(self):
        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._series = QPieSeries()
        self._series.setPieSize(0.8)
        self._chart.addSeries(self._series)
        self.setChart(self._chart)

    def refresh(self):
        # 提示widget
        self.toolTipWidget = GraphicsProxyWidget(self._chart)

    def mouseMoveEvent(self, event):
        super(pieChartView, self).mouseMoveEvent(event)
        pos = event.pos()
        x = pos.x()
        y = pos.y()
        # 得到在坐标系中的所有区域
        self.min_x, self.max_x = self._chart.geometry().width(
        ) * 0.2, self._chart.geometry().width() * 0.8
        self.min_y, self.max_y = self._chart.geometry().height(
        ) * 0.2, self._chart.geometry().height() * 0.9
        serie = self._chart.series()[0]
        slices = [(slice, slice.value()) for slice in serie.slices()]
        if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y:
            t_width = self.toolTipWidget.width()
            t_height = self.toolTipWidget.height()
            title = "数据组成"
            # 如果鼠标位置离右侧的距离小于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, slices, QPoint(x, y))
        else:
            self.toolTipWidget.hide()
Exemple #7
0
    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)
Exemple #8
0
    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 create_histogram(self, series, max_val, animation=True):
        if animation:
            animation_type = QChart.AllAnimations
        else:
            animation_type = QChart.NoAnimation

        font_title = QFont()
        font_title.setBold(True)
        font_title.setPointSize(13)

        chart = QChart()
        chart.addSeries(series)
        chart.setTitle('Histogram of Bot Scores')
        chart.setTitleFont(font_title)
        chart.setBackgroundVisible(False)
        chart.setMargins(QMargins())
        chart.setAnimationOptions(animation_type)

        scores = ('0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8',
                  '0.9')

        axisX = QBarCategoryAxis()
        axisX.setTitleText("Bot Score")
        axisX.append(scores)

        axisY = QValueAxis()
        axisY.setTitleText("Number Of Tweets")
        axisY.setRange(0, max_val)

        chart.addAxis(axisX, Qt.AlignBottom)
        chart.addAxis(axisY, Qt.AlignLeft)

        chart.legend().setVisible(False)
        chart.legend().setAlignment(Qt.AlignBottom)

        self.ui.histogram.setChart(chart)
        self.ui.histogram.setRenderHint(QPainter.Antialiasing)
        QApplication.processEvents()
Exemple #10
0
class MonitorTab(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(1550, 750)

        self.gridLayout_2 = QtWidgets.QGridLayout()
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")

        self.chart4 = QChart()
        self.chart4.setMargins(QMargins(0, 0, 0, 0))
        self.chart4.setBackgroundVisible(False)
        self.chart4.legend().setVisible(False)
        self.chartView4 = QChartView(self.chart4)
        self.gridLayout.addWidget(self.chartView4, 7, 0, 1, 1)

        self.chart3 = QChart()
        self.chart3.setMargins(QMargins(0, 0, 0, 0))
        self.chart3.setBackgroundVisible(False)
        self.chart3.legend().setVisible(False)
        self.chartView3 = QChartView(self.chart3)
        self.gridLayout.addWidget(self.chartView3, 5, 0, 1, 1)

        self.chart2 = QChart()
        self.chart2.setMargins(QMargins(0, 0, 0, 0))
        self.chart2.setBackgroundVisible(False)
        self.chart2.legend().setVisible(False)
        self.chartView2 = QChartView(self.chart2)
        self.gridLayout.addWidget(self.chartView2, 3, 0, 1, 1)

        self.chart1 = QChart()
        self.chart1.setMargins(QMargins(0, 0, 0, 0))
        self.chart1.setBackgroundVisible(False)
        self.chartView = QChartView(self.chart1)
        self.chart1.legend().setVisible(False)
        self.gridLayout.addWidget(self.chartView, 1, 0, 1, 1)

        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "MyForm"))
Exemple #11
0
    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)
Exemple #12
0
class Simulator(QtWidgets.QMainWindow, gui.Ui_MainWindow):
    def __init__(self):
        super().__init__()

        self.__car = car.motion()
        self.__car.param.fromJSON(car.defaultParams())
        self.__canbus = None

        self.__translator = QTranslator(self)

        self.setupUi(self)

        self.positionChart = QChart()
        self.positionSeries = QLineSeries()        

        self.speedChart = QChart()
        self.speedSeries = QLineSeries()

        self.fuelChart = QChart()
        self.fuelSeries = QLineSeries()

        self.engineChart = QChart()
        self.engineSeries = QLineSeries()

        self.positionChart.addSeries(self.positionSeries)
        self.speedChart.addSeries(self.speedSeries)
        self.fuelChart.addSeries(self.fuelSeries)
        self.engineChart.addSeries(self.engineSeries)

        self.positionChart.legend().hide()
        self.speedChart.legend().hide()
        self.fuelChart.legend().hide()
        self.engineChart.legend().hide()   

        self.positionChart.createDefaultAxes()
        self.speedChart.createDefaultAxes()
        self.fuelChart.createDefaultAxes()
        self.engineChart.createDefaultAxes()
        
        self.positionChart.setTitle("Position")
        self.speedChart.setTitle("Speed")
        self.fuelChart.setTitle("Fuel")
        self.engineChart.setTitle("Engine")

        self.positionChart.setMargins(QMargins())
        self.speedChart.setMargins(QMargins())
        self.fuelChart.setMargins(QMargins())
        self.engineChart.setMargins(QMargins())

        self.positionChartW.setChart(self.positionChart)
        self.speedChartW.setChart(self.speedChart)
        self.fuelChartW.setChart(self.fuelChart)
        self.engineChartW.setChart(self.engineChart)

        self.populateFields()

        for file in os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lang')):
            if file.startswith('carSim_') and file.endswith('.qm'):
                self.langSelector.addItem(file[7:-3])

    def changeEvent(self, event):
        if event.type() == QEvent.LanguageChange:
            self.retranslateUi(self)
        super().changeEvent(event)

    @pyqtSlot(str)
    def on_langSelector_currentTextChanged(self, lang):
        if lang:
            self.__translator.load(QLocale(lang), 'carSim', '_', 'lang', '.qm')
            QtWidgets.QApplication.instance().installTranslator(self.__translator)
        else:
            QtWidgets.QApplication.instance().removeTranslator(self.__translator)
    
    @pyqtSlot()
    def on_resetSimulationButton_clicked(self):
        self.__car = car.motion()
        self.__car.param.fromJSON(car.defaultParams())

        self.positionSeries.clear()
        self.speedSeries.clear()
        self.fuelSeries.clear()
        self.engineSeries.clear()

        self.populateFields()

    @pyqtSlot()
    def on_makeStepButton_clicked(self):
        try:
            # self.__car.setThrottle(self.engineField.text())
            self.__car.makeStep()
            # motionMessage=can.Message(arbitration_id=18,is_extended_id=False,data=self.__car.getCanBytes()[:])
            motionMessage = car.canMsg(
                StdId=18, Data=self.__car.getCanBytes()[:])
            print(motionMessage)
            if (self.__canbus is not None and self.__canbus.connected == True):
                self.__canbus.sendMsg(motionMessage)
            with open('log.dat', 'a') as outfile:
                outfile.write("%.1f\t%f\t%f\t%f\n" % (self.__car.getSimTime(),
                                                      self.__car.getSimDistance(), self.__car.getSimSpeed(), self.__car.getSimFuel()))
        except Exception as e:
            QtWidgets.QMessageBox.warning(
                self, _translate("Dialog", "Error"), str(e))

        self.populateFields()
        if float(self.timeField.text()) >= 240:
            if self.simulationStart.isChecked() == True:
                self.simulationStart.click()

    def populateFields(self):
        self.timeField.setText(f"{self.__car.getSimTime():.2f}")
        self.positionField.setText(f"{self.__car.getSimDistance():.2f}")
        self.speedField.setText(f"{self.__car.getSimSpeed():.2f}")
        self.fuelField.setText(f"{self.__car.getSimFuel():.2f}")
        if (self.__canbus is not None and self.__canbus.connected == True):
            self.engineField.setText(f"{self.__car.getThrottle():.2f}")

        xax = self.positionChart.axisX()

        if(self.__car.getSimTime()>self.positionChart.axisX().max()):
            self.positionChart.axisX().setMax(self.__car.getSimTime())
            self.speedChart.axisX().setMax(self.__car.getSimTime())
            self.fuelChart.axisX().setMax(self.__car.getSimTime())
            self.engineChart.axisX().setMax(self.__car.getSimTime())
        #elif(self.__car.getSimTime()<self.positionChart.axisX().min()):
        #    self.positionChart.axisX().setMin(self.__car.getSimTime())
        #    self.speedChart.axisX().setMin(self.__car.getSimTime())
        #    self.fuelChart.axisX().setMin(self.__car.getSimTime())
        #    self.engineChart.axisX().setMin(self.__car.getSimTime())

        if(self.__car.getSimDistance()>self.positionChart.axisY().max()):
            self.positionChart.axisY().setMax(self.__car.getSimDistance())
        elif(self.__car.getSimSpeed()<self.speedChart.axisY().min()):
            self.positionChart.axisY().setMin(self.__car.getSimDistance())

        if(self.__car.getSimSpeed()>self.speedChart.axisY().max()):
            self.speedChart.axisY().setMax(self.__car.getSimSpeed())
        elif(self.__car.getSimSpeed()<self.speedChart.axisY().min()):
            self.speedChart.axisY().setMin(self.__car.getSimSpeed())

        if(self.__car.getSimFuel()>self.fuelChart.axisY().max()):
            self.fuelChart.axisY().setMax(self.__car.getSimFuel())
        elif(self.__car.getSimFuel()<self.fuelChart.axisY().min()):
            self.fuelChart.axisY().setMin(self.__car.getSimFuel())

        self.positionSeries.append(self.__car.getSimTime(),self.__car.getSimDistance())
        self.speedSeries.append(self.__car.getSimTime(),self.__car.getSimSpeed())
        self.fuelSeries.append(self.__car.getSimTime(),self.__car.getSimFuel())
        self.engineSeries.append(self.__car.getSimTime(),self.__car.getThrottle())

    @pyqtSlot(str)
    def on_engineField_textEdited(self,newEngineValue):
        try:
            self.__car.setThrottle(newEngineValue)
        except:
            pass

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        self.AboutDialog = QtWidgets.QDialog()
        self.AboutDialog.ui = gui.Ui_AboutDialog()
        self.AboutDialog.ui.setupUi(self.AboutDialog)
        self.AboutDialog.setAttribute(Qt.WA_DeleteOnClose)
        self.AboutDialog.exec_()

    @pyqtSlot()
    def on_actionExport_Settings_triggered(self):
        filename, _ = QtWidgets.QFileDialog.getSaveFileName(
            self, _translate("Dialog", "Save Config"), ".", filter=_translate("Dialog", "Config Files (*.json)")+";;"+_translate("Dialog", "All Files(*.*)"))
        if filename:
            fp = open(filename, 'w')
            self.__car.param.toJSON(file=fp)
            fp.close()

    @pyqtSlot()
    def on_actionImport_Settings_triggered(self):
        filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, _translate("Dialog", "Open Config"), ".", filter=_translate("Dialog", "Config Files (*.json)")+";;"+_translate("Dialog", "All Files(*.*)"))
        if filename:
            fp = open(filename, 'r')
            self.__car.param.fromJSON(fp)
            fp.close()

    @pyqtSlot()
    def on_refreshAvailablePorts_clicked(self):
        ports = serial.tools.list_ports.comports()
        self.availablePorts.clear()
        for port, desc, hwid in sorted(ports):
            self.availablePorts.addItem(desc, port)

    @pyqtSlot(bool)
    def on_connectPort_clicked(self, state):
        if state:
            try:
                self.__canbus = car.myCan(self.availablePorts.currentData(), [
                                          self.canReceived.appendPlainText], [
                                          self.__car.setSwitchingPoint], loopTime=0.025)
                self.__watch = QTimer(self)
                self.__watch.setInterval(1000)
                self.__watch.timeout.connect(self.syncTime)
                self.__watch.start()
            except Exception as e:
                self.connectPort.setChecked(False)
                QtWidgets.QMessageBox.critical(
                    self, _translate("Dialog", "Error"), str(e))
            else:
                self.connectPort.setText(
                    _translate("MainWindow", "Disconnect"))
                self.canInterfaceTypes.setEnabled(False)
                self.availablePorts.setEnabled(False)
                self.refreshAvailablePorts.setEnabled(False)

        else:
            self.connectPort.setText(_translate("MainWindow", "Connect"))
            self.__canbus = None
            del(self.__watch)
            self.canInterfaceTypes.setEnabled(True)
            self.availablePorts.setEnabled(True)
            self.refreshAvailablePorts.setEnabled(True)

    @pyqtSlot()
    def syncTime(self):
        self.__canbus.sendMsg(car.canMsg(StdId=0, Data=int(
            self.__car.getSimTime()*1000.0).to_bytes(4, 'little')))

    @pyqtSlot(bool)
    def on_simulationStart_clicked(self, state):
        if state:
            self.__ticker = QTimer(self)
            self.__ticker.setInterval(100)
            self.__ticker.timeout.connect(self.on_makeStepButton_clicked)
            self.__ticker.start()
            self.__car.setThrottle(1)
            self.simulationStart.setText(
                _translate("MainWindow", "Stop Simulation!"))
            lapData = 1
            with open('log.dat', 'a') as outfile:
                outfile.write("%.1f\t%f\t%f\t%f\n" % (self.__car.getSimTime(),
                                                      self.__car.getSimDistance(), self.__car.getSimSpeed(), self.__car.getSimFuel()))
        

        else:
            self.__ticker.stop()
            self.simulationStart.setText(
                _translate("MainWindow", "Start Simulation!"))
            lapData = 0

        lapMessage = car.canMsg(StdId=32, Data=[lapData])
        print(lapMessage)
        
        if (self.__canbus is not None and self.__canbus.connected == True):
            self.__canbus.sendMsg(lapMessage)
Exemple #13
0
class KLineChartView(QChartView):

    # QCandlestickSeries的hovered的信号响应后传递日期出去
    candles_hovered = pyqtSignal(bool, str)

    def __init__(self, data: pd.DataFrame):
        super(KLineChartView, self).__init__()
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self._chart = QChart()
        self._series = QCandlestickSeries()
        self._stocks = data
        self._category = list()
        self._count = None

        self.init_chart()
        self._zero_value = (0, self._chart.axisY().min())
        self._max_value = (len(self._chart.axisX().categories()),
                           self._chart.axisY().max())
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        # 计算x轴单个cate的宽度,用来处理横线不能画到边界
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)

        self._series.hovered.connect(self.on_series_hovered)

    def on_series_hovered(self, status, candles_set):
        trade_date = time.strftime('%Y%m%d',
                                   time.localtime(candles_set.timestamp()))
        self.candles_hovered.emit(status, trade_date)

    def set_name(self, name):
        self._series.setName(name)

    def clear_series_values(self):
        self._series.clear()
        self._chart.axisY().setRange(0, 10)
        self._chart.axisX().setCategories(list())
        self._stocks = None

    def add_series_values(self, data: pd.DataFrame, is_init=False):
        self._stocks = data
        self._category = self._stocks['trade_date']
        self._count = len(self._category)
        for _, stock in self._stocks.iterrows():
            time_p = datetime.datetime.strptime(stock['trade_date'], '%Y%m%d')
            time_p = float(time.mktime(time_p.timetuple()))
            _set = QCandlestickSet(float(stock['open']), float(stock['high']),
                                   float(stock['low']), float(stock['close']),
                                   time_p, self._series)
            self._series.append(_set)

        if not is_init:
            self._stocks = data
            self._category = self._stocks['trade_date']
            axis_x = self._chart.axisX()
            axis_y = self._chart.axisY()
            axis_x.setCategories(self._category)
            max_p = self._stocks[['high', 'low']].stack().max()
            min_p = self._stocks[['high', 'low']].stack().min()
            axis_y.setRange(min_p * 0.99, max_p * 1.01)
            self._zero_value = (0, self._chart.axisY().min())
            self._max_value = (len(self._chart.axisX().categories()),
                               self._chart.axisY().max())
            # 计算x轴单个cate的宽度,用来处理横线不能画到边界
            self._cate_width = (self._max_point.x() -
                                self._zero_point.x()) / len(self._category)

    def resizeEvent(self, event):
        super(KLineChartView, self).resizeEvent(event)
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)

    def max_point(self):
        return QPointF(self._max_point.x() + self._cate_width / 2,
                       self._max_point.y())

    def min_point(self):
        return QPointF(self._zero_point.x() - self._cate_width / 2,
                       self._zero_point.y())

    def init_chart(self):
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        self._series.setIncreasingColor(QColor(Qt.red))
        self._series.setDecreasingColor(QColor(Qt.green))
        self._series.setName(self._stocks['name'].iloc[0])
        self.add_series_values(self._stocks, True)
        self._chart.addSeries(self._series)

        self._chart.createDefaultAxes()
        self._chart.setLocalizeNumbers(True)
        axis_x = self._chart.axisX()
        axis_y = self._chart.axisY()
        axis_x.setGridLineVisible(False)
        axis_y.setGridLineVisible(False)
        axis_x.setCategories(self._category)
        axis_x.setLabelsVisible(False)
        axis_x.setVisible(False)
        max_p = self._stocks[['high', 'low']].stack().max()
        min_p = self._stocks[['high', 'low']].stack().min()
        axis_y.setRange(min_p * 0.99, max_p * 1.01)

        # chart的图例
        legend = self._chart.legend()
        # 设置图例由Series来决定样式
        legend.setMarkerShape(QLegend.MarkerShapeFromSeries)

        self.setChart(self._chart)
        # 设置外边界全部为0
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # 设置内边界的bottom为0
        margins = self._chart.margins()
        self._chart.setMargins(QMargins(margins.left(), 0, margins.right(), 0))
        # 设置背景区域无圆角
        self._chart.setBackgroundRoundness(0)
class QIndex_gasList(QDialog):
    username = ''
    person_id = ''
    url = ''
    gas = []

    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Index_gasList()
        self.ui.setupUi(self)

        self.model = QStringListModel(self)
        self.ui.listView.setModel(self.model)
        self.ui.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        #self.ui.listView.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked)

        self.__createChart()

    def setInfo(self, username, person_id, url):
        self.username = username
        self.person_id = person_id
        self.url = url

        #开始查询该用户的所有气体文件,用list变量gas保存
        list_gasInfo = requests.get(self.url + '/person/getGasInfo/' +
                                    str(self.person_id))
        self.gas = eval(list_gasInfo.text)

        #开始将数据添加进list中
        for i in self.gas:
            self.addItem(i["save_time"])

    def addItem(self, name):  #向list添加数据
        #在尾部插入一空行
        lastRow = self.model.rowCount()
        self.model.insertRow(lastRow)
        #给该空行设置显示
        index = self.model.index(lastRow, 0)
        self.model.setData(index, name, Qt.DisplayRole)
        #选中该行
        self.ui.listView.setCurrentIndex(index)

    def on_listView_clicked(self, index):  #如果某条数据信息被点击,则向绘图框发送信息
        self.showGas(self.gas[self.ui.listView.currentIndex().row()])
        self.__prepareData()

    def showGas(self, gasData):  #接收gas数据,并在页面右侧进行显示
        #首先向五个Edit设置数据
        sensor = self.ui.sensorBox.currentIndex()
        self.ui.timeEdit.setText(gasData["gas_time"])
        self.ui.maxEdit.setText(str(eval(gasData["gas_max"])[sensor]))
        self.ui.minEdit.setText(str(eval(gasData["gas_min"])[sensor]))
        self.ui.oriEdit.setText(str(eval(gasData["gas_ori"])[sensor]))
        self.ui.extrEdit.setText(str(eval(gasData["gas_extrTime"])[sensor]))

    def on_sensorBox_currentIndexChanged(self):
        gasData = self.gas[self.ui.listView.currentIndex().row()]
        sensor = self.ui.sensorBox.currentIndex()
        self.ui.timeEdit.setText(gasData["gas_time"])
        self.ui.maxEdit.setText(str(eval(gasData["gas_max"])[sensor]))
        self.ui.minEdit.setText(str(eval(gasData["gas_min"])[sensor]))
        self.ui.oriEdit.setText(str(eval(gasData["gas_ori"])[sensor]))
        self.ui.extrEdit.setText(str(eval(gasData["gas_extrTime"])[sensor]))

    def __createChart(self):
        self.__chart = QChart()
        self.ui.chartView.setChart(self.__chart)
        self.__chart.legend().setVisible(False)  #隐藏图例
        self.__chart.setMargins(QMargins(0, 0, 0, 0))  #把间距设置到最小

        #初始化线条数组
        series = [QLineSeries() for _ in range(15)]
        color = [
            '#FF88C2', '#FF8888', '#FFA488', '#FFBB66', '#FFDD55', '#FFFF77',
            '#DDFF77', '#BBFF66', '#66FF66', '#77FFCC', '#77FFEE', '#66FFFF',
            '#77DDFF', '#99BBFF', '#9999FF'
        ]

        #设置线条颜色形状
        pen = QPen()
        pen.setStyle(Qt.SolidLine)
        pen.setWidth(2)
        for i in range(15):
            pen.setColor(QColor(color[i]))
            series[i].setPen(pen)

        #向表格添加线条
        for i in range(15):
            self.__chart.addSeries(series[i])

        #设置坐标轴
        axisX = QValueAxis()
        #self.__curAxis=axisX       #当前坐标轴
        axisX.setRange(0, 200)  #设置坐标轴范围
        axisX.setLabelFormat("%d")  #标签格式
        axisX.setTickCount(5)  #主分隔个数
        axisX.setMinorTickCount(4)
        axisX.setGridLineVisible(True)
        axisX.setMinorGridLineVisible(False)

        axisY = QValueAxis()
        axisY.setRange(0, 1024)
        axisY.setLabelFormat("%d")  #标签格式
        axisY.setTickCount(5)
        axisY.setMinorTickCount(4)
        axisY.setGridLineVisible(True)
        axisY.setMinorGridLineVisible(False)

        self.__chart.addAxis(axisX, Qt.AlignBottom)  #坐标轴添加到图表,并指定方向
        self.__chart.addAxis(axisY, Qt.AlignLeft)

        for i in range(15):
            series[i].attachAxis(axisX)
            series[i].attachAxis(axisY)

    def __prepareData(self):  ##为序列设置数据点
        chart = self.ui.chartView.chart()  #获取chartView中的QChart对象
        series = [QLineSeries() for _ in range(15)]
        for i in range(15):
            series[i] = chart.series()[i]
            series[i].clear()

        gasData = self.gas[self.ui.listView.currentIndex().row()]

        sensors = ['' for _ in range(15)]
        for i in range(15):
            sensors[i] = eval(gasData['gas_sensors' + str(i + 1)])
            for j in range(len(sensors[i])):
                series[i].append(j, sensors[i][j])

    @pyqtSlot(bool)
    def on_refreshButton_clicked(self):  #刷新列表
        #先清空所有的list
        self.model.removeRows(0, self.model.rowCount())

        #开始查询该用户的所有气体文件,用list变量gas保存
        list_gasInfo = requests.get(self.url + '/person/getGasInfo/' +
                                    str(self.person_id))
        self.gas = eval(list_gasInfo.text)

        #开始将数据添加进list中
        for i in self.gas:
            self.addItem(i["save_time"])

    @pyqtSlot(bool)
    def on_deleteButton_clicked(self):  #删除某条气体数据
        #如果此时listview没有数据,则跳过
        if self.model.rowCount() == 0:
            pass
        else:
            #弹出确认删除的窗口
            result = QMessageBox.question(
                self, '删除', '是否要删除' +
                self.gas[self.ui.listView.currentIndex().row()]["save_time"],
                QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.NoButton)
            if result == QMessageBox.Yes:
                delete_gasInfo = requests.get(
                    self.url + '/person/deleteGas/' + str(self.gas[
                        self.ui.listView.currentIndex().row()]["gas_id"]))
                #这个地方的删除实际上没有删除数据库中的表,是把gas的is_delete写为了True,显示的时候不做显示

                #先清空所有的list
                self.model.removeRows(0, self.model.rowCount())

                #开始查询该用户的所有气体文件,用list变量gas保存
                list_gasInfo = requests.get(self.url + '/person/getGasInfo/' +
                                            str(self.person_id))
                self.gas = eval(list_gasInfo.text)

                #开始将数据添加进list中
                for i in self.gas:
                    self.addItem(i["save_time"])
Exemple #15
0
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()
Exemple #16
0
class Statistics(QWidget):
    """A statistics widget that displays information about studied time, shows grown plants, etc..."""

    def __init__(self, history, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.history = history

        chart = self.generate_chart()

        self.SPACING = 10
        self.MIN_WIDTH = 400
        self.MIN_HEIGHT = 200

        chart.setMinimumWidth(self.MIN_WIDTH)
        chart.setMinimumHeight(self.MIN_HEIGHT)

        image_layout = QVBoxLayout()

        self.plant_study = None  # the study record the plant is a part of
        self.plant: Optional[Plant] = None  # the plant being displayed

        self.plant_date_label = QLabel(self)
        self.plant_date_label.setAlignment(Qt.AlignLeft)

        self.plant_duration_label = QLabel(self)
        self.plant_duration_label.setAlignment(Qt.AlignRight)

        label_layout = QHBoxLayout()
        label_layout.addWidget(self.plant_date_label)
        label_layout.addWidget(self.plant_duration_label)

        self.canvas = Canvas(self)
        self.canvas.setMinimumWidth(self.MIN_HEIGHT)
        self.canvas.setMinimumHeight(self.MIN_HEIGHT)

        stacked_layout = QVBoxLayout()
        stacked_layout.addLayout(label_layout)
        stacked_layout.addWidget(self.canvas)

        image_control = QHBoxLayout()

        text_color = self.palette().text().color()

        self.age_slider = QSlider(Qt.Horizontal, minimum=0, maximum=1000, value=1000,
                                  valueChanged=self.slider_value_changed)

        self.left_button = QPushButton(self, clicked=self.left,
                                       icon=qtawesome.icon('fa5s.angle-left', color=text_color))
        self.right_button = QPushButton(self, clicked=self.right,
                                        icon=qtawesome.icon('fa5s.angle-right', color=text_color))
        self.save_button = QPushButton(self, clicked=self.save,
                                       icon=qtawesome.icon('fa5s.download', color=text_color))

        image_control.addWidget(self.left_button)
        image_control.addWidget(self.right_button)
        image_control.addSpacing(self.SPACING)
        image_control.addWidget(self.age_slider)
        image_control.addSpacing(self.SPACING)
        image_control.addWidget(self.save_button)

        image_layout.addLayout(stacked_layout)
        image_layout.addLayout(image_control)
        image_layout.setContentsMargins(self.SPACING, self.SPACING, self.SPACING, self.SPACING)

        separator = QFrame()
        separator.setStyleSheet(f"background-color: {self.palette().text().color().name()}")
        separator.setFixedWidth(1)

        main_layout = QGridLayout()
        main_layout.setHorizontalSpacing(self.SPACING * 2)
        main_layout.setColumnStretch(0, 1)
        main_layout.setColumnStretch(2, 0)
        main_layout.addWidget(chart, 0, 0)
        main_layout.addWidget(separator, 0, 1)
        main_layout.addLayout(image_layout, 0, 2)

        self.setLayout(main_layout)

        self.move()  # go to the most recent plant

        self.refresh()

    def generate_chart(self):
        """Generate the bar graph for the widget."""
        self.tags = [QBarSet(tag) for tag in ["Study"]]

        series = QStackedBarSeries()

        for set in self.tags:
            series.append(set)

        self.chart = QChart()
        self.chart.addSeries(series)
        self.chart.setTitle("Total time studied (minutes per day)")

        days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        axis = QBarCategoryAxis()
        axis.append(days)

        self.chart.createDefaultAxes()
        self.chart.setAxisX(axis, series)
        self.chart.legend().setAlignment(Qt.AlignBottom)
        self.chart.legend().setVisible(False)
        self.chart.setTheme(QChart.ChartThemeQt)
        self.chart.setBackgroundVisible(False)
        self.chart.setBackgroundRoundness(0)
        self.chart.setMargins(QMargins(0, 0, 0, 0))
        self.chart.setTitleBrush(QBrush(self.palette().text().color()))

        yAxis = self.chart.axes(Qt.Vertical)[0]
        yAxis.setGridLineVisible(False)
        yAxis.setLabelFormat("%d")
        yAxis.setLinePenColor(self.palette().text().color())
        yAxis.setLabelsColor(self.palette().text().color())

        xAxis = self.chart.axes(Qt.Horizontal)[0]
        xAxis.setGridLineVisible(False)
        xAxis.setLinePenColor(self.palette().text().color())
        xAxis.setLabelsColor(self.palette().text().color())

        chartView = QChartView(self.chart)
        chartView.setRenderHint(QPainter.Antialiasing)

        return chartView

    def slider_value_changed(self):
        """Called when the slider value has changed. Sets the age of the plant and updates it."""
        if self.plant is not None:
            # makes it a linear function from 0 to whatever the duration was, so the plant appears to grow normally
            self.plant.set_age(
                self.plant.inverse_age_coefficient_function(self.age_slider.value() / self.age_slider.maximum() *
                                                            self.plant.age_coefficient_function(
                                                                self.plant_study["duration"])))
            self.canvas.update()

    def refresh(self):
        """Refresh the labels."""
        # clear tag values
        for tag in self.tags:
            tag.remove(0, tag.count())

        study_minutes = [0] * 7
        for study in self.history.get_studies():
            # TODO: don't just crash
            study_minutes[study["date"].weekday()] += study["duration"]

        for minutes in study_minutes:
            self.tags[0] << minutes

        # manually set the range of the y axis, because it doesn't for some reason
        yAxis = self.chart.axes(Qt.Vertical)[0]
        yAxis.setRange(0, max(study_minutes))

    def left(self):
        """Move to the left (older) plant."""
        self.move(-1)

    def right(self):
        """Move to the right (newer) plant."""
        self.move(1)

    def move(self, delta: int = 0):
        """Move to the left/right plant by delta. If no plant is currently being displayed or delta is 0, pick the
        latest one."""
        studies = self.history.get_studies()

        # if there are no plants to display, don't do anything
        if len(studies) == 0:
            return

        # if no plant is being displayed or 0 is provided, pick the last one
        if self.plant is None or delta == 0:
            index = -1

        # if one is, find it and move by delta
        else:
            current_index = self.history.get_studies().index(self.plant_study)

            index = max(min(current_index + delta, len(studies) - 1), 0)

        # TODO: check for correct formatting, don't just crash if it's wrong
        self.plant = pickle.loads(studies[index]["plant"])
        self.plant_study = studies[index]

        # TODO: check for correct formatting, don't just crash if it's wrong
        self.plant_date_label.setText(self.plant_study["date"].strftime("%-d/%-m/%Y"))
        self.plant_duration_label.setText(f"{int(self.plant_study['duration'])} minutes")

        self.canvas.set_drawable(self.plant)
        self.slider_value_changed()  # it didn't, but the code should act as if it did (update plant)

    def save(self):
        """Save the current state of the plant to a file."""
        if self.plant is not None:
            name, _ = QFileDialog.getSaveFileName(self, 'Save File', "", "SVG files (*.svg)")

            if name == "":
                return

            if not name.endswith(".svg"):
                name += ".svg"

            self.plant.save(name, 1000, 1000)
Exemple #17
0
class QmyMainWindow(QMainWindow): 

   def __init__(self, parent=None):
      super().__init__(parent)   #调用父类构造函数,创建窗体
      self.ui=Ui_MainWindow()    #创建UI对象
      self.ui.setupUi(self)      #构造UI界面

      self.setWindowTitle("Demo12_2, QChart绘制折线图")
      self.setCentralWidget(self.ui.splitter)

      self.__chart=None       #图表
      self.__curSeries=None   #当前序列
      self.__curAxis=None     #当前坐标轴
      
      self.__createChart()
      self.__prepareData()
      self.__updateFromChart()

##  ==============自定义功能函数========================
   def __createChart(self):
      self.__chart = QChart()
      self.__chart.setTitle("简单函数曲线")
      self.ui.chartView.setChart(self.__chart)
      self.ui.chartView.setRenderHint(QPainter.Antialiasing)

      series0 =  QLineSeries()
      series0.setName("Sin曲线")
      series1 =  QLineSeries()
      series1.setName("Cos曲线")
      self.__curSeries=series0   #当前序列

      pen=QPen(Qt.red)
      pen.setStyle(Qt.DotLine)   #SolidLine, DashLine, DotLine, DashDotLine
      pen.setWidth(2)
      series0.setPen(pen)        #序列的线条设置

      pen.setStyle(Qt.SolidLine) #SolidLine, DashLine, DotLine, DashDotLine
      pen.setColor(Qt.blue)
      series1.setPen(pen)        #序列的线条设置

      self.__chart.addSeries(series0)
      self.__chart.addSeries(series1)

      axisX = QValueAxis()
      self.__curAxis=axisX       #当前坐标轴
      axisX.setRange(0, 10)      #设置坐标轴范围
      axisX.setLabelFormat("%.1f")  #标签格式
      axisX.setTickCount(11)        #主分隔个数
      axisX.setMinorTickCount(4)
      axisX.setTitleText("time(secs)")  #标题
      axisX.setGridLineVisible(True)
      axisX.setMinorGridLineVisible(False)

      axisY = QValueAxis()
      axisY.setRange(-2, 2)
      axisY.setLabelFormat("%.2f")     #标签格式
      axisY.setTickCount(5)
      axisY.setMinorTickCount(4)
      axisY.setTitleText("value")
      axisY.setGridLineVisible(True)
      axisY.setMinorGridLineVisible(False)

   ##      self.__chart.setAxisX(axisX, series0) #添加X坐标轴
   ##      self.__chart.setAxisX(axisX, series1) #添加X坐标轴
   ##      self.__chart.setAxisY(axisY, series0) #添加Y坐标轴
   ##      self.__chart.setAxisY(axisY, series1) #添加Y坐标轴

   ##另一种实现设置坐标轴的方法
      self.__chart.addAxis(axisX,Qt.AlignBottom) #坐标轴添加到图表,并指定方向
      self.__chart.addAxis(axisY,Qt.AlignLeft)

      series0.attachAxis(axisX)  #序列 series0 附加坐标轴
      series0.attachAxis(axisY)

      series1.attachAxis(axisX)  #序列 series1 附加坐标轴
      series1.attachAxis(axisY)

      

   def __prepareData(self):  ##为序列设置数据点
      chart=self.ui.chartView.chart()  #获取chartView中的QChart对象
      series0=chart.series()[0]        #获取第1个序列,QLineSeries
      series0.clear() 

      series1=chart.series()[1]   #获取第2个序列,QLineSeries
      series1.clear()
      
      t,y1,y2=0.0,0.0,0.0
      intv=0.1
      pointCount=100
      for i in range(pointCount):
         rd=random.randint(-5,5)     #随机数,-5~+5
         y1=math.sin(t)+rd/50.0
         series0.append(t,y1)        #序列添加数据点

         rd=random.randint(-5,5)     #随机数,-5~+5
         y2=math.cos(t)+rd/50.0
         series1.append(t,y2)        #序列添加数据点
         t=t+intv

   def __updateFromChart(self):
      self.ui.editTitle.setText(self.__chart.title())    #图表标题
      mg=self.__chart.margins()     #边距, QMargins
      self.ui.spinMarginLeft.setValue(mg.left())
      self.ui.spinMarginRight.setValue(mg.right())
      self.ui.spinMarginTop.setValue(mg.top())
      self.ui.spinMarginBottom.setValue(mg.bottom())
      
      
##  ==============event处理函数==========================


##  ==========由connectSlotsByName()自动连接的槽函数============        
      
##========工具栏上的几个按钮的Actions==============
   @pyqtSlot()  ## "刷新绘图" 工具栏按钮
   def on_actDraw_triggered(self):
      self.__prepareData()


##=====ToolBox 第1组:==="图表设置" 分组里的功能================
##=======1.1 标题========
   @pyqtSlot()   ##设置标题文字
   def on_btnTitleSetText_clicked(self):
      text=self.ui.editTitle.text()
      self.__chart.setTitle(text)
        
   @pyqtSlot()   ##设置标题文字颜色
   def on_btnTitleColor_clicked(self):
      color=self.__chart.titleBrush().color()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__chart.setTitleBrush(QBrush(color))

   @pyqtSlot()   ##设置标题字体
   def on_btnTitleFont_clicked(self):
      iniFont=self.__chart.titleFont()  #QFont
      font,ok=QFontDialog.getFont(iniFont)
      if ok:
         self.__chart.setTitleFont(font)

##=======1.2 图例==========
   @pyqtSlot(bool)   ##图例是否可见
   def on_groupBox_Legend_clicked(self,checked):
      self.__chart.legend().setVisible(checked)

   @pyqtSlot()   ##图例的位置, 上
   def on_radioButton_clicked(self):
      self.__chart.legend().setAlignment(Qt.AlignTop)
         
   @pyqtSlot()   ##图例的位置,下
   def on_radioButton_2_clicked(self):
      self.__chart.legend().setAlignment(Qt.AlignBottom)
      
   @pyqtSlot()   ##图例的位置,左
   def on_radioButton_3_clicked(self):
      self.__chart.legend().setAlignment(Qt.AlignLeft)

   @pyqtSlot()   ##图例的位置,右
   def on_radioButton_4_clicked(self):
      self.__chart.legend().setAlignment(Qt.AlignRight)

   @pyqtSlot()   ##图例的文字颜色
   def on_btnLegendlabelColor_clicked(self):
      color=self.__chart.legend().labelColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__chart.legend().setLabelColor(color)

   @pyqtSlot()   ##图例的字体
   def on_btnLegendFont_clicked(self):
      iniFont=self.__chart.legend().font()
      font,ok=QFontDialog.getFont(iniFont)
      if ok:
         self.__chart.legend().setFont(font)

##=======1.3 边距========
   @pyqtSlot()   ##设置图表的4个边距
   def on_btnSetMargin_clicked(self):
      mgs=QMargins()
      mgs.setLeft(self.ui.spinMarginLeft.value())
      mgs.setRight(self.ui.spinMarginRight.value())
      mgs.setTop(self.ui.spinMarginTop.value())
      mgs.setBottom(self.ui.spinMarginBottom.value())
      self.__chart.setMargins(mgs)

##=======1.4 动画效果========        
   @pyqtSlot(int)   ##动画效果
   def on_comboAnimation_currentIndexChanged(self,index):
      animation=QChart.AnimationOptions(index)
      self.__chart.setAnimationOptions(animation)

   @pyqtSlot(int)   ##图表的主题
   def on_comboTheme_currentIndexChanged(self,index):
      self.__chart.setTheme(QChart.ChartTheme(index))


##=====ToolBox 第2组:==="曲线设置" 分组里的功能================
##=======2.1 选择操作序列========
   @pyqtSlot()   ##获取当前数据序列,sin
   def on_radioSeries0_clicked(self):
      if self.ui.radioSeries0.isChecked():
         self.__curSeries=self.__chart.series()[0]
      else:
         self.__curSeries=self.__chart.series()[1]
      ##获取序列的属性值,并显示到界面上
      self.ui.editSeriesName.setText(self.__curSeries.name())
      self.ui.groupBox_Series.setChecked(self.__curSeries.isVisible())  #序列是否显示
      self.ui.chkBoxPointVisible.setChecked(self.__curSeries.pointsVisible())    #数据点是否显示
      self.ui.chkkBoxUseOpenGL.setChecked(self.__curSeries.useOpenGL()) #使用openGL

      self.ui.sliderOpacity.setValue(self.__curSeries.opacity()*10)  #透明度

      visible=self.__curSeries.pointLabelsVisible()   #数据点标签可见性
      self.ui.groupBox_PointLabel.setChecked(visible)

   @pyqtSlot()   ##获取当前数据序列,cos
   def on_radioSeries1_clicked(self):
      self.on_radioSeries0_clicked()

      
##======2.2 序列曲线 设置======== 
   @pyqtSlot(bool)   ##序列是否可见
   def on_groupBox_Series_clicked(self,checked):
      self.__curSeries.setVisible(checked)

   @pyqtSlot()   ##设置序列名称
   def on_btnSeriesName_clicked(self):
      seriesName=self.ui.editSeriesName.text()
      self.__curSeries.setName(seriesName)
      if self.ui.radioSeries0.isChecked():
         self.ui.radioSeries0.setText(seriesName)
      else:
         self.ui.radioSeries1.setText(seriesName)

   @pyqtSlot()   ##序列的曲线颜色
   def on_btnSeriesColor_clicked(self):
      color=self.__curSeries.color()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curSeries.setColor(color)

   @pyqtSlot()   ##序列曲线的Pen设置
   def on_btnSeriesPen_clicked(self):
      iniPen=self.__curSeries.pen()
      pen,ok=QmyDialogPen.staticGetPen(iniPen)
      if ok:
         self.__curSeries.setPen(pen)

   @pyqtSlot(bool)   ##序列的数据点是否可见,数据点形状是固定的
   def on_chkBoxPointVisible_clicked(self,checked):
      self.__curSeries.setPointsVisible(checked)

   @pyqtSlot(bool)   ##使用openGL加速后,不能设置线型,不能显示数据点
   def on_chkkBoxUseOpenGL_clicked(self,checked):
      self.__curSeries.setUseOpenGL(checked)

   @pyqtSlot(int)   ##序列的透明度
   def on_sliderOpacity_sliderMoved(self,position):
      self.__curSeries.setOpacity(position/10.0)

##=======2.3 数据点标签 ========     
   @pyqtSlot(bool)   ##数据点标签 groupBox
   def on_groupBox_PointLabel_clicked(self,checked):
      self.__curSeries.setPointLabelsVisible(checked)

   @pyqtSlot()   ##序列数据点标签颜色
   def on_btnSeriesLabColor_clicked(self):
      color=self.__curSeries.pointLabelsColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curSeries.setPointLabelsColor(color)

   @pyqtSlot()   ##序列数据点标签字体
   def on_btnSeriesLabFont_clicked(self):
      font=self.__curSeries.pointLabelsFont()    #QFont
      font,ok=QFontDialog.getFont(font)
      if ok:
         self.__curSeries.setPointLabelsFont(font)

   @pyqtSlot()   ##序列数据点标签的显示格式
   def on_radioSeriesLabFormat0_clicked(self):
      self.__curSeries.setPointLabelsFormat("@yPoint")
         
   @pyqtSlot()   ##序列数据点标签的显示格式
   def on_radioSeriesLabFormat1_clicked(self):
      self.__curSeries.setPointLabelsFormat("(@xPoint,@yPoint)")

##=====ToolBox 第3组:==="坐标轴设置" 分组里的功能================

##=======3.1 选择操作的坐标轴对象=======
   @pyqtSlot()   ##选择坐标轴X
   def on_radioAxisX_clicked(self):
      if (self.ui.radioAxisX.isChecked()):
         self.__curAxis=self.ui.chartView.chart().axisX()   #QValueAxis
      else:
         self.__curAxis=self.ui.chartView.chart().axisY()

      ##获取坐标轴的各种属性,显示到界面上
      self.ui.groupBox_Axis.setChecked(self.__curAxis.isVisible()) #坐标轴可见性

      self.ui.chkBoxAxisReverse.setChecked(self.__curAxis.isReverse())
         
      self.ui.spinAxisMin.setValue(self.__curAxis.min())
      self.ui.spinAxisMax.setValue(self.__curAxis.max())

      self.ui.editAxisTitle.setText(self.__curAxis.titleText())   #轴标题
      self.ui.groupBox_AxisTitle.setChecked(self.__curAxis.isTitleVisible())  #轴标题可见

      self.ui.editAxisLabelFormat.setText(self.__curAxis.labelFormat())       #标签格式
      self.ui.groupBox_AxisLabel.setChecked(self.__curAxis.labelsVisible())   #标签可见

      self.ui.groupBox_GridLine.setChecked(self.__curAxis.isGridLineVisible()) #网格线

      self.ui.groupBox_Ticks.setChecked(self.__curAxis.isLineVisible())    #主刻度线

      self.ui.spinTickCount.setValue(self.__curAxis.tickCount())           #主刻度个数

      self.ui.spinMinorTickCount.setValue(self.__curAxis.minorTickCount()) #次刻度个数
      self.ui.groupBox_MinorGrid.setChecked(self.__curAxis.isMinorGridLineVisible())   #次网格线可见


   @pyqtSlot()   ##选择坐标轴Y
   def on_radioAxisY_clicked(self):
      self.on_radioAxisX_clicked()

##======3.2 坐标轴可见性和范围=======
   @pyqtSlot(bool)   ##坐标轴可见性
   def on_groupBox_Axis_clicked(self,checked):
      self.__curAxis.setVisible(checked)

   @pyqtSlot(bool)   ##坐标反向
   def on_chkBoxAxisReverse_clicked(self,checked):
      self.__curAxis.setReverse(checked)
      
   @pyqtSlot()   ##设置坐标范围
   def on_btnSetAxisRange_clicked(self):
      minV=self.ui.spinAxisMin.value()
      maxV=self.ui.spinAxisMax.value()
      self.__curAxis.setRange(minV,maxV)
      
##======3.3 轴标题=======
   @pyqtSlot(bool)   ##坐标轴标题可见性
   def on_groupBox_AxisTitle_clicked(self,checked):
      self.__curAxis.setTitleVisible(checked)

   @pyqtSlot()   ##设置轴标题
   def on_btnAxisSetTitle_clicked(self):
      self.__curAxis.setTitleText(self.ui.editAxisTitle.text())

   @pyqtSlot()   ##设置轴标题的颜色
   def on_btnAxisTitleColor_clicked(self):
      color=self.__curAxis.titleBrush().color()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curAxis.setTitleBrush(QBrush(color))

   @pyqtSlot()   ##设置轴标题的字体
   def on_btnAxisTitleFont_clicked(self):
      iniFont=self.__curAxis.titleFont() #QFont
      font,ok=QFontDialog.getFont(iniFont)
      if ok:
         self.__curAxis.setTitleFont(font)

##======3.4 轴刻度标签=======
   @pyqtSlot(bool)   ##可见性
   def on_groupBox_AxisLabel_clicked(self,checked):
      self.__curAxis.setLabelsVisible(checked)
         
   @pyqtSlot()   ##设置标签格式
   def on_btnAxisLabelFormat_clicked(self):
      strFormat=self.ui.editAxisLabelFormat.text()
      self.__curAxis.setLabelFormat(strFormat)
      
   @pyqtSlot()   ##设置标签文字颜色
   def on_btnAxisLabelColor_clicked(self):
      color=self.__curAxis.labelsColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curAxis.setLabelsColor(color)

   @pyqtSlot()   ##设置标签字体
   def on_btnAxisLabelFont_clicked(self):
      iniFont=self.__curAxis.labelsFont() #QFont
      font,ok=QFontDialog.getFont(iniFont)
      if ok:
         self.__curAxis.setLabelsFont(font)

##======3.5 轴线和主刻度=========
   @pyqtSlot(bool)   ##可见性
   def on_groupBox_Ticks_clicked(self,checked):
      self.__curAxis.setLineVisible(checked)

   @pyqtSlot(int)   ##主刻度个数
   def on_spinTickCount_valueChanged(self,arg1):
      self.__curAxis.setTickCount(arg1)

   @pyqtSlot()   ##设置线条Pen
   def on_btnAxisLinePen_clicked(self):
      iniPen=self.__curAxis.linePen()
      pen,ok=QmyDialogPen.staticGetPen(iniPen)
      if ok:
         self.__curAxis.setLinePen(pen)
         
   @pyqtSlot()   ##设置线条颜色
   def on_btnAxisLinePenColor_clicked(self):
      color=self.__curAxis.linePenColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curAxis.setLinePenColor(color)
         
##======3.6 主网格线=========
   @pyqtSlot(bool)   ##可见性
   def on_groupBox_GridLine_clicked(self,checked):
      self.__curAxis.setGridLineVisible(checked)
         

   @pyqtSlot()   ##设置线条Pen
   def on_btnGridLinePen_clicked(self):
      iniPen=self.__curAxis.gridLinePen()
      pen,ok=QmyDialogPen.staticGetPen(iniPen)
      if ok:
         self.__curAxis.setGridLinePen(pen)

   @pyqtSlot()   ##设置线条颜色
   def on_btnGridLineColor_clicked(self):
      color=self.__curAxis.gridLineColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curAxis.setGridLineColor(color)

##======3.7 次网格线=======
   @pyqtSlot(bool)   ##可见性
   def on_groupBox_MinorGrid_clicked(self,checked):
      self.__curAxis.setMinorGridLineVisible(checked)

   @pyqtSlot(int)   ##次刻度个数
   def on_spinMinorTickCount_valueChanged(self,arg1):
      self.__curAxis.setMinorTickCount(arg1)
         
   @pyqtSlot()   ##设置线条Pen
   def on_btnMinorPen_clicked(self):
      iniPen=self.__curAxis.minorGridLinePen()
      pen,ok=QmyDialogPen.staticGetPen(iniPen)    #使用类函数调用方法
      if ok:
         self.__curAxis.setMinorGridLinePen(pen)
         
   @pyqtSlot()   ##设置线条颜色
   def on_btnMinorColor_clicked(self):
      color=self.__curAxis.minorGridLineColor()
      color=QColorDialog.getColor(color)
      if color.isValid():
         self.__curAxis.setMinorGridLineColor(color)
Exemple #18
0
class ChartView(QChartView):
    def __init__(self, file, parent=None):
        super(ChartView, self).__init__(parent)
        self._chart = QChart()
        self._chart.setAcceptHoverEvents(True)
        self.setChart(self._chart)
        self.initUi(file)

    def initUi(self, file):
        if isinstance(file, dict):
            return self.__analysis(file)
        if isinstance(file, str):
            if not os.path.isfile(file):
                return self.__analysis(json.loads(file))
            with open(file, "rb") as fp:
                data = fp.read()
                encoding = chardet.detect(data) or {}
                data = data.decode(encoding.get("encoding") or "utf-8")
            self.__analysis(json.loads(data))

    #     def onSeriesHoverd(self, point, state):
    #         print(point, state)

    def mouseMoveEvent(self, event):
        super(ChartView, self).mouseMoveEvent(event)
        # 获取x和y轴的最小最大值
        axisX, axisY = self._chart.axisX(), self._chart.axisY()
        min_x, max_x = axisX.min(), axisX.max()
        min_y, max_y = axisY.min(), axisY.max()
        # 把鼠标位置所在点转换为对应的xy值
        x = self._chart.mapToValue(event.pos()).x()
        y = self._chart.mapToValue(event.pos()).y()
        index = round(x)  # 四舍五入
        print(x, y, index)
        # 得到在坐标系中的所有series的类型和点
        points = [(s.type(), s.at(index)) for s in self._chart.series()
                  if min_x <= x <= max_x and min_y <= y <= max_y]
        print(points)

    def __getColor(self, color=None, default=Qt.white):
        '''
        :param color: int|str|[r,g,b]|[r,g,b,a]
        '''
        if not color:
            return QColor(default)
        if isinstance(color, QBrush):
            return color
        # 比如[r,g,b]或[r,g,b,a]
        if isinstance(color, list) and 3 <= len(color) <= 4:
            return QColor(*color)
        else:
            return QColor(color)

    def __getPen(self,
                 pen=None,
                 default=QPen(Qt.white, 1, Qt.SolidLine, Qt.SquareCap,
                              Qt.BevelJoin)):
        '''
        :param pen: pen json
        '''
        if not pen or not isinstance(pen, dict):
            return default
        return QPen(self.__getColor(pen.get("color", None) or default.color()),
                    pen.get("width", 1) or 1,
                    pen.get("style", 0) or 0,
                    pen.get("capStyle", 16) or 16,
                    pen.get("joinStyle", 64) or 64)

    def __getAlignment(self, alignment):
        '''
        :param alignment: left|top|right|bottom
        '''
        try:
            return getattr(Qt, "Align" + alignment.capitalize())
        except:
            return Qt.AlignTop

    #         if alignment == "left":
    #             return Qt.AlignLeft
    #         if alignment == "right":
    #             return Qt.AlignRight
    #         if alignment == "bottom":
    #             return Qt.AlignBottom
    #         return Qt.AlignTop

    def __setTitle(self, title=None):
        '''
        :param title: title json
        '''
        if not title or not isinstance(title, dict):
            return
        # 设置标题
        self._chart.setTitle(title.get("text", "") or "")
        # 设置标题颜色
        self._chart.setTitleBrush(
            self.__getColor(
                title.get("color", self._chart.titleBrush())
                or self._chart.titleBrush()))
        # 设置标题字体
        font = QFont(title.get("font", "") or self._chart.titleFont())
        pointSize = title.get("pointSize", -1) or -1
        if pointSize > 0:
            font.setPointSize(pointSize)
        font.setWeight(title.get("weight", -1) or -1)
        font.setItalic(title.get("italic", False) or False)
        self._chart.setTitleFont(font)

    def __setAnimation(self, animation=None):
        '''
        :param value: animation json
        '''
        if not animation or not isinstance(animation, dict):
            return
        # 动画持续时间
        self._chart.setAnimationDuration(
            animation.get("duration", 1000) or 1000)
        # 设置动画曲线
        self._chart.setAnimationEasingCurve(
            EasingCurve.get(animation.get("curve", 10) or 10, None)
            or QEasingCurve.OutQuart)
        # 设置开启何种动画
        self._chart.setAnimationOptions(
            AnimationOptions.get(animation.get("options", 0) or 0, None)
            or QChart.NoAnimation)

    def __setBackground(self, background=None):
        '''
        :param background:background json
        '''
        if not background or not isinstance(background, dict):
            return
        # 设置是否背景可用
        self._chart.setBackgroundVisible(
            background.get("visible", True) or True)
        # 设置背景矩形的圆角
        self._chart.setBackgroundRoundness(background.get("radius", 0) or 0)
        # 设置下拉阴影
        self._chart.setDropShadowEnabled(
            background.get("dropShadow", True) or True)
        # 设置pen
        self._chart.setBackgroundPen(
            self.__getPen(background.get("pen", None),
                          self._chart.backgroundPen()))
        # 设置背景
        image = background.get("image", None)
        color = background.get("color", None)
        if image:
            self._chart.setBackgroundBrush(QBrush(QPixmap(image)))
        elif color:
            self._chart.setBackgroundBrush(
                self.__getColor(color, self._chart.backgroundBrush()))

    def __setMargins(self, margins=None):
        '''
        :param margins: margins json
        '''
        if not margins or not isinstance(margins, dict):
            return
        left = margins.get("left", 20) or 20
        top = margins.get("top", 20) or 20
        right = margins.get("right", 20) or 20
        bottom = margins.get("bottom", 20) or 20
        self._chart.setMargins(QMargins(left, top, right, bottom))

    def __setLegend(self, legend=None):
        '''
        :param legend: legend json
        '''
        if not legend or not isinstance(legend, dict):
            return
        _legend = self._chart.legend()
        _legend.setAlignment(self.__getAlignment(legend.get("alignment",
                                                            None)))
        _legend.setShowToolTips(legend.get("showToolTips", True) or True)

    def __getSerie(self, serie=None):
        if not serie or not isinstance(serie, dict):
            return None
        types = serie.get("type", "") or ""
        data = serie.get("data", []) or []
        if not data or not isinstance(data, list):
            return None
        if types == "line":
            _series = QLineSeries(self._chart)
        else:
            return None
        # 设置series名字
        _series.setName(serie.get("name", "") or "")
        # 添加数据到series中
        for index, value in enumerate(data):
            # 保证vlaue必须是数字
            _series.append(index, value if type(value) in (int, float) else 0)
        return _series

    def __setSeries(self, series=None):
        if not series or not isinstance(series, list):
            return
        for serie in series:
            _serie = self.__getSerie(serie)
            if _serie:
                #                 _serie.hovered.connect(self.onSeriesHoverd)
                self._chart.addSeries(_serie)
        # 创建默认的xy轴
        self._chart.createDefaultAxes()

    def __setAxisX(self, axisx=None):
        if not axisx or not isinstance(axisx, dict):
            return
        series = self._chart.series()
        if not series:
            return
        types = axisx.get("type", None)
        data = axisx.get("data", []) or []
        if not data or not isinstance(data, list):
            return None
        minx = self._chart.axisX().min()
        maxx = self._chart.axisX().max()
        if types == "category":
            xaxis = QCategoryAxis(
                self._chart,
                labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
            # 隐藏网格
            xaxis.setGridLineVisible(False)
            # 刻度条数
            tickc_d = len(data)
            tickc = tickc_d if tickc_d > 1 else self._chart.axisX().tickCount()
            xaxis.setTickCount(tickc)
            # 强制x轴刻度与新刻度条数一致
            self._chart.axisX().setTickCount(tickc)
            step = (maxx - minx) / (tickc - 1)
            for i in range(min(tickc_d, tickc)):
                xaxis.append(data[i], minx + i * step)
            self._chart.setAxisX(xaxis, series[-1])

    def __analysis(self, datas):
        '''
        analysis json data
        :param datas: json data
        '''
        # 标题
        self.__setTitle(datas.get("title", None))
        # 抗锯齿
        if (datas.get("antialiasing", False) or False):
            self.setRenderHint(QPainter.Antialiasing)
        # 主题
        self._chart.setTheme(datas.get("theme", 0) or 0)
        # 动画
        self.__setAnimation(datas.get("animation", None))
        # 背景设置
        self.__setBackground(datas.get("background", None))
        # 边距设置
        self.__setMargins(datas.get("margins", None))
        # 设置图例
        self.__setLegend(datas.get("legend", None))
        # 设置series
        self.__setSeries(datas.get("series", None))
        # 自定义的x轴
        self.__setAxisX(datas.get("axisx", None))
Exemple #19
0
def bars_stacked(name, table_df, x_bottom_cols, y_left_cols, y_right_cols,
                 legend_labels, tick_count):
    """
    柱形堆叠图
    :param name: 图表名称
    :param table_df: 用于画图的pandas DataFrame对象
    :param x_bottom_cols:  下轴列索引列表
    :param y_left_cols: 左轴列索引列表
    :param y_right_cols: 右轴列索引列表
    :param legend_labels: 图例名称标签列表
    :param tick_count: 横轴刻度标签数
    :return: QChart实例
    """
    """ 过滤轴 """
    for y_left_col in y_left_cols:
        if is_datetime64_any_dtype(table_df[y_left_col]):  # 如果是时间轴
            y_left_cols.remove(y_left_col)
    for y_right_col in y_right_cols:
        if is_datetime64_any_dtype(table_df[y_right_col]):  # 如果是时间轴
            y_right_cols.remove(y_right_col)
    # 将x轴转为字符串
    x_bottom = x_bottom_cols[0]  # x轴列
    if is_datetime64_any_dtype(table_df[x_bottom]):  # 如果x轴是时间轴
        table_df[x_bottom] = table_df[x_bottom].apply(
            lambda x: x.strftime('%Y-%m-%d'))
    else:  # x轴非时间轴
        table_df[x_bottom] = table_df[x_bottom].apply(lambda x: str(x))
    font = QFont()  # 轴文字风格
    font.setPointSize(7)  # 轴标签文字大小
    chart = QChart()  # 图表实例
    chart.layout().setContentsMargins(0, 0, 0, 0)  # chart的外边距
    chart.setMargins(QMargins(15, 5, 15, 0))  # chart内边距
    chart.setTitle(name)  # chart名称
    """ x轴 """
    axis_x_bottom = QCategoryAxis(
        chart, labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
    axis_x_bottom.setLabelsAngle(-90)  # 逆时针旋转90度
    axis_x_bottom.setLabelsFont(font)  # 设置字体样式
    axis_x_bottom.setGridLineVisible(False)  # 竖向连接线不可见
    # chart.addAxis(axis_x_bottom, Qt.AlignBottom)  # 加入坐标x轴
    has_x_labels = False  # 收集x轴刻度的开关
    chart.x_labels = list()  # 绑定chart一个x轴的刻度列表
    """ 左Y轴 """
    axis_y_left = QValueAxis()
    axis_y_left.setLabelsFont(font)
    axis_y_left.setLabelFormat('%i')
    chart.addAxis(axis_y_left, Qt.AlignLeft)  # 图表加入左轴
    """ 右Y轴 """
    axis_y_right = QValueAxis()
    axis_y_right.setLabelsFont(font)
    axis_y_right.setLabelFormat('%.2f')
    chart.addAxis(axis_y_right, Qt.AlignRight)
    # 记录各轴的最值
    x_bottom_min, x_bottom_max = 0, table_df.shape[0]
    y_left_min, y_left_max = 0, 0
    y_right_min, y_right_max = 0, 0
    # 柱形图
    left_bars = QBarSeries()
    """ 根据左轴画柱形 """
    for y_left_col in y_left_cols:  # 根据左轴画折线
        # 计算做轴的最值用于设置范围
        table_df[y_left_col] = table_df[y_left_col].apply(
            covert_float)  # y轴列转为浮点数值
        # 获取最值
        y_min, y_max = table_df[y_left_col].min(), table_df[y_left_col].max()
        if y_min < y_left_min:
            y_left_min = y_min
        if y_max > y_left_max:
            y_left_max = y_max
        # 取得图表的源数据作柱形
        left_bar_data = table_df.iloc[:, [x_bottom, y_left_col]]
        bar = QBarSet(legend_labels[y_left_col])
        bar.setPen(QPen(Qt.transparent))  # 设置画笔轮廓线透明(数据量大会出现空白遮住柱形)
        for index, point_item in enumerate(left_bar_data.values.tolist()):
            bar.append(point_item[1])
            if not has_x_labels:
                chart.x_labels.append(point_item[0])
        has_x_labels = True  # 关闭添加轴标签
        left_bars.append(bar)  # 柱形加入系列
    left_bars.attachAxis(axis_y_left)
    # 左轴的范围
    axis_y_left.setRange(y_left_min, y_left_max)
    """ 根据右轴画柱形 """
    right_bars = QBarSeries()
    for y_right_col in y_right_cols:  # 根据右轴画柱形
        # 计算做轴的最值用于设置范围
        table_df[y_right_col] = table_df[y_right_col].apply(
            covert_float)  # y轴列转为浮点数值
        # 获取最值
        y_min, y_max = table_df[y_right_col].min(), table_df[y_right_col].max()
        if y_min < y_right_min:
            y_right_min = y_min
        if y_max > y_right_max:
            y_right_max = y_max
        # 取得图线的源数据作折线图
        right_bar_data = table_df.iloc[:, [x_bottom, y_right_col]]
        bar = QBarSet(legend_labels[y_right_col])
        bar.setPen(QPen(Qt.transparent))
        for position_index, point_item in enumerate(
                right_bar_data.values.tolist()):
            bar.append(point_item[1])  # 取出源数据后一条线就2列数据
        right_bars.append(bar)
        right_bars.attachAxis(axis_x_bottom)
        right_bars.attachAxis(axis_y_right)
    # 右轴范围
    axis_y_right.setRange(y_right_min, y_right_max)
    chart.addSeries(left_bars)  # 左轴的柱形图加入图表
    # print(right_bars.count())
    if right_bars.count() != 0:  # 为空时加入会导致空位
        chart.addSeries(right_bars)
    chart.setAxisX(axis_x_bottom, left_bars)  # 关联设置x轴
    # 横轴标签设置
    x_bottom_interval = int(x_bottom_max / (tick_count - 1))
    if x_bottom_interval == 0:
        for i in range(0, x_bottom_max):
            axis_x_bottom.append(chart.x_labels[i], i)
    else:
        for i in range(0, x_bottom_max, x_bottom_interval):
            axis_x_bottom.append(chart.x_labels[i], i)
    chart.legend().setAlignment(Qt.AlignBottom)
    return chart
Exemple #20
0
def lines_stacked(name, table_df, x_bottom_cols, y_left_cols, y_right_cols,
                  legend_labels, tick_count):
    """
    折线堆叠图
    :param name: 图表名称
    :param table_df: 用于画图的pandas DataFrame对象
    :param x_bottom_cols:  下轴列索引列表
    :param y_left_cols: 左轴列索引列表
    :param y_right_cols: 右轴列索引列表
    :param legend_labels: 图例名称标签列表
    :param tick_count: 横轴刻度标签数
    :return: QChart实例
    """
    """ 过滤轴 """
    for y_left_col in y_left_cols:
        if is_datetime64_any_dtype(table_df[y_left_col]):  # 如果是时间轴
            y_left_cols.remove(y_left_col)
    for y_right_col in y_right_cols:
        if is_datetime64_any_dtype(table_df[y_right_col]):  # 如果是时间轴
            y_right_cols.remove(y_right_col)
    # 将x轴转为字符串
    x_bottom = x_bottom_cols[0]  # x轴列
    if is_datetime64_any_dtype(table_df[x_bottom]):  # 如果x轴是时间轴
        table_df[x_bottom] = table_df[x_bottom].apply(
            lambda x: x.strftime('%Y-%m-%d'))
    else:  # x轴非时间轴
        table_df[x_bottom] = table_df[x_bottom].apply(lambda x: str(x))
    font = QFont()  # 轴文字风格
    font.setPointSize(7)  # 轴标签文字大小
    chart = QChart()  # 图表实例
    chart.layout().setContentsMargins(0, 0, 0, 0)  # chart的外边距
    chart.setMargins(QMargins(15, 5, 15, 0))  # chart内边距
    chart.setTitle(name)  # chart名称
    """ x轴 """
    axis_x_bottom = QCategoryAxis(
        chart, labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
    axis_x_bottom.setLabelsAngle(-90)  # 逆时针旋转90度
    axis_x_bottom.setLabelsFont(font)  # 设置字体样式
    axis_x_bottom.setGridLineVisible(False)  # 竖向连接线不可见
    chart.addAxis(axis_x_bottom, Qt.AlignBottom)  # 加入坐标x轴
    has_x_labels = False  # 收集x轴刻度的开关
    chart.x_labels = list()  # 绑定chart一个x轴的刻度列表
    """ 左Y轴 """
    axis_y_left = QValueAxis()
    axis_y_left.setLabelsFont(font)
    axis_y_left.setLabelFormat('%i')
    chart.addAxis(axis_y_left, Qt.AlignLeft)  # 图表加入左轴
    """ 右Y轴 """
    axis_y_right = QValueAxis()
    axis_y_right.setLabelsFont(font)
    axis_y_right.setLabelFormat('%.2f')
    chart.addAxis(axis_y_right, Qt.AlignRight)
    # 记录各轴的最值
    x_bottom_min, x_bottom_max = 0, table_df.shape[0]
    y_left_min, y_left_max = 0, 0
    y_right_min, y_right_max = 0, 0
    """ 根据左轴画折线 """
    for y_left_col in y_left_cols:  # 根据左轴画折线
        # 计算做轴的最值用于设置范围
        table_df[y_left_col] = table_df[y_left_col].apply(
            covert_float)  # y轴列转为浮点数值
        # 获取最值
        y_min, y_max = table_df[y_left_col].min(), table_df[y_left_col].max()
        if y_min < y_left_min:
            y_left_min = y_min
        if y_max > y_left_max:
            y_left_max = y_max
        # 取得图线的源数据作折线图
        left_line_data = table_df.iloc[:, [x_bottom, y_left_col]]
        series = QLineSeries()
        series.setName(legend_labels[y_left_col])
        for position_index, point_item in enumerate(
                left_line_data.values.tolist()):
            series.append(position_index, point_item[1])  # 取出源数据后一条线就2列数据
            # 收集坐标标签
            if not has_x_labels:
                chart.x_labels.append(point_item[0])
        chart.addSeries(series)  # 折线入图
        series.attachAxis(axis_x_bottom)
        series.attachAxis(axis_y_left)
    # 左轴范围
    axis_y_left.setRange(y_left_min, y_left_max)
    """ 根据右轴画折线 """
    for y_right_col in y_right_cols:  # 根据右轴画折线
        # 计算做轴的最值用于设置范围
        table_df[y_right_col] = table_df[y_right_col].apply(
            covert_float)  # y轴列转为浮点数值
        # 获取最值
        y_min, y_max = table_df[y_right_col].min(), table_df[y_right_col].max()
        if y_min < y_right_min:
            y_right_min = y_min
        if y_max > y_right_max:
            y_right_max = y_max
        # 取得图线的源数据作折线图
        left_line_data = table_df.iloc[:, [x_bottom, y_right_col]]
        series = QLineSeries()
        series.setName(legend_labels[y_right_col])
        for position_index, point_item in enumerate(
                left_line_data.values.tolist()):
            series.append(position_index, point_item[1])  # 取出源数据后一条线就2列数据
        chart.addSeries(series)
        series.attachAxis(axis_x_bottom)
        series.attachAxis(axis_y_right)
    # 右轴范围
    axis_y_right.setRange(y_right_min, y_right_max)
    # 设置下轴刻度标签
    # print('x轴最大值', x_bottom_max)
    x_bottom_interval = int(x_bottom_max / (tick_count - 1))
    if x_bottom_interval == 0:
        for i in range(0, x_bottom_max):
            axis_x_bottom.append(chart.x_labels[i], i)
    else:
        for i in range(0, x_bottom_max, x_bottom_interval):
            axis_x_bottom.append(chart.x_labels[i], i)
    chart.legend().setAlignment(Qt.AlignBottom)
    return chart
Exemple #21
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()