Exemple #1
0
    def set_series(self, series: QLineSeries):
        self.chart().removeAllSeries()

        if not series or len(series) == 0:
            return

        self.chart().addSeries(series)
        series.setPointLabelsClipping(False)
        series.hovered.connect(lambda p, s: series.setPointLabelsVisible(s))

        x_y_points = list(zip(*((e.x(), e.y())
                                for e in series.pointsVector())))

        axisX = self.chart().axisX()
        axisX.setRange(min(x_y_points[0]), max(x_y_points[0]))
        axisX.setMinorTickCount(1)
        axisX.setTickCount(10)
        axisX.applyNiceNumbers()
        self.chart().setAxisX(axisX, series)

        axisY = self.chart().axisY()
        axisY.setRange(min(x_y_points[1]), max(x_y_points[1]))
        axisY.setTickCount(18)
        axisY.applyNiceNumbers()
        self.chart().setAxisY(axisY, series)
Exemple #2
0
    def update_range(self, series: QLineSeries):
        x_y_points = list(zip(*((e.x(), e.y())
                                for e in series.pointsVector())))

        self.x_range = min(x_y_points[0]), max(x_y_points[0])
        self.chart().axisX().setRange(*self.x_range)

        if not self.y_range_fixed:
            self.y_range = min(x_y_points[1]), max(x_y_points[1])
        self.chart().axisY().setRange(*self.y_range)
class ChartWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        uic.loadUi("chart.ui", self)
        self.ticker = ticker
        self.viewLimit = 128

        self.priceData = QLineSeries()
        self.priceChart = QChart()
        self.priceChart.addSeries(self.priceData)
        self.priceChart.legend().hide()

        axisX = QDateTimeAxis()
        axisX.setFormat("hh:mm:ss")
        axisX.setTickCount(4)
        dt = QDateTime.currentDateTime()
        axisX.setRange(dt, dt.addSecs(self.viewLimit))
        axisY = QValueAxis()
        axisY.setVisible(False)

        self.priceChart.addAxis(axisX, Qt.AlignBottom)
        self.priceChart.addAxis(axisY, Qt.AlignRight)
        self.priceData.attachAxis(axisX)
        self.priceData.attachAxis(axisY)
        self.priceChart.layout().setContentsMargins(0, 0, 0, 0)

        self.priceView.setChart(self.priceChart)
        self.priceView.setRenderHints(QPainter.Antialiasing)

        # ----------------- 추 가 ------------------
        self.pw = PriceWorker(ticker)
        self.pw.dataSent.connect(self.appendData)
        self.pw.start()
        # ------------------------------------------

    def appendData(self, currPirce):
        if len(self.priceData) == self.viewLimit:
            self.priceData.remove(0)
        dt = QDateTime.currentDateTime()
        self.priceData.append(dt.toMSecsSinceEpoch(), currPirce)
        self.__updateAxis()

    def __updateAxis(self):
        pvs = self.priceData.pointsVector()
        dtStart = QDateTime.fromMSecsSinceEpoch(int(pvs[0].x()))
        if len(self.priceData) == self.viewLimit:
            dtLast = QDateTime.fromMSecsSinceEpoch(int(pvs[-1].x()))
        else:
            dtLast = dtStart.addSecs(self.viewLimit)
        ax = self.priceChart.axisX()
        ax.setRange(dtStart, dtLast)

        ay = self.priceChart.axisY()
        dataY = [v.y() for v in pvs]
        ay.setRange(min(dataY), max(dataY))
Exemple #4
0
class PeersCountGraphView(BaseTimedGraph):
    peersCountFetched = AsyncSignal(int)

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

        self.setObjectName('PeersCountGraph')
        self.peersCountFetched.connectTo(self.onPeersCount)
        self.axisY.setTitleText(iPeers())

        pen = QPen(QColor('#60cccf'))
        pen.setWidth(2)

        self.seriesPeers = QLineSeries()
        self.seriesPeers.setName('Peers')
        self.seriesPeers.setPen(pen)
        self.chart.addSeries(self.seriesPeers)
        self.seriesPeers.attachAxis(self.axisX)
        self.seriesPeers.attachAxis(self.axisY)

        self.setChart(self.chart)

    async def onPeersCount(self, count):
        dtNow = QDateTime.currentDateTime()
        dtMsecs = dtNow.toMSecsSinceEpoch()

        delta = 120 * 1000
        if not self.seriesPurgedT or (dtMsecs - self.seriesPurgedT) > delta:
            self.removeOldSeries(self.seriesPeers, dtMsecs - delta)
            self.seriesPurgedT = dtMsecs

        peersVector = self.seriesPeers.pointsVector()
        values = [p.y() for p in peersVector]

        if values:
            self.axisY.setMax(max(values) + 10)
            self.axisY.setMin(min(values) - 10)

        dateMin = QDateTime.fromMSecsSinceEpoch(dtMsecs - (30 * 1000))
        dateMax = QDateTime.fromMSecsSinceEpoch(dtMsecs + 2000)

        self.seriesPeers.append(dtMsecs, count)
        self.axisX.setRange(dateMin, dateMax)
Exemple #5
0
class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # thread
        self.worker = Worker()
        self.worker.price.connect(self.get_price)
        self.worker.start()

        # window size
        self.setMinimumSize(600, 400)

        # data
        self.series = QLineSeries()

        # chart object
        self.chart = QChart()
        self.chart.legend().hide()
        self.chart.addSeries(self.series)  # data feeding

        # axis
        axis_x = QDateTimeAxis()
        axis_x.setFormat("hh:mm:ss")

        dt = QDateTime.currentDateTime()
        axis_x.setRange(dt, dt.addSecs(128))

        self.chart.addAxis(axis_x, Qt.AlignBottom)
        self.series.attachAxis(axis_x)

        axis_y = QValueAxis()
        axis_y.setLabelFormat("%i")
        self.chart.addAxis(axis_y, Qt.AlignLeft)
        self.series.attachAxis(axis_y)

        # margin
        self.chart.layout().setContentsMargins(0, 0, 0, 0)

        # displaying chart
        chart_view = QChartView(self.chart)
        chart_view.setRenderHint(QPainter.Antialiasing)
        self.setCentralWidget(chart_view)

    @pyqtSlot(float)
    def get_price(self, cur_price):
        if len(self.series) == 128:
            self.series.remove(0)  # delete first data

        # append current price
        dt = QDateTime.currentDateTime()
        ts = dt.toMSecsSinceEpoch()
        self.series.append(ts, cur_price)
        print(ts, cur_price)

        # update asis
        data = self.series.pointsVector()
        first_ts = data[0].x()
        last_ts = data[-1].x()
        first_dt = QDateTime.fromMSecsSinceEpoch(first_ts)
        last_dt = QDateTime.fromMSecsSinceEpoch(last_ts)

        axis_x = self.chart.axisX()
        axis_x.setRange(first_dt, last_dt)

        axis_y = self.chart.axisY()
        axis_y.setRange(70000000, 71000000)
