示例#1
0
class BaseTimedGraph(QChartView):
    def __init__(self, chart=None, parent=None):
        super(BaseTimedGraph, self).__init__(parent)
        self.setObjectName('BaseGraph')

        self.seriesPurgedT = None
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.chart = chart if chart else QChart()

        self.setRenderHint(QPainter.Antialiasing)

        self.axisX = QDateTimeAxis()
        self.axisX.setTickCount(5)
        self.axisX.setFormat('hh:mm:ss')
        self.axisX.setTitleText('Time')
        self.chart.addAxis(self.axisX, Qt.AlignBottom)

        self.axisY = QValueAxis()
        self.axisY.setLabelFormat('%i')
        self.axisY.setMin(0)
        self.axisY.setMax(1024)

        self.chart.addAxis(self.axisY, Qt.AlignLeft)

    def removeOldSeries(self, series, before: int):
        for point in series.pointsVector():
            if point.x() < before:
                series.remove(point)

    async def onBwStats(self, stats):
        pass
示例#2
0
文件: test.py 项目: 524836851/RT_GUI
class ChartView(QChartView,QChart):
    def __init__(self, *args, **kwargs):
        super(ChartView, self).__init__(*args, **kwargs)
        self.resize(800, 600)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self.chart_init()
        self.timer_init()
    def timer_init(self):
        #使用QTimer,2秒触发一次,更新数据
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.drawLine)
        self.timer.start(100)
    def chart_init(self):
        self.chart = QChart()
        self.series = QScatterSeries()
        #设置曲线名称
        self.series.setName("实时数据")
        self.series.setColor(QColor(255,0,0))
        self.series.setMarkerSize(20.0)
        self.series.setPen(QPen(QtCore.Qt.PenStyle.NoPen))
        #把曲线添加到QChart的实例中
        self.chart.addSeries(self.series)
        #声明并初始化X轴,Y轴
        self.dtaxisX = QDateTimeAxis()
        self.vlaxisY = QValueAxis()
        #设置坐标轴显示范围
        self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300*1))
        self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
        self.vlaxisY.setMin(0)
        self.vlaxisY.setMax(1500)
        #设置X轴时间样式
        self.dtaxisX.setFormat("MM月dd hh:mm:ss")
        #设置坐标轴上的格点
        self.dtaxisX.setTickCount(6)
        self.vlaxisY.setTickCount(11)
        #设置坐标轴名称
        self.dtaxisX.setTitleText("时间")
        self.vlaxisY.setTitleText("量程")
        #设置网格不显示`
        #把坐标轴添加到chart中
        self.chart.addAxis(self.dtaxisX,Qt.AlignBottom)
        self.chart.addAxis(self.vlaxisY,Qt.AlignLeft)
        #把曲线关联到坐标轴
        self.series.attachAxis(self.dtaxisX)
        self.series.attachAxis(self.vlaxisY)

        self.setChart(self.chart)
    def drawLine(self):
        #获取当前时间
        bjtime = QDateTime.currentDateTime()
        #更新X轴坐标
        self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300*1))
        self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
        #当曲线上的点超出X轴的范围时,移除最早的点
        if(self.series.count()>149):
            self.series.removePoints(0,self.series.count()-149)
        #产生随即数
        yint = random.randint(0,1500)
        #添加数据到曲线末端
        self.series.append(bjtime.toMSecsSinceEpoch(),yint)
示例#3
0
    def make_axis(self):
        if self.x_time_scaled:
            axis_x = QDateTimeAxis()
            axis_x.setFormat("yyyy-MM-dd HH:mm:ss")
            axis_x.setTitleText("Время")
        else:
            axis_x = QValueAxis()
            axis_x.setTitleText(self.x_name)

        if self.x_min:
            axis_x.setMin(self.x_min)
        if self.x_max:
            axis_x.setMax(self.x_max)

        axis_x.setLabelsAngle(self.x_label_angle)
        axis_x.setTickCount(self.x_tick_num)

        axis_y = QValueAxis()
        if self.y_min:
            axis_y.setMin(self.y_min)
        if self.y_max:
            axis_y.setMax(self.y_max)

        axis_y.setTitleText(self.y_name)
        axis_y.setTickCount(self.y_tick_num)
        axis_y.setLabelsAngle(self.y_label_angle)

        return axis_x, axis_y
示例#4
0
def auto_adjust_axis(axis: QValueAxis,
                     bar_sets: [QBarSet],
                     padding: float = 2):

    # Adjust the range so that everything is visible and add some gaps

    set_count = len(bar_sets)

    minimums = []

    maximums = []

    for i in range(set_count):
        minimums.append(sys.maxsize)
        maximums.append(-sys.maxsize)

    for set_index in range(set_count):

        bar_set = bar_sets[set_index]

        for i in range(bar_set.count()):
            minimums[set_index] = min(minimums[set_index], bar_set.at(i))
            maximums[set_index] = max(maximums[set_index], bar_set.at(i))

    minimums.append(0)
    axis_min = min(minimums) - padding

    maximums.append(0)
    axis_max = max(maximums) + padding

    print("axis min = {}, axis max = {}".format(axis_min, axis_max))

    axis.setMin(axis_min)
    axis.setMax(axis_max)
示例#5
0
class ChartView(QChartView):
    def __init__(self):
        QChartView.__init__(self)
        #self.resize(300, 300)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self.chart = QChart()
        self.seriesAcc = QLineSeries()
        self.seriesAcc.setName(CONF.leftUpNames[0])
        self.chart.addSeries(self.seriesAcc)
        #声明并初始化X轴,Y轴
        self.dtaxisX = QValueAxis()
        self.vlaxisY = QValueAxis()
        #设置坐标轴显示范围
        self.dtaxisX.setMin(0)
        #self.dtaxisX.setMax(100)
        self.vlaxisY.setMin(0)
        #self.vlaxisY.setMax(100)
        self.dtaxisX.setTickCount(3)
        self.vlaxisY.setTickCount(3)
        #设置坐标轴名称
        self.dtaxisX.setTitleText(CONF.leftUpNames[1])
        self.vlaxisY.setTitleText(CONF.leftUpNames[2])
        #设置网格不显示
        self.vlaxisY.setGridLineVisible(False)
        #把坐标轴添加到chart中
        self.chart.addAxis(self.dtaxisX, Qt.AlignBottom)
        self.chart.addAxis(self.vlaxisY, Qt.AlignLeft)

        self.seriesAcc.attachAxis(self.dtaxisX)
        self.seriesAcc.attachAxis(self.vlaxisY)

        self.initUI()

    def initUI(self):
        self.backend = BackendThread()
        self.backend.update_line.connect(self.handleLine)
        self.backend.start()

    def handleLine(self, data):
        if data[0] == 0:
            self.seriesAcc.clear()
        else:
            self.dtaxisX.setMax(data[0])
            self.vlaxisY.setMax(data[0])
            self.seriesAcc.clear()
            self.seriesAcc.append(0, 0)
            self.seriesAcc.append(data[0], data[1])

        self.setChart(self.chart)
示例#6
0
    def update_graph(self, index):
        if index == 2:
            self.graph_chart.removeAllSeries()

            axis_x = QBarCategoryAxis()
            axis_x.setTitleText("日期")
            if self.graph_chart.axisX():
                self.graph_chart.removeAxis(self.graph_chart.axisX())
            self.graph_chart.addAxis(axis_x, Qt.AlignBottom)

            axis_y = QValueAxis()
            axis_y.setLabelFormat("%i")
            axis_y.setTitleText("售出量")
            if self.graph_chart.axisY():
                self.graph_chart.removeAxis(self.graph_chart.axisY())
            self.graph_chart.addAxis(axis_y, Qt.AlignLeft)

            max_num = 0
            total_date = 0
            set_dict = {}
            for key, data in sorted(self.graph_series.items(),
                                    key=lambda i: int(i[0])):
                axis_x.append(
                    QDateTime.fromSecsSinceEpoch(
                        int(key)).toString("yyyy年MM月dd日"))
                for set_name, value in data.items():
                    if set_name not in set_dict:
                        set_dict[set_name] = QBarSet(set_name)
                        for _ in range(total_date):
                            set_dict[set_name].append(0)
                    set_dict[set_name].append(value)
                    max_num = max(max_num, value)
                total_date += 1
                for _, bar_set in set_dict.items():
                    if bar_set.count() < total_date:
                        bar_set.append(0)
            bar_series = QBarSeries()
            for _, bar_set in set_dict.items():
                bar_series.append(bar_set)
            bar_series.hovered.connect(self.graph_tooltip)
            axis_y.setMax(max_num + 1)
            axis_y.setMin(0)
            self.graph_chart.addSeries(bar_series)
            bar_series.attachAxis(axis_x)
            bar_series.attachAxis(axis_y)
示例#7
0
    def createChart(self):
        self.timeChart = QChart()
        titleFont = QFont()
        titleFont.setPixelSize(18)
        titleBrush = QBrush(QColor(0, 0, 255))
        self.timeChart.setTitleFont(titleFont)
        self.timeChart.setTitleBrush(titleBrush)
        self.timeChart.setTitle('Signal (Past ' + str(self.maxPoints) +
                                ' Samples)')
        # self.timeChart.addSeries(testseries)
        # self.timeChart.createDefaultAxes()
        self.timeChart.legend().hide()

        # Axis examples: https://doc.qt.io/qt-5/qtcharts-multiaxis-example.html
        newAxis = QValueAxis()
        newAxis.setMin(0)
        newAxis.setMax(self.maxPoints)
        newAxis.setTickCount(11)
        newAxis.setLabelFormat("%d")
        newAxis.setTitleText("Sample")
        self.timeChart.addAxis(newAxis, Qt.AlignBottom)

        newAxis = QValueAxis()
        newAxis.setMin(-100)
        newAxis.setMax(-10)
        newAxis.setTickCount(9)
        newAxis.setLabelFormat("%d")
        newAxis.setTitleText("dBm")
        self.timeChart.addAxis(newAxis, Qt.AlignLeft)

        chartBorder = Qt.darkGray
        self.timePlot = QChartView(self.timeChart, self)
        self.timePlot.setBackgroundBrush(chartBorder)
        self.timePlot.setRenderHint(QPainter.Antialiasing)

        self.timeSeries = QLineSeries()
        pen = QPen(Qt.yellow)

        pen.setWidth(2)
        self.timeSeries.setPen(pen)
        self.timeChart.addSeries(self.timeSeries)
        self.timeSeries.attachAxis(self.timeChart.axisX())
        self.timeSeries.attachAxis(self.timeChart.axisY())
    def create_graph(self):
        self.emotion_set = QBarSet('Confidence Level')

        self.emotion_set.append([
            self.face_anger_digust, self.face_happy, self.face_neutral,
            self.face_sadness, self.face_surprise_fear
        ])

        series = QHorizontalBarSeries()
        series.append(self.emotion_set)

        chart = QChart()
        chart.addSeries(series)
        chart.setTitle('ReLuu FaceReader')

        chart.setAnimationOptions(QChart.SeriesAnimations)

        months = ('Angery and Disgusted', 'Happy', 'Neutral', 'Sadness',
                  'Fear and Surprise')

        axisY = QBarCategoryAxis()
        axisY.append(months)
        chart.addAxis(axisY, Qt.AlignLeft)
        series.attachAxis(axisY)

        axisX = QValueAxis()
        axisX.setMax(1.0)
        chart.addAxis(axisX, Qt.AlignBottom)
        series.attachAxis(axisX)

        axisX.applyNiceNumbers()

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

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

        self.setCentralWidget(chartView)