Exemple #6
0
class BandwidthGraphView(BaseTimedGraph):
    bwStatsFetched = AsyncSignal(dict)

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

        self.setObjectName('BandwidthGraph')
        self.chart.setTitle(iBandwidthUsage())
        self.axisY.setTitleText(iRateKbPerSecond())

        self.bwStatsFetched.connectTo(self.onBwStats)

        penIn = QPen(QColor('red'))
        penIn.setWidth(2)
        penOut = QPen(QColor('blue'))
        penOut.setWidth(2)

        self.seriesKbIn = QLineSeries()
        self.seriesKbIn.setName(iRateInput())
        self.seriesKbIn.setPen(penIn)
        self.chart.addSeries(self.seriesKbIn)
        self.seriesKbIn.attachAxis(self.axisX)
        self.seriesKbIn.attachAxis(self.axisY)

        self.seriesKbOut = QLineSeries()
        self.seriesKbOut.setName(iRateOutput())
        self.seriesKbOut.setPen(penOut)
        self.chart.addSeries(self.seriesKbOut)
        self.seriesKbOut.attachAxis(self.axisX)
        self.seriesKbOut.attachAxis(self.axisY)

        self.setChart(self.chart)

    async def onBwStats(self, stats):
        dtNow = QDateTime.currentDateTime()
        dtMsecs = dtNow.toMSecsSinceEpoch()

        delta = 120 * 1000
        if not self.seriesPurgedT or (dtMsecs - self.seriesPurgedT) > delta:
            self.removeOldSeries(self.seriesKbIn, dtMsecs - delta)
            self.removeOldSeries(self.seriesKbOut, dtMsecs - delta)
            self.seriesPurgedT = dtMsecs

        rateIn = stats.get('RateIn', 0)
        rateOut = stats.get('RateOut', 0)
        rateInKb = int(rateIn / 1024)
        rateOutKb = int(rateOut / 1024)

        inVector = self.seriesKbIn.pointsVector()
        outVector = self.seriesKbIn.pointsVector()

        inValues = [p.y() for p in inVector]
        outValues = [p.y() for p in outVector]

        if inValues or outValues:
            self.axisY.setMax(max(max(inValues), max(outValues)))

        dateMin = QDateTime.fromMSecsSinceEpoch(dtMsecs - (30 * 1000))
        dateMax = QDateTime.fromMSecsSinceEpoch(dtMsecs + 2000)

        self.seriesKbIn.append(dtMsecs, rateInKb)
        self.seriesKbOut.append(dtMsecs, rateOutKb)
        self.axisX.setRange(dateMin, dateMax)
Exemple #7
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()
class MainInterface(QMainWindow):
    '''实现 GUI 以及其连接整个程序的功能

    @属性说明: 


    @方法说明: 


    @注意: 

    '''
    def __init__(self, parent=None):
        super().__init__(parent)  # 父类初始化
        self.ui = Ui_main_interface()  # 创建UI类
        self.ui.setupUi(self)
        self.showMaximized()  # 最大化界面
        self.setWindowTitle("疲劳检测")  # 界面标题
        self.time = QTimer()  # 创建定时器
        self._connect_slot()  # 初始化槽函数连接
        self.eye_data_chart_init()  # 初始化眼睛闭合数据折线图
        self._t = 0  # 用来计数
        self._perclos_threshold = 0.3  # 设置初始化阈值

    def _connect_slot(self):
        '''初始化信号与槽的连接

        @参数说明: 
            无

        @返回值: 
            无

        @注意: 
            无
        '''
        self.ui.btn_start.clicked.connect(self._display)
        self.time.timeout.connect(self.test)

    def paintEvent(self, evevt):
        """绘图软件背景图

        Qt里面默认事件处理函数,在界面需要重新绘制时触发
        此方法主要是绘制软件的背景图

        @参数说明: 
            evevt:Qt默认事件

        @返回值: 
            无

        @注意: 
            无
        """
        temp_painter = QPainter(self)
        # 创建背景图QPixmap()对象
        soft_background_image = QPixmap("resources/groud.jpg")
        # 绘制背景图
        temp_painter.drawPixmap(0, 0, self.width(), self.height(),
                                soft_background_image)
        # 执行父类的paintEvent()函数,以便父类执行其内建的一些操作
        super().paintEvent(evevt)

    def eye_data_chart_init(self):
        '''初始化左右眼闭合程度曲线图表

        @参数说明: 
            无

        @返回值: 
            无

        @注意: 
            无
        '''
        # 创建 chart 和 chartview
        self._chart = QChart()
        self._chart.setTitle("眼睛闭合程度值")  # 设置图表标题
        self._chartView = QChartView(self)
        self._chartView.setChart(self._chart)  # chart 添加到 chartview

        # 完成布局
        self.ui.horizontalLayout_2.addWidget(self._chartView)

        ## 创建曲线系列
        self._series0 = QLineSeries()
        self._series1 = QLineSeries()
        self._series0.setName("左眼曲线")  # 设置曲线名
        self._series1.setName("右眼曲线")
        self._chart.addSeries(self._series0)  # 序列添加到图表
        self._chart.addSeries(self._series1)

        # 创建坐标轴
        self._axis_x = QValueAxis()  # x 轴
        self._axis_x.setRange(0, 60)  # 设置 x 轴坐标范围
        self._axis_x.setTitleText("time(secs)")  # x 轴标题
        self._axis_y = QValueAxis()  # y 轴
        self._axis_y.setRange(0, 0.5)  # 设置 y 轴坐标范围
        self._axis_y.setTitleText("value")  # y 轴标题

        # 为序列设置坐标轴
        self._chart.setAxisX(self._axis_x, self._series0)
        self._chart.setAxisY(self._axis_y, self._series0)
        self._chart.setAxisX(self._axis_x, self._series1)
        self._chart.setAxisY(self._axis_y, self._series1)

    @pyqtSlot(bool)
    def _display(self, checked):
        '''

        @参数说明: 


        @返回值: 


        @注意: 

        '''
        if (checked == False):  # 当按键为 False 时,停止检查
            self.ui.le_eye_threshold.setEnabled(True)
            self.ui.btn_start.setText("启动")
            self.ui.lb_fatigue_detection.setText("检测停止")
            self.time.stop()
        else:
            threshold_str = self.ui.le_eye_threshold.text()  # 获得睁闭眼阈值
            threshold_str = re.match(r"\d\.\d\d$", threshold_str)  # 对睁闭眼阈值做限定
            if (threshold_str == None):
                message_title = "阈值格式错误"
                message_text = "请输入正确的阈值格式,格式为 x.xx (x 为数字)"
                QMessageBox.critical(self, message_title, message_text)
            else:
                self.ui.btn_start.setText("停止")
                self.ui.le_eye_threshold.setEnabled(False)
                model_path = r"E:\make_data\facial"  # 人脸关键模型路径
                opencv_facial_path = r"E:\Fatigue_Detection\model_data\facial_model\haarcascade_frontalface_default.xml"  # 人脸检测模型路径
                cap_index = eval(
                    self.ui.cmb_cap_index.currentText())  # 从 combabox 获取设想头索引
                # cap_file = r"C:\Users\LWL\Pictures\Camera Roll\WIN_20200503_07_51_19_Pro.mp4"
                self.facial_data = GetFacialData(
                    tf_model=model_path,
                    facial_model_file=opencv_facial_path,
                    cap_index=cap_index)  # 创建 GetFacialData 类
                self.time.start(1000)  # 设置每次检测的间隔时间
                self.ui.lb_fatigue_detection.setText("检测中")
                self._series0.clear()
                self._series1.clear()
                self._t = 0  # 重新开始计数
                self._perclos_threshold = eval(threshold_str.group())

    def test(self):
        ret, frame = self.facial_data.get_frame()
        if (ret == -1):
            message_title = "摄像头打开失败"
            message_text = "摄像头打开失败,请检测摄像头索引是否正确"
            self.time.stop()
            QMessageBox.critical(self, message_title, message_text)
        if (ret == -2):
            message_title = "获取帧失败"
            message_text = "从摄像头获取帧失败,请重启软件"
            self.time.stop()
            QMessageBox.critical(self, message_title, message_text)
        else:
            frame = cv2.medianBlur(frame, 5)
            ret, rect = self.facial_data.get_facial(frame)
            h, w = frame.shape[:2]
            if (ret == -1):
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                temp_q_image = QImage(frame, w, h, QImage.Format_RGB888)
                #  在 lb_display 中显示图片
                self.ui.lb_display.setPixmap(QPixmap.fromImage(temp_q_image))
                self.ui.lb_facial_number.setText(str(rect))  # 显示当前检测人脸数
            else:
                self.ui.lb_facial_number.setText("1")  # 显示当前检测人脸数
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                facial = frame[rect[2]:rect[3], rect[0]:rect[1]]

                image = cv2.cvtColor(facial, cv2.COLOR_RGB2GRAY)
                image_h, image_w = image.shape[:2]
                image = cv2.resize(image, (150, 150))
                image = np.reshape(image, [1, 150, 150, 1])
                image = image / 255.
                facial_keypoints = self.facial_data.get_result(image)
                facial_keypoints = (facial_keypoints[0] + 1) / 2
                facial_keypoints[::
                                 2] = facial_keypoints[::2] * image_w + rect[0]
                facial_keypoints[
                    1::2] = facial_keypoints[1::2] * image_h + rect[2]

                # 圈出人脸范围
                facial = cv2.rectangle(frame, (rect[0], rect[2]),
                                       (rect[1], rect[3]), (255, 0, 0), 1)

                # 将人脸多特征点标记到图片上
                for i in range(12):
                    facial = cv2.circle(frame,
                                        (int(facial_keypoints[2 * i]),
                                         int(facial_keypoints[2 * i + 1])), 2,
                                        (255, 0, 0), -1)  # 进行打点

                # 获得左右眼的闭合程度
                eye_process_data = result_process.eyes_process(
                    facial_keypoints)

                # 添加点到图表上
                self._series0.append(self._t, eye_process_data[0])
                self._series1.append(self._t, eye_process_data[1])

                # 在label上显示左右眼计算值
                self.ui.lb_left_eye_figure.setText(str(
                    eye_process_data[0]))  # 显示左眼的计算值
                self.ui.lb_right_eye_figure.setText(str(
                    eye_process_data[1]))  # 显示右眼的计算值

                temp_q_image = QImage(facial.data, w, h, QImage.Format_RGB888)
                #  在 lb_display 中显示图片
                self.ui.lb_display.setPixmap(QPixmap.fromImage(temp_q_image))

                self._t += 1  # 每个 1s 绘制点
                if (self._t > 60):
                    # 获取 series0 以及 series1 中所有的数据
                    left_eye_point = self._series0.pointsVector()
                    right_eye_point = self._series1.pointsVector()
                    # 使用正则表达式提取其中的计算数据
                    left_eye_data = np.array(
                        re.findall(r"\d+\.\d{2,5}", str(left_eye_point)))
                    right_eye_data = np.array(
                        re.findall(r"\d+\.\d{2,5}", str(right_eye_point)))
                    perclos_judge_result = result_process.perclos_judge(
                        left_eye_data, self._perclos_threshold)
                    # 对 perclos_judge 的结果进行输出
                    if (perclos_judge_result == -2):
                        self.ui.lb_fatigue_detection.setText("过度疲劳")
                        message_title = "过度疲劳警告提醒"
                        message_text = "为了你的人身安全,请停下手中工作,休息一段时间!"
                        QMessageBox.critical(self, message_title,
                                             message_text)  # 过度疲劳提醒
                    elif (perclos_judge_result == -1):
                        self.ui.lb_fatigue_detection.setText("疲劳状态")
                    else:
                        self.ui.lb_fatigue_detection.setText("状态良好")
                    # 清除所有的 series0 以及 series1 数据,重新绘图
                    self._series0.clear()
                    self._series1.clear()
                    self._t = 0  # 重新开始计数