示例#9
0
class PulseGen(QtWidgets.QMainWindow, Ui_MainWindow):

    GENERATOR_PORT = 5000

    def __init__(self, parent=None):

        super(PulseGen, self).__init__(parent)
        self.setupUi(self)
        self.pulse_gen_display = PulseGenDisplay()
        self.display_data = [0] * 500

        self.pulse_height_max = self.pulse_height_dial.maximum()
        self.pulse_height_min = self.pulse_height_dial.minimum()

        self.pulse_gen_display.pulse_height = self.pulse_height_max
        # set pulse height
        self.pulse_gen_display.pulse_height = self.pulse_height_max
        self.pulse_height_dial.setValue(self.pulse_gen_display.pulse_height)
        self.pulse_height_dial.actionTriggered.connect(self.avoid_wrapping)
        self.pulse_height_dial.valueChanged.connect(self.pulse_height_changed)

        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))

        # don't allow editing
        self.pulse_height_text.textChanged.connect(self.no_editing)

        # pulse shape
        for pulse_form in self.pulse_gen_display.pulse_shape.keys():
            self.pulse_shape_combo.addItem(pulse_form)
        self.pulse_shape_combo.currentIndexChanged.connect(
            self.pulse_shape_changed)

        current_pulse_form = self.pulse_shape_combo.currentText()
        self.pulse_gen_display.pulse_form = self.pulse_gen_display.pulse_shape[
            current_pulse_form]
        print("Current pulse form: " + current_pulse_form + " code: " +
              str(self.pulse_gen_display.pulse_form))

        for pulse_freq in self.pulse_gen_display.frequencies.keys():
            self.gen_freq_combo.addItem(pulse_freq)

        current_pulse_freq = self.gen_freq_combo.currentText()
        self.pulse_gen_display.pulse_T = self.pulse_gen_display.frequencies[
            current_pulse_freq]
        print("Current pulse T: " + str(self.pulse_gen_display.pulse_T))
        self.gen_freq_combo.currentIndexChanged.connect(
            self.pulse_freq_changed)

        for display_freq in self.pulse_gen_display.frequencies.keys():
            self.display_freq_combo.addItem(display_freq)
        self.display_freq_combo.currentIndexChanged.connect(
            self.display_freq_changed)

        current_display_freq = self.display_freq_combo.currentText()
        self.pulse_gen_display.display_T = self.pulse_gen_display.frequencies[
            current_display_freq]
        print("Current display T: " + str(self.pulse_gen_display.display_T))

        self.start_stop_pb.clicked.connect(self.start_stop_meas)
        self.connect_pb.clicked.connect(self.connect)

        self.gen_chart = QChart()
        self.gen_chart.legend().hide()
        self.x_axis = QValueAxis()
        self.x_axis.setMax(500 * self.pulse_gen_display.display_T)
        self.x_axis.setMin(0)
        self.y_axis = QValueAxis()
        self.y_axis.setMax(3.3)
        self.y_axis.setMin(0)
        self.gen_chart.addAxis(self.x_axis, Qt.AlignBottom)
        self.gen_chart.addAxis(self.y_axis, Qt.AlignLeft)
        self.generator_screen.setChart(self.gen_chart)
        # display the initial pulse
        self.pulse_gen_display.calc_pulse()
        self.pulse_gen_display.get_display_data()

        self.series = QLineSeries()

        for i in range(500):
            self.series.append(
                i * self.pulse_gen_display.display_T,
                self.pulse_gen_display.display_data[i] *
                self.pulse_gen_display.calib)
        self.gen_chart.addSeries(self.series)
        self.series.attachAxis(self.x_axis)
        self.series.attachAxis(self.y_axis)
        self.display_pulse()

        self.pulse_height_timer = QTimer()
        self.pulse_height_timer.setSingleShot(True)
        self.pulse_height_timer.timeout.connect(self.pulse_height_ready)

        self.genRunning = False
        self.actionQuit.triggered.connect(self.quit)

        self.client_socket = QTcpSocket(self)
        self.connected = False
        self.show()

    def no_editing(self):
        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))

    def avoid_wrapping(self, val):
        if val == QtWidgets.QAbstractSlider.SliderMove:
            minDistance = 1
            if self.pulse_height_dial.value() == self.pulse_height_max \
               and self.pulse_height_dial.sliderPosition()<self.pulse_height_max-minDistance:
                self.pulse_height_dial.setSliderPosition(self.pulse_height_max)
            elif self.pulse_height_dial.value() == self.pulse_height_min \
               and self.pulse_height_dial.sliderPosition()>self.pulse_height_min+minDistance:
                self.pulse_height_dial.setSliderPosition(self.pulse_height_min)

    def pulse_shape_changed(self):
        '''
        if self.genRunning:
            print("Current shape index: ",self.pulse_shape_combo.currentIndex())
            print("current pulse form: ",self.pulse_gen_display.pulse_form)
            if self.pulse_shape_combo.currentIndex() == self.pulse_gen_display.pulse_form:
                return
            QMessageBox.warning(self,
                                'Pulse generation is active',
                                'Pulse generator is running\nPlease stop pulse generation before changing parameters')
            self.pulse_shape_combo.setCurrentIndex(self.pulse_gen_display.pulse_form)
            return
        '''
        print("pulse shape changed")
        current_pulse_form = self.pulse_shape_combo.currentText()
        self.pulse_gen_display.pulse_form = self.pulse_gen_display.pulse_shape[
            current_pulse_form]
        print("Current pulse form: " + current_pulse_form + " code: " +
              str(self.pulse_gen_display.pulse_form))
        self.display_pulse()
        if not self.connected:
            return
        else:
            pulse_form_msg = "pulse_shape=" + str(
                self.pulse_gen_display.pulse_form) + "\n"
            print("Sending: " + pulse_form_msg)
            self.client_socket.write(bytes(pulse_form_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def pulse_freq_changed(self):

        new_freq = self.gen_freq_combo.currentText()
        self.pulse_gen_display.pulse_T = self.pulse_gen_display.frequencies[
            new_freq]
        print("Pulse frequency changed to " + new_freq + "T: " +
              str(self.pulse_gen_display.pulse_T))
        self.display_pulse()
        '''
        if self.genRunning:
            if self.pulse_gen_display.frequencies[self.gen_freq_combo.currentText()] == self.pulse_gen_display.pulse_T:
                return

            QMessageBox.warning(self,
                                'Pulse generation is active',
                                'Pulse generator is running\nPlease stop pulse generation before changing parameters')
            index = 0
            for freq in self.pulse_gen_display.frequencies.keys():
                print("freq: ",freq)
                print("val: ",self.pulse_gen_display.frequencies[freq])
                if self.pulse_gen_display.frequencies[freq] == self.pulse_gen_display.pulse_T:
                    self.gen_freq_combo.setCurrentIndex(index)
                    break                     
                index += 1
            return
        '''
        if not self.connected:
            return
        else:
            pulse_T_msg = "pulse_T=" + str(
                self.pulse_gen_display.pulse_T) + "\n"
            print("Sending: " + pulse_T_msg)
            self.client_socket.write(bytes(pulse_T_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def display_freq_changed(self):
        new_freq = self.display_freq_combo.currentText()
        self.pulse_gen_display.display_T = self.pulse_gen_display.frequencies[
            new_freq]
        self.display_pulse()

    def pulse_height_changed(self):
        self.pulse_gen_display.pulse_height = self.pulse_height_dial.value()
        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))
        self.display_pulse()
        self.pulse_height_timer.start(500)

    def pulse_height_ready(self):
        print("Timeout")
        if not self.connected:
            return
        else:
            pulse_height_msg = "pulse_height=" + str(
                self.pulse_gen_display.pulse_height) + "\n"
            print("Sending: " + pulse_height_msg)
            self.client_socket.write(bytes(pulse_height_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def connect(self):
        if self.connected:
            self.client_socket.close()
            self.connected = False
            self.connect_pb.setChecked(False)
            self.connect_pb.setText("Connect to Pulse Generator")
            return
        server_ip = str(self.server_ip_text.text())
        port = self.GENERATOR_PORT
        print("Server IP: ", server_ip)
        if server_ip.find('xxx') != -1:
            print("bad IP")
            QMessageBox.about(
                self, 'Bad Server IP', 'Please give a correct Server IP\n'
                'IP is ' + server_ip)
            self.connect_pb.setChecked(False)
            return
        else:
            print("Connecting to " + server_ip + ":", port)
            self.client_socket.connectToHost(server_ip, port)
            self.client_socket.waitForConnected(1000)

        if self.client_socket.state() != QTcpSocket.ConnectedState:
            QMessageBox.warning(
                self, 'Connection failed',
                'Please check IP address and port number\nIs the server running?'
            )
            self.connect_pb.setChecked(False)
            return

        print("Connection established")
        self.connect_pb.setText("Connected")

        self.client_socket.waitForReadyRead()
        connectMsg = self.client_socket.readAll()
        msgstring = bytes(connectMsg).decode()
        print("Connection message:" + msgstring)

        print("Send generator settings")
        pulse_form_msg = "pulse_shape=" + str(
            self.pulse_gen_display.pulse_form) + "\n"
        print("Sending: " + pulse_form_msg)
        self.client_socket.write(bytes(pulse_form_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        pulse_T_msg = "pulse_T=" + str(self.pulse_gen_display.pulse_T) + "\n"
        print("Sending: " + pulse_T_msg)
        self.client_socket.write(bytes(pulse_T_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        pulse_height_msg = "pulse_height=" + str(
            self.pulse_gen_display.pulse_height) + "\n"
        print("Sending: " + pulse_height_msg)
        self.client_socket.write(bytes(pulse_height_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        running_msg = 'running?=\n'
        print("Sending: " + running_msg)
        self.client_socket.write(bytes(running_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        response = bytes(responseMsg).decode()
        print("reponse msg: ", response)
        if response == 'yes\n':
            print("task is running")
        elif response == 'no\n':
            print("task is not running")
        else:
            print("Don't know if task is running")

        self.connected = True

    def start_stop_meas(self):
        if not self.connected:
            QMessageBox.about(
                self, 'You must be connected to the generator server\n'
                'please connect and try again')
            return

        if self.start_stop_pb.isChecked():
            print("Start generation")
            # send current generator settings

            self.start_stop_pb.setText("Stop Pulse Generation")
            msg = 'start=\n'
            print("Sending: " + msg)
            self.client_socket.write(msg.encode())
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())
            self.genRunning = True
        else:
            print("Stop generation")
            self.start_stop_pb.setText("Start Pulse Generation")
            msg = 'stop=\n'
            self.client_socket.write(msg.encode())
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())
            self.genRunning = False

    def readTrace(self):
        print("Message from the generator")
        data = self.server_socket.readAll()
        msgstring = bytes(data).decode()
        print(msgstring)
        print(data, type(data))

    def display_pulse(self):
        self.pulse_gen_display.calc_pulse()
        self.pulse_gen_display.get_display_data()

        self.x_axis.setMax(500 * self.pulse_gen_display.display_T)
        data_points = self.series.pointsVector()
        for i in range(500):
            data_points[i].setX(i * self.pulse_gen_display.display_T)
            data_points[i].setY(self.pulse_gen_display.display_data[i] *
                                self.pulse_gen_display.calib)
        self.series.replace(data_points)

    def quit(self):
        app.exit()
示例#10
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_8, 极坐标图")

        self.__iniChart()  # 创建self.chart
        self.__drawRose()

##  ==============自定义功能函数========================

    def __iniChart(self):  #图表初始化
        self.chart = QPolarChart()  ##极坐标图
        self.chart.legend().setVisible(False)
        self.ui.chartView.setChart(self.chart)
        self.ui.chartView.setRenderHint(QPainter.Antialiasing)
        self.ui.chartView.setCursor(Qt.CrossCursor)

        self.__axisAngle = QValueAxis()  #角度坐标轴
        self.__axisAngle.setRange(0, 360)  #角度范围
        self.__axisAngle.setLabelFormat("NE %.0f")
        self.__axisAngle.setTickCount(9)
        self.chart.addAxis(self.__axisAngle,
                           QPolarChart.PolarOrientationAngular)

        self.__axisRadial = QValueAxis()  #径向坐标轴
        self.__axisRadial.setTickCount(6)
        self.__axisRadial.setLabelFormat("%.1f")  #标签格式
        self.chart.addAxis(self.__axisRadial,
                           QPolarChart.PolarOrientationRadial)

        pen = QPen(Qt.blue)
        pen.setWidth(2)
        seriesSpLine = QSplineSeries()
        seriesSpLine.setPen(pen)
        seriesSpLine.setPointsVisible(True)  #数据点可见
        seriesSpLine.hovered.connect(self.do_series_hovered)

        self.chart.addSeries(seriesSpLine)
        seriesSpLine.attachAxis(self.__axisAngle)
        seriesSpLine.attachAxis(self.__axisRadial)

    def __drawRose(self):
        series0 = self.chart.series()[0]
        series0.clear()

        theta = 0.0  #角度
        delta = 5.0  #角度变化量
        R = 10.0  #最大长度
        N = self.ui.spinCount.value()  #花瓣数

        cnt = 1 + math.ceil(360 / delta)  #数据点个数
        for i in range(cnt):
            ang = math.radians(theta)  #角度转换为弧度
            rho = R * math.cos(N * ang)
            series0.append(theta, rho)  #数据点:角度,长度
            theta = theta + delta

        self.__axisRadial.setRange(0, 2 + R)

##  ==============event处理函数==========================

##  ==========由connectSlotsByName()自动连接的槽函数============
## 工具栏按钮

    @pyqtSlot()  ##重画曲线
    def on_actRedraw_triggered(self):
        self.ui.spinAngle_Min.setValue(0)
        self.ui.spinAngle_Max.setValue(360)
        self.__drawRose()

    @pyqtSlot()  ##放大
    def on_actZoomIn_triggered(self):
        self.ui.chartView.chart().zoom(1.2)

    @pyqtSlot()  ##缩小
    def on_actZoomOut_triggered(self):
        self.ui.chartView.chart().zoom(0.8)

    @pyqtSlot()  ##恢复原始大小
    def on_actZoomReset_triggered(self):
        self.ui.chartView.chart().zoomReset()

    ##图表外观控制
    @pyqtSlot(int)  ##主题
    def on_comboTheme_currentIndexChanged(self, index):
        self.ui.chartView.chart().setTheme(QChart.ChartTheme(index))

    @pyqtSlot(bool)  ##显示数据点
    def on_chkBox_ShowPoints_clicked(self, checked):
        series = self.ui.chartView.chart().series()[0]
        series.setPointsVisible(checked)

    ## 角度坐标轴设置
    @pyqtSlot(int)  ##设置坐标最小值
    def on_spinAngle_Min_valueChanged(self, arg1):
        self.__axisAngle.setMin(arg1)

    @pyqtSlot(int)  ##设置坐标最大值
    def on_spinAngle_Max_valueChanged(self, arg1):
        self.__axisAngle.setMax(arg1)

    @pyqtSlot(int)  ##分度数
    def on_spinAngle_Ticks_valueChanged(self, arg1):
        self.__axisAngle.setTickCount(arg1)

    ## 径向坐标轴设置
    @pyqtSlot(int)  ##设置坐标范围
    def on_spinRadial_Max_valueChanged(self, arg1):
        self.__axisRadial.setMax(arg1)

    @pyqtSlot(int)  ##分度数
    def on_spinRadial_Ticks_valueChanged(self, arg1):
        self.__axisRadial.setTickCount(arg1)

    @pyqtSlot(int)  ##花瓣个数
    def on_spinCount_valueChanged(self, value):
        self.__drawRose()

    ## 旋转
    @pyqtSlot()  ##两个相邻点的角度差如果大于180度,就不会直连,而是连接到中心
    def on_btnRotate_clicked(self):
        dltAng = self.ui.spinRotate.value()  #旋转的角度,顺时针方向为正
        series0 = self.chart.series()[0]  #获取序列

        pointCount = len(series0.pointsVector())  #数据点个数
        for i in range(pointCount):
            pt = series0.pointsVector()[i]  #QPointF
            ang = pt.x() + dltAng
            if ang >= 360:
                ang = ang - 360
            elif ang < 0:
                ang = 360 + ang
            series0.replace(i, ang, pt.y())

##  =============自定义槽函数===============================

    def do_series_hovered(self, point, state):
        info = "Series 极径=, 角度="
        if state:
            info = "Series 极径=%.1f,角度=NE %.1f°" % (point.y(), point.x())
        self.ui.statusBar.showMessage(info)
class Plot(QChartView):
    def __init__(self, parent=None):
        super(Plot, self).__init__(parent)

        self.setFixedSize(PLOT_WIDTH, PLOT_HEIGHT)

        self.xMax = None
        self.yMin = None
        self.yMax = None

        self.xAutoRescale = True
        self.yMinAutoRescale = True
        self.yMaxAutoRescale = True

        self.seriesList = []

        self.chart = QChart()

        self.xAxis = QValueAxis()
        self.chart.addAxis(self.xAxis, Qt.AlignBottom)

        self.yAxis = QValueAxis()
        self.chart.addAxis(self.yAxis, Qt.AlignLeft)

        self.setSubplots(1)

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

        self.setChart(self.chart)
        # self.setRenderHint(QPainter.Antialiasing)

    def grabScreenshot(self, title):
        pixmap = QPixmap(self.grab())
        pixmap.save(title + '.png', 'PNG')

    @pyqtSlot(int)
    def setSubplots(self, count: int):
        for _ in range(count):
            series = QLineSeries()
            self.chart.addSeries(series)
            series.attachAxis(self.xAxis)
            series.attachAxis(self.yAxis)
            self.seriesList.append(series)

    @pyqtSlot(str)
    def setTitle(self, title: str):
        self.chart.setTitle(title)

    @pyqtSlot(str)
    def setXaxisTitle(self, title: str):
        self.xAxis.setTitleText(title)

    @pyqtSlot(str)
    def setYaxisTitle(self, title: str):
        self.yAxis.setTitleText(title)

    @pyqtSlot(float)
    def setXmax(self, xMax: float):
        self.xAxis.setMax(xMax)
        self.xAutoRescale = False

    @pyqtSlot(float)
    def setYmin(self, yMin: float):
        self.yAxis.setMin(yMin)
        self.yMinAutoRescale = False

    @pyqtSlot(float)
    def setYmax(self, yMax: float):
        self.yAxis.setMax(yMax)
        self.yMaxAutoRescale = False

    @pyqtSlot(float, float, int)
    def plot(self, x: float, y: float, subplotIndex: int):
        if subplotIndex > len(self.seriesList) - 1:
            raise IndexError(f'Invalid subplot index ({subplotIndex}, max: {len(self.seriesList)})')
        if self.xAutoRescale:
            self.xAxis.setMax(x)
        if self.yMinAutoRescale:
            if not self.yMin or y < self.yMin:
                self.yMin = y
                self.yAxis.setMin(y - 0.001)
        if self.yMaxAutoRescale:
            if not self.yMax or y > self.yMax:
                self.yMax = y
                self.yAxis.setMax(y + 0.001)
        self.seriesList[subplotIndex] << QPointF(float(x), float(y))
示例#12
0
class BalanceHistoryChartView(QChartView):
    """
    Chart that displays the balance between several dates
    from an account, token or whole portfolio
    """

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

        self.chart = QChart()
        self.FIAT_CURRENCY = confighandler.get_fiat_currency()

    def setupChartWithData(self, selectiontype, name=None):
        """
        Chart gets updated displaying new data.
        The data gets extracted from cbalancehistory, according 
        to the selection

        Parameters:
            - selectiontype : in ('account','token','all')
            - name: str, corresponds to account/token on cbalancehistory

        """
        self.chart = QChart()

        self.chart.setTheme(QChart.ChartThemeDark)
        self.chart.setAnimationOptions(QChart.SeriesAnimations)
        self.chart.setBackgroundBrush(QBrush(QColor('#19232d')))
#         self.chart.setTitle("")
#         self.chart.setTitleBrush(QBrush(QColor('white')))

        # Data
        # Get data
        if selectiontype == 'token':
            assert(name is not None)
            data = chistoricalbalances.get_balances_with_token_tuple(name)
        elif selectiontype == 'account':
            assert(name is not None)
            data = chistoricalbalances.get_balances_with_account_tuple(name)
        elif selectiontype == 'all':
            data = chistoricalbalances.get_balances_by_day_tuple()
        # Separate balance_btc from balance_fiat
        dates, balances_btc, balances_fiat = [], [], []
        for date in data:
            dates.append(int(date))
            balances_btc.append(data[date][0])
            balances_fiat.append(data[date][1])

        # Series
        self.btcseries = QSplineSeries()
        self.fiatseries = QSplineSeries()
        for date, balance_btc, balance_fiat in zip(dates, balances_btc, balances_fiat):
            date = datetime.fromtimestamp(date)
            date = datetime(date.year, date.month, date.day)
            dateQ = QDateTime(date).toMSecsSinceEpoch()
            self.btcseries.append(dateQ, balance_btc)
            self.fiatseries.append(dateQ, balance_fiat)

        # Append current point
        currentdate = QDateTime(datetime.today()).toMSecsSinceEpoch()
        if selectiontype == "all":
            # Append current balances
            self.btcseries.append(currentdate,
                                  cbalances.get_total_balance_all_accounts())
            self.fiatseries.append(currentdate,
                                   cbalances.get_total_balance_all_accounts_fiat())
        elif name != '':
            if selectiontype == "account":
                # Append current balances
                self.btcseries.append(
                    currentdate, cbalances.get_total_account_balance(name))
                self.fiatseries.append(
                    currentdate, cbalances.get_total_account_balance_fiat(name))
            elif selectiontype == "token":
                pass

        # Axis X (Dates)
        self.x_axis = QDateTimeAxis()
        self.x_axis.setTickCount(11)
        self.x_axis.setLabelsAngle(70)
        self.x_axis.setFormat("dd-MM-yy")
        self.x_axis.setTitleText(self.tr('Date'))

        # Axis Y (Balances)
        # BTC
        self.y_axis_btc = QValueAxis()
        if len(balances_btc) > 0:
            self.y_axis_btc.setMax(max(balances_btc)*1.1)
            self.y_axis_btc.setMin(min(balances_btc)*0.9)
        # Fiat
        self.y_axis_fiat = QValueAxis()
        if len(balances_fiat) > 0:
            self.y_axis_fiat.setMax(max(balances_fiat)*1.1)
            self.y_axis_fiat.setMin(min(balances_fiat)*0.9)

        self.chart.addAxis(self.y_axis_btc, Qt.AlignLeft)
        self.chart.addAxis(self.y_axis_fiat, Qt.AlignRight)
        self.chart.addAxis(self.x_axis, Qt.AlignBottom)

        # Add series to chart
        # BTC
        self.btcseries.setName("BTC")
        self.chart.addSeries(self.btcseries)
        self.btcseries.attachAxis(self.x_axis)
        self.btcseries.attachAxis(self.y_axis_btc)
        # Fiat
        self.fiatseries.setName(self.FIAT_CURRENCY.upper())
        self.chart.addSeries(self.fiatseries)
        self.fiatseries.attachAxis(self.x_axis)
        self.fiatseries.attachAxis(self.y_axis_fiat)

        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)
        self.setStyleSheet("border: 0px")
示例#13
0
class AmzHistoryChart(QWidget):
    """A chart that graphs the history of an AmazonListing's sales rank, price, and number of offers."""

    def __init__(self, parent=None):
        super(AmzHistoryChart, self).__init__(parent=parent)

        self.dbsession = Session()
        self.context_menu_actions = []
        self._avg_pointspan = 0
        self._max_points = 100
        self.source = None
        self.history = None

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        # Set up the chart
        self.chart_view = QChartView(self)
        self.chart_view.setRenderHint(QPainter.Antialiasing)
        self.chart_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.chart_view.customContextMenuRequested.connect(self.context_menu)

        self.chart = QChart()
        self.chart.legend().hide()
        self.chart.setFlags(QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsSelectable)
        self.chart.installEventFilter(self)
        self.chart_view.setChart(self.chart)

        self.layout().addWidget(self.chart_view)

        # Create the axes
        rcolor = QColor(50, 130, 220)
        pcolor = QColor(0, 200, 0)
        ocolor = QColor(255, 175, 0)

        self.timeAxis = QDateTimeAxis()
        self.timeAxis.setFormat('M/dd hh:mm')
        self.timeAxis.setTitleText('Date/Time')
        self.chart.addAxis(self.timeAxis, Qt.AlignBottom)

        self.timeAxis.minChanged.connect(self.on_timeaxis_min_changed)

        self.rankAxis = QValueAxis()
        self.rankAxis.setLabelFormat('%\'i')
        self.rankAxis.setTitleText('Sales Rank')
        self.rankAxis.setLinePenColor(rcolor)
        self.rankAxis.setLabelsColor(rcolor)
        self.chart.addAxis(self.rankAxis, Qt.AlignLeft)

        self.priceAxis = QValueAxis()
        self.priceAxis.setLabelFormat('$%.2f')
        self.priceAxis.setTitleText('Price')
        self.priceAxis.setLinePenColor(pcolor)
        self.priceAxis.setLabelsColor(pcolor)
        self.chart.addAxis(self.priceAxis, Qt.AlignRight)

        # Create the series
        self.rankLine = QLineSeries()
        self.chart.addSeries(self.rankLine)
        self.rankLine.attachAxis(self.timeAxis)
        self.rankLine.attachAxis(self.rankAxis)
        self.rankLine.setColor(rcolor)

        self.priceLine = QLineSeries()
        self.chart.addSeries(self.priceLine)
        self.priceLine.attachAxis(self.timeAxis)
        self.priceLine.attachAxis(self.priceAxis)
        self.priceLine.setColor(pcolor)

        self.salesPoints = QScatterSeries()
        self.chart.addSeries(self.salesPoints)
        self.salesPoints.attachAxis(self.timeAxis)
        self.salesPoints.attachAxis(self.rankAxis)
        self.salesPoints.setColor(ocolor)

    def add_context_action(self, action):
        """Add an action to the chart's context menu."""
        self.context_menu_actions.append(action)

    def add_context_actions(self, actions):
        """Adds all action in an iterable."""
        self.context_menu_actions.extend(actions)

    def remove_context_action(self, action):
        """Removes an action from the chart's context menu."""
        self.context_menu_actions.remove(action)

    def context_menu(self, point):
        """Show a context menu on the chart."""
        menu = QMenu(self)
        menu.addActions(self.context_menu_actions)

        point = self.chart_view.viewport().mapToGlobal(point)
        menu.popup(point)

    def set_source(self, source):
        """Set the source listing for the graph."""
        self.source = source

        # Update the chart
        self.rankLine.clear()
        self.priceLine.clear()
        self.salesPoints.clear()
        self.history = None

        start_date = datetime.utcnow() - timedelta(days=5)
        self.load_history_from(start_date)

        self.reset_axes()

    def load_history_from(self, start_date=datetime.utcfromtimestamp(0)):
        """Load history data from start-present."""
        if not self.source:
            self._avg_pointspan = 0
            return

        # Get the earliest point already in the chart
        points = self.rankLine.pointsVector()

        if points:
            # The chart is drawn right-to-left, so the last point is the earliest point
            earliest_msecs = points[-1].x()
            earliest = datetime.fromtimestamp(earliest_msecs / 1000, timezone.utc)

            if earliest <= start_date:
                return

        else:
            earliest = datetime.now(timezone.utc)

        # Get the product history stats if we don't already have them
        if self.history is None:
            self.history = dbhelpers.ProductHistoryStats(self.dbsession, self.source.id)

        # Start adding points to the chart
        last_row = None
        for row in self.dbsession.query(AmzProductHistory).\
                                  filter(AmzProductHistory.amz_listing_id == self.source.id,
                                         AmzProductHistory.timestamp > start_date.replace(tzinfo=None),
                                         AmzProductHistory.timestamp < earliest.replace(tzinfo=None)).\
                                  order_by(AmzProductHistory.timestamp.desc()):

            # SqlAlchemy returns naive timestamps
            time = row.timestamp.replace(tzinfo=timezone.utc).timestamp() * 1000

            self.rankLine.append(time, row.salesrank or 0)
            self.priceLine.append(time, row.price or 0)

            if last_row:
                # It's possible for salesrank to be None
                try:
                    slope = (last_row.salesrank - row.salesrank) / (last_row.timestamp.timestamp() - row.timestamp.timestamp())
                    if slope < -0.3:
                        self.salesPoints.append(last_row.timestamp.replace(tzinfo=timezone.utc).timestamp() * 1000,
                                                last_row.salesrank)
                except (TypeError, AttributeError):
                    pass

            last_row = row

        # Calculate the average span between points
        spans = 0
        for p1, p2 in itertools.zip_longest(itertools.islice(points, 0, None, 2), itertools.islice(points, 1, None, 2)):
            if p1 and p2: spans += abs(p1.x() - p2.x())

        self._avg_pointspan = spans // 2

    def on_timeaxis_min_changed(self, min):
        """Respond to a change in the time axis' minimum value."""
        # toTime_t() converts to UTC automatically
        utc_min = datetime.fromtimestamp(min.toTime_t(), timezone.utc)
        self.load_history_from(start_date=utc_min - timedelta(days=1))

    def reset_axes(self):
        """Resets the chart axes."""
        r = self.rankLine.pointsVector()
        p = self.priceLine.pointsVector()

        # If there is only one data point, set the min and max to the day before and the day after
        if len(r) == 1:
            tmin = QDateTime.fromMSecsSinceEpoch(r[0].x(), Qt.LocalTime).addDays(-1)
            tmax = QDateTime.fromMSecsSinceEpoch(r[0].x(), Qt.LocalTime).addDays(+1)
        else:
            tmin = min(r, key=lambda pt: pt.x(), default=QPointF(QDateTime.currentDateTime().addDays(-1).toMSecsSinceEpoch(), 0)).x()
            tmax = max(r, key=lambda pt: pt.x(), default=QPointF(QDateTime.currentDateTime().addDays(+1).toMSecsSinceEpoch(), 0)).x()
            tmin = QDateTime.fromMSecsSinceEpoch(tmin, Qt.LocalTime)
            tmax = QDateTime.fromMSecsSinceEpoch(tmax, Qt.LocalTime)

        self.timeAxis.setMin(tmin)
        self.timeAxis.setMax(tmax)

        # Find the min and max values of the series
        min_point = lambda pts: min(pts, key=lambda pt: pt.y(), default=QPointF(0, 0))
        max_point = lambda pts: max(pts, key=lambda pt: pt.y(), default=QPointF(0, 0))

        rmin = min_point(r)
        rmax = max_point(r)
        pmin = min_point(p)
        pmax = max_point(p)

        # Scale the mins and maxes to 'friendly' values
        scalemin = lambda v, step: ((v - step / 2) // step) * step
        scalemax = lambda v, step: ((v + step / 2) // step + 1) * step

        # The the axis bounds

        rmin = max(scalemin(rmin.y(), 1000), 0)
        rmax = scalemax(rmax.y(), 1000)
        pmin = max(scalemin(pmin.y(), 5), 0)
        pmax = scalemax(pmax.y(), 5)

        self.rankAxis.setMin(rmin)
        self.rankAxis.setMax(rmax)
        self.priceAxis.setMin(pmin)
        self.priceAxis.setMax(pmax)

    def eventFilter(self, watched, event):
        """Intercept and handle mouse events."""
        if event.type() == QEvent.GraphicsSceneWheel and event.orientation() == Qt.Vertical:
            factor = 0.95 if event.delta() < 0 else 1.05
            self.chart.zoom(factor)
            return True

        if event.type() == QEvent.GraphicsSceneMouseDoubleClick:
            self.chart.zoomReset()
            self.reset_axes()
            return True

        if event.type() == QEvent.GraphicsSceneMouseMove:
            delta = event.pos() - event.lastPos()
            self.chart.scroll(-delta.x(), delta.y())
            return True

        return False
示例#14
0
class SeeingMonitor(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(SeeingMonitor, self).__init__()
        self.setupUi(self)

        self.Camera = None
        self.THRESH = None
        self.threshold_auto = False
        self.frame = None
        self.draw_only_frame = None
        self.video_source = VideoSource.NONE
        self.export_video = False
        self.select_noiseArea = False
        self.coordinates_noiseArea = []
        self.lineedit_path.setText(QDir.currentPath())
        self.lineedit_filename.setText("seeing.csv")
        self.save_filename = None
        self._updateFileSave()
        self.pause_pressed = False

        self.datetimeedit_start.setMinimumDateTime(QDateTime.currentDateTime())
        self.datetimeedit_end.setMinimumDateTime(QDateTime.currentDateTime())

        if platform.system() == 'Linux':
            self.button_start.setEnabled(False)
            self.button_settings.setEnabled(False)

        self.button_start.clicked.connect(self.startLiveCamera)
        self.button_settings.clicked.connect(self.showSettings)
        self.button_simulation.clicked.connect(self.startSimulation)
        self.button_import.clicked.connect(self.importVideo)
        self.button_export.clicked.connect(self.exportVideo)
        self.button_noise.clicked.connect(self.selectNoiseArea)
        self.lineedit_path.textEdited.connect(self._updateFileSave)
        self.lineedit_filename.textEdited.connect(self._updateFileSave)
        self.slider_threshold.valueChanged.connect(self._updateThreshold)
        self.checkbox_thresh.stateChanged.connect(self._updateThresholdState)

        # Update the Tilt value
        self.spinbox_b.valueChanged.connect(self._updateFormulaZTilt)
        self.spinbox_d.valueChanged.connect(self._updateFormulaZTilt)
        # Update the constants in the FWHM seeing formula
        self.spinbox_d.valueChanged.connect(self._updateFormulaConstants)
        self.spinbox_lambda.valueChanged.connect(self._updateFormulaConstants)

        # Timer for acquiring images at regular intervals
        self.acquisition_timer = QTimer(parent=self.centralwidget)
        self.timer_interval = None

        self._updateThreshold()
        self._updateFormulaZTilt()
        self._updateFormulaConstants()

        # Storing the Delta X and Y in an array to calculate the Standard Deviation
        self.arr_delta_x = deque(maxlen=100)
        self.arr_delta_y = deque(maxlen=100)

        self.plot_length = 1000
        self.fwhm_lat = 0
        self.fwhm_tra = 0
        self.max_lat = 1
        self.min_lat = 0
        self.max_tra = 1
        self.min_tra = 0

        self.series_lat = QLineSeries()
        self.series_lat.setName("Lateral")
        self.series_tra = QLineSeries()
        self.series_tra.setName("Transversal")

        self.chart = QChart()
        self.chart.addSeries(self.series_lat)
        self.chart.addSeries(self.series_tra)

        # self.chart.createDefaultAxes()
        self.axis_horizontal = QDateTimeAxis()
        self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 *
                                                                        1))
        self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0))
        self.axis_horizontal.setFormat("HH:mm:ss.zzz")
        self.axis_horizontal.setLabelsFont(
            QFont(QFont.defaultFamily(self.font()), pointSize=5))
        self.axis_horizontal.setLabelsAngle(-20)
        self.chart.addAxis(self.axis_horizontal, Qt.AlignBottom)

        self.axis_vertical_lat = QValueAxis()
        self.axis_vertical_lat.setRange(self.max_lat, self.min_lat)
        self.chart.addAxis(self.axis_vertical_lat, Qt.AlignLeft)

        self.axis_vertical_tra = QValueAxis()
        self.axis_vertical_tra.setRange(self.max_tra, self.min_tra)
        self.chart.addAxis(self.axis_vertical_tra, Qt.AlignRight)

        self.series_lat.attachAxis(self.axis_horizontal)
        self.series_lat.attachAxis(self.axis_vertical_lat)

        self.series_tra.attachAxis(self.axis_horizontal)
        self.series_tra.attachAxis(self.axis_vertical_tra)

        self.chart.setTitle("Full Width at Half Maximum")
        self.chart.legend().setVisible(True)
        self.chart.legend().setAlignment(Qt.AlignBottom)
        self.chartView = QChartView(self.chart, parent=self.graphicsView)
        self.chartView.resize(640, 250)
        self.chartView.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.chartView.setRenderHint(QPainter.Antialiasing)

    def closeEvent(self, event):
        try:
            self.Camera.StopLive()
        except AttributeError:
            pass

        try:
            self.cap.release()
        except AttributeError:
            pass

        try:
            self.video_writer.release()
        except AttributeError:
            pass

        event.accept()

    def _callbackFunction(self, hGrabber, pBuffer, framenumber, pData):
        """ This is an example callback function for image processig  with 
            opencv. The image data in pBuffer is converted into a cv Matrix
            and with cv.mean() the average brightness of the image is
            measuered.

        :param: hGrabber: This is the real pointer to the grabber object.
        :param: pBuffer : Pointer to the first pixel's first byte
        :param: framenumber : Number of the frame since the stream started
        :param: pData : Pointer to additional user data structure
        """
        if pData.buffer_size > 0:
            image = C.cast(pBuffer, C.POINTER(C.c_ubyte * pData.buffer_size))

            cvMat = np.ndarray(buffer=image.contents,
                               dtype=np.uint8,
                               shape=(pData.height, pData.width,
                                      pData.iBitsPerPixel))

            frame = np.uint8(cvMat)
            self.frame = cv2.resize(frame, (640, 480))
            self.draw_only_frame = self.frame.copy()
            self._monitor()

    def _startLiveCamera(self):

        # Create a function pointer
        Callbackfunc = IC.TIS_GrabberDLL.FRAMEREADYCALLBACK(
            self._callbackFunction)
        ImageDescription = CallbackUserData()

        # Create the camera object
        self.Camera = IC.TIS_CAM()

        self.Camera.ShowDeviceSelectionDialog()
        if self.Camera.IsDevValid() != 1:
            print("[Error Camera Selection] Couldn't open camera device !")
            # QMessageBox.warning(self, "Error Camera Selection", "Couldn't open camera device !")
            # raise Exception("Unable to open camera device !")
            return

        # Now pass the function pointer and our user data to the library
        self.Camera.SetFrameReadyCallback(Callbackfunc, ImageDescription)

        # Handle each incoming frame automatically
        self.Camera.SetContinuousMode(0)

        print('Starting live stream ...')
        self.Camera.StartLive(
            0
        )  ####### PAUSE LIVE STREAM WHEN PAUSE CLICKED ??? ##############################################
        # self.Camera.StartLive(1)

        Imageformat = self.Camera.GetImageDescription()[:3]
        ImageDescription.width = Imageformat[0]
        ImageDescription.height = Imageformat[1]
        ImageDescription.iBitsPerPixel = Imageformat[2] // 8
        ImageDescription.buffer_size = ImageDescription.width * ImageDescription.height * ImageDescription.iBitsPerPixel

        while self.video_source == VideoSource.CAMERA:
            pass

        # self.timer_interval = 20
        # try:
        #     self.acquisition_timer.disconnect()
        # except TypeError:
        #     pass
        # self.acquisition_timer.timeout.connect(self._updateLiveCamera)
        # self.acquisition_timer.start(self.timer_interval)

    def startLiveCamera(self):
        try:
            self.acquisition_timer.disconnect()
        except TypeError:
            pass

        self.video_source = VideoSource.CAMERA
        self.button_export.setEnabled(True)
        self._setPauseButton()

        # Disable other functionalities
        # self.button_simulation.setEnabled(False)

        t = threading.Thread(target=self._startLiveCamera,
                             args=(),
                             daemon=True)
        t.start()

    def showSettings(self):
        if not self.Camera.IsDevValid():
            QMessageBox.warning(
                self, "Camera Selection Error",
                "Please select a camera first by clicking on the button <strong>Start</strong>"
            )
            return

        try:
            self.Camera.ShowPropertyDialog()
        except Exception as e:
            logging.error(traceback.format_exc())
            QMessageBox.warning(self, "Property Dialog Error",
                                traceback.format_exc())

    # def _updateLiveCamera(self):
    #     # Capturing a frame
    #     self.Camera.SnapImage()
    #     frame = self.Camera.GetImage()
    #     frame = np.uint8(frame)
    #     self.frame = cv2.resize(frame, (640, 480))
    #     self.draw_only_frame = self.frame.copy()
    #     self._monitor()

    # self.displayParameters()

    def displayParameters(self):
        parameters_text = ""

        ExposureTime = [0]
        self.Camera.GetPropertyAbsoluteValue("Exposure", "Value", ExposureTime)
        parameters_text = parameters_text + str(ExposureTime[0]) + "\n"

        GainValue = [0]
        self.Camera.GetPropertyAbsoluteValue("Gain", "Value", GainValue)
        parameters_text = parameters_text + str(GainValue[0]) + "\n"

        self.parameters_label.setText(parameters_text)
        self.parameters_label.adjustSize()

    def startSimulation(self):

        if self.Camera != None and self.Camera.IsDevValid() == 1:
            self.Camera.StopLive()
        self.video_source = VideoSource.SIMULATION
        self.button_export.setEnabled(True)
        self._setPauseButton()

        # Disable other functionalities
        # self.button_start.setEnabled(False)
        self.button_settings.setEnabled(False)

        # Generating fake images of DIMM star (One single star that is split by the DIMM)
        self.starsGenerator = FakeStars()
        self.timer_interval = 100

        try:
            self.acquisition_timer.disconnect()
        except TypeError:
            pass
        self.acquisition_timer.timeout.connect(self._updateSimulation)
        self.acquisition_timer.start(self.timer_interval)

    def _updateSimulation(self):
        frame = self.starsGenerator.generate()
        self.frame = cv2.resize(frame, (640, 480))
        self.draw_only_frame = self.frame.copy()
        self._monitor()


################################################################################################################################################################

    def _writeCSV(self, headerOnly=False):
        if headerOnly:
            with open(self.save_filename, "w") as csvFile:
                fieldnames = ["timestamp", "lateral", "transversal", "star"]
                writer = csv.DictWriter(csvFile, fieldnames=fieldnames)
                writer.writeheader()
                csvFile.close()

        else:
            with open(self.save_filename, "a") as csvFile:
                writer = csv.writer(csvFile)
                writer.writerow([
                    self.current.toTime_t(), self.fwhm_lat, self.fwhm_tra,
                    self.lineedit_star.text()
                ])
                # csvFile.write(",".join([str(self.current) , str(self.fwhm_lat), str(self.fwhm_tra), self.lineedit_star.text()]))
                # csvFile.write("\n")
                # csvFile.close()

    def selectNoiseArea(self):
        self.label_info.setText("Please select on the video a noise area.")
        self.button_noise.setText("Selecting ...")
        self.coordinates_noiseArea = []
        self.select_noiseArea = True

    def _set_noiseArea(self, x1, y1, x2, y2):
        if len(self.coordinates_noiseArea) == 0:
            self.coordinates_noiseArea.append([x1, y1])
            self.coordinates_noiseArea.append([x2, y2])

        elif len(self.coordinates_noiseArea) == 2:
            self.coordinates_noiseArea[0] = [x1, y1]
            self.coordinates_noiseArea[1] = [x2, y2]

    def _draw_noiseArea(self):
        if len(self.coordinates_noiseArea) >= 2:
            cv2.rectangle(self.draw_only_frame,
                          (self.coordinates_noiseArea[0][0],
                           self.coordinates_noiseArea[0][1]),
                          (self.coordinates_noiseArea[1][0],
                           self.coordinates_noiseArea[1][1]), (0, 255, 0), 1)

    def _updateFileSave(self):
        self.save_filename = join(self.lineedit_path.text(),
                                  self.lineedit_filename.text())
        self._writeCSV(headerOnly=True)

    def _updateThreshold(self):
        if self.threshold_auto:
            if self.coordinates_noiseArea.__len__() >= 2:
                noise_area = self.frame[self.coordinates_noiseArea[0][1]:self.
                                        coordinates_noiseArea[1][1],
                                        self.coordinates_noiseArea[0][0]:self.
                                        coordinates_noiseArea[1][0]]
                try:
                    self.THRESH = noise_area.max() + 20
                    # self.THRESH = int(round(noise_area.mean()))
                except ValueError:
                    return

                self.slider_threshold.setValue(self.THRESH)
                self.checkbox_thresh.setText("Threshold ({}, auto)".format(
                    self.THRESH))
        else:
            self.THRESH = self.slider_threshold.value()
            self.checkbox_thresh.setText("Threshold ({})".format(self.THRESH))

    def _updateThresholdState(self, state):
        if state == 0:
            self.threshold_auto = False
            self.slider_threshold.setEnabled(True)
        else:
            if self.coordinates_noiseArea.__len__() < 2:
                QMessageBox.information(self, "Select Noise Area",
                                        "Please select the noise area")
                self.selectNoiseArea()

            self.threshold_auto = True
            self.slider_threshold.setEnabled(False)

    def _updateFormulaZTilt(self):
        self.spinbox_d.setStyleSheet("QSpinBox { background-color: blue; }")
        try:
            b = float(self.spinbox_b.value()) / float(self.spinbox_d.value())
        except ZeroDivisionError:
            QMessageBox.warning(self, "Zero Division Error",
                                "D (Apertures Diameter cannot be Zero")
            return
        self.K_lat = 0.364 * (1 - 0.532 * np.power(b, -1 / 3) -
                              0.024 * np.power(b, -7 / 3))
        self.K_tra = 0.364 * (1 - 0.798 * np.power(b, -1 / 3) -
                              0.018 * np.power(b, -7 / 3))

    def _updateFormulaConstants(self):
        # Calculate value to make process faster
        self.A = 0.98 * np.power(
            float(self.spinbox_d.value()) / float(self.spinbox_lambda.value()),
            0.2)

    def _calcSeeing(self):
        std_x = np.std(self.arr_delta_x)
        std_y = np.std(self.arr_delta_y)

        # Seeing
        self.current = QDateTime.currentDateTime()
        self.fwhm_lat = self.A * np.power(std_x / self.K_lat, 0.6)
        self.fwhm_tra = self.A * np.power(std_y / self.K_tra, 0.6)

        threading.Thread(target=self._plotSeeing, args=(), daemon=True).start()
        threading.Thread(target=self._writeCSV, args=(), daemon=True).start()

        self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " +
                                str(self.fwhm_tra))

    def _calcSeeing_arcsec(self):
        std_x = np.std(self.arr_delta_x)
        std_y = np.std(self.arr_delta_y)

        # Seeing
        self.current = QDateTime.currentDateTime()
        self.fwhm_lat = self.A * np.power(
            std_x / self.K_lat, 0.6) * 205.0 * self.spinbox_pwidth.value(
            ) / self.spinbox_focal.value()
        self.fwhm_tra = self.A * np.power(
            std_y / self.K_tra, 0.6) * 205.0 * self.spinbox_pheight.value(
            ) / self.spinbox_focal.value()

        threading.Thread(target=self._plotSeeing, args=(), daemon=True).start()
        threading.Thread(target=self._writeCSV, args=(), daemon=True).start()

        self.label_info.setText("lat: " + str(self.fwhm_lat) + " | lon: " +
                                str(self.fwhm_tra))

    def _monitor(self):

        tic = time.time()

        gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)

        self._updateThreshold()
        _, thresholded = cv2.threshold(gray, self.THRESH, 255,
                                       cv2.THRESH_TOZERO)

        # _, contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL,
                                       cv2.CHAIN_APPROX_NONE)

        contours = contours[:2]

        # if contours.__len__() > 2:
        #     QMessageBox.warning(self, "Thresholding error", "More than 2 projections were found. " + \
        #         "Please increase threshold manually or select a better noise area.")

        cv2.drawContours(self.draw_only_frame, contours, -1, (0, 255, 0), 2)
        self._draw_noiseArea()

        try:
            moments_star_1 = cv2.moments(contours[0])
            moments_star_2 = cv2.moments(contours[1])

        except IndexError:
            print("Only {} were found ! (Must be at least 2)".format(
                len(contours)))

        else:

            try:
                cX_star1 = int(moments_star_1["m10"] / moments_star_1["m00"])
                cY_star1 = int(moments_star_1["m01"] / moments_star_1["m00"])

                cX_star2 = int(moments_star_2["m10"] / moments_star_2["m00"])
                cY_star2 = int(moments_star_2["m01"] / moments_star_2["m00"])

            except ZeroDivisionError:
                return

            if self.enable_seeing.isChecked():
                delta_x = abs(cX_star2 - cX_star1)
                delta_y = abs(cY_star2 - cY_star1)

                self.arr_delta_x.append(delta_x)
                self.arr_delta_y.append(delta_y)

                # self._calcSeeing()
                self._calcSeeing_arcsec()

            cv2.drawMarker(self.draw_only_frame, (cX_star1, cY_star1),
                           color=(0, 0, 255),
                           markerSize=30,
                           thickness=1)
            cv2.drawMarker(self.draw_only_frame, (cX_star2, cY_star2),
                           color=(0, 0, 255),
                           markerSize=30,
                           thickness=1)

        finally:

            self._displayImage()

            threading.Thread(target=self._writeVideoFile, args=(),
                             daemon=True).start()

        toc = time.time()
        elapsed = toc - tic
        try:
            print("FPS max = {}".format(int(1.0 / elapsed)))
        except ZeroDivisionError:
            pass

    def _displayImage(self):
        qImage = array2qimage(self.draw_only_frame)
        self.stars_capture.setPixmap(QPixmap(qImage))

    def _plotSeeing(self):

        self.axis_horizontal.setMin(QDateTime.currentDateTime().addSecs(-60 *
                                                                        1))
        self.axis_horizontal.setMax(QDateTime.currentDateTime().addSecs(0))

        if self.series_lat.count() > self.plot_length - 1:
            self.series_lat.removePoints(
                0,
                self.series_lat.count() - self.plot_length - 1)

        if self.series_tra.count() > self.plot_length - 1:
            self.series_tra.removePoints(
                0,
                self.series_tra.count() - self.plot_length - 1)

        if self.fwhm_lat > self.max_lat:
            self.max_lat = self.fwhm_lat
            self.axis_vertical_lat.setMax(self.max_lat + 10)
        if self.fwhm_lat < self.min_lat:
            self.min_lat = self.fwhm_lat
            self.axis_vertical_lat.setMax(self.min_lat - 10)
        if self.fwhm_tra > self.max_tra:
            self.max_tra = self.fwhm_tra
            self.axis_vertical_tra.setMax(self.max_tra + 10)
        if self.fwhm_tra < self.min_tra:
            self.min_tra = self.fwhm_tra
            self.axis_vertical_tra.setMax(self.min_tra - 10)

        # print(self.fwhm_lat, self.fwhm_tra)

        self.series_lat.append(self.current.toMSecsSinceEpoch(), self.fwhm_lat)
        self.series_tra.append(self.current.toMSecsSinceEpoch(), self.fwhm_tra)

    def importVideo(self):

        self.video_source = VideoSource.VIDEO
        self.button_export.setEnabled(True)
        self._setPauseButton()

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "Import from Video File",
            QDir.currentPath(),
            "Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov);;All Files (*)",
            options=options)

        if filename:
            if self.Camera != None and self.Camera.IsDevValid() == 1:
                self.Camera.StopLive()

            self.cap = cv2.VideoCapture(filename)

            # print("CAP_PROP_POS_MSEC :", self.cap.get(cv2.CAP_PROP_POS_MSEC))
            # print("CAP_PROP_POS_FRAMES :", self.cap.get(cv2.CAP_PROP_POS_FRAMES))
            # print("CAP_PROP_POS_AVI_RATIO :", self.cap.get(cv2.CAP_PROP_POS_AVI_RATIO))
            # print("CAP_PROP_FRAME_WIDTH :", self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            # print("CAP_PROP_FRAME_HEIGHT :", self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            # print("CAP_PROP_FPS :", self.cap.get(cv2.CAP_PROP_FPS))
            # print("CAP_PROP_FOURCC :", self.cap.get(cv2.CAP_PROP_FOURCC))
            # print("CAP_PROP_FRAME_COUNT :", self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
            # print("CAP_PROP_FORMAT :", self.cap.get(cv2.CAP_PROP_FORMAT))
            # print("CAP_PROP_MODE :", self.cap.get(cv2.CAP_PROP_MODE))
            # print("CAP_PROP_BRIGHTNESS :", self.cap.get(cv2.CAP_PROP_BRIGHTNESS))
            # print("CAP_PROP_CONTRAST :", self.cap.get(cv2.CAP_PROP_CONTRAST))
            # print("CAP_PROP_SATURATION :", self.cap.get(cv2.CAP_PROP_SATURATION))
            # print("CAP_PROP_HUE :", self.cap.get(cv2.CAP_PROP_HUE))
            # print("CAP_PROP_GAIN :", self.cap.get(cv2.CAP_PROP_GAIN))
            # print("CAP_PROP_EXPOSURE :", self.cap.get(cv2.CAP_PROP_EXPOSURE))
            # print("CAP_PROP_CONVERT_RGB :", self.cap.get(cv2.CAP_PROP_CONVERT_RGB))
            # print("CAP_PROP_WHITE_APERTURE :", self.cap.get(cv2.CAP_PROP_APERTURE))
            # print("CAP_PROP_RECTIFICATION :", self.cap.get(cv2.CAP_PROP_RECTIFICATION))
            # print("CAP_PROP_ISO_SPEED :", self.cap.get(cv2.CAP_PROP_ISO_SPEED))
            # print("CAP_PROP_BUFFERSIZE :", self.cap.get(cv2.CAP_PROP_BUFFERSIZE))

            if self.cap.isOpened() == False:
                QMessageBox.warning(self, "Import from Video",
                                    "Cannot load file '{}'.".format(filename))
                return

            self.timer_interval = round(1000.0 /
                                        self.cap.get(cv2.CAP_PROP_FPS))
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass
            self.acquisition_timer.timeout.connect(self._grabVideoFrame)
            self.acquisition_timer.start(self.timer_interval)

    def _grabVideoFrame(self):
        ret, frame = self.cap.read()
        if ret == True:
            self.frame = cv2.resize(frame, (640, 480))
            self.draw_only_frame = self.frame.copy()
            self._monitor()

        else:
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass

            QMessageBox.information(self, "Import from Video",
                                    "Video complete !")
            self.cap.release()

    def exportVideo(self):
        # if not self.enable_seeing.isChecked():
        #     answer = QMessageBox.question(self,
        #         "Export to Video File",
        #         "Seeing Monitoring is not activated. Continue ?",
        #         QMessageBox.Yes|QMessageBox.No,
        #         QMessageBox.No)

        #     if answer == QMessageBox.No:
        #         return

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getSaveFileName(
            self,
            "Export to Video File",
            QDir.currentPath(),
            "All Files (*);;Video Files (*.avi *.mp4 *.mpeg *.flv *.3gp *.mov)",
            options=options)

        if filename:
            if splitext(filename)[1] != ".avi":
                filename = splitext(filename)[0] + ".avi"
                QMessageBox.information(
                    self, "Export to Video File",
                    "Only '.avi' extension is supported. Video will be saved as '{}'"
                    .format(filename))

            print(round(1000.0 / float(self.timer_interval)))

            self.video_writer = cv2.VideoWriter(
                filename,
                cv2.VideoWriter_fourcc(*'MJPG'),
                round(1000.0 / float(self.timer_interval)),
                (
                    640, 480
                )  #################################################################################
            )
            self.export_video = True

    def _writeVideoFile(self):
        current = QDateTime.currentDateTime()
        if self.export_video and current >= self.datetimeedit_start.dateTime() and \
            current < self.datetimeedit_end.dateTime():

            # self.video_writer.write(self.frame)
            self.video_writer.write(self.draw_only_frame)

    def _setPauseButton(self):
        self.button_pause.setEnabled(True)
        self.button_pause.setText("⏸ Pause")
        self.button_pause.clicked.connect(self._pause)

    def _pause(self):
        self.pause_pressed = True

        # IC_SuspendLive IC_StopLive ##################################################################################
        self.button_pause.setText("▶ Resume")
        self.button_pause.clicked.connect(self._resume)

        if self.video_source == VideoSource.CAMERA:
            self.Camera.StopLive()
        else:
            self.acquisition_timer.stop()

    def _resume(self):
        self.pause_pressed = False
        self._setPauseButton()

        if self.video_source == VideoSource.CAMERA:
            self.Camera.StartLive(0)
        else:
            try:
                self.acquisition_timer.disconnect()
            except TypeError:
                pass

            self.acquisition_timer.start(self.timer_interval)

            if self.video_source == VideoSource.CAMERA:
                pass
            elif self.video_source == VideoSource.SIMULATION:
                self.acquisition_timer.timeout.connect(self._updateSimulation)
            elif self.video_source == VideoSource.VIDEO:
                self.acquisition_timer.timeout.connect(self._grabVideoFrame)
class LastMonthsHistogram(QChartView):
    """
    Chart that displays the balance
    from the whole portfolio from the last months
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.chart = QChart()

    def setupChartWithData(self):
        """
        Chart gets updated displaying the new data.

        Data has to be expressed on a dictionary form:
            - keys are timestamps
            - values are total balance for that timestamp
        """
        self.chart = QChart()
        self.chart.setTheme(QChart.ChartThemeDark)
        self.chart.setAnimationOptions(QChart.SeriesAnimations)
        self.chart.setBackgroundBrush(QBrush(QColor("transparent")))

        # Series
        self.barseries = QBarSeries()

        currentyear, currentmonth = datetime.today().year, datetime.today(
        ).month
        dates, amounts = [], []
        # Get 5 previous month numbers
        for _ in range(5):
            dates.append((currentmonth, currentyear))
            currentmonth -= 1
            if currentmonth == 0:
                currentmonth = 12
                currentyear -= 1
        # Get amounts for each month
        for d in dates:
            month, year = d
            amounts.append(
                dbhandler.get_total_wealth_on_month(month, year=year))

        # Iterate months and amount and insert them into the histogram appropiately
        barset = QBarSet('Total wealth')
        labelsfont = QFont()
        labelsfont.setFamily('Inter')
        labelsfont.setBold(True)
        barset.setLabelFont(labelsfont)
        barset.setColor(QColor("#D3EABD"))
        x_values = []
        for d, a in zip(reversed(dates), reversed(amounts)):
            if a > 0:
                barset.append(int(a))
                x_values.append(calendar.month_name[d[0]])

        self.barseries.append(barset)
        self.barseries.setName("Last Months")
        self.barseries.setLabelsVisible(True)
        self.barseries.setBarWidth(0.2)
        self.barseries.setLabelsPosition(QAbstractBarSeries.LabelsOutsideEnd)
        self.chart.addSeries(self.barseries)

        # Axis X (Dates)
        self.x_axis = QBarCategoryAxis()
        self.x_axis.setTitleText(self.tr('Date'))
        labelsfont = QFont()
        labelsfont.setFamily('Roboto')
        labelsfont.setLetterSpacing(QFont.AbsoluteSpacing, 1)
        labelsfont.setWeight(QFont.Light)
        labelsfont.setPointSize(9)
        self.x_axis.setLabelsFont(labelsfont)
        self.x_axis.setGridLineVisible(False)
        self.x_axis.setLineVisible(False)
        self.x_axis.setLinePenColor(QColor("#D3EABD"))
        self.x_axis.setTitleVisible(False)

        self.x_axis.append(x_values)
        self.chart.addAxis(self.x_axis, Qt.AlignBottom)

        # Axis Y (Balances)
        self.y_axis = QValueAxis()
        self.y_axis.setMax(max(amounts) * 1.3)
        self.y_axis.setMin(min(amounts) * 0.95)
        self.y_axis.hide()

        labelsfont = QFont()
        labelsfont.setPointSize(4)
        self.y_axis.setLabelsFont(labelsfont)
        self.chart.addAxis(self.y_axis, Qt.AlignLeft)

        # Attach axis to series
        self.barseries.attachAxis(self.x_axis)
        self.barseries.attachAxis(self.y_axis)

        # Legend
        self.chart.legend().hide()

        # Set up chart on ChartView
        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)
        self.setStyleSheet("border: 0px; background-color: rgba(0,0,0,0)")
class ResonanceFrequencyFinder(QMainWindow):

	# AVAILABLE_WINDOW_SIZES = ["5 Sec", "8 Sec", "10 Sec", "15 Sec", "20 Sec"]

	DEFAULT_GRAPH_PADDING = 2

	DEFAULT_FFT_WINDOW_SIZE = 5

	DEFAULT_SAMPLE_PADDING = 2

	DEFAULT_RECORDING_DURATION = 30 + DEFAULT_SAMPLE_PADDING

	DEFAULT_MIN_FREQUENCY = 17

	DEFAULT_MAX_FREQUENCY = 35

	DEFAULT_FREQUENCY_STEP = 2

	# Used to create a band for which the average frequency amplitude is computed
	DEFAULT_FREQUENCY_PADDING = 0.2

	DEFAULT_BANDPASS_MIN = 8

	DEFAULT_BANDPASS_MAX = 40

	DEFAULT_C3_CHANNEL_INDEX = 4

	DEFAULT_CZ_CHANNEL_INDEX = 2

	DEFAULT_C4_CHANNEL_INDEX = 0

	def __init__(self, board: BoardShim):
		super().__init__()
		self.setGeometry(0, 0, 1800, 900)
		self.setWindowTitle("Resonance-Like Frequency")

		self.board = board

		self.recording_progress_dialog = None
		self.eeg_data_buffer = utils.EegData()
		self.reading_timer = QTimer()
		self.recording = False

		self.recording_reference = False
		self.reference_eeg_data = utils.EegData()

		self.index_generator = utils.FrequencyIndexGenerator(global_config.SAMPLING_RATE)
		self.eeg_sample_count = 0

		self.root_widget = QWidget()
		self.root_layout = QGridLayout()
		self.root_widget.setLayout(self.root_layout)
		self.setCentralWidget(self.root_widget)

		title = QLabel("<h1>Resonance Frequency Finder</h1>")
		title.setAlignment(Qt.AlignCenter)
		self.root_layout.addWidget(title, 0, 0, 1, 3)

		# window_size_label = QLabel("window size: ")
		# window_size_label.setAlignment(Qt.AlignRight)

		# self.window_size_combo_box = QComboBox()
		# self.window_size_combo_box.addItems(self.AVAILABLE_WINDOW_SIZES)

		self.root_directory_label = QLabel()
		self.select_root_directory = QPushButton("Select/Change")
		self.select_root_directory.clicked.connect(self.pick_root_directory)

		self.record_btn = QPushButton("Record")
		self.record_btn.setEnabled(False)
		self.record_btn.clicked.connect(self.record_clicked)

		self.record_reference_btn = QPushButton("Record Reference")
		self.record_reference_btn.clicked.connect(self.record_reference_clicked)

		# self.root_layout.addWidget(utils.construct_horizontal_box([
		# 	window_size_label, self.window_size_combo_box, self.record_btn
		# ]), 1, 0, 1, 3)

		self.load_results_btn = QPushButton("Load Existing Data")
		self.load_results_btn.clicked.connect(self.load_existing_data)

		self.root_layout.addWidget(utils.construct_horizontal_box([
			self.record_btn, self.record_reference_btn, self.root_directory_label,
			self.select_root_directory, self.load_results_btn
		]), 1, 0, 1, 3)

		self.current_freq_label = QLabel()

		self.root_layout.addWidget(utils.construct_horizontal_box([self.current_freq_label]), 2, 0, 1, 3)

		self.frequency_slider = QSlider()
		self.frequency_slider.setRange(self.DEFAULT_MIN_FREQUENCY, self.DEFAULT_MAX_FREQUENCY)
		self.frequency_slider.setSingleStep(self.DEFAULT_FREQUENCY_STEP)
		self.frequency_slider.setTickInterval(self.DEFAULT_FREQUENCY_STEP)
		self.frequency_slider.valueChanged.connect(self.update_freq_label)
		self.frequency_slider.setTickPosition(QSlider.TicksBelow)
		self.frequency_slider.setOrientation(Qt.Horizontal)

		min_freq_label = QLabel(f"<b>{self.DEFAULT_MIN_FREQUENCY} Hz</b>")
		max_freq_label = QLabel(f"<b>{self.DEFAULT_MAX_FREQUENCY} Hz</b>")

		self.root_layout.addWidget(utils.construct_horizontal_box([
			min_freq_label, self.frequency_slider, max_freq_label
		]), 3, 0, 1, 3)

		self.c3_amplitude_bar_set = QBarSet("Electrode C3")
		self.cz_amplitude_bar_set = QBarSet("Electrode Cz")
		self.c4_amplitude_bar_set = QBarSet("Electrode C4")

		self.frequencies = []

		for freq in range(self.DEFAULT_MIN_FREQUENCY, self.DEFAULT_MAX_FREQUENCY + 1, self.DEFAULT_FREQUENCY_STEP):
			self.frequencies.append(f"{freq} Hz")
			self.c3_amplitude_bar_set.append(1)
			self.cz_amplitude_bar_set.append(1)
			self.c4_amplitude_bar_set.append(1)

		self.freq_axis = QBarCategoryAxis()
		self.freq_axis.append(self.frequencies)

		self.amplitude_axis = QValueAxis()
		self.amplitude_axis.setRange(0, 4)

		self.freq_chart = QChart()
		self.freq_chart.setAnimationOptions(QChart.SeriesAnimations)

		self.electrodes_data_series = QBarSeries()
		self.electrodes_data_series.append(self.c3_amplitude_bar_set)
		self.electrodes_data_series.append(self.cz_amplitude_bar_set)
		self.electrodes_data_series.append(self.c4_amplitude_bar_set)

		self.freq_chart.addSeries(self.electrodes_data_series)
		self.freq_chart.setTitle("<h1>Frequency Amplitude Increase</h1>")
		self.freq_chart.addAxis(self.freq_axis, Qt.AlignBottom)
		self.freq_chart.addAxis(self.amplitude_axis, Qt.AlignLeft)

		self.electrodes_data_series.attachAxis(self.amplitude_axis)
		self.electrodes_data_series.attachAxis(self.freq_axis)

		self.frequency_amplitude_graph = QChartView(self.freq_chart)
		self.frequency_amplitude_graph.setRenderHint(QPainter.Antialiasing)

		self.root_layout.addWidget(self.frequency_amplitude_graph, 4, 0, 15, 3)

		self.auto_adjust_axis()

	def update_freq_label(self):
		self.current_freq_label.setText("Selected Frequency: {} Hz".format(self.frequency_slider.value()))

	def pick_root_directory(self):
		path = QFileDialog.getExistingDirectory(self, "Root Directory...")
		self.root_directory_label.setText(path)

	def record_clicked(self, reference: bool = False):
		# selected_window_text = self.window_size_combo_box.currentText()
		# window_size_text = selected_window_text.replace(" Sec", "")

		# window_size = -1
		#
		# if utils.is_integer(window_size_text):
		# 	window_size = int(window_size_text)
		# else:
		# 	print("Invalid window size...")
		# 	return

		# window_size_in_samples = window_size * SAMPLING_RATE

		recording_duration_in_samples = self.DEFAULT_RECORDING_DURATION * global_config.SAMPLING_RATE

		if not reference and (self.frequency_slider.value() - self.DEFAULT_MIN_FREQUENCY) % self.DEFAULT_FREQUENCY_STEP != 0:
			err = QErrorMessage(self)
			err.showMessage("Invalid Frequency Selected")
			err.exec()
			return

		self.recording_progress_dialog = \
			QProgressDialog("Reading EEG data from board...", "Stop Recording", 0, int(recording_duration_in_samples), self)
		self.recording_progress_dialog.setWindowTitle("Reading Data, Please Wait...")
		self.recording_progress_dialog.setWindowModality(Qt.WindowModal)
		self.recording_progress_dialog.show()

		if reference:
			self.recording_reference = True
		else:
			self.recording = True
			self.eeg_data_buffer.clear()

		self.board.start_stream()

		self.reading_timer = QTimer()
		self.reading_timer.timeout.connect(self.read_data)
		self.reading_timer.start(100)

	def record_reference_clicked(self):
		print("Record reference clicked")
		if self.reference_eeg_data.get_channel_data(0).shape[0] > 0:
			self.reference_eeg_data.clear()
		self.record_clicked(reference=True)

	def read_data(self):
		if not self.recording and not self.recording_reference:
			return

		recording_duration_in_samples = self.recording_progress_dialog.maximum()

		if self.recording_reference:
			if self.reference_eeg_data.get_channel_data(0).shape[0] > recording_duration_in_samples or\
					self.recording_progress_dialog.wasCanceled():
				self.stop_recording(True)
				return

		if self.recording:
			if self.recording_progress_dialog.wasCanceled() or\
					self.eeg_data_buffer.get_channel_data(0).shape[0] > recording_duration_in_samples:
				self.stop_recording(self.recording_reference)
				return

		if self.board.get_board_data_count() > 0:
			raw_data = self.board.get_board_data()
			raw_eeg_data = utils.extract_eeg_data(raw_data, global_config.BOARD_ID)

			self.eeg_sample_count += raw_eeg_data.shape[1]

			path = self.root_directory_label.text()

			if path != "":
				full_path = path + "/" + global_config.RESONANCE_DATA_FILE_NAME
				DataFilter.write_file(raw_eeg_data, full_path, "a")

			# c3 = raw_eeg_data[self.DEFAULT_C3_CHANNEL_INDEX, :]
			# cz = raw_eeg_data[self.DEFAULT_CZ_CHANNEL_INDEX, :]
			# c4 = raw_eeg_data[self.DEFAULT_C4_CHANNEL_INDEX, :]

			if self.recording_reference:
				self.reference_eeg_data.append_data(raw_eeg_data)
				print(f"reference size: {self.reference_eeg_data.sample_count()}")
				self.recording_progress_dialog.setValue(self.reference_eeg_data.get_channel_data(0).shape[0])
			else:
				self.eeg_data_buffer.append_data(raw_eeg_data)
				print(f"data size: {self.eeg_data_buffer.sample_count()}")
				self.recording_progress_dialog.setValue(self.eeg_data_buffer.get_channel_data(0).shape[0])

	def load_existing_data(self):
		path = QFileDialog.getExistingDirectory(self, "Root Directory...")

		if path == "":
			return

		filter_settings = utils.FilterSettings(global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX)

		frequencies, eeg_data, reference_data = utils.load_slice_and_filter_resonance_data(path, filter_settings)

		print(frequencies)

		size = len(frequencies)

		x = np.arange(size)

		x_ticks = []

		plot_data = np.zeros((3, size))

		for i in range(size):
			current_eeg_data = eeg_data[i]
			freq = frequencies[i]
			x_ticks.append(f"{freq} Hz")
			freq_band = utils.FrequencyBand(
				freq - self.DEFAULT_FREQUENCY_PADDING,
				freq + self.DEFAULT_FREQUENCY_PADDING)

			reference_c3_extractor = reference_data.feature_extractor(
				self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			reference_cz_extractor = reference_data.feature_extractor(
				self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			reference_c4_extractor = reference_data.feature_extractor(
				self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_c3_extractor = current_eeg_data.feature_extractor(
				self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_cz_extractor = current_eeg_data.feature_extractor(
				self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_c4_extractor = current_eeg_data.feature_extractor(
				self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			c3_diff, cz_diff, c4_diff = self.amplitude_diff(freq_band, reference_c3_extractor, reference_cz_extractor,
															reference_c4_extractor, data_c3_extractor,
															data_cz_extractor, data_c4_extractor)

			plot_data[0, i] = c3_diff
			plot_data[1, i] = cz_diff
			plot_data[2, i] = c4_diff

		plt.figure()
		plt.title("Amplitude Increase")

		plt.bar(x, plot_data[0], width=0.25, label="C3 amplitude increase")
		plt.bar(x + 0.25, plot_data[1], width=0.25, label="Cz amplitude increase")
		plt.bar(x + 0.50, plot_data[2], width=0.25, label="C4 amplitude increase")

		plt.xticks(x + 0.25, x_ticks)
		plt.ylabel("Average Band Amplitude")

		plt.legend(loc="best")
		plt.show()

	def amplitude_diff(self, freq_band, ref_c3_extractor, ref_cz_extractor, ref_c4_extractor, data_c3_extractor, data_cz_extractor, data_c4_extractor):
		ref_c3_amplitude = ref_c3_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)
		ref_cz_amplitude = ref_cz_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)
		ref_c4_amplitude = ref_c4_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)

		data_c3_amplitude = data_c3_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)
		data_cz_amplitude = data_cz_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)
		data_c4_amplitude = data_c4_extractor.average_band_amplitude(freq_band, self.DEFAULT_FFT_WINDOW_SIZE)

		c3_diff = data_c3_amplitude - ref_c3_amplitude
		cz_diff = data_cz_amplitude - ref_cz_amplitude
		c4_diff = data_c4_amplitude - ref_c4_amplitude

		return c3_diff, cz_diff, c4_diff
		# return data_c3_amplitude, data_cz_amplitude, data_c4_amplitude

	def stop_recording(self, reference: bool = False):
		if self.reading_timer is not None:
			self.reading_timer.deleteLater()

		self.board.stop_stream()
		self.recording = False
		self.recording_reference = False
		self.recording_progress_dialog.setValue(self.recording_progress_dialog.maximum())

		recording_duration_in_samples = self.recording_progress_dialog.maximum()
		selected_freq = self.frequency_slider.value()

		if reference:
			sample_count = min(self.reference_eeg_data.get_channel_data(0).shape[0], recording_duration_in_samples)
			sample_count -= global_config.SAMPLING_RATE * self.DEFAULT_SAMPLE_PADDING
			self.index_generator.add_slice(0, self.eeg_sample_count - sample_count, self.eeg_sample_count)
		else:
			sample_count = min(self.eeg_data_buffer.get_channel_data(0).shape[0], recording_duration_in_samples)
			sample_count -= global_config.SAMPLING_RATE * self.DEFAULT_SAMPLE_PADDING
			self.index_generator.add_slice(selected_freq, self.eeg_sample_count - sample_count, self.eeg_sample_count)

		if self.root_directory_label.text() != "":
			self.index_generator.write_to_file(self.root_directory_label.text())

		QApplication.beep()

		start = self.DEFAULT_SAMPLE_PADDING * global_config.SAMPLING_RATE

		if reference:
			print(f"reference size: {self.reference_eeg_data.sample_count()}")
			self.record_btn.setEnabled(True)
			# self.record_reference_btn.setEnabled(False)
			self.reference_eeg_data.filter_all_channels(
				global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX, True
			)
			self.reference_eeg_data = utils.EegData(self.reference_eeg_data.to_row_array()[:, start:])
			print("Reference data saved...")
		else:
			print("Stopping the recording...")

			print("Filtering data...")

			self.eeg_data_buffer.filter_all_channels(
				global_config.SAMPLING_RATE, self.DEFAULT_BANDPASS_MIN, self.DEFAULT_BANDPASS_MAX, subtract_average=True
			)

			self.eeg_data_buffer = utils.EegData(self.eeg_data_buffer.to_row_array()[:, start:])

			print(f"data size: {self.eeg_data_buffer.sample_count()}")

			reference_c3_extractor = self.reference_eeg_data.feature_extractor(
				self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			reference_cz_extractor = self.reference_eeg_data.feature_extractor(
				self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			reference_c4_extractor = self.reference_eeg_data.feature_extractor(
				self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_c3_extractor = self.eeg_data_buffer.feature_extractor(
				self.DEFAULT_C3_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_cz_extractor = self.eeg_data_buffer.feature_extractor(
				self.DEFAULT_CZ_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			data_c4_extractor = self.eeg_data_buffer.feature_extractor(
				self.DEFAULT_C4_CHANNEL_INDEX, global_config.SAMPLING_RATE
			)

			for i in range(self.c3_amplitude_bar_set.count()):
				current_freq = int(self.frequencies[i].replace(" Hz", ""))
				if current_freq == selected_freq:
					freq_band = utils.FrequencyBand(
						current_freq - self.DEFAULT_FREQUENCY_PADDING,
						current_freq + self.DEFAULT_FREQUENCY_PADDING)

					c3_diff, cz_diff, c4_diff = self.amplitude_diff(freq_band, reference_c3_extractor,reference_cz_extractor, reference_c4_extractor,
																	data_c3_extractor, data_cz_extractor, data_c4_extractor)

					print(f"C3 diff = {c3_diff}")
					print(f"Cz diff = {cz_diff}")
					print(f"C4 diff = {c4_diff}")

					self.c3_amplitude_bar_set.replace(i, c3_diff)
					self.cz_amplitude_bar_set.replace(i, cz_diff)
					self.c4_amplitude_bar_set.replace(i, c4_diff)

			utils.auto_adjust_axis(self.amplitude_axis,
								[self.c3_amplitude_bar_set, self.cz_amplitude_bar_set, self.c4_amplitude_bar_set], self.DEFAULT_GRAPH_PADDING)

	def auto_adjust_axis(self):
		# Adjust the range so that everything is visible and add some gaps

		c3_min = sys.maxsize
		cz_min = sys.maxsize
		c4_min = sys.maxsize

		c3_max = -sys.maxsize
		cz_max = -sys.maxsize
		c4_max = -sys.maxsize

		for i in range(self.c3_amplitude_bar_set.count()):
			c3_min = min(c3_min, self.c3_amplitude_bar_set.at(i))
			cz_min = min(cz_min, self.cz_amplitude_bar_set.at(i))
			c4_min = min(c4_min, self.c4_amplitude_bar_set.at(i))

			c3_max = max(c3_max, self.c3_amplitude_bar_set.at(i))
			cz_max = max(cz_max, self.cz_amplitude_bar_set.at(i))
			c4_max = max(c4_max, self.c4_amplitude_bar_set.at(i))

		print("c3 min = {}, cz min = {}, c4 min = {}".format(c3_min, cz_min, c4_min))
		print("c3 max = {}, cz max = {}, c4 max = {}".format(c3_max, cz_max, c4_max))

		axis_min = min(0, c3_min, cz_min, c4_min) - self.DEFAULT_GRAPH_PADDING
		axis_max = max(0, c3_max, cz_max, c4_max) + self.DEFAULT_GRAPH_PADDING

		print("axis min = {}, axis max = {}".format(axis_min, axis_max))

		self.amplitude_axis.setMin(axis_min)
		self.amplitude_axis.setMax(axis_max)
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, weight_path, out_file_path, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle("VAT ROLL COMPARE LABEL TOOL" + " " + CODE_VER)
        self.showMaximized()
        '''按键绑定'''
        # 输入媒体
        self.import_media_pushButton.clicked.connect(self.import_media)  # 导入
        self.start_predict_pushButton.clicked.connect(
            self.predict_button_click)  # 开始推理
        # 输出媒体
        self.open_predict_file_pushButton.clicked.connect(
            self.open_file_in_browser)  # 文件中显示推理视频
        # 下方
        self.play_pushButton.clicked.connect(
            self.play_pause_button_click)  # 播放
        self.pause_pushButton.clicked.connect(
            self.play_pause_button_click)  # 暂停
        self.button_dict = dict()
        self.button_dict.update({
            "import_media_pushButton": self.import_media_pushButton,
            "start_predict_pushButton": self.start_predict_pushButton,
            "open_predict_file_pushButton": self.open_predict_file_pushButton,
            "play_pushButton": self.play_pushButton,
            "pause_pushButton": self.pause_pushButton,
        })
        '''媒体流绑定输出'''
        self.input_player = QMediaPlayer()  # 媒体输入的widget
        self.input_player.setVideoOutput(self.input_video_widget)
        self.input_player.positionChanged.connect(
            self.change_slide_bar)  # 播放进度条

        self.output_player = QMediaPlayer()  # 媒体输出的widget
        self.output_player.setVideoOutput(self.output_video_widget)
        '''初始化GPU chart'''
        self.series = QSplineSeries()
        self.chart_init()
        '''初始化GPU定时查询定时器'''
        # 使用QTimer,0.5秒触发一次,更新数据
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.draw_gpu_info_chart)
        self.timer.start(500)

        # 播放时长, 以 input 的时长为准
        self.video_length = 0
        self.out_file_path = out_file_path
        # 推理使用另外一线程
        self.predict_handler_thread = PredictHandlerThread(
            self.output_player, self.out_file_path, weight_path,
            self.predict_info_plainTextEdit, self.predict_progressBar,
            self.fps_label, self.button_dict)
        # 界面美化
        self.gen_better_gui()

    def gen_better_gui(self):
        """
        美化界面
        :return:
        """
        # Play 按钮
        play_icon = QIcon()
        play_icon.addPixmap(QPixmap("./UI/icon/play.png"), QIcon.Normal,
                            QIcon.Off)
        self.play_pushButton.setIcon(play_icon)

        # Pause 按钮
        play_icon = QIcon()
        play_icon.addPixmap(QPixmap("./UI/icon/pause.png"), QIcon.Normal,
                            QIcon.Off)
        self.pause_pushButton.setIcon(play_icon)

    def chart_init(self):
        """
        初始化 GPU 折线图
        :return:
        """
        # self.gpu_info_chart._chart = QChart(title="折线图堆叠")  # 创建折线视图
        self.gpu_info_chart._chart = QChart()  # 创建折线视图
        # chart._chart.setBackgroundVisible(visible=False)      # 背景色透明
        self.gpu_info_chart._chart.setBackgroundBrush(QBrush(
            QColor("#FFFFFF")))  # 改变图背景色

        # 设置曲线名称
        self.series.setName("GPU Utilization")
        # 把曲线添加到QChart的实例中
        self.gpu_info_chart._chart.addSeries(self.series)
        # 声明并初始化X轴,Y轴
        self.dtaxisX = QDateTimeAxis()
        self.vlaxisY = QValueAxis()
        # 设置坐标轴显示范围
        self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300 * 1))
        self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
        self.vlaxisY.setMin(0)
        self.vlaxisY.setMax(100)
        # 设置X轴时间样式
        self.dtaxisX.setFormat("hh:mm:ss")
        # 设置坐标轴上的格点
        self.dtaxisX.setTickCount(5)
        self.vlaxisY.setTickCount(10)
        # 设置坐标轴名称
        self.dtaxisX.setTitleText("Time")
        self.vlaxisY.setTitleText("Percent")
        # 设置网格不显示
        self.vlaxisY.setGridLineVisible(False)
        # 把坐标轴添加到chart中
        self.gpu_info_chart._chart.addAxis(self.dtaxisX, Qt.AlignBottom)
        self.gpu_info_chart._chart.addAxis(self.vlaxisY, Qt.AlignLeft)
        # 把曲线关联到坐标轴
        self.series.attachAxis(self.dtaxisX)
        self.series.attachAxis(self.vlaxisY)
        # 生成 折线图
        self.gpu_info_chart.setChart(self.gpu_info_chart._chart)

    def draw_gpu_info_chart(self):
        """
        绘制 GPU 折线图
        :return:
        """
        # 获取当前时间
        time_current = QDateTime.currentDateTime()
        # 更新X轴坐标
        self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300 * 1))
        self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
        # 当曲线上的点超出X轴的范围时,移除最早的点
        remove_count = 600
        if self.series.count() > remove_count:
            self.series.removePoints(0, self.series.count() - remove_count)
        # 对 y 赋值
        # yint = random.randint(0, 100)
        gpu_info = get_gpu_info()
        yint = gpu_info[0].get("gpu_load")
        # 添加数据到曲线末端
        self.series.append(time_current.toMSecsSinceEpoch(), yint)

    def import_media(self):
        """
        导入媒体文件
        :return:
        """
        self.parameter_source = QFileDialog.getOpenFileUrl()[0]
        self.input_player.setMedia(QMediaContent(
            self.parameter_source))  # 选取视频文件

        # 设置 output 为一张图片,防止资源被占用
        path_current = str(Path.cwd().joinpath("area_dangerous\1.jpg"))
        self.output_player.setMedia(
            QMediaContent(QUrl.fromLocalFile(path_current)))

        # 将 QUrl 路径转为 本地路径str
        self.predict_handler_thread.parameter_source = self.parameter_source.toLocalFile(
        )
        self.input_player.pause()  # 显示媒体

        image_flag = os.path.splitext(
            self.predict_handler_thread.parameter_source)[-1].lower(
            ) in img_formats
        for item, button in self.button_dict.items():
            if image_flag and item in ['play_pushButton', 'pause_pushButton']:
                button.setEnabled(False)
            else:
                button.setEnabled(True)
        # self.output_player.setMedia(QMediaContent(QFileDialog.getOpenFileUrl()[0]))  # 选取视频文件

    def predict_button_click(self):
        """
        推理按钮
        :return:
        """
        # 启动线程去调用
        self.predict_handler_thread.start()

    def change_slide_bar(self, position):
        """
        进度条移动
        :param position:
        :return:
        """
        self.video_length = self.input_player.duration() + 0.1
        self.video_horizontalSlider.setValue(
            round((position / self.video_length) * 100))
        self.video_percent_label.setText(
            str(round((position / self.video_length) * 100, 2)) + '%')

    @pyqtSlot()
    def play_pause_button_click(self):
        """
        播放、暂停按钮回调事件
        :return:
        """
        name = self.sender().objectName()

        if self.parameter_source == "":
            return

        if name == "play_pushButton":
            print("play")
            self.input_player.play()
            self.output_player.play()

        elif name == "pause_pushButton":
            self.input_player.pause()
            self.output_player.pause()

    @pyqtSlot()
    def open_file_in_browser(self):
        os.system(f"start explorer {self.out_file_path}")

    @pyqtSlot()
    def closeEvent(self, *args, **kwargs):
        """
        重写关闭事件
        :param args:
        :param kwargs:
        :return:
        """
        print("Close")
示例#18
0
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        uic.loadUi('ws_ui.ui', self)
        self.con = sqlite3.connect("ws_database.db")
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)

        self.create_linechart()
        self.tmp, self.hmd, self.prs = 0, 0, 0
        self.make_measure()

        self.measure_timer = QTimer(self)
        self.measure_timer.setInterval(MEASURE_FREQUENCIES * 1000)
        self.measure_timer.timeout.connect(self.make_measure)
        self.measure_timer.start()

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(1000)
        self.update_timer.timeout.connect(self.update_labels)
        self.update_timer.start()

        self.update_labels()

    def quit(self):
        self.destroy()
        quit()

    def make_measure(self):
        sns = sensor_measure()

        if sns[0] != ERROR_CODE:
            self.tmp = sns[0]

        else:
            print('tmp error')

        if sns[1] != ERROR_CODE:
            self.hmd = sns[1]

        else:
            print('hmd error')

        if sns[2] != ERROR_CODE:
            self.prs = sns[2]

        else:
            print('prs error')

        time = int(dt.datetime.now().timestamp())

        req = """
              INSERT INTO short_term_data(tmp, hmd, prs, time_from_epoch)
              VALUES(?,?,?,?)
              """

        self.con.execute(req, (self.tmp, self.hmd, self.prs, time))
        self.con.commit()

        self.update_linechart()

    def update_labels(self):
        deg = u'\N{DEGREE SIGN}'
        hpa = 'ʰᴾᵃ'
        self.time_label.setText(dt.datetime.now().strftime('%H:%M'))
        self.tmp_label.setText('{} {}C'.format(self.tmp, deg))
        self.hmd_label.setText('{} %'.format(self.hmd))
        self.prs_label.setText('{} {}'.format(self.prs, hpa))

    def create_linechart(self):
        self.chart = QChart()
        self.chart.legend().hide()

        self.series = QLineSeries()

        self.axisValue = QValueAxis()
        self.axisCurrentTime = QValueAxis()
        self.axisTime = QDateTimeAxis()
        self.axisTime.setFormat("hh:mm")

        self.chartview = QChartView(self.chart, self.groupBox)
        self.chartview.resize(540, 460)
        self.chartview.move(0, 0)
        self.chartview.setRenderHint(QPainter.Antialiasing)

    def update_linechart(self):
        if self.axisTime in self.chart.axes():
            self.chart.removeAxis(self.axisTime)

        if self.axisCurrentTime in self.chart.axes():
            self.chart.removeAxis(self.axisCurrentTime)

        if self.axisValue in self.chart.axes():
            self.chart.removeAxis(self.axisValue)

        if self.series in self.chart.series():
            self.chart.removeSeries(self.series)

        self.series.clear()

        self.axisValue.setMax(50)
        self.axisValue.setMin(-50)

        req = """
              SELECT tmp, time_from_epoch
              FROM short_term_data
              WHERE (time_from_epoch - ?) < 86400 AND NOT tmp = ?
              """

        cur = self.con.cursor()
        result = list(cur.execute(req, (int(dt.datetime.now().timestamp()), ERROR_CODE)))

        for measure in result:
            self.series.append(measure[1] * 1000, measure[0])

        self.axisTime.setMin(QDateTime.fromMSecsSinceEpoch(int(dt.datetime.now().timestamp()) * 1000 - 86390000))
        self.axisTime.setMax(QDateTime.fromMSecsSinceEpoch(int(dt.datetime.now().timestamp()) * 1000))

        self.chart.addSeries(self.series)
        self.chart.addAxis(self.axisTime, Qt.AlignBottom)
        self.series.attachAxis(self.axisTime)
        self.chart.addAxis(self.axisValue, Qt.AlignLeft)
        self.series.attachAxis(self.axisValue)

        self.chart.setTitle('Температура')
示例#19
0
class XChart(QChart):
    def __init__(self, parent=None):
        super(QChart, self).__init__(parent)

        self.setAnimationOptions(QChart.SeriesAnimations)

        self.axisX = QValueAxis()
        self.axisY = QValueAxis()

        self.axisX.setTickCount(10)
        self.axisY.setTickCount(10)

        self.axisX.setMin(0)
        self.axisX.setMax(1)
        self.axisY.setMin(0)
        self.axisY.setMax(1)

        series = []
        #Temporay Test Data
        for i in range(0, 10):
            x = np.random.rand(10)
            y = np.random.rand(10)
            #self.series = XScatterSeries(tooltips = True)
            #self.series.addXY(x,y)
            #self.addSeries(self.series)
            #self.setAxisX(self.axisX, self.series); self.setAxisY(self.axisY, self.series)

            serset = XScatterSet()  # many options not supported with openGl
            serset.setChart(self)
            serset.addXY(x, y)
            serset.setAxisX(self.axisX)
            serset.setAxisY(self.axisY)
            series.append(serset)

        #self.mousePressEvent.connect(self.zoomSelectionAction)

    def mousePressEvent(self, event):
        self._clickpos = event.buttonDownScenePos(Qt.LeftButton)
        self._clickval = self.mapToValue(self._clickpos)

    def mouseMoveEvent(self, event):
        self._clickpos = event.buttonDownScenePos(Qt.LeftButton)
        self._clickval = self.mapToValue(self._clickpos)
        dragpos = event.scenePos()
        c1 = self._clickpos.x()
        c2 = self._clickpos.y()
        d1 = dragpos.x()
        d2 = dragpos.y()
        x1 = min(c1, d1)
        y1 = min(c2, d2)
        x2 = abs(c1 - d1)
        y2 = abs(c2 - d2)
        try:
            self.selectbox.prepareGeometryChange()
            self.scene().removeItem(self.selectbox)
        except AttributeError:
            pass
        self.selectbox = self.scene().addRect(
            x1, y1, x2, y2, QPen(QColor(0, 0, 0, 0)),
            QBrush(QColor(125, 125, 255, 100)))

    def mouseReleaseEvent(self, event):
        try:
            self.selectbox.prepareGeometryChange()
            self.scene().removeItem(self.selectbox)
        except AttributeError:
            pass
        self._releasepos = event.lastScenePos()
        self._releaseval = self.mapToValue(self._releasepos)
        self.scene().update()
        print(self._clickval, self._releaseval)

    def keyReleaseEvent(self, event):

        print(dir(event))
        if event == Qt.Key_Z:
            print('zoom')

    @pyqtSlot()
    def zoomSelectionAction(self):
        print('click')
示例#20
0
class TotalEquityChartView(QChartView):
    """
    Chart that displays the balance between several dates
    from an account, token or whole portfolio
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.chart = QChart()

    def setupChartWithData(self, data, linecolor='#422F8A'):
        """
        Chart gets updated displaying the new data.

        Data has to be expressed on a dictionary form:
            - keys are timestamps
            - values are total balance for that timestamp
        """
        self.chart = QChart()

        self.chart.setTheme(QChart.ChartThemeDark)
        self.chart.setAnimationOptions(QChart.SeriesAnimations)
        self.chart.setBackgroundBrush(QBrush(QColor("transparent")))
        #         self.chart.setTitle("")
        #         self.chart.setTitleBrush(QBrush(QColor('white')))

        # Axis X (Dates)
        self.x_axis = QDateTimeAxis()
        self.x_axis.setTickCount(11)
        self.x_axis.setLabelsAngle(70)
        font = QFont()
        font.setFamily('Roboto')
        font.setLetterSpacing(QFont.PercentageSpacing, 110)
        font.setPointSize(8)
        self.x_axis.setLabelsFont(font)
        self.x_axis.setFormat("dd-MM-yy")
        self.x_axis.setTitleText(self.tr('Date'))
        self.x_axis.setTitleVisible(False)
        self.x_axis.setLineVisible(False)
        self.x_axis.setGridLineVisible(False)

        # Axis Y (Balances)
        self.y_axis = QValueAxis()
        if data != {}:
            self.y_axis.setMax(max(data.values()) * 1.05)
            self.y_axis.setMin(min(data.values()) * 0.95)
        # self.y_axis.setMinorGridLineVisible(False)
        self.y_axis.setLineVisible(False)
        self.y_axis.setGridLineColor(QColor("#ECE9F1"))

        self.chart.addAxis(self.y_axis, Qt.AlignLeft)
        self.chart.addAxis(self.x_axis, Qt.AlignBottom)

        # Series
        self.btcseries = QSplineSeries()
        for date in data:
            balance = data[date]
            date = QDateTime(datetime.fromtimestamp(int(float(date))))
            self.btcseries.append(date.toMSecsSinceEpoch(), balance)

        self.btcseries.setName("BTC")
        pen = QPen(QColor(linecolor))
        pen.setWidth(3)
        self.btcseries.setPen(pen)

        # Series functionality
        self.btcseries.hovered.connect(self.selectPoint)

        self.chart.addSeries(self.btcseries)
        self.btcseries.attachAxis(self.x_axis)
        self.btcseries.attachAxis(self.y_axis)

        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)
        self.setStyleSheet("border: 0px; background-color: rgba(0,0,0,0); ")

        self.chart.legend().hide()

    def selectPoint(self, point, state):
        """ Shows point where mouse is hovered """
        self.chart.setTitle(
            f"{int(point.y())} {confighandler.get_fiat_currency().upper()}")
示例#21
0
class XChartProbit(QChart):
    def __init__(self, parent=None):
        super(QChart, self).__init__(parent)

        # Class Vars
        self.activeDistr = 'lognorm'
        self.knowndistr = distr._distrnames()
        self.data = dict()

        # Axis Setup
        self.axisX = QValueAxis()
        self.axisY = QValueAxis()

        self.axisX.setLabelsVisible(False)
        self.axisX.setTickCount(2)
        self.axisX.setTitleText("Series Fractional Probability")
        self.axisY.setTitleText("Value")
        self.setAxesMinMax(-3, 3, 0.01, 1.5)

        self.axisX.setMinorGridLineVisible(False)
        self.axisX.setGridLineVisible(False)

        # define the default grid colour to grey
        self.setGridColor(110, 110, 110)

        self.setActiveProbit(self.activeDistr)
        self.plotAreaChanged.connect(self.onPlotSizeChanged)
        # method needed for axes change to redraw grid lines

    def addLinearReg(self, seriesname):
        x = self.data[seriesname]['X'], y = self.data[seriesname][seriesname]
        # adds a linear regression line for a data set x,y
        slope, intercept, r_value, p_value, std_err = linregress(x, y)
        xmin = distr.distrppf(self.activeDistr, 0.01)
        xmax = distr.distrppf(self.activeDistr, 0.99)
        ymin = slope * xmin + intercept
        ymax = slope * xmax + intercept
        data = dict()
        data['X'] = [xmin, xmax]
        data['LinearReg'] = [ymin, ymax]
        lines = XLineSeries(data, xkey='X', openGL=True)

        self.addSeries(lines[0])
        self.setAxes(lines[0])

    def loadSeries(self, arr, name):
        # takes a list/array arr
        y = array(arr).copy()
        y.sort()
        self.data[name] = y
        self.redrawChart()

    def plotSeries(self, name):
        nsamp = len(self.data[name])
        # add data to temport dictionary
        tdict = dict()
        if self.activeScale == 'log10':
            tdict[name] = log10(self.data[name])
        elif self.activeScale == 'linear':
            tdict[name] = self.data[name]
        tdict['X'] = distr.distrppf(self.activeProbit, [
            percentileofscore(self.data[name], self.data[name][i]) / 100.00001
            for i in range(0, nsamp)
        ])
        series = XScatterSeries(tdict, xkey='X', openGL=True)
        self.addSeries(series[0])
        self.setAxes(series[0])

    def _replotData(self):
        for key in self.data.keys():
            self.pl

    def axesMinMax(self):
        # returns a length 4 list of the axes min and max values [x1,x2,y1,y2]
        return [
            self.axisX.min(),
            self.axisX.max(),
            self.axisY.min(),
            self.axisY.max()
        ]

    def redrawChart(self):
        self.removeAllSeries()
        self._removeHorizontalGridLabels()
        self.resetAxes()
        self._drawVerticalGridLines()
        if self.activeScale == 'log10':
            self.axisY.setLabelsVisible(False)
            self.axisY.setTickCount(1)
            self.setTitle("Log Probit Plot")
            self.axisY.setMinorGridLineVisible(False)
            self.axisY.setGridLineVisible(False)
            self._drawHorizontalGridLine()
            self._drawHorizontalLabels()
            self._drawHorizontalGridlLabels()
        elif self.activeScale == 'linear':
            self.axisY.setLabelsVisible(True)
            self.axisY.setTickCount(10)
            self.setTitle("Probit Plot")
            self.axisY.setMinorGridLineVisible(True)
            self.axisY.setGridLineVisible(True)

        for serkey in self.data.keys():
            self.plotSeries(serkey)

    def resetAxes(self):
        ymins = []
        ymaxs = []
        for key in self.data.keys():
            ymins.append(min(self.data[key]))
            ymaxs.append(max(self.data[key]))
        try:
            ymin = min(ymins)
            ymax = max(ymaxs)
        except ValueError:
            ymin = 1.1
            ymax = 2

        xmin = distr.distrppf(self.activeProbit, 0.001)
        xmax = distr.distrppf(self.activeProbit, 0.999)
        if self.activeScale == 'linear':
            yscal = 0.1 * (ymax - ymin)
            self.setAxesMinMax(xmin, xmax, ymin - yscal, ymax + yscal)
        elif self.activeScale == 'log10':
            yscal = 0.1 * (log10(ymax) - log10(ymin))
            self.setAxesMinMax(xmin, xmax, log10(ymin), log10(ymax))
            #self.setAxesMinMax(xmin,xmax,log10(ymin)-yscal,log10(ymax)+yscal*0.1)

    def setGridColor(self, r, g, b):
        # sets the colour of the background grid
        self.gridcolor = QColor(r, g, b)

    def setActiveProbit(self, type):
        if type in self.knowndistr:
            self.activeDistr = type
            if type == 'norm':
                self.activeProbit = 'norm'
                self.activeScale = 'linear'
            elif type == 'lognorm':
                self.activeProbit = 'norm'
                self.activeScale = 'log10'
        #self.redrawChart()

    def setActiveScale(self, newscale):
        self.activeScale = newscale

    def setAxes(self, series):
        # assigns a series to the chart default axes
        self.setAxisX(self.axisX, series)
        self.setAxisY(self.axisY, series)

    def setAxesMinMax(self, x1, x2, y1, y2):
        # sets the min max values in X and Y
        self.axisX.setMin(x1)
        self.axisX.setMax(x2)
        self.axisY.setMin(y1)
        self.axisY.setMax(y2)

    def _drawHorizontalLabels(self):
        xmin = self.axisX.min()
        xmax = self.axisX.max()
        axisScale = 1 / (xmax - xmin
                         )  # scaler for plotted axis (reduces to 0-1.0)
        # calculate probit values to scale from grid lines insert min and max values to scale correctly
        vlabx = distr.distrppf(self.activeProbit, self.vgridx)
        vlabx = insert(vlabx, 0, xmin)
        vlabx = insert(vlabx, len(vlabx), xmax)
        vlabx = (
            vlabx - xmin
        ) * axisScale  #scale the probit value to ratios of the Xaxis length
        paw = self.plotArea().width()
        pah = self.plotArea().height()  #find the plot width and height
        # find plot bottom left corner X and Y
        pblx = self.plotArea().bottomLeft().x()
        pbly = self.plotArea().bottomLeft().y()
        # offset from axix by 10 pixels -> may need to automate this offset in future
        pbly_lab = pbly + 10
        # calculate the position on the chart in x plane with which to place each label.
        pblx = [pblx + int(paw * x) for x in vlabx[1:-1]]
        try:
            self.hlabels
        except AttributeError:
            self.hlabels = []
            for i, labx in enumerate(
                    pblx):  #run through labels and create and position them
                # label text based on P scale
                ltext = 'P' + '%02d' % round(100.0 * (1.0 - self.vgridx[i]))
                self.hlabels.append(self.scene().addText(ltext))

        for i, labx in enumerate(
                pblx):  #run through labels and create and position them
            self.hlabels[i].setPos(
                labx - 0.5 * self.hlabels[i].boundingRect().width(),
                pbly)  #centre on tick marks

    def _drawVerticalGridLines(self):
        self.vgridx = arange(0.05, 1.0, 0.05)
        self.vgridx = insert(self.vgridx, 0, [0.01, 0.02])
        self.vgridx = insert(self.vgridx, len(self.vgridx), [0.98, 0.99])
        vgridy = [self.axisY.min(), self.axisY.max()]
        self.vgridseries = []
        for val in self.vgridx:
            line = 'P' + '%02d' % round(100.0 * (1.0 - val))
            tdict = {
                'X': [distr.distrppf(self.activeProbit, val)] * 2,
                line: vgridy
            }
            self.vgridseries = self.vgridseries + XLineSeries(
                tdict, xkey='X', openGL=True)
        for i, line in enumerate(self.vgridseries):
            pen = line.pen()
            pen.setColor(self.gridcolor)
            pen.setWidthF(0.4), line.setPen(pen)
            line.setPointLabelsVisible(True)
            self.addSeries(line)
            self.setAxes(line)
            self.legend().markers(line)[0].setVisible(False)

    def _drawHorizontalGridLine(self):
        # calculate xmin and xmax points for lines to completely cross graph
        hgridx = [
            distr.distrppf(self.activeProbit, 0.0001) - 1,
            distr.distrppf(self.activeProbit, 0.9999) + 1
        ]
        # calculate log scale for lines y values
        self.hgridy = self._logrange(10**self.axisY.min(),
                                     10**self.axisY.max(),
                                     base=10)
        self.hgridseries = []
        # create a line series for each lines and add to list
        for val in self.hgridy:
            line = '%d' % val
            tdict = {'X': hgridx, line: [log10(val)] * 2}
            self.hgridseries = self.hgridseries + XLineSeries(
                tdict, xkey='X', openGL=True)
        # add each of the series to the grid with special formatting
        for i, line in enumerate(self.hgridseries):
            pen = line.pen()
            pen.setColor(self.gridcolor)
            pen.setWidthF(0.4), line.setPen(pen)
            self.addSeries(line)
            self.setAxes(line)
            self.legend().markers(line)[0].setVisible(False)

    def _drawHorizontalGridlLabels(self):
        ymin = self.axisY.min()
        ymax = self.axisY.max()
        axisScale = 1 / (ymax - ymin
                         )  # scaler for plotted axis (reduces to 0-1.0)
        # calculate base10 values to scale from grid lines insert min and max values to scale correctly
        vlaby = log10(self.hgridy)
        vlaby = insert(vlaby, 0, ymin)
        vlaby = insert(vlaby, len(vlaby), ymax)
        vlaby = (
            vlaby - ymin
        ) * axisScale  # scale the probit value to ratios of the Xaxis length
        paw = self.plotArea().width()
        pah = self.plotArea().height()  # find the plot width and height
        # find plot bottom left corner X and Y
        pblx = self.plotArea().bottomLeft().x()
        pbly = self.plotArea().bottomLeft().y()
        # offset from axix by 10 pixels -> may need to automate this offset in future
        pblx_lab = pblx - 10
        # calculate the position on the chart in y plane with which to place each label.
        pbly = [pbly - int(pah * y) for y in vlaby[1:-1]]
        self.vlabels = []
        for i, labx in enumerate(
                pbly):  # run through labels and create and position them
            # label text based on P scale
            ltext = str(self.hgridy[i])
            self.vlabels.append(self.scene().addText(ltext))

        for i, laby in enumerate(
                pbly):  #run through labels and create and position them
            # label text based on P scale
            self.vlabels[i].setPos(
                pblx - self.vlabels[i].boundingRect().width() - 10,
                laby - 0.5 *
                self.vlabels[i].boundingRect().height())  #centre on tick marks

    def _removeHorizontalGridLine(self):
        for ser in self.hgridseries:
            self.removeSeries(ser)

    def _removeVerticalGridLine(self):
        for ser in self.vgridseries:
            self.removeSeries(ser)

    def _removeHorizontalGridLabels(self):
        try:
            for lab in self.vlabels:
                self.scene().removeItem(lab)
        except AttributeError:
            pass

    def _logrange(self, min, max, base=10):
        if min <= 0:
            min += max / (base**10)
        y = 1
        bpow = base
        if min < base:
            while min < bpow:
                y -= 1
                bpow = pow(base, y)
        else:
            while min > bpow:
                y += 1
                bpow = pow(base, y)
        out = array([])
        while bpow < max:
            y += 1
            bpown = pow(base, y)
            out = append(out, arange(bpow, bpown, bpow))
            bpow = bpown
        i = 0
        j = 0
        for ind, val in enumerate(out):
            if val <= min:
                i = ind
            if val <= max:
                j = ind
        return out[i:j + 1]

    @pyqtSlot()
    def onPlotSizeChanged(self):
        #reset position of labels
        self.redrawChart()
class Example(QMainWindow):
    def __init__(self, ):
        super().__init__()
        self.bijiao = [0, 0, 0]

        self.res = ""
        self.queue = []
        self.k = -1
        self.flag = -1

        try:
            self.initUI()
            self.chart_init(10)
        except:
            traceback.print_exc()

    def initUI(self):

        icon = QtGui.QIcon()
        icon.addPixmap(
            QtGui.QPixmap("D:\\Sysytem\\Desktop\\zhong\\data\\ico.ico"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.setWindowIcon(icon)

        self.resize(1000, 700)
        self.setWindowTitle('Icon')

        self.setObjectName("清华大学得不到的学生")
        self.setWindowTitle("一枚小乖乖~")
        self.label = QLabel(self)
        self.label.setWindowTitle("清华大学得不到的学生")
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.label.setGeometry(QtCore.QRect(15, 15, 970, self.height() - 30))
        self.label.setText("")
        palette = QtGui.QPalette()

        self.label.setStyleSheet("background-color: #fff;border-radius: 15px;")
        self.labelshadow = QGraphicsDropShadowEffect(self)
        self.labelshadow.setBlurRadius(15)
        self.labelshadow.setOffset(1, 1)
        self.label.setGraphicsEffect(self.labelshadow)

        self.label.setScaledContents(True)
        self.label.setObjectName("label")

        self.pushButton_12 = QtWidgets.QPushButton(self)
        self.pushButton_12.setGeometry(
            QtCore.QRect(self.width() - 55, 29, 20, 20))
        self.pushButton_12.setStyleSheet(
            "QPushButton{\n"
            "    background:#fc625d;\n"
            "    color:white;\n"
            "    box-shadow: 1px 1px 3px rgba(0,0,0,0.3);font-size:20px;border-radius: 10px;font-family: 微软雅黑;\n"
            "}\n"
            "QPushButton:hover{                    \n"
            "    background:#FF2D2D;\n"
            "}\n"
            "QPushButton:pressed{\n"
            "    border: 1px solid #3C3C3C!important;\n"
            "    background:#AE0000;\n"
            "}")
        self.pushButton_12.clicked.connect(self.close)

        self.pushButton_14 = QtWidgets.QPushButton(self)
        self.pushButton_14.setGeometry(
            QtCore.QRect(self.width() - 55 - 35, 29, 20, 20))
        self.pushButton_14.setStyleSheet(
            "QPushButton{\n"
            "    background:#35cd4b;\n"
            "    color:white;\n"
            "    box-shadow: 1px 1px 3px rgba(0,0,0,0.3);font-size:20px;border-radius: 10px;font-family: 微软雅黑;\n"
            "}\n"
            "QPushButton:hover{                    \n"
            "    background:#00CC00;\n"
            "}\n"
            "QPushButton:pressed{\n"
            "    border: 1px solid #3C3C3C!important;\n"
            "    background:#009900;\n"
            "}")
        self.pushButton_14.clicked.connect(self.showMinimized)

        self.color = ["#e89291", "#c4b98b", "#81a8e1", "#8cc9c4", "#83bde2"]
        # -----------------------------------------------------------------测试数量------------------------
        error = QtWidgets.QLineEdit(self)
        error.setGeometry(QtCore.QRect(70, 70, 150, 50))
        error.setStyleSheet(
            "text-align: center;background-color: " + self.color[0] +
            ";border-radius: 7px;border: 0px solid #000;color:#ffffff;font-size:20px;font-family: 微软雅黑;"
        )
        errorshadow = QGraphicsDropShadowEffect(self)
        error.setPlaceholderText("测试数量")
        errorshadow.setBlurRadius(30)
        cl = QColor("#cacaca")
        errorshadow.setColor(cl)
        error.setAlignment(Qt.AlignCenter)
        errorshadow.setOffset(0, 0)
        error.textChanged.connect(self.set_suliang)
        # error.setGraphicsEffect(errorshadow)

        # -----------------------------------------------------------------随机范围------------------------

        fan = QtWidgets.QLineEdit(self)
        fan.setGeometry(QtCore.QRect(240, 70, 150, 50))
        fan.setStyleSheet(
            "text-align: center;background-color: " + self.color[2] +
            ";border-radius: 7px;border: 0px solid #000;color:#ffffff;font-size:20px;font-family: 微软雅黑;"
        )
        fanshadow = QGraphicsDropShadowEffect(self)
        fanshadow.setBlurRadius(30)
        fancl = QColor("#cacaca")
        fan.setPlaceholderText("随机范围")
        fanshadow.setColor(fancl)
        fan.setAlignment(Qt.AlignCenter)
        fanshadow.setOffset(0, 0)
        fan.textChanged.connect(self.set_fanwei)
        # fan.setGraphicsEffect(fanshadow)

        # -----------------------------------------------------------------内存块数-----------------------

        kuai = QtWidgets.QLineEdit(self)
        kuai.setGeometry(QtCore.QRect(410, 70, 150, 50))
        kuai.setStyleSheet(
            "text-align: center;background-color: " + self.color[3] +
            ";border-radius: 7px;border: 0px solid #000;color:#ffffff;font-size:20px;font-family: 微软雅黑;"
        )
        kuaishadow = QGraphicsDropShadowEffect(self)
        kuaishadow.setBlurRadius(30)
        kuaicl = QColor("#cacaca")
        kuai.setPlaceholderText("内存块数")
        kuaishadow.setColor(kuaicl)
        kuai.setAlignment(Qt.AlignCenter)
        kuaishadow.setOffset(0, 0)
        kuai.textChanged.connect(self.set_kuai)
        # kuai.setGraphicsEffect(kuaishadow)

        self.Button = QtWidgets.QPushButton(self)
        self.Button.setGeometry(QtCore.QRect(580, 70, 150, 50))
        self.Button.setStyleSheet(
            "QPushButton{text-align: center;background-color: #83bde2;"
            "border-radius: 7px;border: 0px solid #000;color:#ffffff;"
            "font-size:20px;font-family: 微软雅黑;}" + "QPushButton:hover{ " +
            "    background-color: #9ad0d0;color: white;" + "}")
        Buttonshadow = QGraphicsDropShadowEffect(self)
        Buttonshadow.setBlurRadius(30)
        Buttoncl = QColor("#cacaca")
        self.Button.setText("执行")
        Buttonshadow.setColor(Buttoncl)
        Buttonshadow.setOffset(0, 0)
        # Button.setGraphicsEffect(Buttonshadow)
        self.Button.clicked.connect(self.on_click_start)

        self.avgflag = 0

        self.qq = QtWidgets.QPushButton(self)
        self.qq.setGeometry(QtCore.QRect(750, 70, 180, 50))
        self.qq.setStyleSheet(
            "color: #000;text-align: center;background-color: #f0f0f0;border-radius: 7px;border: 0px solid #000;font-size:14px;font-family: 微软雅黑;"
        )
        self.qq.clicked.connect(self.on_avg)

        self.show()

    def on_avg(self):
        if self.avgflag == 0:
            self.series.hide()

            self.serieslru.hide()

            self.seriesopt.hide()

            self.seriesfifoavg.show()

            self.serieslruavg.show()

            self.seriesoptavg.show()
            self.avgflag = 1
        else:

            self.series.show()

            self.serieslru.show()

            self.seriesopt.show()

            self.seriesfifoavg.hide()

            self.serieslruavg.hide()

            self.seriesoptavg.hide()
            self.avgflag = 0

    def set_kuai(self, text):
        self.kuai = text

    def set_fanwei(self, text):
        self.fan = text

    def set_suliang(self, text):
        self.su = text

    def hideerror(self):
        self.error.hide()

    def set_kuaishu(self, text):
        self.kuaishu = text

    def set_yemian(self, text):
        self.yemian = text

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate

    def mousePressEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.m_drag = True
            self.m_DragPosition = e.globalPos() - self.pos()
            e.accept()

    def mouseReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.m_drag = False

    def mouseMoveEvent(self, e):
        try:
            if Qt.LeftButton and self.m_drag:
                self.move(e.globalPos() - self.m_DragPosition)
                e.accept()
        except:
            print("错误代码:000x0")

    def on_click_start(self):
        try:
            self.jishu = 0
            self.thread = MyThread()
            self.thread.set_su(self.su)
            self.thread.set_kuai(self.kuai)
            self.thread.set_x(self.dtaxisX)
            self.thread.set_fan(self.fan)
            self.thread.det_bijiao(self.bijiao)
            self.dailist = []
            self.avg = []
            self.avg1 = []
            self.avg2 = []
            self.dailistlru = []
            self.dailistopt = []
            self.thread.sinOut.connect(self.change)
            self.thread.start()

            # self.qq.setText("FIFO:%0.2f   LRU:%0.2f \n OPT:%0.2f" % (self.bijiao[0], self.bijiao[1], self.bijiao[2]))

        except:
            traceback.print_exc()
        # self.sinOut.emit(self.dailist)
        # self.sinOut2.emit(self.dailistlru)
        # self.sinOut3.emit(self.dailistopt)

    def change(self, dailist):
        try:
            # print(dailist)
            # arr = str.split(dailist)
            # print(arr)

            flag = 0
            start = 0
            flag = dailist.find(" ", flag)
            flag = dailist.find(" ", flag + 1)
            end = flag
            arr = str.split(dailist[start:end])

            start = flag
            flag = dailist.find(" ", flag + 1)
            flag = dailist.find(" ", flag + 1)
            end = flag
            arr1 = str.split(dailist[start:end])

            start = flag
            flag = dailist.find(" ", flag + 1)
            flag = dailist.find(" ", flag + 1)
            end = flag
            arr2 = str.split(dailist[start:end])

            self.dailist.append(QPointF(float(arr[0]), float(arr[1])))

            self.dailistlru.append(QPointF(float(arr1[0]), float(arr1[1])))

            self.dailistopt.append(QPointF(float(arr2[0]), float(arr2[1])))
            #
            self.series.replace(self.dailist)
            self.serieslru.replace(self.dailistlru)
            self.seriesopt.replace(self.dailistopt)

            if self.jishu == 0:
                self.bijiao[0] = float(arr[1])
                self.bijiao[1] = float(arr1[1])
                self.bijiao[2] = float(arr2[1])
                self.jishu = 1
            else:
                self.bijiao[0] = (float(arr[1]) + self.bijiao[0]) / 2.0
                self.bijiao[1] = (float(arr1[1]) + self.bijiao[1]) / 2.0
                self.bijiao[2] = (float(arr2[1]) + self.bijiao[2]) / 2.0
                self.jishu = self.jishu + 1

            self.avg.append(QPointF(float(arr[0]), self.bijiao[0]))
            self.avg1.append(QPointF(float(arr[0]), self.bijiao[1]))
            self.avg2.append(QPointF(float(arr[0]), self.bijiao[2]))

            # print(self.avg)
            self.seriesfifoavg.replace(self.avg)
            self.serieslruavg.replace(self.avg1)
            self.seriesoptavg.replace(self.avg2)

            self.qq.setText("FIFO:%0.2f   LRU:%0.2f \n OPT:%0.2f" %
                            (self.bijiao[0], self.bijiao[1], self.bijiao[2]))
        except:
            traceback.print_exc()

    def drawLine(self):
        self.series.replace(self.dailist)
        # print("uiy")

    def chart_init(self, su):
        self.start_num = 0
        self.chart = QChartView(self)
        self.chart.setGeometry(50, 150,
                               self.width() - 100,
                               self.height() - 150 - 50)  # 设置charView位置、大小
        self.series = QSplineSeries()
        self.series.setName("FIFO")
        self.chart.chart().addSeries(self.series)

        pen = QPen(Qt.gray)
        pen.setWidth(2)
        self.serieslru = QSplineSeries()
        self.serieslru.setPen(pen)
        self.serieslru.setName("LRU")
        self.serieslru.setColor(QColor("#e89291"))
        self.chart.chart().addSeries(self.serieslru)

        pen2 = QPen(Qt.gray)
        pen2.setWidth(2)
        self.seriesopt = QSplineSeries()
        self.seriesopt.setPen(pen2)
        self.seriesopt.setColor(QColor("#3ea54f"))
        self.seriesopt.setName("OPT")
        self.chart.chart().addSeries(self.seriesopt)

        penfifo = QPen(Qt.gray)
        penfifo.setWidth(2)
        self.seriesfifoavg = QSplineSeries()
        self.seriesfifoavg.setPen(penfifo)
        self.seriesfifoavg.setName("FIFO-avg")
        self.seriesfifoavg.setColor(QColor("#209fdf"))
        self.chart.chart().addSeries(self.seriesfifoavg)
        self.seriesfifoavg.hide()

        penavg = QPen(Qt.gray)
        penavg.setWidth(2)
        self.serieslruavg = QSplineSeries()
        self.serieslruavg.setPen(penavg)
        self.serieslruavg.setName("LRU-avg")
        self.serieslruavg.setColor(QColor("#e89291"))
        self.chart.chart().addSeries(self.serieslruavg)
        self.serieslruavg.hide()

        pen2avg = QPen(Qt.gray)
        pen2avg.setWidth(2)
        self.seriesoptavg = QSplineSeries()
        self.seriesoptavg.setPen(pen2avg)
        self.seriesoptavg.setColor(QColor("#3ea54f"))
        self.seriesoptavg.setName("OPT-avg")
        self.chart.chart().addSeries(self.seriesoptavg)
        self.seriesoptavg.hide()

        self.dtaxisX = QValueAxis()
        self.vlaxisY = QValueAxis()
        self.dtaxisX.setMin(10)
        self.dtaxisX.setMax(100)
        self.vlaxisY.setMin(0)
        self.vlaxisY.setMax(100)
        self.dtaxisX.setTickCount(6)
        self.vlaxisY.setTickCount(11)
        self.dtaxisX.setTitleText("页数")
        self.vlaxisY.setTitleText("缺页率")
        self.vlaxisY.setGridLineVisible(False)
        self.chart.chart().addAxis(self.dtaxisX, Qt.AlignBottom)
        self.chart.chart().addAxis(self.vlaxisY, Qt.AlignLeft)
        self.series.attachAxis(self.dtaxisX)
        self.series.attachAxis(self.vlaxisY)

        self.serieslru.attachAxis(self.dtaxisX)
        self.serieslru.attachAxis(self.vlaxisY)

        self.seriesopt.attachAxis(self.dtaxisX)
        self.seriesopt.attachAxis(self.vlaxisY)

        self.seriesoptavg.attachAxis(self.dtaxisX)
        self.seriesoptavg.attachAxis(self.vlaxisY)
        self.serieslruavg.attachAxis(self.dtaxisX)
        self.serieslruavg.attachAxis(self.vlaxisY)
        self.seriesfifoavg.attachAxis(self.dtaxisX)
        self.seriesfifoavg.attachAxis(self.vlaxisY)

        self.chart.chart().setTitleBrush(QBrush(Qt.cyan))
        cc = QColor("#f0f0f0")
        self.chart.setBackgroundBrush(cc)
        self.chart.setStyleSheet(
            "QChartView{ background-color: #83bde2;border-radius: 20px;}")
        self.chart.show()