Exemple #9
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
class TelemetryDialog(QDialog):
    resized = QtCore.pyqtSignal()
    visibility = QtCore.pyqtSignal(bool)

    def __init__(self, winTitle="Network Telemetry", parent=None):
        super(TelemetryDialog, self).__init__(parent)

        self.visibility.connect(self.onVisibilityChanged)

        self.winTitle = winTitle

        self.updateLock = Lock()

        # Used to detect network change
        self.lastNetKey = ""
        self.lastSeen = None
        self.maxPoints = 20
        self.maxRowPoints = 60

        self.paused = False
        self.streamingSave = False
        self.streamingFile = None
        self.linesBeforeFlush = 10
        self.currentLine = 0

        # OK and Cancel buttons
        #buttons = QDialogButtonBox(QDialogButtonBox.Ok,Qt.Horizontal, self)
        #buttons.accepted.connect(self.accept)
        #buttons.move(170, 280)

        desktopSize = QApplication.desktop().screenGeometry()
        #self.mainWidth=1024
        #self.mainHeight=768
        #self.mainWidth = desktopSize.width() * 3 / 4
        #self.mainHeight = desktopSize.height() * 3 / 4

        self.setGeometry(self.geometry().x(),
                         self.geometry().y(),
                         desktopSize.width() / 2,
                         desktopSize.height() / 2)

        self.setWindowTitle(winTitle)

        self.radar = RadarWidget(self)
        self.radar.setGeometry(self.geometry().width() / 2, 10,
                               self.geometry().width() / 2 - 20,
                               self.geometry().width() / 2 - 20)

        self.createTable()

        self.btnExport = QPushButton("Export Table", self)
        self.btnExport.clicked[bool].connect(self.onExportClicked)
        self.btnExport.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.btnPause = QPushButton("Pause Table", self)
        self.btnPause.setCheckable(True)
        self.btnPause.clicked[bool].connect(self.onPauseClicked)
        self.btnPause.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.btnStream = QPushButton("Streaming Save", self)
        self.btnStream.setCheckable(True)
        self.btnStream.clicked[bool].connect(self.onStreamClicked)
        self.btnStream.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.createChart()

        self.setBlackoutColors()

        self.setMinimumWidth(600)
        self.setMinimumHeight(600)

        self.center()

    def createTable(self):
        # Set up location table
        self.locationTable = QTableWidget(self)
        self.locationTable.setColumnCount(8)
        self.locationTable.setGeometry(10, 10,
                                       self.geometry().width() / 2 - 20,
                                       self.geometry().height() / 2)
        self.locationTable.setShowGrid(True)
        self.locationTable.setHorizontalHeaderLabels([
            'macAddr', 'SSID', 'Strength', 'Timestamp', 'GPS', 'Latitude',
            'Longitude', 'Altitude'
        ])
        self.locationTable.resizeColumnsToContents()
        self.locationTable.setRowCount(0)
        self.locationTable.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)

        self.ntRightClickMenu = QMenu(self)
        newAct = QAction('Copy', self)
        newAct.setStatusTip('Copy data to clipboard')
        newAct.triggered.connect(self.onCopy)
        self.ntRightClickMenu.addAction(newAct)

        self.locationTable.setContextMenuPolicy(Qt.CustomContextMenu)
        self.locationTable.customContextMenuRequested.connect(
            self.showNTContextMenu)

    def setBlackoutColors(self):
        self.locationTable.setStyleSheet(
            "QTableView {background-color: black;gridline-color: white;color: white} QTableCornerButton::section{background-color: white;}"
        )
        headerStyle = "QHeaderView::section{background-color: white;border: 1px solid black;color: black;} QHeaderView::down-arrow,QHeaderView::up-arrow {background: none;}"
        self.locationTable.horizontalHeader().setStyleSheet(headerStyle)
        self.locationTable.verticalHeader().setStyleSheet(headerStyle)

        mainTitleBrush = QBrush(Qt.red)
        self.timeChart.setTitleBrush(mainTitleBrush)

        self.timeChart.setBackgroundBrush(QBrush(Qt.black))
        self.timeChart.axisX().setLabelsColor(Qt.white)
        self.timeChart.axisY().setLabelsColor(Qt.white)
        titleBrush = QBrush(Qt.white)
        self.timeChart.axisX().setTitleBrush(titleBrush)
        self.timeChart.axisY().setTitleBrush(titleBrush)

    def resizeEvent(self, event):
        wDim = self.geometry().width() / 2 - 20
        hDim = self.geometry().height() / 2

        smallerDim = wDim
        if hDim < smallerDim:
            smallerDim = hDim

        # Radar
        self.radar.setGeometry(self.geometry().width() - smallerDim - 10, 10,
                               smallerDim, smallerDim)

        # chart
        self.timePlot.setGeometry(10, 10,
                                  self.geometry().width() - smallerDim - 30,
                                  smallerDim)

        # Buttons
        self.btnPause.setGeometry(10,
                                  self.geometry().height() / 2 + 18, 110, 25)
        self.btnExport.setGeometry(150,
                                   self.geometry().height() / 2 + 18, 110, 25)
        self.btnStream.setGeometry(290,
                                   self.geometry().height() / 2 + 18, 110, 25)

        # Table
        self.locationTable.setGeometry(10,
                                       self.geometry().height() / 2 + 50,
                                       self.geometry().width() - 20,
                                       self.geometry().height() / 2 - 60)

    def center(self):
        # Get our geometry
        qr = self.frameGeometry()
        # Find the desktop center point
        cp = QDesktopWidget().availableGeometry().center()
        # Move our center point to the desktop center point
        qr.moveCenter(cp)
        # Move the top-left point of the application window to the top-left point of the qr rectangle,
        # basically centering the window
        self.move(qr.topLeft())

    def showNTContextMenu(self, pos):
        curRow = self.locationTable.currentRow()

        if curRow == -1:
            return

        self.ntRightClickMenu.exec_(self.locationTable.mapToGlobal(pos))

    def onCopy(self):
        self.updateLock.acquire()

        curRow = self.locationTable.currentRow()
        curCol = self.locationTable.currentColumn()

        if curRow == -1 or curCol == -1:
            self.updateLock.release()
            return

        curText = self.locationTable.item(curRow, curCol).text()

        clipboard = QApplication.clipboard()
        clipboard.setText(curText)

        self.updateLock.release()

    def onVisibilityChanged(self, visible):
        if not visible:
            self.paused = True
            self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);")
            # We're coming out of streaming
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            if (self.streamingFile):
                self.streamingFile.close()
                self.streamingFile = None
            return
        else:
            self.paused = False
            self.btnPause.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            if self.locationTable.rowCount() > 1:
                self.locationTable.scrollToItem(self.locationTable.item(0, 0))

    def hideEvent(self, event):
        self.visibility.emit(False)

    def showEvent(self, event):
        self.visibility.emit(True)

    def onPauseClicked(self, pressed):
        if self.btnPause.isChecked():
            self.paused = True
            self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);")
        else:
            self.paused = False
            self.btnPause.setStyleSheet(
                "background-color: rgba(2,128,192,255);")

    def onStreamClicked(self, pressed):
        if not self.btnStream.isChecked():
            # We're coming out of streaming
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            if (self.streamingFile):
                self.streamingFile.close()
                self.streamingFile = None
            return

        self.btnStream.setStyleSheet("background-color: rgba(255,0,0,255);")
        self.streamingSave = True

        fileName = self.saveFileDialog()

        if not fileName:
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            return

        try:
            self.streamingFile = open(
                fileName, 'w', 1
            )  # 1 says use line buffering, otherwise it fully buffers and doesn't write
        except:
            QMessageBox.question(self, 'Error',
                                 "Unable to write to " + fileName,
                                 QMessageBox.Ok)
            self.streamingFile = None
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            return

        self.streamingFile.write(
            'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n'
        )

    def onExportClicked(self):
        fileName = self.saveFileDialog()

        if not fileName:
            return

        try:
            outputFile = open(fileName, 'w')
        except:
            QMessageBox.question(self, 'Error',
                                 "Unable to write to " + fileName,
                                 QMessageBox.Ok)
            return

        outputFile.write(
            'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n'
        )

        numItems = self.locationTable.rowCount()

        if numItems == 0:
            outputFile.close()
            return

        self.updateLock.acquire()

        for i in range(0, numItems):
            outputFile.write(
                self.locationTable.item(i, 0).text() + ',"' +
                self.locationTable.item(i, 1).text() + '",' +
                self.locationTable.item(i, 2).text() + ',' +
                self.locationTable.item(i, 3).text())
            outputFile.write(',' + self.locationTable.item(i, 4).text() + ',' +
                             self.locationTable.item(i, 5).text() + ',' +
                             self.locationTable.item(i, 6).text() + ',' +
                             self.locationTable.item(i, 7).text() + '\n')

        self.updateLock.release()
        outputFile.close()

    def saveFileDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(
            self,
            "QFileDialog.getSaveFileName()",
            "",
            "CSV Files (*.csv);;All Files (*)",
            options=options)
        if fileName:
            return fileName
        else:
            return None

    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 updateNetworkData(self, curNet):
        if not self.isVisible():
            return

        # Signal is -NN dBm.  Need to make it positive for the plot
        self.radar.updateData(curNet.signal * -1)

        if self.winTitle == "Client Telemetry":
            self.setWindowTitle(self.winTitle + " - [" + curNet.macAddr +
                                "] " + curNet.ssid)
        else:
            self.setWindowTitle(self.winTitle + " - " + curNet.ssid)

        self.radar.draw()

        #  Network changed.  Clear our table and time data
        updateChartAndTable = False

        self.updateLock.acquire()

        if (curNet.getKey() != self.lastNetKey):
            self.lastNetKey = curNet.getKey()
            self.locationTable.setRowCount(0)
            self.timeSeries.clear()
            updateChartAndTable = True

            ssidTitle = curNet.ssid
            if len(ssidTitle) > 28:
                ssidTitle = ssidTitle[:28]
                ssidTitle = ssidTitle + '...'

            self.timeChart.setTitle(ssidTitle + ' Signal (Past ' +
                                    str(self.maxPoints) + ' Samples)')
        else:
            if self.lastSeen != curNet.lastSeen:
                updateChartAndTable = True

        if updateChartAndTable:
            # Update chart
            numPoints = len(self.timeSeries.pointsVector())

            if numPoints >= self.maxPoints:
                self.timeSeries.remove(0)
                # Now we need to reset the x data to pull the series back
                counter = 0
                for curPoint in self.timeSeries.pointsVector():
                    self.timeSeries.replace(counter, counter, curPoint.y())
                    counter += 1

            if curNet.signal >= -100:
                self.timeSeries.append(numPoints, curNet.signal)
            else:
                self.timeSeries.append(numPoints, -100)

            # Update Table
            self.addTableData(curNet)

            # Limit points in each
            if self.locationTable.rowCount() > self.maxRowPoints:
                self.locationTable.setRowCount(self.maxRowPoints)

        self.updateLock.release()

    def addTableData(self, curNet):
        if self.paused:
            return

        # rowPosition = self.locationTable.rowCount()
        # Always insert at row(0)
        rowPosition = 0

        self.locationTable.insertRow(rowPosition)

        #if (addedFirstRow):
        #    self.locationTable.setRowCount(1)

        # ['macAddr','SSID', 'Strength', 'Timestamp','GPS', 'Latitude', 'Longitude', 'Altitude']
        self.locationTable.setItem(rowPosition, 0,
                                   QTableWidgetItem(curNet.macAddr))
        tmpssid = curNet.ssid
        if (len(tmpssid) == 0):
            tmpssid = '<Unknown>'
        newSSID = QTableWidgetItem(tmpssid)

        self.locationTable.setItem(rowPosition, 1, newSSID)
        self.locationTable.setItem(rowPosition, 2,
                                   IntTableWidgetItem(str(curNet.signal)))
        self.locationTable.setItem(
            rowPosition, 3,
            DateTableWidgetItem(curNet.lastSeen.strftime("%m/%d/%Y %H:%M:%S")))
        if curNet.gps.isValid:
            self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('Yes'))
        else:
            self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('No'))

        self.locationTable.setItem(
            rowPosition, 5, FloatTableWidgetItem(str(curNet.gps.latitude)))
        self.locationTable.setItem(
            rowPosition, 6, FloatTableWidgetItem(str(curNet.gps.longitude)))
        self.locationTable.setItem(
            rowPosition, 7, FloatTableWidgetItem(str(curNet.gps.altitude)))
        #order = Qt.DescendingOrder
        #self.locationTable.sortItems(3, order )

        # If we're in streaming mode, write the data out to disk as well
        if self.streamingFile:
            self.streamingFile.write(
                self.locationTable.item(rowPosition, 0).text() + ',"' +
                self.locationTable.item(rowPosition, 1).text() + '",' +
                self.locationTable.item(rowPosition, 2).text() + ',' +
                self.locationTable.item(rowPosition, 3).text() + ',' +
                self.locationTable.item(rowPosition, 4).text() + ',' +
                self.locationTable.item(rowPosition, 5).text() + ',' +
                self.locationTable.item(rowPosition, 6).text() + ',' +
                self.locationTable.item(rowPosition, 7).text() + '\n')

            if (self.currentLine > self.linesBeforeFlush):
                self.streamingFile.flush()
                self.currentLine += 1

        numRows = self.locationTable.rowCount()

        if numRows > 1:
            self.locationTable.scrollToItem(self.locationTable.item(0, 0))

    def onTableHeadingClicked(self, logical_index):
        header = self.locationTable.horizontalHeader()
        order = Qt.DescendingOrder
        # order = Qt.DescendingOrder
        if not header.isSortIndicatorShown():
            header.setSortIndicatorShown(True)
        elif header.sortIndicatorSection() == logical_index:
            # apparently, the sort order on the header is already switched
            # when the section was clicked, so there is no need to reverse it
            order = header.sortIndicatorOrder()
        header.setSortIndicator(logical_index, order)
        self.locationTable.sortItems(logical_index, order)

    def updateData(self, newRadius):
        self.radar.updateData(newRadius)

    def showTelemetry(parent=None):
        dialog = TelemetryDialog(parent)
        result = dialog.exec_()
        return (result == QDialog.Accepted)
Exemple #11
0
class Chart(QChart):
    MIN_X = 0
    MAX_X = 750
    MIN_Y = -1
    MAX_Y = 1
    TICKS = 5
    PENCOLOR = Qt.red
    PENWIDTH = 1

    def __init__(self, parent=None):
        super(Chart, self).__init__(parent)
        self.parent = parent
        # we will draw lines
        self.series = QLineSeries(parent)
        # color and pen-width
        self.series.setPen(QPen(self.PENCOLOR, self.PENWIDTH))

        self.addSeries(self.series)

        self.legend().hide()
        self.__construct_axises()

    def setRange_X_axis(self, min_X, max_X):
        self.MIN_X = min_X
        self.MAX_X = max_X
        self.axisX().setRange(self.MIN_X, self.MAX_X)

    def setRange_Y_axis(self, min_Y, max_Y):
        self.MIN_Y = min_Y
        self.MAX_Y = max_Y
        self.axisY().setRange(self.MIN_Y, self.MAX_Y)

    def add_point(self, x, y):
        self.series.append(x, y)

    def get_series(self) -> list:
        return self.series.pointsVector()

    def remove_point(self, index):
        self.series.remove(index)

    def remove_points(self, index, count):
        self.series.removePoints(index, count)

    def replace_point(self, index, x, y):
        self.series.replace(index, x, y)

    def replace_series(self, lst):
        self.series.replace(lst)

    def get_series_count(self):
        return self.series.count()

    def __construct_axises(self):
        self.createDefaultAxes()

        # X-Axis
        x_axis = self.axisX()
        x_axis.hide()
        x_axis.setRange(self.MIN_X, self.MAX_X)

        # Y-axis
        y_axis = self.axisY()
        y_axis.setRange(self.MIN_Y, self.MAX_Y)
        y_axis.setTickCount(self.TICKS)
class MainView(QWidget, Ui_Dialog):
    def __init__(self):
        super().__init__()
        Ui_Dialog.setupUi(self, self)
        self.pushButton_3.clicked.connect(self.showRecords)
        self.pushButton.clicked.connect(self.start)
        self.recive = False
        self.s = socket.socket()  # Create a socket object
        self.c = socket.socket()  # Create a socket object
        host = "192.168.1.40"  # Get local machine name
        port = 12345  # Reserve a port for your serv
        host = ""  # Get local machine nameice.
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.pushButton_3.setDisabled(True)
        self.pushButton.setText("Stop")
        try:
            self.s.bind(("", port))  # Bind to the port
        except:
            print("error")

        # self.s.listen(5)                 # Now wait for client connection.

    def __del__(self):
        self.s.close()

    def showConfiguration(self):
        self.hide()
        self.conf = configureView.configureView(self)
        self.conf.setMain(self)
        self.conf.show()

    def showRecords(self):
        self.w = QWidget()
        self.w.show()
        self.hide()
        self.gridLayout = QtWidgets.QVBoxLayout(self.w)
        self.text = QtWidgets.QLabel(self.w)
        self.chart = QChart()
        self.chart2 = QChart()
        self.chart3 = QChart()
        self.text.setText("none")
        self.backButton = QtWidgets.QPushButton(self.w)
        self.chartView = QChartView(self.chart)
        self.chartView.setRenderHint(QtGui.QPainter.Antialiasing)
        # self.chartView2.setRenderHint(QtGui.QPainter.Antialiasing)
        # self.chartView3.setRenderHint(QtGui.QPainter.Antialiasing)
        self.gridLayout.addWidget(self.chartView)
        # self.gridLayout.addWidget(self.chartView3)
        self.backButton.setText("Back")
        self.gridLayout.addWidget(self.backButton)
        self.backButton.clicked.connect(self.back)
        self.recive = True
        # self.series2 = QLineSeries(self.chart2)
        # self.series3 = QLineSeries(self.chart3)
        self.series = QLineSeries(self.chart)
        self.series2 = QLineSeries(self.chart)
        self.series3 = QLineSeries(self.chart)
        # self.series2.setUseOpenGL(True)
        # self.series3.setUseOpenGL(True)
        self.series.setUseOpenGL(True)
        self.series2.setUseOpenGL(True)
        self.series3.setUseOpenGL(True)
        # self.chart.addSeries(self.series)
        self.startServer()

    def createLineChart(self, dataTable):
        self.chart.setTitle("Sensor1")
        series = QLineSeries(self.chart)
        series2 = QLineSeries(self.chart)
        series3 = QLineSeries(self.chart)
        # series2 = QLineSeries(self.chart)
        # series3 = QLineSeries(self.chart)
        series.setUseOpenGL(True)
        series2.setUseOpenGL(True)
        series3.setUseOpenGL(True)
        # series2.setUseOpenGL(True)
        # series3.setUseOpenGL(True)

        series.replace(self.series.pointsVector())
        series2.replace(self.series2.pointsVector())
        series3.replace(self.series3.pointsVector())
        # series2.replace(self.series2.pointsVector())
        # series3.replace(self.series2.pointsVector())
        self.chart.removeAllSeries()
        self.chart.addSeries(series2)
        self.chart.addSeries(series)
        self.chart.addSeries(series3)
        # self.chart2.removeAllSeries()
        # self.chart2.addSeries(series2)
        # self.chart3.removeAllSeries()
        # self.chart3.addSeries(series3)
        # self.chart.scroll(1,2)

    def startServer(self):
        # Establish connection with client.
        a = []
        QApplication.processEvents()
        self.c.connect(("192.168.1.41", 12346))
        self.c.send(b'RecordView True')
        print("connected")
        index = 0
        while self.recive:

            QApplication.processEvents()  # c, addr = self.s.accept()
            message, adre = self.s.recvfrom(1024)
            # print(message)
            values = message.decode("utf-8").split("-")
            value1 = int(values[0])
            value2 = int(values[1])
            value3 = int(values[2])
            self.series.append(index, value1)
            self.series2.append(index, value2)
            self.series3.append(index, value3)
            # self.series2.append(index, int(message.decode("utf-8")))
            # self.series3.append(index, int(message.decode("utf-8")))
            if self.series.count() > 100:
                self.series.removePoints(0, 1)
                self.series2.removePoints(0, 1)
                self.series3.removePoints(0, 1)
                # self.series2.removePoints(0,1)
                # self.series3.removePoints(0,1)
            index += 1
            a.append(message.decode("utf-8"))
            self.createLineChart(a)
        self.c.connect(("192.168.1.41", 12346))
        self.c.send(b'RecordView False')

    def back(self):
        self.w.hide()
        self.show()
        self.recive = False

    def configure(self, arguments):
        print(arguments)
        self.c.connect(("192.168.1.41", 12346))
        self.c.send(b'Sensor ' + arguments)

    def start(self):
        self.c.connect(("192.168.1.41", 12346))
        if self.pushButton.text() == "Start":
            text = "Stop"
            self.pushButton_3.setEnabled(False)
            self.c.send(b'Record False')
        else:
            text = "Start"
            self.pushButton_3.setEnabled(True)
            self.c.send(b'Record True')

        self.recive = self.pushButton.text() == "Start"
        self.pushButton.setText(text)
Exemple #13
0
class ChartWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        # chart.ui 파일을 읽어와서 디자인을 적용한다.
        uic.loadUi("resource/chart.ui", self)
        self.ticker = ticker
        self.viewLimit = 120  # 라인 차트로 그릴 데이터의 수를 미리 정의한다.

        self.priceData = QLineSeries()
        self.priceChart = QChart()
        self.priceChart.addSeries(self.priceData)
        self.priceChart.legend().hide()  # 차트의 범례를 숨긴다.

        axisX = QDateTimeAxis()  # PyChart에서 날짜 축을 관리하는 QDateTimeAxis 객체를 생성한다.
        axisX.setFormat("hh:mm:ss")  # 시:분:초 형태로 차트에 표시한다.
        axisX.setTickCount(4)  # 차트에 표시할 날짜의 개수를 4로 지정한다.
        dt = QDateTime.currentDateTime()  # 현재 시간 정보를 QDateTime 객체로 얻어온다.

        # X축에 출력될 값의 범위를 현재 시간부터 viewLimit(120)초 이후까지 설정한다.
        # addSecs 메서드는 지정된 초 이후의 시간을 QDateTime으로 반환한다.
        axisX.setRange(dt, dt.addSecs(self.viewLimit))

        axisY = QValueAxis()  # 정수를 저장하는 축을 생성하고 축의 레이블을 차트에 표시하지 않는다.
        axisY.setVisible(False)

        self.priceChart.addAxis(axisX, Qt.AlignBottom)
        self.priceChart.addAxis(axisY, Qt.AlignRight)
        self.priceData.attachAxis(axisX)
        self.priceData.attachAxis(axisY)

        # 차트 객체 안에 여백을 최소화해서 차트를 크게 그린다.
        self.priceChart.layout().setContentsMargins(0, 0, 0, 0)

        self.priceView.setChart(self.priceChart)
        self.priceView.setRenderHints(
            QPainter.Antialiasing)  # 차트에 anti-aliasing을 적용한다.

        # PriceWorker 객체 생성 및 dataSent 이벤트를 연결할 슬롯을 지정한다.
        self.pw = PriceWorker(ticker)
        self.pw.dataSent.connect(self.appendData)
        self.pw.start()

    # 차트에 그릴 데이터를 입력받는다.
    def appendData(self, currPrice):
        # 정해진 데이터 개수만큼 저장되어 있다면 오래된 0번 인덱스의 데이터를 삭제한다.
        # 삭제 로직이 없다면 저장되는 데이터의 개수가 무한히 증가할 것이다.
        if len(self.priceData) == self.viewLimit:
            self.priceData.remove(0)
        dt = QDateTime.currentDateTime()

        # append 메서드는 millisecond(ms)를 입력받기 때문에 MSecsSinceEpoch() 메서드로 QDateTime 객체를 millisecond로 변환한다.
        self.priceData.append(dt.toMSecsSinceEpoch(), currPrice)

        # 차트의 축 정보를 업데이트 한다. 실시간으로 추가되는 데이터의 위치를 지정한다.
        self.__updateAxis()

    def __updateAxis(self):
        # QLineSerires 객체에 저장된 데이터를 리스트로 얻어온다.
        # pvs에 저장된 리스트 안에는 QPointF 객체로 위치 정보가 저장되어 있다.
        pvs = self.priceData.pointsVector()

        # 가장 오래된 0번 인덱스의 객체를 하나 선택해서 x 좌표에 저장된 값을 가져온다.
        # ms로 변환해서 들어간 좌표 데이터를 fromMSecsSinceEpoch 메서드를 사용해서 QDateTime 객체로 변환한다.
        dtStart = QDateTime.fromMSecsSinceEpoch(int(pvs[0].x()))

        # 데이터가 꽉 차 있다면 최근 시간 정보가 들어 있는 마지막 객체를 선택한다.
        if len(self.priceData) == self.viewLimit:
            dtLast = QDateTime.fromMSecsSinceEpoch(int(pvs[-1].x()))
        # 데이터가 꽉 차 있지 않다면 시작 위치를 기준으로 viewLimit 초 이후까지 출력한다.
        # 항상 viewLimit 개의 데이터를 출력하는데 사용된다.
        else:
            dtLast = dtStart.addSecs(self.viewLimit)

        # 앞서 얻어온 위치 정보를 보여줄 수 있도록 X 축의 범위를 설정한다.
        ax = self.priceChart.axisX()
        ax.setRange(dtStart, dtLast)

        # QPointF 객체에서 y 좌표를 가져와서 최소값, 최대값으로 Y축에 표시될 범위를 지정한다.
        ay = self.priceChart.axisY()
        dataY = [v.y() for v in pvs]
        ay.setRange(min(dataY), max(dataY))

    # QWidget에 정의된 메서드로 UI의 종료 버튼을 누르면 실행된다.
    # 자식 클래스에서 closeEvent를 재정의해서 종료되기 전 쓰레드를 종료한다.
    def closeEvent(self, event):
        self.pw.close()
Exemple #14
0
class ChartWidget(QWidget
                  ):  #추후 메인 GUI에 추가할 목적이므로 QWidget 클래스를 상속 ChartWidget클래스를 정의
    def __init__(
        self,
        parent=None,
        ticker="KRW-ETH"
    ):  #파라미터 parent는 위젯이 그려질 위치를 지정하는데 사용, 입력하지 않으면 None #티커는 조회할 코인의 종류를 지정
        super().__init__(parent)
        uic.loadUi("source/chart.ui", self)
        self.ticker = ticker
        self.viewLimit = 128  #라인 차트로 그릴 데이터의 수를 미리 정의

        self.pw = PriceWorker(ticker)
        self.pw.dataSent.connect(self.appendData)
        self.pw.start()

        self.priceData = QLineSeries(
        )  #QLineSeries 객체의 append메서드로 출력할 데이터의 좌표를 x, y 순서대로 입력
        self.priceChart = QChart()  #데이터를 차트 객체로 전달해서 시각화
        #QChart를 사용해 차트의 타이틀을 입력하거나 범례를 추가하는 등의 일을 할 수 있음
        self.priceChart.addSeries(self.priceData)
        self.priceChart.legend().hide()  #차트의 범례를 숨김

        axisX = QDateTimeAxis()  #PyChart에서 날짜 축을 관리하는 QDateTimeAxis 객체를 생성
        axisX.setFormat("hh:mm:ss")  #"시:분:초" 형태로 차트에 표시
        axisX.setTickCount(4)  #표시할 날짜의 개수를 4로 지정
        dt = QDateTime.currentDateTime()  #현재 시간 정보를 QDateTime 객체로
        axisX.setRange(
            dt, dt.addSecs(self.viewLimit)
        )  #X축에 출력될 값의 범위를 현재 시간부터 viewLimit (120)초 이후까지 설정, 지정된 초 이후의 시간을 QDateTime으로 반환

        axisY = QValueAxis()  #정수를 저장하는 축을 생성
        axisY.setVisible(False)  #축의 레이블을 차트에 표시하지 않음

        #X, Y축을 차트와 데이터에 연결
        self.priceChart.addAxis(axisX, Qt.AlignBottom)
        self.priceChart.addAxis(axisY, Qt.AlignRight)
        self.priceData.attachAxis(axisX)
        self.priceData.attachAxis(axisY)
        self.priceChart.layout().setContentsMargins(0, 0, 0, 0)  #여백을 최소화

    def closeEvent(self, event):
        self.pw.close()

    def appendData(self, currPirce):
        if len(self.priceData) == self.viewLimit:  #정해진 데이터 개수만큼 저장돼 있다면
            self.priceData.remove(0)  #오래된 0번 인덱스의 데이터를 삭제
        dt = QDateTime.currentDateTime()  #간과 현재가 (currPrice)를 함께 저장
        self.priceData.append(dt.toMSecsSinceEpoch(), currPirce)
        self.__updateAxis()  #차트의 축정보를 업데이트하는 __updateAxis() 메서드를 호출

    def __updateAxis(self):
        #pointsVector 메서드를 사용해서 QLineSeries 객체에 저장된 데이터를 리스트로 얻어 옴
        pvs = self.priceData.pointsVector()
        dtStart = QDateTime.fromMSecsSinceEpoch(int(
            pvs[0].x()))  #가장 오래된 0번 인덱스 x 좌표에 저장된 값을 가져옴
        if len(self.priceData) == self.viewLimit:
            dtLast = QDateTime.fromMSecsSinceEpoch(int(pvs[-1].x(
            )))  #마지막 데이터는 119 번 인덱스에 저장 = 최근 시간 정보가 들어 있는 마지막 객체를 선택
        else:
            dtLast = dtStart.addSecs(
                self.viewLimit
            )  #viewLimit 보다 작다면 시작 위치 0번을 기준으로 viewLimit 초 이후까지 출력

        ax = self.priceChart.axisX()
        ax.setRange(dtStart, dtLast)

        ay = self.priceChart.axisY()
        dataY = [v.y() for v in pvs]
        ay.setRange(min(dataY), max(dataY))

        self.priceView.setChart(self.priceChart)
        self.priceView.setRenderHints(
            QPainter.Antialiasing)  #차트에 anti-aliasing을 적용