示例#1
0
class ChartWidget(QWidget):
    def __init__(self, number: int, parent=None):
        super(QWidget, self).__init__(parent)

        self.layout = QVBoxLayout(self)

        self.chart = QChart()
        self.chartView = QChartView(self.chart)
        self.chartView.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self.layout.addWidget(self.chartView)

        self.channelNumber = number
        for index in range(self.channelNumber):
            tmp = QLineSeries()
            tmp.setName("channel "+str(index))
            self.chart.addSeries(tmp)

        self.chart.createDefaultAxes()
        self.chart.axisX().setRange(0, 25)
        self.chart.axisX().setTitleText("AAA")
        self.chart.axisY().setRange(0, 25)
        self.chart.axisY().setTitleText("BBB")

        # 标题
        self.chart.setTitle("XXX XXX XXX")
        # 指示颜色所代表的内容
        # self.chart.legend().hide()
        # 动画效果
        self.chart.setAnimationOptions(QChart.AllAnimations)

    def set_line(self, *lines):
        for index in range(len(lines)):
            self.chart.series()[index].clear()
            for v1, v2 in enumerate(lines[index]):
                self.chart.series()[index].append(v1, v2)
示例#2
0
class QtChartCanvas(QWidget):
    def __init__(self, parent=None):
        super(QtChartCanvas, self).__init__(parent)
        self.plotChart = QChart()
        self.plotChart.legend().hide()
        self.verticalLayout = QtWidgets.QVBoxLayout(self)

        self.plotView = QChartView(self.plotChart)
        self.verticalLayout.addWidget(self.plotView)
        # self.setCentralWidget(self.plotView)

        self.plotCurve = QSplineSeries()
        self.plotCurve.setUseOpenGL(True)
        self.plotCurve.pen().setColor(Qt.red)
        self.plotChart.addSeries(self.plotCurve)

        self.plotChart.createDefaultAxes()
        # self.plotChart.axisX().setLabelFormat('%d')
        self.plotChart.axisX().hide()

        self.RecvData = []  # 存储接收到的传感器数据
        self.RecvIndx = 0

        self.setLockY = True

        self.isTop = False
        self.minY = 0
        self.maxY = 100

    def update_figure(self, payload):
        self.RecvData.append(payload["data"])
        self.RecvData = self.RecvData[-20:]
        plotData = []
        #print("call")
        if self.isTop:
            for i, val in enumerate(self.RecvData):
                plotData.append(QPoint(i, val))

            self.plotCurve.replace(plotData)
            self.plotChart.axisX().setMax(len(plotData))
            if not self.setLockY:
                self.plotChart.axisY().setRange(min(self.RecvData),
                                                max(self.RecvData))
            else:
                self.plotChart.axisY().setRange(self.minY, self.maxY)

    def setYLimit(self, miny=0, maxy=100, lockY=True):
        self.setLockY = lockY
        if self.setLockY:
            self.maxY = maxy
            self.minY = miny
            # self.plotChart.axisY().setRange(miny,maxy)

    def changeTop(self, isTop):
        self.isTop = isTop
示例#3
0
def test_generations():
    range_a = float(str(form.input_a_test.text()))
    range_b = float(str(form.input_b_test.text()))
    precision = int(str(form.input_d_test.text()))
    generations = int(str(form.input_generations_test.text()))

    app.setOverrideCursor(QtCore.Qt.WaitCursor)
    start = time()
    result  = test_generation(range_a, range_b, precision, generations)
    app.restoreOverrideCursor()

    chart = QChart()
    series = QLineSeries()

    form.test_table.setRowCount(0)

    form.test_table.insertRow(0)
    item = QtWidgets.QTableWidgetItem("iteracje")
    item.setTextAlignment(QtCore.Qt.AlignCenter)
    form.test_table.setItem(0, 0, item)

    item = QtWidgets.QTableWidgetItem("wystąpienia")
    item.setTextAlignment(QtCore.Qt.AlignCenter)
    form.test_table.setItem(0, 1, item)

    item = QtWidgets.QTableWidgetItem("%")
    item.setTextAlignment(QtCore.Qt.AlignCenter)
    form.test_table.setItem(0, 2, item)

    for i in range(0, generations):
        percent = sum(result[:i+1])/100000*100
        series.append(i+1, percent)

        form.test_table.insertRow(i+1)
        form.test_table.setItem(i+1, 0, QtWidgets.QTableWidgetItem(str(i+1)))
        form.test_table.setItem(i+1, 1, QtWidgets.QTableWidgetItem(str(result[i])))
        form.test_table.setItem(i+1, 2, QtWidgets.QTableWidgetItem(str(round(percent, 2))))
 
    chart.addSeries(series)

    chart.setBackgroundBrush(QtGui.QColor(41, 43, 47))
    chart.createDefaultAxes()
    chart.legend().hide()
    chart.setContentsMargins(-10, -10, -10, -10)
    chart.layout().setContentsMargins(0, 0, 0, 0)
    chart.axisX().setTickCount(10)
    chart.axisY().setRange(0, 100)
    chart.axisY().setTickCount(11)
    chart.axisX().setLabelsColor(QtGui.QColor("white"))
    chart.axisY().setLabelsColor(QtGui.QColor("white"))
    form.widget_test.setChart(chart)
示例#4
0
def update_particles(particles):
    animation_chart = QChart()
    reals = QScatterSeries()

    pen_reals = reals.pen()
    pen_reals.setBrush(QtGui.QColor("white"))
    reals.setMarkerSize(5)
    reals.setColor(QtGui.QColor("red"))
    reals.setPen(pen_reals)

    for particle in particles:
        reals.append(particle, 0)

    animation_chart.addSeries(reals)
    animation_chart.setBackgroundBrush(QtGui.QColor(41, 43, 47))
    animation_chart.createDefaultAxes()
    animation_chart.legend().hide()
    animation_chart.setContentsMargins(-10, -10, -10, -10)
    animation_chart.layout().setContentsMargins(0, 0, 0, 0)
    animation_chart.axisX().setTickCount(17)
    animation_chart.axisY().setTickCount(3)
    animation_chart.axisX().setLabelsColor(QtGui.QColor("white"))
    animation_chart.axisX().setGridLineColor(QtGui.QColor("grey"))
    animation_chart.axisX().setRange(-4, 12)
    animation_chart.axisY().setRange(-1, 1)
    animation_chart.axisY().setLabelsColor(QtGui.QColor("white"))
    animation_chart.axisY().setGridLineColor(QtGui.QColor("grey"))
    form.widget_animation.setChart(animation_chart)
示例#5
0
class DemoWindow(QMainWindow):
    def __init__(self, parent=None):
        super(DemoWindow, self).__init__(parent=parent)

        self.plotChart = QChart()
        self.plotChart.legend().hide()

        self.plotView = QChartView(self.plotChart)
        self.setCentralWidget(self.plotView)

        self.plotCurve = QLineSeries()
        self.plotCurve.setUseOpenGL(True)
        self.plotCurve.pen().setColor(Qt.red)
        self.plotChart.addSeries(self.plotCurve)

        self.plotChart.createDefaultAxes()
        self.plotChart.axisX().setLabelFormat('%d')

        self.RecvData = array.array('f')  # 存储接收到的传感器数据
        self.RecvIndx = 0

        self.tmrData = QTimer()  # 模拟传感器传送过来数据
        self.tmrData.setInterval(3)
        self.tmrData.timeout.connect(self.on_tmrData_timeout)
        self.tmrData.start()

        self.tmrPlot = QTimer()
        self.tmrPlot.setInterval(100)
        self.tmrPlot.timeout.connect(self.on_tmrPlot_timeout)
        self.tmrPlot.start()

    def on_tmrData_timeout(self):
        val = math.sin(2 * 3.14 / 500 * self.RecvIndx)
        self.RecvData.append(val)

        self.RecvIndx += 1

    def on_tmrPlot_timeout(self):
        self.RecvData = self.RecvData[-1000:]

        plotData = []
        for i, val in enumerate(self.RecvData):
            plotData.append(QPointF(i, val))

        self.plotCurve.replace(plotData)
        self.plotChart.axisX().setMax(len(plotData))
        self.plotChart.axisY().setRange(min(self.RecvData), max(self.RecvData))
示例#6
0
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.resize(400, 300)
        # 抗锯齿
        self.setRenderHint(QPainter.Antialiasing)

        # 图表
        chart = QChart()
        self.setChart(chart)
        # 设置标题
        chart.setTitle('Simple areachart example')
        # 添加Series
        chart.addSeries(self.getSeries())
        # 创建默认轴线
        chart.createDefaultAxes()
        # 设置xy轴的范围
        chart.axisX().setRange(0, 20)
        chart.axisY().setRange(0, 10)
示例#7
0
class VLineChartView(QChartView):
    def __init__(self):
        super(VLineChartView, self).__init__()
        self.stocks = read_tick_data()
        self.category = [
            trade_date[4:] for trade_date in self.stocks['trade_date']
        ]
        self.resize(800, 300)
        self.initChart()

    def initChart(self):
        self._chart = QChart(title='数量')
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        series = QStackedBarSeries()
        series.setName('数量')
        bar_red = QBarSet('red')
        bar_red.setColor(Qt.red)
        bar_green = QBarSet('green')
        bar_green.setColor(Qt.green)
        for _, stock in self.stocks.iterrows():
            if stock['open'] < stock['close']:
                bar_red.append(stock['vol'] / 100)
                bar_green.append(0)
            else:
                bar_red.append(0)
                bar_green.append(stock['vol'] / 100)

        series.append(bar_red)
        series.append(bar_green)
        self._chart.addSeries(series)
        self._chart.createDefaultAxes()
        self._chart.setLocalizeNumbers(True)
        axis_x = self._chart.axisX()
        axis_y = self._chart.axisY()
        axis_x.setGridLineVisible(False)
        axis_y.setGridLineVisible(False)
        axis_y.setLabelFormat("%.2f")
        axis_x.setCategories(self.category)
        max_p = self.stocks[[
            'vol',
        ]].stack().max() / 100 + 10
        min_p = self.stocks[[
            'vol',
        ]].stack().min() / 100 - 10
        axis_y.setRange(min_p, max_p)

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

        self.setChart(self._chart)
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # self._chart.setMargins(QMargins(0, 0, 0, 0))
        self._chart.setBackgroundRoundness(0)
示例#8
0
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))
示例#9
0
    def setupUi(self, Form):
        Form.resize(800, 600)
        Form.setWindowTitle("Analytics")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("assets/FaceAttend2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        Form.setWindowIcon(icon)
        self.Calculate()
        low = QBarSet("Short")
        high = QBarSet("Clear")
        soshort = QBarSet("So Short")

        low << self.Low[0] << self.Low[1] << self.Low[2] << self.Low[3] << self.Low[4] << self.Low[5] << self.Low[6]
        soshort << self.SoShort[0] << self.SoShort[1] << self.SoShort[2] << self.SoShort[3] << self.SoShort[4] << self.SoShort[5] << self.SoShort[6]
        # high <<40 << -50 << -45.3 << -37.0 << -25.6 << -8.0 << -6.0
        high << self.High[0] << self.High[1] << self.High[2] << self.High[3] << self.High[4] << self.High[5] << self.High[6]

        series = QStackedBarSeries()
        series.append(low)
        series.append(high)
        series.append(soshort)

        chart = QChart()
        chart.addSeries(series)
        chart.setTitle("Attendance Graph")
        chart.setAnimationOptions(QChart.SeriesAnimations)

        categories = [self.Subjects[0],self.Subjects[1],self.Subjects[2],self.Subjects[3],self.Subjects[4],self.Subjects[5],self.Subjects[6]]

        axis = QBarCategoryAxis()
        axis.append(categories)
        axis.setTitleText("Month")
        chart.createDefaultAxes()
        chart.setAxisX(axis, series)
        chart.axisY(series).setRange(0, 100)
        chart.axisY(series).setTitleText("Percentage (%)")

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

        chartView = QChartView(chart)
        Form.setCentralWidget(chartView)
示例#10
0
class ErrorLineChart(QFrame):
    def __init__(self, nseries=1, series_names=None):
        super().__init__()
        if nseries < 1:
            raise ValueError(
                'The number of serieses must be larger than zero.')
        self.nseries = nseries
        self.series_names = series_names
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)
        self.setMinimumHeight(110)
        self.setMinimumWidth(400)

        self.serieses = [QLineSeries() for _ in range(self.nseries)]
        self.chart = QChart()
        if self.series_names is None:
            self.chart.legend().hide()
        for idx, series in enumerate(self.serieses):
            self.chart.addSeries(series)
            if self.series_names is not None:
                series.setName(self.series_names[idx])
        self.chart.createDefaultAxes()
        self.chart.layout().setContentsMargins(0, 0, 0, 0)
        # self.chart.setTheme(QChart.ChartThemeDark)
        self.chart.axisY().setTickCount(3)
        chart_view = QChartView(self.chart)
        chart_view.setRenderHint(QPainter.Antialiasing)
        layout.addWidget(chart_view)

        self.x_max = 2
        self.y_pts = list()

    def append_point(self, x, y, series_idx=0):
        self.serieses[series_idx].append(x, y)
        self.x_max = max(x, self.x_max)
        self.y_pts.append(y)
        if self.x_max > 100:
            self.chart.axisX().setRange(self.x_max - 100, self.x_max)
            y_max = max(self.y_pts[-100:])
            self.serieses[series_idx].remove(self.x_max - 100,
                                             self.y_pts[self.x_max - 101])
        else:
            self.chart.axisX().setRange(1, self.x_max)
            y_max = max(self.y_pts)
        self.chart.axisY().setRange(0, y_max + y_max / 5)

    def clear(self):
        self.chart.removeAllSeries()
        self.serieses = [QLineSeries() for _ in range(self.nseries)]
        for idx, series in enumerate(self.serieses):
            self.chart.addSeries(series)
            if self.series_names is not None:
                series.setName(self.series_names[idx])
        self.chart.createDefaultAxes()
        self.chart.axisY().setTickCount(3)
        self.x_max = 2
        self.y_pts = list()
示例#11
0
    def setupUi(self, Form):
        Form.resize(800, 600)

        color = QColor("red")
        low = QBarSet("Short")
        high = QBarSet("Clear")

        low << 40.0 << 75.0 << 45.3 << 37.0 << 25.6 << 8.0 << 6.0
        # high << value[0] << value[1] << value[2] << value[3] << value[4] << value[5] << value[6]
        # high <<40 << -50 << -45.3 << -37.0 << -25.6 << -8.0 << -6.0
        high << self.percentage[0] << self.percentage[1] << self.percentage[2] << self.percentage[3] << self.percentage[4] << self.percentage[5] << self.percentage[6]

        series = QStackedBarSeries()
        series.append(low)
        series.append(high)

        chart = QChart()
        chart.addSeries(series)
        chart.setTitle("Attendance Graph")
        chart.setAnimationOptions(QChart.SeriesAnimations)

        categories = [self.Subjects[0],self.Subjects[1],self.Subjects[2],self.Subjects[3],self.Subjects[4],self.Subjects[5],self.Subjects[6]]

        axis = QBarCategoryAxis()
        axis.append(categories)
        axis.setTitleText("Month")
        chart.createDefaultAxes()
        chart.setAxisX(axis, series)
        chart.axisY(series).setRange(0, 100)
        chart.axisY(series).setTitleText("Percentage (%)")

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

        chartView = QChartView(chart)
        Form.setCentralWidget(chartView)
示例#12
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)
示例#13
0
class KLineChartView(QChartView):
    def __init__(self):
        super(KLineChartView, self).__init__()
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self._chart = QChart(title='蜡烛图悬浮提示')
        self.stocks = read_tick_data()
        self.category = [
            trade_date[4:] for trade_date in self.stocks['trade_date']
        ]
        self._count = len(self.category)
        self.resize(800, 300)

        self.init_chart()

        self.toolTipWidget = GraphicsProxyWidget(self._chart)

        # 鼠标跟踪的十字线
        self.lineItem_h = QGraphicsLineItem(self._chart)
        self.lineItem_v = QGraphicsLineItem(self._chart)
        pen = QPen()
        pen.setStyle(Qt.DotLine)
        pen.setColor(QColor(Qt.gray))
        pen.setWidth(2)
        self.lineItem_h.setPen(pen)
        self.lineItem_v.setPen(pen)
        self.lineItem_h.setZValue(100)
        self.lineItem_v.setZValue(100)
        self.lineItem_h.hide()
        self.lineItem_v.hide()

        # 坐标轴上最大最小的值
        # x 轴是
        self.min_x, self.max_x = 0, len(self._chart.axisX().categories())
        self.min_y, self.max_y = self._chart.axisY().min(), self._chart.axisY(
        ).max()
        # y 轴最高点坐标
        self.point_y_max = self._chart.mapToPosition(
            QPointF(self.min_x, self.max_y))
        # x 轴最高点坐标
        self.point_x_max = self._chart.mapToPosition(
            QPointF(self.max_x, self.min_y))
        # self.point_x_min = self._chart.mapToPosition(QPointF(self.min_x, self.min_y))

        # 计算x轴单个cate的宽度,用来处理横线不能画到边界
        self.x_width = (self.point_x_max.x() - self.point_y_max.x()) / len(
            self.category)
        self.x_x_min = self.point_y_max.x() - self.x_width / 2
        self.x_x_max = self.point_x_max.x() - self.x_width / 2

        # 中间位置,用来判断TipWidget放在哪里
        mid_date = self.stocks['trade_date'].iloc[len(
            self.stocks['trade_date']) // 2]
        self.mid_x = float(
            time.mktime(
                datetime.datetime.strptime(str(mid_date),
                                           '%Y%m%d').timetuple()))
        self.left_pos = self.point_y_max
        self.right_pos = self._chart.mapToPosition(
            QPointF(self.max_x, self.max_y))

    def mouseMoveEvent(self, event):
        super(KLineChartView, self).mouseMoveEvent(event)
        pos = event.pos()
        if self.x_x_min < pos.x() < self.x_x_max \
                and self.point_x_max.y() > pos.y() > self.point_y_max.y():
            self.lineItem_h.setLine(self.x_x_min, pos.y(), self.x_x_max,
                                    pos.y())
            self.lineItem_v.setLine(pos.x(), self.point_y_max.y(), pos.x(),
                                    self.point_x_max.y())
            self.lineItem_h.show()
            self.lineItem_v.show()
        else:
            self.lineItem_h.hide()
            self.lineItem_v.hide()

    def resizeEvent(self, event):
        super(KLineChartView, self).resizeEvent(event)
        # y 轴最高点坐标
        self.point_y_max = self._chart.mapToPosition(
            QPointF(self.min_x, self.max_y))
        # x 轴最高点坐标
        self.point_x_max = self._chart.mapToPosition(
            QPointF(self.max_x, self.min_y))
        # 计算x轴单个cate的宽度,用来处理横线不能画到边界
        self.x_width = (self.point_x_max.x() - self.point_y_max.x()) / len(
            self.category)
        self.x_x_min = self.point_y_max.x() - self.x_width / 2
        self.x_x_max = self.point_x_max.x() - self.x_width / 2
        self.left_pos = self.point_y_max
        self.right_pos = self._chart.mapToPosition(
            QPointF(self.max_x, self.max_y))

    def init_chart(self):
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        series = QCandlestickSeries()
        series.setIncreasingColor(QColor(Qt.red))
        series.setDecreasingColor(QColor(Qt.green))
        series.setName(self.stocks['name'].iloc[0])
        for _, stock in self.stocks.iterrows():
            time_p = datetime.datetime.strptime(stock['trade_date'], '%Y%m%d')
            time_p = float(time.mktime(time_p.timetuple()))
            _set = QCandlestickSet(float(stock['open']), float(stock['high']),
                                   float(stock['low']), float(stock['close']),
                                   time_p, series)
            _set.hovered.connect(self.handleBarHoverd)  # 鼠标悬停
            series.append(_set)
        self._chart.addSeries(series)

        self._chart.createDefaultAxes()
        self._chart.setLocalizeNumbers(True)
        axis_x = self._chart.axisX()
        axis_y = self._chart.axisY()
        axis_x.setGridLineVisible(False)
        axis_y.setGridLineVisible(False)
        axis_x.setCategories(self.category)
        max_p = self.stocks[['high', 'low']].stack().max() + 10
        min_p = self.stocks[['high', 'low']].stack().min() - 10
        axis_y.setRange(min_p, max_p)

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

        self.setChart(self._chart)
        # 设置外边界全部为0
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # 设置内边界都为0
        # self._chart.setMargins(QMargins(0, 0, 0, 0))
        # 设置背景区域无圆角
        self._chart.setBackgroundRoundness(0)

    def handleBarHoverd(self, status):
        """ 改变画笔的风格 """
        bar = self.sender()  # 信号发送者
        pen = bar.pen()
        if not pen:
            return
        pen.setStyle(Qt.DotLine if status else Qt.SolidLine)
        bar.setPen(pen)
        if status:
            # 通过 bar 可以获取横轴坐标(timestamp)和纵轴坐标(high)
            # 然后将坐标值转换为位置,显示 TipWidget 的位置
            right_pos = QPointF(
                self.right_pos.x() - self.toolTipWidget.width() - self.x_width,
                self.right_pos.y())
            pos = self.left_pos if bar.timestamp() > self.mid_x else right_pos
            trade_date = time.strftime('%Y%m%d',
                                       time.localtime(bar.timestamp()))
            self.toolTipWidget.show(str(trade_date), str(bar.open()),
                                    str(bar.close()), str(bar.high()),
                                    str(bar.low()), pos)
        else:
            self.toolTipWidget.hide()
示例#14
0
    sys.exit(1)

dataReader.setDevice(boxwhiskData)
while not dataReader.atEnd():
    box = dataReader.readBox()
    if box is not None:
        boxWhiskSeries.append(box)

chart = QChart()
chart.addSeries(acmeSeries)
chart.addSeries(boxWhiskSeries)
chart.setTitle("Acme Ltd and BoxWhisk Inc share deviation in 2012")
chart.setAnimationOptions(QChart.SeriesAnimations)

chart.createDefaultAxes()
chart.axisY().setMin(15.0)
chart.axisY().setMax(34.0)

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

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

window = QMainWindow()
window.setCentralWidget(chartView)
window.resize(800, 600)
window.show()

sys.exit(app.exec_())
示例#15
0
class Simulator(QtWidgets.QMainWindow, gui.Ui_MainWindow):
    def __init__(self):
        super().__init__()

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

        self.__translator = QTranslator(self)

        self.setupUi(self)

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

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

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

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

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

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

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

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

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

        self.populateFields()

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

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

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

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

        self.populateFields()

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

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

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

        xax = self.positionChart.axisX()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        lapMessage = car.canMsg(StdId=32, Data=[lapData])
        print(lapMessage)
        
        if (self.__canbus is not None and self.__canbus.connected == True):
            self.__canbus.sendMsg(lapMessage)
示例#16
0
class QtAgentGraph(QChartView):
    def __init__(self, spec):
        super().__init__(None)
        self.spec = spec
        self.chart = QChart()
        self.chart.setTitle(str(self.spec.variable))
        self.chart.legend().hide()

        self.setMinimumWidth(400)
        self.setMinimumHeight(230)

        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)
        self.chart.createDefaultAxes()
        self.autoscale_y_axis = True
        if self.spec.min_y and self.spec.max_y:
            self.autoscale_y_axis = False
            self.chart.axes()[1].setRange(self.spec.min_y, self.spec.max_y)

        self.axis_x = QValueAxis()
        self.axis_y = QValueAxis()
        self.chart.addAxis(self.axis_x, Qt.AlignBottom)
        self.chart.addAxis(self.axis_y, Qt.AlignLeft)

        self._updates_per_second = 60
        self._data = []
        self._min = 0
        self._max = 0

    def clear(self):
        for chart in self.chart.series():
            chart.clear()
        self._data = []

    def update_data(self):
        for a in self.spec.agents:
            if not hasattr(a, "_agent_series"):
                a._agent_series = QLineSeries()
                a._agent_series.setColor(
                    QColor(a.color[0], a.color[1], a.color[2]))
                a._agent_series_data = [getattr(a, self.spec.variable)]
                self.chart.addSeries(a._agent_series)
                a._agent_series.attachAxis(self.chart.axisX())
                a._agent_series.attachAxis(self.chart.axisY())
            else:
                a._agent_series_data.append(getattr(a, self.spec.variable))

    def redraw(self):
        for a in self.spec.agents:
            if hasattr(a, "_agent_series") and len(a._agent_series_data) > 0:
                datapoint = sum(a._agent_series_data) / len(
                    a._agent_series_data)
                a._agent_series.append(
                    QPointF(
                        a._agent_series.count() / self._updates_per_second,
                        datapoint,
                    ))
                self._min = min(self._min, datapoint)
                self._max = max(self._max, datapoint)
                a._agent_series.setColor(
                    QColor(a.color[0], a.color[1], a.color[2]))
            a._agent_series_data = []
        if len(self.spec.agents) > 0:
            first_agent = self.spec.agents[0]
            if hasattr(first_agent, "_agent_series"):
                first_series = first_agent._agent_series
                self.chart.axes()[0].setRange(0, (first_series.count() - 1) /
                                              self._updates_per_second)
                diff = self._max - self._min
                if self.autoscale_y_axis:
                    if diff > 0:
                        self.chart.axes()[1].setRange(self._min, self._max)
                    else:
                        self.chart.axes()[1].setRange(self._min - 0.5,
                                                      self._max + 0.5)
示例#17
0
class VLineChartView(QChartView):

    bar_hovered = pyqtSignal(bool, str)

    def __init__(self, data: pd.DataFrame):
        super(VLineChartView, self).__init__()
        self._stocks = data
        self._category = self._stocks['trade_date']
        self._chart = QChart()
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        self._series = QStackedBarSeries()
        # 成交量以万股为单位
        self._vol_multiple = 10000
        self.init_chart()
        self._zero_value = (0, self._chart.axisY().min())
        self._max_value = (len(self._chart.axisX().categories()),
                           self._chart.axisY().max())
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        # 计算x轴单个cate的宽度,用来处理横线不能画到边界
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)
        self._series.hovered.connect(self.on_series_hovered)

        x_index_list = np.percentile(range(len(self._category)),
                                     [0, 25, 50, 75, 100])
        self._x_axis_list = [
            QGraphicsSimpleTextItem(self._category[int(index)], self._chart)
            for index in x_index_list
        ]
        [axis.setText(axis.text()[4:]) for axis in self._x_axis_list[1:]]
        self._v_b = QGraphicsSimpleTextItem('B', self._chart)
        self._v_b.setZValue(100)

    def on_series_hovered(self, status, index):
        self.bar_hovered.emit(status, self._category[index])

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

    def add_series_values(self, data: pd.DataFrame, is_init=False):
        self._stocks = data
        bar_red = QBarSet('red')
        bar_red.setColor(Qt.red)
        bar_green = QBarSet('green')
        bar_green.setColor(Qt.green)
        for _, stock in self._stocks.iterrows():
            if stock['open'] < stock['close']:
                bar_red.append(stock['vol'] / self._vol_multiple)
                bar_green.append(0)
            else:
                bar_red.append(0)
                bar_green.append(stock['vol'] / self._vol_multiple)

        self._series.append(bar_red)
        self._series.append(bar_green)

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

    def resizeEvent(self, event):
        super(VLineChartView, self).resizeEvent(event)
        self._zero_point = self._chart.mapToPosition(
            QPointF(self._zero_value[0], self._zero_value[1]))
        self._max_point = self._chart.mapToPosition(
            QPointF(self._max_value[0], self._max_value[1]))
        self._cate_width = (self._max_point.x() - self._zero_point.x()) / len(
            self._category)
        # 绘制自定义X轴
        self._x_axis_list[0].setPos(self._zero_point.x() - self._cate_width,
                                    self._zero_point.y() + 10)
        self._x_axis_list[1].setPos(self._max_point.x() * 0.25,
                                    self._zero_point.y() + 10)
        self._x_axis_list[2].setPos(self._max_point.x() * 0.5,
                                    self._zero_point.y() + 10)
        self._x_axis_list[3].setPos(self._max_point.x() * 0.75,
                                    self._zero_point.y() + 10)
        self._x_axis_list[4].setPos(
            self._max_point.x() - self._x_axis_list[-1].boundingRect().width(),
            self._zero_point.y() + 10)
        # 20180207 这个日期的柱形图上面画一个字母b
        vol = self._stocks[self._stocks['trade_date'] ==
                           '20180207']['vol'] / self._vol_multiple
        print('vol:', vol, ' trade_date:', '20180207')
        pos = self._chart.mapToPosition(
            QPointF(list(self._category).index('20180207'), vol))
        pos = QPointF(pos.x() - self._cate_width / 2,
                      pos.y() - self._v_b.boundingRect().height())
        self._v_b.setPos(pos)

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

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

    def init_chart(self):
        self.add_series_values(self._stocks, True)
        self._chart.addSeries(self._series)
        self._chart.createDefaultAxes()
        self._chart.setLocalizeNumbers(True)
        axis_x = self._chart.axisX()
        axis_y = self._chart.axisY()
        axis_x.setGridLineVisible(False)
        axis_y.setGridLineVisible(False)
        axis_y.setLabelFormat("%.2f")
        axis_x.setCategories(self._category)
        axis_x.setLabelsVisible(False)
        max_p = self._stocks[[
            'vol',
        ]].stack().max()
        min_p = self._stocks[[
            'vol',
        ]].stack().min()
        axis_y.setRange(min_p / self._vol_multiple * 0.9,
                        max_p / self._vol_multiple * 1.1)

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

        self.setChart(self._chart)
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # 设置内边界的bottom为0
        # margins = self._chart.margins()
        # self._chart.setMargins(QMargins(margins.left(), 0, margins.right(), 0))
        self._chart.setBackgroundRoundness(0)
示例#18
0
class ChartView(QChartView):

    def __init__(self, *args, **kwargs):
        super(ChartView, self).__init__(*args, **kwargs)
        self.resize(800, 600)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        self.initChart()

        self.toolTipWidget = GraphicsProxyWidget(self._chart)

        # line
        self.lineItem = QGraphicsLineItem(self._chart)
        self.lineItem.setZValue(998)
        self.lineItem.hide()
        
        # 一些固定计算,减少mouseMoveEvent中的计算量
        # 获取x和y轴的最小最大值
        axisX, axisY = self._chart.axisX(), self._chart.axisY()
        self.min_x, self.max_x = axisX.min(), axisX.max()
        self.min_y, self.max_y = axisY.min(), axisY.max()
        # 坐标系中左上角顶点
        self.point_top = self._chart.mapToPosition(QPointF(self.min_x, self.max_y))
        # 坐标原点坐标
        self.point_bottom = self._chart.mapToPosition(QPointF(self.min_x, self.min_y))
        self.step_x = (self.max_x - self.min_x) / (axisX.tickCount() - 1)
#         self.step_y = (self.max_y - self.min_y) / (axisY.tickCount() - 1)

    def mouseMoveEvent(self, event):
        super(ChartView, self).mouseMoveEvent(event)
        # 把鼠标位置所在点转换为对应的xy值
        x = self._chart.mapToValue(event.pos()).x()
        y = self._chart.mapToValue(event.pos()).y()
        index = round((x - self.min_x) / self.step_x)
        pos_x = self._chart.mapToPosition(
            QPointF(index * self.step_x + self.min_x, self.min_y))
#         print(x, pos_x, index, index * self.step_x + self.min_x)
        # 得到在坐标系中的所有series的类型和点
        points = [(serie, serie.at(index))
                  for serie in self._chart.series() if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y]
        if points:
            # 永远在轴上的黑线条
            self.lineItem.setLine(pos_x.x(), self.point_top.y(),
                                  pos_x.x(), self.point_bottom.y())
            self.lineItem.show()
            self.toolTipWidget.show("", points, event.pos() + QPoint(20, 20))
        else:
            self.toolTipWidget.hide()
            self.lineItem.hide()

    def onSeriesHoverd(self, point, state):
        if state:
            try:
                name = self.sender().name()
            except:
                name = ""
            QToolTip.showText(QCursor.pos(), "%s\nx: %s\ny: %s" % 
                              (name, point.x(), point.y()))

    def initChart(self):
        self._chart = QChart(title="Line Chart")
        self._chart.setAcceptHoverEvents(True)
        dataTable = [
            [120, 132, 101, 134, 90, 230, 210],
            [220, 182, 191, 234, 290, 330, 310],
            [150, 232, 201, 154, 190, 330, 410],
            [320, 332, 301, 334, 390, 330, 320],
            [820, 932, 901, 934, 1290, 1330, 1320]
        ]
        for i, data_list in enumerate(dataTable):
            series = QLineSeries(self._chart)
            for j, v in enumerate(data_list):
                series.append(j, v)
            series.setName("Series " + str(i))
            series.setPointsVisible(True)  # 显示原点
            series.hovered.connect(self.onSeriesHoverd)
            self._chart.addSeries(series)
        self._chart.createDefaultAxes()  # 创建默认的轴
        self._chart.axisX().setTickCount(7)  # x轴设置7个刻度
        self._chart.axisY().setTickCount(7)  # y轴设置7个刻度
        self._chart.axisY().setRange(0, 1500)  # 设置y轴范围
        self.setChart(self._chart)
示例#19
0
class ChartView(QChartView):
    def __init__(self, file, parent=None):
        super(ChartView, self).__init__(parent)
        self._chart = QChart()
        self._chart.setAcceptHoverEvents(True)
        self.setChart(self._chart)
        self.initUi(file)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def __analysis(self, datas):
        '''
        analysis json data
        :param datas: json data
        '''
        # 标题
        self.__setTitle(datas.get("title", None))
        # 抗锯齿
        if (datas.get("antialiasing", False) or False):
            self.setRenderHint(QPainter.Antialiasing)
        # 主题
        self._chart.setTheme(datas.get("theme", 0) or 0)
        # 动画
        self.__setAnimation(datas.get("animation", None))
        # 背景设置
        self.__setBackground(datas.get("background", None))
        # 边距设置
        self.__setMargins(datas.get("margins", None))
        # 设置图例
        self.__setLegend(datas.get("legend", None))
        # 设置series
        self.__setSeries(datas.get("series", None))
        # 自定义的x轴
        self.__setAxisX(datas.get("axisx", None))
示例#20
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """
    Main application window
    """
    WIDTH = 150
    HEIGHT = 50
    MARGIN = 5
    max_ping = 0
    max_loss = 0

    def __init__(self, host, history, history_size, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.host = host
        self.history = history
        self.history_size = history_size
        self.setupUi(self)
        self.setWindowFlag(Qt.WindowStaysOnTopHint)
        self.position_to_dock()
        self.series_delay = QLineSeries()
        self.series_loss = QLineSeries()
        self.axis_X = QDateTimeAxis()  # pylint: disable=invalid-name
        self.axis_X.setTickCount(3)
        self.axis_X.setFormat("HH:mm")
        self.axis_X.setTitleText("Time")
        self.chart = QChart()
        self.chart.addSeries(self.series_delay)
        self.chart.addSeries(self.series_loss)
        self.chart.setTitle(f"Connection to {self.host}")
        self.init_series(self.series_delay, "Delay ms")
        self.init_series(self.series_loss, "Loss %")
        self.chart.legend().setVisible(False)
        self.chart.legend().setAlignment(Qt.AlignBottom)
        self.chart.layout().setContentsMargins(0, 0, 0, 0)
        self.chart.setBackgroundRoundness(0)
        self.chart.setMargins(QMargins(0, 0, 0, 0))
        self.chartWidget.setChart(self.chart)
        self.chartWidget.setRenderHint(QPainter.Antialiasing)

    def init_series(self, series, label):
        """
        Series settings
        """
        self.chart.setAxisX(self.axis_X, series)
        axis_Y = QValueAxis()  # pylint: disable=invalid-name
        axis_Y.setLabelFormat("%i")
        axis_Y.setTitleText(label)
        axis_Y.setRange(0, 100)
        self.chart.addAxis(axis_Y, Qt.AlignLeft)
        self.chart.setAxisY(axis_Y, series)

    def add_series(self, ping, loss):
        """
        Append series data
        """
        self.max_ping = max(ping or 0, self.max_ping)
        self.max_loss = max(loss, self.max_loss)
        if self.series_delay.count() > self.history_size:
            self.series_delay.remove(0)
        self.series_delay.append(
            QDateTime.currentDateTime().toMSecsSinceEpoch(), ping or 0)
        if self.series_loss.count() > self.history_size:
            self.series_loss.remove(0)
        self.series_loss.append(
            QDateTime.currentDateTime().toMSecsSinceEpoch(), loss)
        self.axis_X.setRange(
            QDateTime.currentDateTime().addSecs(-self.history),
            QDateTime.currentDateTime())
        self.chart.axisY().setRange(0, self.max_ping + self.MARGIN)

    def position_to_dock(self):
        """
        Adjust main window position according to it's size and desktop
        """
        desktop_geometry = QDesktopWidget().availableGeometry()
        self.setGeometry(
            desktop_geometry.width() - self.width() - self.MARGIN,
            desktop_geometry.height() - self.height() - self.MARGIN,
            self.width(), self.height())

    def set_labels(self, mean_=None, curr=None, loss=None):
        """
        Update window text
        """
        mean_text = curr_text = loss_text = "No connection"
        if mean_ is not None:
            mean_text = f"Mean ping: {mean_}ms"
        if curr is not None:
            curr_text = f"Last ping: {curr}ms"
        if loss is not None:
            loss_text = f"Ping loss: {loss}%"
        self.meanLabel.setText(mean_text)
        self.currLabel.setText(curr_text)
        self.lossLabel.setText(loss_text)

    def toggle(self, reason):
        """
        Toggle window visibility
        """
        if reason == QSystemTrayIcon.ActivationReason.DoubleClick:  # pylint: disable=no-member
            self.setVisible(not self.isVisible())
            if self.isVisible():
                self.activateWindow()
示例#21
0
class RTTView(QWidget):
    def __init__(self, parent=None):
        super(RTTView, self).__init__(parent)

        uic.loadUi('RTTView.ui', self)

        self.initSetting()

        self.initQwtPlot()

        self.rcvbuff = b''

        self.tmrRTT = QtCore.QTimer()
        self.tmrRTT.setInterval(10)
        self.tmrRTT.timeout.connect(self.on_tmrRTT_timeout)
        self.tmrRTT.start()

        self.tmrRTT_Cnt = 0

    def initSetting(self):
        if not os.path.exists('setting.ini'):
            open('setting.ini', 'w', encoding='utf-8')

        self.conf = configparser.ConfigParser()
        self.conf.read('setting.ini', encoding='utf-8')

        if not self.conf.has_section('J-Link'):
            self.conf.add_section('J-Link')
            self.conf.set('J-Link', 'dllpath', '')
            self.conf.set('J-Link', 'mcucore', 'Cortex-M0')
            self.conf.add_section('Memory')
            self.conf.set('Memory', 'rttaddr', '0x20000000')

        self.linDLL.setText(self.conf.get('J-Link', 'dllpath'))
        self.linRTT.setText(self.conf.get('Memory', 'rttaddr'))
        self.cmbCore.setCurrentIndex(
            self.cmbCore.findText(self.conf.get('J-Link', 'mcucore')))

    def initQwtPlot(self):
        self.PlotData = [[0] * 1000 for i in range(N_CURVES)]
        self.PlotPoint = [[QtCore.QPointF(j, 0) for j in range(1000)]
                          for i in range(N_CURVES)]

        self.PlotChart = QChart()

        self.ChartView = QChartView(self.PlotChart)
        self.ChartView.setVisible(False)
        self.vLayout.insertWidget(0, self.ChartView)

        self.PlotCurve = [QLineSeries() for i in range(N_CURVES)]

    @pyqtSlot()
    def on_btnOpen_clicked(self):
        if self.btnOpen.text() == '打开连接':
            try:
                self.jlink = ctypes.cdll.LoadLibrary(self.linDLL.text())

                err_buf = (ctypes.c_char * 64)()
                self.jlink.JLINKARM_ExecCommand(
                    f'Device = {self.cmbCore.currentText()}'.encode('latin-1'),
                    err_buf, 64)

                self.jlink.JLINKARM_TIF_Select(1)
                self.jlink.JLINKARM_SetSpeed(4000)

                buff = ctypes.create_string_buffer(1024)
                Addr = int(self.linRTT.text(), 16)
                for i in range(128):
                    self.jlink.JLINKARM_ReadMem(Addr + 1024 * i, 1024, buff)
                    index = buff.raw.find(b'SEGGER RTT')
                    if index != -1:
                        self.RTTAddr = Addr + 1024 * i + index

                        buff = ctypes.create_string_buffer(
                            ctypes.sizeof(SEGGER_RTT_CB))
                        self.jlink.JLINKARM_ReadMem(
                            self.RTTAddr, ctypes.sizeof(SEGGER_RTT_CB), buff)

                        rtt_cb = SEGGER_RTT_CB.from_buffer(buff)
                        self.aUpAddr = self.RTTAddr + 16 + 4 + 4
                        self.aDownAddr = self.aUpAddr + ctypes.sizeof(
                            RingBuffer) * rtt_cb.MaxNumUpBuffers

                        self.txtMain.append(
                            f'\n_SEGGER_RTT @ 0x{self.RTTAddr:08X} with {rtt_cb.MaxNumUpBuffers} aUp and {rtt_cb.MaxNumDownBuffers} aDown\n'
                        )
                        break
                else:
                    raise Exception('Can not find _SEGGER_RTT')
            except Exception as e:
                self.txtMain.append(f'\n{str(e)}\n')
            else:
                self.linDLL.setEnabled(False)
                self.btnDLL.setEnabled(False)
                self.linRTT.setEnabled(False)
                self.cmbCore.setEnabled(False)
                self.btnOpen.setText('关闭连接')
        else:
            self.linDLL.setEnabled(True)
            self.btnDLL.setEnabled(True)
            self.linRTT.setEnabled(True)
            self.cmbCore.setEnabled(True)
            self.btnOpen.setText('打开连接')

    def aUpRead(self):
        buf = ctypes.create_string_buffer(ctypes.sizeof(RingBuffer))
        self.jlink.JLINKARM_ReadMem(self.aUpAddr, ctypes.sizeof(RingBuffer),
                                    buf)

        aUp = RingBuffer.from_buffer(buf)

        if aUp.RdOff == aUp.WrOff:
            str = ctypes.create_string_buffer(0)

        elif aUp.RdOff < aUp.WrOff:
            cnt = aUp.WrOff - aUp.RdOff
            str = ctypes.create_string_buffer(cnt)
            self.jlink.JLINKARM_ReadMem(
                ctypes.cast(aUp.pBuffer, ctypes.c_void_p).value + aUp.RdOff,
                cnt, str)

            aUp.RdOff += cnt

            self.jlink.JLINKARM_WriteU32(self.aUpAddr + 4 * 4, aUp.RdOff)

        else:
            cnt = aUp.SizeOfBuffer - aUp.RdOff
            str = ctypes.create_string_buffer(cnt)
            self.jlink.JLINKARM_ReadMem(
                ctypes.cast(aUp.pBuffer, ctypes.c_void_p).value + aUp.RdOff,
                cnt, str)

            aUp.RdOff = 0  #这样下次再读就会进入执行上个条件

            self.jlink.JLINKARM_WriteU32(self.aUpAddr + 4 * 4, aUp.RdOff)

        return str.raw

    def on_tmrRTT_timeout(self):
        if self.btnOpen.text() == '关闭连接':
            try:
                self.rcvbuff += self.aUpRead()

                if self.txtMain.isVisible():
                    if self.chkHEXShow.isChecked():
                        text = ''.join(f'{x:02X} ' for x in self.rcvbuff)

                    else:
                        text = self.rcvbuff.decode('latin')

                    if len(self.txtMain.toPlainText()) > 25000:
                        self.txtMain.clear()
                    self.txtMain.moveCursor(QtGui.QTextCursor.End)
                    self.txtMain.insertPlainText(text)

                    self.rcvbuff = b''

                else:
                    if self.rcvbuff.rfind(b',') == -1: return

                    d = self.rcvbuff[0:self.rcvbuff.rfind(b',')].split(
                        b',')  # [b'12', b'34'] or [b'12 34', b'56 78']
                    d = [[float(x) for x in X.strip().split()]
                         for X in d]  # [[12], [34]]   or [[12, 34], [56, 78]]
                    for arr in d:
                        for i, x in enumerate(arr):
                            if i == N_CURVES: break

                            self.PlotData[i].pop(0)
                            self.PlotData[i].append(x)
                            self.PlotPoint[i].pop(0)
                            self.PlotPoint[i].append(QtCore.QPointF(999, x))

                    self.rcvbuff = self.rcvbuff[self.rcvbuff.rfind(b',') + 1:]

                    self.tmrRTT_Cnt += 1
                    if self.tmrRTT_Cnt % 4 == 0:
                        if len(d[-1]) != len(self.PlotChart.series()):
                            for series in self.PlotChart.series():
                                self.PlotChart.removeSeries(series)
                            for i in range(min(len(d[-1]), N_CURVES)):
                                self.PlotCurve[i].setName(f'Curve {i+1}')
                                self.PlotChart.addSeries(self.PlotCurve[i])
                            self.PlotChart.createDefaultAxes()

                        for i in range(len(self.PlotChart.series())):
                            for j, point in enumerate(self.PlotPoint[i]):
                                point.setX(j)

                            self.PlotCurve[i].replace(self.PlotPoint[i])

                        miny = min([
                            min(d) for d in
                            self.PlotData[:len(self.PlotChart.series())]
                        ])
                        maxy = max([
                            max(d) for d in
                            self.PlotData[:len(self.PlotChart.series())]
                        ])
                        self.PlotChart.axisY().setRange(miny, maxy)
                        self.PlotChart.axisX().setRange(0000, 1000)

            except Exception as e:
                self.rcvbuff = b''
                print(str(e))  # 波形显示模式下 txtMain 不可见,因此错误信息不能显示在其上

    def aDownWrite(self, bytes):
        buf = ctypes.create_string_buffer(ctypes.sizeof(RingBuffer))
        self.jlink.JLINKARM_ReadMem(self.aDownAddr, ctypes.sizeof(RingBuffer),
                                    buf)

        aDown = RingBuffer.from_buffer(buf)

        if aDown.WrOff >= aDown.RdOff:
            if aDown.RdOff != 0:
                cnt = min(aDown.SizeOfBuffer - aDown.WrOff, len(bytes))
            else:
                cnt = min(
                    aDown.SizeOfBuffer - 1 - aDown.WrOff,
                    len(bytes))  # 写入操作不能使得 aDown.WrOff == aDown.RdOff,以区分满和空
            str = ctypes.create_string_buffer(bytes[:cnt])
            self.jlink.JLINKARM_WriteMem(
                ctypes.cast(aDown.pBuffer, ctypes.c_void_p).value +
                aDown.WrOff, cnt, str)

            aDown.WrOff += cnt
            if aDown.WrOff == aDown.SizeOfBuffer: aDown.WrOff = 0

            bytes = bytes[cnt:]

        if bytes and aDown.RdOff != 0 and aDown.RdOff != 1:  # != 0 确保 aDown.WrOff 折返回 0,!= 1 确保有空间可写入
            cnt = min(aDown.RdOff - 1 - aDown.WrOff,
                      len(bytes))  # - 1 确保写入操作不导致WrOff与RdOff指向同一位置
            str = ctypes.create_string_buffer(bytes[:cnt])
            self.jlink.JLINKARM_WriteMem(
                ctypes.cast(aDown.pBuffer, ctypes.c_void_p).value +
                aDown.WrOff, cnt, str)

            aDown.WrOff += cnt

        self.jlink.JLINKARM_WriteU32(self.aDownAddr + 4 * 3, aDown.WrOff)

    @pyqtSlot()
    def on_btnSend_clicked(self):
        if self.btnOpen.text() == '关闭连接':
            text = self.txtSend.toPlainText()

            try:
                if self.chkHEXSend.isChecked():
                    text = ''.join([chr(int(x, 16)) for x in text.split()])

                self.aDownWrite(text.encode('latin'))

            except Exception as e:
                self.txtMain.append(f'\n{str(e)}\n')

    @pyqtSlot()
    def on_btnDLL_clicked(self):
        dllpath, filter = QFileDialog.getOpenFileName(
            caption='JLink_x64.dll路径',
            filter='动态链接库文件 (*.dll)',
            directory=self.linDLL.text())
        if dllpath != '':
            self.linDLL.setText(dllpath)

    @pyqtSlot(int)
    def on_chkWavShow_stateChanged(self, state):
        self.ChartView.setVisible(state == Qt.Checked)
        self.txtMain.setVisible(state == Qt.Unchecked)

    @pyqtSlot()
    def on_btnClear_clicked(self):
        self.txtMain.clear()

    def closeEvent(self, evt):
        self.conf.set('J-Link', 'dllpath', self.linDLL.text())
        self.conf.set('J-Link', 'mcucore', self.cmbCore.currentText())
        self.conf.set('Memory', 'rttaddr', self.linRTT.text())
        self.conf.write(open('setting.ini', 'w', encoding='utf-8'))
示例#22
0
class RTTView(QWidget):
    def __init__(self, parent=None):
        super(RTTView, self).__init__(parent)

        uic.loadUi('RTTView.ui', self)

        self.initSetting()

        self.initQwtPlot()

        self.rcvbuff = ''

        self.daplink = None

        self.tmrRTT = QtCore.QTimer()
        self.tmrRTT.setInterval(10)
        self.tmrRTT.timeout.connect(self.on_tmrRTT_timeout)
        self.tmrRTT.start()

        self.tmrRTT_Cnt = 0

    def initSetting(self):
        if not os.path.exists('setting.ini'):
            open('setting.ini', 'w', encoding='utf-8')

        self.conf = configparser.ConfigParser()
        self.conf.read('setting.ini', encoding='utf-8')

        if not self.conf.has_section('Memory'):
            self.conf.add_section('Memory')
            self.conf.set('Memory', 'StartAddr', '0x20000000')

    def initQwtPlot(self):
        self.PlotData = [[0] * 1000 for i in range(N_CURVES)]
        self.PlotPoint = [[QtCore.QPointF(j, 0) for j in range(1000)]
                          for i in range(N_CURVES)]

        self.PlotChart = QChart()

        self.ChartView = QChartView(self.PlotChart)
        self.ChartView.setVisible(False)
        self.vLayout.insertWidget(0, self.ChartView)

        self.PlotCurve = [QLineSeries() for i in range(N_CURVES)]

    @pyqtSlot()
    def on_btnOpen_clicked(self):
        if self.btnOpen.text() == u'打开连接':
            try:
                self.daplink = self.daplinks[self.cmbDAP.currentText()]
                self.daplink.open()

                _dp = dap.DebugPort(self.daplink, None)
                _dp.init()
                _dp.power_up_debug()

                _ap = ap.AHB_AP(_dp, 0)
                _ap.init()

                self.dap = cortex_m.CortexM(None, _ap)

                Addr = int(self.conf.get('Memory', 'StartAddr'), 16)
                for i in range(256):
                    buff = self.dap.read_memory_block8(Addr + 1024 * i, 1024)
                    buff = ''.join([chr(x) for x in buff])
                    index = buff.find('SEGGER RTT')
                    if index != -1:
                        self.RTTAddr = Addr + 1024 * i + index

                        buff = self.dap.read_memory_block8(
                            self.RTTAddr, ctypes.sizeof(SEGGER_RTT_CB))

                        rtt_cb = SEGGER_RTT_CB.from_buffer(bytearray(buff))
                        self.aUpAddr = self.RTTAddr + 16 + 4 + 4
                        self.aDownAddr = self.aUpAddr + ctypes.sizeof(
                            RingBuffer) * rtt_cb.MaxNumUpBuffers

                        self.txtMain.append(
                            '\n_SEGGER_RTT @ 0x%08X with %d aUp and %d aDown\n'
                            % (self.RTTAddr, rtt_cb.MaxNumUpBuffers,
                               rtt_cb.MaxNumDownBuffers))
                        break
                else:
                    raise Exception('Can not find _SEGGER_RTT')
            except Exception as e:
                self.txtMain.append(f'\n{str(e)}\n')
            else:
                self.cmbDAP.setEnabled(False)
                self.btnOpen.setText(u'关闭连接')
        else:
            self.daplink.close()
            self.cmbDAP.setEnabled(True)
            self.btnOpen.setText(u'打开连接')

    def aUpRead(self):
        buf = self.dap.read_memory_block8(self.aUpAddr,
                                          ctypes.sizeof(RingBuffer))
        aUp = RingBuffer.from_buffer(bytearray(buf))

        if aUp.RdOff == aUp.WrOff:
            buf = []

        elif aUp.RdOff < aUp.WrOff:
            cnt = aUp.WrOff - aUp.RdOff
            buf = self.dap.read_memory_block8(
                ctypes.cast(aUp.pBuffer, ctypes.c_void_p).value + aUp.RdOff,
                cnt)

            aUp.RdOff += cnt

            self.dap.write32(self.aUpAddr + 4 * 4, aUp.RdOff)

        else:
            cnt = aUp.SizeOfBuffer - aUp.RdOff
            buf = self.dap.read_memory_block8(
                ctypes.cast(aUp.pBuffer, ctypes.c_void_p).value + aUp.RdOff,
                cnt)

            aUp.RdOff = 0  #这样下次再读就会进入执行上个条件

            self.dap.write32(self.aUpAddr + 4 * 4, aUp.RdOff)

        return ''.join([chr(x) for x in buf])

    def on_tmrRTT_timeout(self):
        if self.btnOpen.text() == u'关闭连接':
            try:
                self.rcvbuff += self.aUpRead()

                if self.txtMain.isVisible():
                    if self.chkHEXShow.isChecked():
                        text = ''.join(f'{ord(x):02X} ' for x in self.rcvbuff)
                    else:
                        text = self.rcvbuff

                    if len(self.txtMain.toPlainText()) > 25000:
                        self.txtMain.clear()
                    self.txtMain.moveCursor(QtGui.QTextCursor.End)
                    self.txtMain.insertPlainText(text)

                    self.rcvbuff = ''

                else:
                    if self.rcvbuff.rfind(',') == -1: return

                    d = self.rcvbuff[0:self.rcvbuff.rfind(',')].split(
                        ',')  # [b'12', b'34'] or [b'12 34', b'56 78']
                    d = [[float(x) for x in X.strip().split()]
                         for X in d]  # [[12], [34]]   or [[12, 34], [56, 78]]
                    for arr in d:
                        for i, x in enumerate(arr):
                            if i == N_CURVES: break

                            self.PlotData[i].pop(0)
                            self.PlotData[i].append(x)
                            self.PlotPoint[i].pop(0)
                            self.PlotPoint[i].append(QtCore.QPointF(999, x))

                    self.rcvbuff = self.rcvbuff[self.rcvbuff.rfind(',') + 1:]

                    self.tmrRTT_Cnt += 1
                    if self.tmrRTT_Cnt % 4 == 0:
                        if len(d[-1]) != len(self.PlotChart.series()):
                            for series in self.PlotChart.series():
                                self.PlotChart.removeSeries(series)
                            for i in range(min(len(d[-1]), N_CURVES)):
                                self.PlotCurve[i].setName(f'Curve {i+1}')
                                self.PlotChart.addSeries(self.PlotCurve[i])
                            self.PlotChart.createDefaultAxes()

                        for i in range(len(self.PlotChart.series())):
                            for j, point in enumerate(self.PlotPoint[i]):
                                point.setX(j)

                            self.PlotCurve[i].replace(self.PlotPoint[i])

                        miny = min([
                            min(d) for d in
                            self.PlotData[:len(self.PlotChart.series())]
                        ])
                        maxy = max([
                            max(d) for d in
                            self.PlotData[:len(self.PlotChart.series())]
                        ])
                        self.PlotChart.axisY().setRange(miny, maxy)
                        self.PlotChart.axisX().setRange(0000, 1000)

            except Exception as e:
                self.rcvbuff = ''
                print(str(e))  # 波形显示模式下 txtMain 不可见,因此错误信息不能显示在其上

        else:
            self.tmrRTT_Cnt += 1
            if self.tmrRTT_Cnt % 20 == 0:
                self.detect_daplink()  # 自动检测 DAPLink 的热插拔

    def aDownWrite(self, text):
        buf = self.dap.read_memory_block8(self.aDownAddr,
                                          ctypes.sizeof(RingBuffer))
        aDown = RingBuffer.from_buffer(bytearray(buf))

        if aDown.WrOff >= aDown.RdOff:
            if aDown.RdOff != 0:
                cnt = min(aDown.SizeOfBuffer - aDown.WrOff, len(text))
            else:
                cnt = min(
                    aDown.SizeOfBuffer - 1 - aDown.WrOff,
                    len(text))  # 写入操作不能使得 aDown.WrOff == aDown.RdOff,以区分满和空
            self.dap.write_memory_block8(
                ctypes.cast(aDown.pBuffer, ctypes.c_void_p).value +
                aDown.WrOff, [ord(x) for x in text[:cnt]])

            aDown.WrOff += cnt
            if aDown.WrOff == aDown.SizeOfBuffer: aDown.WrOff = 0

            text = text[cnt:]

        if text and aDown.RdOff != 0 and aDown.RdOff != 1:  # != 0 确保 aDown.WrOff 折返回 0,!= 1 确保有空间可写入
            cnt = min(aDown.RdOff - 1 - aDown.WrOff,
                      len(text))  # - 1 确保写入操作不导致WrOff与RdOff指向同一位置
            self.dap.write_memory_block8(
                ctypes.cast(aDown.pBuffer, ctypes.c_void_p).value +
                aDown.WrOff, [ord(x) for x in text[:cnt]])

            aDown.WrOff += cnt

        self.dap.write32(self.aDownAddr + 4 * 3, aDown.WrOff)

    @pyqtSlot()
    def on_btnSend_clicked(self):
        if self.btnOpen.text() == u'关闭连接':
            text = self.txtSend.toPlainText()

            try:
                if self.chkHEXSend.isChecked():
                    text = ''.join([chr(int(x, 16)) for x in text.split()])

                self.aDownWrite(text)

            except Exception as e:
                self.txtMain.append(f'\n{str(e)}\n')

    def detect_daplink(self):
        daplinks = aggregator.DebugProbeAggregator.get_all_connected_probes()

        if len(daplinks) != self.cmbDAP.count():
            self.cmbDAP.clear()
            for daplink in daplinks:
                self.cmbDAP.addItem(daplink.product_name)

            self.daplinks = collections.OrderedDict([
                (daplink.product_name, daplink) for daplink in daplinks
            ])

            if self.daplink and self.daplink.product_name in self.daplinks:
                self.cmbDAP.setCurrentIndex(self.daplinks.keys().index(
                    self.daplink.product_name))
            else:  # daplink被拔掉
                self.btnOpen.setText(u'打开连接')

    @pyqtSlot(int)
    def on_chkWavShow_stateChanged(self, state):
        self.ChartView.setVisible(state == Qt.Checked)
        self.txtMain.setVisible(state == Qt.Unchecked)

    @pyqtSlot()
    def on_btnClear_clicked(self):
        self.txtMain.clear()

    def closeEvent(self, evt):
        self.conf.write(open('setting.ini', 'w', encoding='utf-8'))
示例#23
0
   def __createChart(self):  ##创建图表
      chart = QChart()  #创建 Chart
   ##      chart.setTitle("简单函数曲线")
      chart.legend().setVisible(True)
      self.chartView.setChart(chart)   #Chart添加到chartView

      pen=QPen()
      pen.setWidth(2)

   ##========LineSeries折线 和 ScatterSeries散点
      seriesLine = QLineSeries()
      seriesLine.setName("LineSeries折线")
      seriesLine.setPointsVisible(False)     #数据点不可见
      pen.setColor(Qt.red)
      seriesLine.setPen(pen)
      seriesLine.hovered.connect(self.do_series_hovered)    #信号 hovered
      seriesLine.clicked.connect(self.do_series_clicked)    #信号 clicked
      chart.addSeries(seriesLine)   #添加到chart

      seriesLinePoint = QScatterSeries()    #散点序列
      seriesLinePoint.setName("ScatterSeries散点")
      shape=QScatterSeries.MarkerShapeCircle  #MarkerShapeRectangle
      seriesLinePoint.setMarkerShape(shape)   #散点形状,只有2种
      seriesLinePoint.setBorderColor(Qt.yellow)
      seriesLinePoint.setBrush(QBrush(Qt.red))
      seriesLinePoint.setMarkerSize(10)      #散点大小
      seriesLinePoint.hovered.connect(self.do_series_hovered)  #信号 hovered
      seriesLinePoint.clicked.connect(self.do_series_clicked)  #信号 clicked
      chart.addSeries(seriesLinePoint)    #添加到chart

   ##======== SplineSeries 曲线和 QScatterSeries 散点
      seriesSpLine = QSplineSeries()
      seriesSpLine.setName("SplineSeries曲线")
      seriesSpLine.setPointsVisible(False)    #数据点不可见
      pen.setColor(Qt.blue)
      seriesSpLine.setPen(pen)
      seriesSpLine.hovered.connect(self.do_series_hovered)  #信号 hovered
      seriesSpLine.clicked.connect(self.do_series_clicked)  #信号 clicked


      seriesSpPoint = QScatterSeries()    #散点序列
      seriesSpPoint.setName("QScatterSeries")
      shape=QScatterSeries.MarkerShapeRectangle  #MarkerShapeCircle
      seriesSpPoint.setMarkerShape(shape) #散点形状,只有2种
      seriesSpPoint.setBorderColor(Qt.green)
      seriesSpPoint.setBrush(QBrush(Qt.blue))
      seriesSpPoint.setMarkerSize(10)     #散点大小
      seriesSpPoint.hovered.connect(self.do_series_hovered) #信号 hovered
      seriesSpPoint.clicked.connect(self.do_series_clicked) #信号 clicked

      chart.addSeries(seriesSpLine)
      chart.addSeries(seriesSpPoint)

   ##  创建缺省坐标轴
      chart.createDefaultAxes()  #创建缺省坐标轴并与序列关联
      chart.axisX().setTitleText("time(secs)")
      chart.axisX().setRange(0,10)
      chart.axisX().applyNiceNumbers()

      chart.axisY().setTitleText("value")
      chart.axisY().setRange(-2,2)
      chart.axisY().applyNiceNumbers()

      for marker in chart.legend().markers():  #QLegendMarker类型列表
         marker.clicked.connect(self.do_LegendMarkerClicked)
示例#24
0
class KLineChartView(QChartView):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.setChart(self._chart)
        # 设置外边界全部为0
        self._chart.layout().setContentsMargins(0, 0, 0, 0)
        # 设置内边界的bottom为0
        margins = self._chart.margins()
        self._chart.setMargins(QMargins(margins.left(), 0, margins.right(), 0))
        # 设置背景区域无圆角
        self._chart.setBackgroundRoundness(0)
示例#25
0
class Display(QWidget):
    def __init__(self, trainer='MLP', debug=False):
        # QWidget Setup
        QWidget.__init__(self,
                         flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
        self.setWindowTitle("NeuroSky GUI")
        self.resize(1400, 1000)

        # Linker Params
        self._linker = Linker(debug=debug, trainer=trainer)
        self.TRAINER_FORWARD = self._linker.trainer.add_identifier('forward')
        self.TRAINER_BACKWARD = self._linker.trainer.add_identifier('backward')
        self.TRAINER_IDLE = self._linker.trainer.add_identifier('idle')

        # Indicators
        self._raw_data_indicator = self._create_indicator('Raw Data:')
        self._poor_level_indicator = self._create_indicator(
            'Poor Level Signal:')
        self._sample_rate_indicator = self._create_indicator('Sample Rate:')
        self._prediction_indicator = self._create_indicator('Prediction:')
        self._training_status_indicator = self._create_indicator(
            'Training Status:')
        self._forward_counter_indicator = self._create_indicator(
            'Current Forward Count:')
        self._backward_counter_indicator = self._create_indicator(
            'Current Backward Count:')
        self._idle_counter_indicator = self._create_indicator(
            'Current Idle Count:')

        # Initializing layout
        self.main_page()

        # Series
        self._x_axis = 0
        self._connect_data()

    def main_page(self):  # type: (Display) -> None
        # Top Layout
        top_left_layout = QVBoxLayout()
        top_left_layout.addLayout(self._raw_data_indicator['layout'])
        top_left_layout.addLayout(self._poor_level_indicator['layout'])
        top_left_layout.addLayout(self._sample_rate_indicator['layout'])

        top_right_layout = QVBoxLayout()
        top_right_layout.addWidget(self._get_connector_chart(),
                                   alignment=Qt.AlignCenter)
        # top_right_layout.setStretchFactor(self._get_connector_chart(), 1)

        top_layout = QHBoxLayout()
        top_layout.addLayout(top_left_layout)
        top_layout.addLayout(top_right_layout)

        # Bottom Layout
        bottom_left_layout = QVBoxLayout()
        bottom_left_layout.addLayout(self._prediction_indicator['layout'])
        bottom_left_layout.addLayout(self._training_status_indicator['layout'])
        bottom_left_layout.addLayout(self._idle_counter_indicator['layout'])
        bottom_left_layout.addLayout(self._forward_counter_indicator['layout'])
        bottom_left_layout.addLayout(
            self._backward_counter_indicator['layout'])

        bottom_right_layout = QVBoxLayout()
        bottom_right_layout.addWidget(self._get_processor_chart(),
                                      alignment=Qt.AlignCenter)

        bottom_layout = QHBoxLayout()
        bottom_layout.addLayout(bottom_left_layout)
        bottom_layout.addLayout(bottom_right_layout)

        # Outer Layout
        outer_layout = QVBoxLayout()
        outer_layout.addLayout(top_layout)
        outer_layout.addLayout(bottom_layout)

        # Set Layout
        self.setLayout(outer_layout)

    def _get_connector_chart(self):  # type: (Display) -> QChartView
        # Create pen
        pen = QLineSeries().pen()
        pen.setColor(Qt.blue)
        pen.setWidthF(1)

        # Series
        self._connector_series = QLineSeries()
        self._connector_series.setPen(pen)
        self._connector_series.useOpenGL()

        # Chart
        self._connector_chart = QChart()
        self._connector_chart.legend().hide()
        self._connector_chart.addSeries(self._connector_series)
        self._connector_chart.createDefaultAxes()
        self._connector_chart.axisX().setMax(100)
        self._connector_chart.axisX().setMin(0)
        self._connector_chart.axisY().setMax(500)
        self._connector_chart.axisY().setMin(-500)

        # Chart View
        view = QChartView(self._connector_chart)
        view.setRenderHint(QPainter.Antialiasing)
        view.setStyleSheet('margin: 0px; height: 250%; width: 400%;')
        return view

    def _get_processor_chart(self):  # type: (Display) -> QChartView
        # Create pen
        pen = QLineSeries().pen()
        pen.setColor(Qt.red)
        pen.setWidthF(1)

        # Series
        self._processor_series = QLineSeries()
        self._processor_series.setPen(pen)
        self._processor_series.useOpenGL()

        # Chart
        self._processor_chart = QChart()
        self._processor_chart.legend().hide()
        self._processor_chart.addSeries(self._processor_series)
        self._processor_chart.createDefaultAxes()
        self._processor_chart.axisX().setMax(100)
        self._processor_chart.axisX().setMin(0)
        self._processor_chart.axisY().setMax(5000)
        self._processor_chart.axisY().setMin(0)

        self._processor_x_axis = QValueAxis()
        self._processor_x_axis.setLabelFormat('%i')
        self._processor_chart.setAxisX(self._processor_x_axis,
                                       self._processor_series)

        self._processor_y_axis = QLogValueAxis()
        self._processor_y_axis.setLabelFormat('%g')
        self._processor_y_axis.setBase(8)

        # Chart View
        view = QChartView(self._processor_chart)
        view.setRenderHint(QPainter.Antialiasing)
        view.setStyleSheet('margin: 0px; height: 250%; width: 400%;')
        return view

    def _connect_data(self):  # type: (Display) -> None
        self._linker.raw.connect(self._add_connector_data)
        self._linker.poor_signal_level.connect(
            lambda level: self._poor_level_indicator['label'].setText(
                str(level)))
        self._linker.sampling_rate.connect(
            lambda rate: self._sample_rate_indicator['label'].setText(str(rate)
                                                                      ))
        self._linker.fft.connect(self._add_processor_data)
        self._linker.prediction.connect(
            lambda prediction: self._prediction_indicator['label'].setText(
                str(prediction)))
        self._linker.training_status.connect(
            lambda status: self._training_status_indicator['label'].setText(
                str(status)))
        self._linker.identifiers.connect(self._connect_identifiers)

    def keyPressEvent(self, event):  # type: (Display, {key}) -> None
        key = event.key()
        if key == Qt.Key_Escape:
            self._linker.close()
            self.close()
        elif key == Qt.Key_W:
            # self._linker.connector.record(
            #     './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_FORWARD)
            # )
            # self._linker.processor.record(
            #     './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_FORWARD)
            # )
            self._linker.trainer.train(self.TRAINER_FORWARD)
        elif key == Qt.Key_S:
            # self._linker.connector.record(
            #     './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_BACKWARD)
            # )
            # self._linker.processor.record(
            #     './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_BACKWARD)
            # )
            self._linker.trainer.train(self.TRAINER_BACKWARD)
        elif key == Qt.Key_Space:
            # self._linker.connector.record(
            #     './data/raw_data/' + self._linker.trainer.get_next_connector_label(self.TRAINER_IDLE)
            # )
            # self._linker.processor.record(
            #     './data/processed_data/' + self._linker.trainer.get_next_processor_label(self.TRAINER_IDLE)
            # )
            self._linker.trainer.train(self.TRAINER_IDLE)
        else:
            print(key)

    @staticmethod
    def _create_indicator(
            label):  # type: (Any) -> Dict[str, Union[QHBoxLayout, QLabel]]
        layout = QHBoxLayout()
        display_widget = QLabel(label)
        layout.addWidget(display_widget, alignment=Qt.AlignCenter)
        label_widget = QLabel('Initializing...')
        layout.addWidget(label_widget, alignment=Qt.AlignCenter)
        return {
            'layout': layout,
            'display': display_widget,
            'label': label_widget
        }

    @pyqtSlot(int)
    def _add_connector_data(self,
                            data):  # type: (Display, Any) -> Optional[Any]
        self._raw_data_indicator['label'].setText(str(data))
        self._connector_series.append(self._x_axis, data)
        if self._connector_series.count() >= 100:
            self._connector_series.clear()
            self._x_axis = 0
        else:
            self._x_axis += 1

    @pyqtSlot(np.ndarray)
    def _add_processor_data(
            self, data):  # type: (Display, {__getitem__}) -> Optional[Any]
        self._processor_series.clear()
        x_axis = data[0]
        y_axis = data[1]
        for i in range(len(x_axis)):
            self._processor_series.append(x_axis[i], y_axis[i])

    @pyqtSlot(list)
    def _connect_identifiers(self, identifiers):
        for identifier in identifiers:
            if identifier['name'] == self.TRAINER_IDLE:
                self._idle_counter_indicator['label'].setText(
                    str(identifier['training_count']))
            elif identifier['name'] == self.TRAINER_FORWARD:
                self._forward_counter_indicator['label'].setText(
                    str(identifier['training_count']))
            elif identifier['name'] == self.TRAINER_BACKWARD:
                self._backward_counter_indicator['label'].setText(
                    str(identifier['training_count']))
示例#26
0
def main():
    import sys
    from PyQt5.QtChart import QChart, QChartView
    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QPainter
    from PyQt5.QtWidgets import QApplication, QMainWindow

    import numpy as np

    @pyqtSlot(QPointF, bool)
    def help(point, state):
        print('help')

    app = QApplication(sys.argv)

    size = 50
    bdr = 2
    opc = 0.3
    special = False

    markers = [
        XMarkerCircle(),
        XMarkerPlus(),
        XMarkerDash(),
        XMarkerSquare(),
        XMarkerDiamond(),
        XMarkerCross(),
        XMarkerTriangle()
    ]

    # Chart Setup
    chart = QChart()
    chart.axisX = QValueAxis()
    chart.axisY = QValueAxis()
    chart.axisX.setTickCount(11)
    chart.axisY.setTickCount(11)

    chart.legend().setVisible(True)
    chart.legend().setAlignment(Qt.AlignBottom)
    chartView = QChartView(chart)
    chartView.setRenderHint(QPainter.Antialiasing)

    class scatser(QScatterSeries):
        def __init__(self, parent=None):
            super(scatser, self).__init__(parent)
            self.hovered.connect(self.onHovered)
            self.pen = QPen(Qt.black)

        @pyqtSlot(QPointF, bool)
        def onHovered(self, point, state):
            if state:
                spoint = self.chart().mapToPosition(point) - QPointF(
                    0, size / 2)
                self.ttip = XToolTipLabel('Hello from:\n x: %.1f, y: %.1f' %
                                          (point.x(), point.y()),
                                          colour=self.color())

                self.ttip_proxy = chart.scene().addWidget(self.ttip)
                w = self.ttip.width()
                h = self.ttip.height()
                self.ttip_proxy.setPos(spoint.x() - w / 2.0, spoint.y() - h)
                self.ttip.updateGeometry()
            else:
                self.ttip_proxy.deleteLater()

    mcount = 0
    nm = len(markers)
    pos = [0.1, 0.3, 0.5, 0.7, 0.9]
    for i in pos:
        for j in pos:
            if mcount == nm:
                mcount = 0
            #print(mcount)
            m = markers[mcount]
            m.setBrush(size, size, border=bdr, opacity=opc)
            ser = scatser()

            ser.append(i, j)

            if special:
                ser.setBorderColor(QColor(1, 1, 1, 1))
                ser.setMarkerSize(size)
                #ser.setMarkerShape(1)
                ser.setBrush(m)

            else:
                xtypemarker(ser, size=size, width=bdr, fillalpha=50)
            chart.addSeries(ser)
            chart.setAxisX(chart.axisX, ser)
            chart.setAxisY(chart.axisY, ser)
            mcount += 1

    chart.axisX.setMin(0)
    chart.axisY.setMin(0)
    chart.axisX.setMax(1)
    chart.axisY.setMax(1)
    window = QMainWindow()
    window.setCentralWidget(chartView)
    window.resize(800, 800)
    window.show()

    sys.exit(app.exec_())
示例#27
0
class ChartView(QChartView):
    def __init__(self, *args, **kwargs):
        super(ChartView, self).__init__(*args, **kwargs)
        self.resize(800, 600)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        # 自定义x轴label
        self.category = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        self.initChart()

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

        # line
        self.lineItem = QGraphicsLineItem(self._chart)
        pen = QPen(Qt.gray)
        pen.setWidth(1)

        self.lineItem.setPen(pen)
        self.lineItem.setZValue(996)
        self.lineItem.hide()

        self.lineItemX = QGraphicsLineItem(self._chart)
        penx = QPen(Qt.gray)
        penx.setWidth(1)
        self.lineItemX.setPen(penx)
        self.lineItemX.setZValue(997)
        self.lineItemX.hide()

        # 一些固定计算,减少mouseMoveEvent中的计算量
        # 获取x和y轴的最小最大值
        axisX, axisY = self._chart.axisX(), self._chart.axisY()
        self.min_x, self.max_x = axisX.min(), axisX.max()
        self.min_y, self.max_y = axisY.min(), axisY.max()

    def resizeEvent(self, event):
        super(ChartView, self).resizeEvent(event)
        # 当窗口大小改变时需要重新计算
        # 坐标系中左上角顶点
        self.point_top = self._chart.mapToPosition(
            QPointF(self.min_x, self.max_y))
        # 坐标右上点
        self.point_right_top = self._chart.mapToPosition(
            QPointF(self.max_x, self.max_y))
        # 坐标右下点
        self.point_right_bottom = self._chart.mapToPosition(
            QPointF(self.max_x, self.min_y))
        # 坐标原点坐标
        self.point_bottom = self._chart.mapToPosition(
            QPointF(self.min_x, self.min_y))
        self.step_x = (self.max_x - self.min_x) / \
            (self._chart.axisX().tickCount() - 1)

    def mouseMoveEvent(self, event):
        super(ChartView, self).mouseMoveEvent(event)
        pos = event.pos()
        # 把鼠标位置所在点转换为对应的xy值
        x = self._chart.mapToValue(pos).x()
        y = self._chart.mapToValue(pos).y()

        # 根据间隔来确定鼠标当前所在的索引
        index = round((x - self.min_x) / self.step_x)
        # 得到在坐标系中的所有正常显示的series的类型和点
        points = [
            (serie, serie.at(index)) for serie in self._chart.series()
            if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y
        ]
        if points:
            # 根据鼠标的点获取对应曲线的坐标点,
            # pos_x = self._chart.mapToPosition(
            #     QPointF(index * self.step_x + self.min_x, self.min_y))
            # 设置鼠标的垂直线
            self.lineItem.setLine(pos.x(), self.point_top.y(), pos.x(),
                                  self.point_bottom.y())
            self.lineItem.show()

            # 设置鼠标的水平线
            self.lineItemX.setLine(self.point_top.x(), pos.y(),
                                   self.point_right_top.x(), pos.y())
            self.lineItemX.show()

            try:
                title = self.category[index]
            except:
                title = ""
            t_width = self.toolTipWidget.width()
            t_height = self.toolTipWidget.height()
            # 如果鼠标位置离右侧的距离小于tip宽度
            x = pos.x() - t_width if self.width() - \
                pos.x() - 20 < t_width else pos.x()
            # 如果鼠标位置离底部的高度小于tip高度
            y = pos.y() - t_height if self.height() - \
                pos.y() - 20 < t_height else pos.y()
            self.toolTipWidget.show(title, points, QPoint(x, y))
        else:
            self.toolTipWidget.hide()
            self.lineItem.hide()
            self.lineItemX.hide()

    def handleMarkerClicked(self):
        marker = self.sender()  # 信号发送者
        if not marker:
            return
        visible = not marker.series().isVisible()
        # 隐藏或显示series
        marker.series().setVisible(visible)
        marker.setVisible(True)  # 要保证marker一直显示
        # 透明度
        alpha = 1.0 if visible else 0.4
        # 设置label的透明度
        brush = marker.labelBrush()
        color = brush.color()
        color.setAlphaF(alpha)
        brush.setColor(color)
        marker.setLabelBrush(brush)
        # 设置marker的透明度
        brush = marker.brush()
        color = brush.color()
        color.setAlphaF(alpha)
        brush.setColor(color)
        marker.setBrush(brush)
        # 设置画笔透明度
        pen = marker.pen()
        color = pen.color()
        color.setAlphaF(alpha)
        pen.setColor(color)
        marker.setPen(pen)

    def handleMarkerHovered(self, status):
        # 设置series的画笔宽度
        marker = self.sender()  # 信号发送者
        if not marker:
            return
        series = marker.series()
        if not series:
            return
        pen = series.pen()
        if not pen:
            return
        pen.setWidth(pen.width() + (1 if status else -1))
        series.setPen(pen)

    def handleSeriesHoverd(self, point, state):
        # 设置series的画笔宽度
        series = self.sender()  # 信号发送者
        pen = series.pen()
        if not pen:
            return
        pen.setWidth(pen.width() + (1 if state else -1))
        series.setPen(pen)

    def initChart(self):
        self._chart = QChart(title="折线图堆叠")
        self._chart.setAcceptHoverEvents(True)
        # Series动画
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        dataTable = [["邮件营销", [120, 132, 101, 134, 90, 230, 210]],
                     ["联盟广告", [220, 182, 191, 234, 290, 330, 310]],
                     ["视频广告", [150, 232, 201, 154, 190, 330, 410]],
                     ["直接访问", [320, 332, 301, 334, 390, 330, 320]],
                     ["搜索引擎", [820, 932, 901, 934, 1290, 1330, 1320]]]
        for series_name, data_list in dataTable:
            series = QLineSeries(self._chart)
            for j, v in enumerate(data_list):
                series.append(j, v)
            series.setName(series_name)
            series.setPointsVisible(True)  # 显示圆点
            series.hovered.connect(self.handleSeriesHoverd)  # 鼠标悬停
            self._chart.addSeries(series)
        self._chart.createDefaultAxes()  # 创建默认的轴
        axisX = self._chart.axisX()  # x轴
        axisX.setTickCount(7)  # x轴设置7个刻度
        axisX.setGridLineVisible(False)  # 隐藏从x轴往上的线条
        axisY = self._chart.axisY()
        axisY.setTickCount(7)  # y轴设置7个刻度
        axisY.setRange(0, 1500)  # 设置y轴范围
        # 自定义x轴
        axis_x = QCategoryAxis(
            self._chart,
            labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
        axis_x.setTickCount(7)
        axis_x.setGridLineVisible(False)
        min_x = axisX.min()
        max_x = axisX.max()
        step = (max_x - min_x) / (7 - 1)  # 7个tick
        for i in range(0, 7):
            axis_x.append(self.category[i], min_x + i * step)
        self._chart.setAxisX(axis_x, self._chart.series()[-1])
        # self._chart.addAxis(axis_x, Qt.AlignBottom)
        # chart的图例
        legend = self._chart.legend()
        # 设置图例由Series来决定样式
        legend.setMarkerShape(QLegend.MarkerShapeFromSeries)
        # 遍历图例上的标记并绑定信号
        for marker in legend.markers():
            # 点击事件
            marker.clicked.connect(self.handleMarkerClicked)
            # 鼠标悬停事件
            marker.hovered.connect(self.handleMarkerHovered)
        self.setChart(self._chart)
示例#28
0
class QtChartCanvas(QWidget):
    def __init__(self, parent=None):
        super(QtChartCanvas, self).__init__(parent)
        self.setStyleSheet("border:0;background-color:#263848")
        self.plotChart = QChart()
        self.plotChart.legend().hide()
        self.verticalLayout = QtWidgets.QVBoxLayout(self)

        self.plotView = QChartView(self.plotChart)
        self.plotView.setStyleSheet("border:0;background-color:#263848;")
        self.plotView.setBackgroundBrush(QBrush(QColor("#263848")))
        self.plotChart.setBackgroundBrush(QBrush(QColor("#263848")))

        #self.plotChart.setStyle()
        self.verticalLayout.addWidget(self.plotView)

        self.plotCurve = QSplineSeries()
        self.plotCurve.setColor(QColor("#AABFFF"))
        self.plotCurve.setUseOpenGL(True)
        self.plotCurve.pen().setColor(QColor("#FAF0FF"))
        self.plotChart.addSeries(self.plotCurve)

        # self.scatter=QScatterSeries()
        # self.scatter.setMarkerSize(8)
        # self.plotChart.addSeries(self.scatter)

        self.plotChart.createDefaultAxes()
        self.plotChart.axisY().setGridLineColor(QColor("#5D5C72"))
        self.plotChart.axisY().setLinePenColor(QColor("#9D9CA2"))
        self.plotChart.axisY().setLabelsColor(QColor("#F8F6F6"))
        self.plotChart.axisY().setRange(0, 100)
        self.plotChart.axisX().hide()

        self.RecvData = []  # 存储接收到的传感器数据
        self.RecvIndx = 0

        self.setLockY = True

        self.isTop = False
        self.minY = 0
        self.maxY = 100

    def update_figure(self, payload):
        data = payload["data"]
        self.RecvData.append(data)
        self.RecvData = self.RecvData[-20:]
        plotData = []
        if self.isTop:
            for i, val in enumerate(self.RecvData):
                plotData.append(QPoint(i, val))
            self.plotCurve.replace(plotData)
            #self.scatter.replace(plotData)
            self.plotChart.axisX().setMax(len(plotData))
            if not self.setLockY:
                self.plotChart.axisY().setRange(
                    min(self.RecvData) * 0.5,
                    max(self.RecvData) * 1.3)
            else:
                self.plotChart.axisY().setRange(self.minY, self.maxY)

    def setYLimit(self, miny=0, maxy=100, lockY=True):
        self.setLockY = lockY
        if self.setLockY:
            self.maxY = maxy
            self.minY = miny

    def changeTop(self, isTop):
        self.isTop = isTop
示例#29
0
class MainWindow(QMainWindow):
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    MAIN_UI_FILE = os.path.join(BASE_DIR, "main.ui")
    NEW_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "new_dish_popup.ui")
    NEW_DISH_MULTI_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                                "new_dish_multi_popup.ui")
    NEW_DISH_DATA_POPUP_UI_FILE = os.path.join(BASE_DIR,
                                               "new_dish_data_popup.ui")
    MODIFY_DISH_POPUP_UI_FILE = os.path.join(BASE_DIR, "modify_dish_popup.ui")
    DB_FILE = os.path.join(BASE_DIR, "restaurant.db")

    def __init__(self):
        super(MainWindow, self).__init__()
        # Initialize variable
        self.db_connection = None
        self.new_dish_popup = QWidget()
        self.new_dish_multi_popup = QWidget()
        self.new_dish_data_popup = QWidget()
        self.modify_dish_popup = QWidget()
        self.dish_table_model = QStandardItemModel(0, 6)
        self.dish_table_proxy = TableFilter()
        self.dish_data_table_model = QStandardItemModel(0, 6)
        self.dish_data_table_proxy = TableFilter()
        self.graph_chart = None
        self.graph_series = {}

        # Load UI designs
        uic.loadUi(self.MAIN_UI_FILE, self)
        uic.loadUi(self.NEW_DISH_POPUP_UI_FILE, self.new_dish_popup)
        uic.loadUi(self.NEW_DISH_MULTI_POPUP_UI_FILE,
                   self.new_dish_multi_popup)
        uic.loadUi(self.NEW_DISH_DATA_POPUP_UI_FILE, self.new_dish_data_popup)
        uic.loadUi(self.MODIFY_DISH_POPUP_UI_FILE, self.modify_dish_popup)
        self.init_dish_table()
        self.init_dish_data_table()
        self.init_graph()

        # Connect to database
        self.init_db_connection()

        # MainWindow Bind action triggers
        self.action_new_dish.triggered.connect(self.show_new_dish_popup)
        self.action_new_dish_multi.triggered.connect(
            self.show_new_dish_multi_popup)
        self.action_new_data_multi.triggered.connect(
            lambda: self.modify_new_dish_data_popup_table(show=True))
        self.tabWidget.currentChanged.connect(self.update_graph)

        # Dish Table filter bind
        self.dish_lineEdit.textChanged.connect(
            lambda text, col_idx=1: self.dish_table_proxy.set_col_regex_filter(
                col_idx, text))
        self.lower_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_price_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=2: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_week_sell_spinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_table_proxy.
            set_col_number_filter(col_idx, -1, value))

        # Dish Data Table filter bind
        self.lower_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, date, -1))
        self.higher_data_dateEdit.dateChanged.connect(
            lambda date, col_idx=1: self.dish_data_table_proxy.
            set_col_date_filter(col_idx, -1, date))
        self.data_lineEdit.textChanged.connect(
            lambda text, col_idx=2: self.dish_data_table_proxy.
            set_col_regex_filter(col_idx, text))
        self.lower_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_doubleSpinBox.valueChanged.connect(
            lambda value, col_idx=3: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.lower_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, value, -1))
        self.higher_data_spinBox.valueChanged.connect(
            lambda value, col_idx=4: self.dish_data_table_proxy.
            set_col_number_filter(col_idx, -1, value))
        self.data_all_check_checkBox.stateChanged.connect(
            lambda state, col_idx=5: self.data_table_check_state(
                state, col_idx))
        self.dish_data_table_model.itemChanged.connect(self.update_series)

        # Popup bind action triggers
        self.new_dish_popup.create_new_dish_btn.clicked.connect(
            self.create_new_dish)
        self.new_dish_multi_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_multi)
        self.new_dish_data_popup.dateEdit.dateChanged.connect(
            self.modify_new_dish_data_popup_table)
        self.new_dish_data_popup.pushButton_ok.clicked.connect(
            self.create_new_dish_data)

        # Get current dishes
        self.load_dish_table()
        self.load_dish_data_table()
        self.new_dish_data_popup.dateEdit.setDate(QtCore.QDate.currentDate())

    def init_dish_table(self):
        self.dish_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        # Set Header data and stretch
        for col, col_name in enumerate(
            ["ID", "菜品", "价格", "近7天总售出", "操作", "备注"]):
            self.dish_table_model.setHeaderData(col, Qt.Horizontal, col_name,
                                                Qt.DisplayRole)
        self.dish_table_proxy.setSourceModel(self.dish_table_model)
        self.dish_tableView.setModel(self.dish_table_proxy)
        self.dish_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Regex"), (2, "Number"), (3, "Number"),
                              (5, "Regex")]:
            self.dish_table_proxy.filter_method[col] = method

    def init_dish_data_table(self):
        self.data_tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        for col, col_name in enumerate(
            ["Dish_ID", "日期", "菜品", "价格", "售出", "选择"]):
            self.dish_data_table_model.setHeaderData(col, Qt.Horizontal,
                                                     col_name, Qt.DisplayRole)
        self.dish_data_table_proxy.setSourceModel(self.dish_data_table_model)
        self.data_tableView.setModel(self.dish_data_table_proxy)
        self.data_tableView.setColumnHidden(0, True)
        for (col, method) in [(1, "Date"), (2, "Regex"), (3, "Number"),
                              (4, "Number")]:
            self.dish_data_table_proxy.filter_method[col] = method

    def init_graph(self):
        self.graph_chart = QChart(title="售出图")
        self.graph_chart.legend().setVisible(True)
        self.graph_chart.setAcceptHoverEvents(True)

        graph_view = QChartView(self.graph_chart)
        graph_view.setRenderHint(QPainter.Antialiasing)
        self.gridLayout_5.addWidget(graph_view)

    def init_db_connection(self):
        self.db_connection = sqlite3.connect(self.DB_FILE)
        cursor = self.db_connection.cursor()
        # check create table if not exist
        sql_create_dish_table = """ CREATE TABLE IF NOT EXISTS dish (
                                        id integer PRIMARY KEY,
                                        name text NOT NULL,
                                        price numeric Not NULL,
                                        remarks text,
                                        UNIQUE (name, price)
                                    ); """
        sql_create_dish_data_table = """ CREATE TABLE IF NOT EXISTS dish_data (
                                            dish_id integer NOT NULL REFERENCES dish(id) ON DELETE CASCADE,
                                            date date,
                                            sell_num integer DEFAULT 0,
                                            PRIMARY KEY (dish_id, date),
                                            CONSTRAINT dish_fk 
                                                FOREIGN KEY (dish_id) 
                                                REFERENCES dish (id) ON DELETE CASCADE 
                                        ); """
        sql_trigger = """
            CREATE TRIGGER IF NOT EXISTS place_holder_data
            AFTER INSERT ON dish
            BEGIN
                INSERT INTO dish_data (dish_id, date, sell_num) VALUES(new.id, null, 0);
            END;
        """
        cursor.execute(sql_create_dish_table)
        cursor.execute(sql_create_dish_data_table)
        cursor.execute("PRAGMA FOREIGN_KEYS = on")
        cursor.execute(sql_trigger)

        cursor.close()

    def load_dish_table(self):
        today = datetime.today()
        sql_select_query = """
            SELECT dish.id, dish.name, dish.price, COALESCE(SUM(dish_data.sell_num), 0), dish.remarks
            FROM dish LEFT JOIN dish_data 
            ON dish.id = dish_data.dish_id
            WHERE dish_data.date IS NULL OR dish_data.date BETWEEN date('{}') and date('{}')
            GROUP BY dish.id
            ORDER BY dish.name, dish.price;""".format(
            (today - timedelta(days=7)).strftime("%Y-%m-%d"),
            today.strftime("%Y-%m-%d"))
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_table_model.appendRow(create_dish_table_row(*record))
        cursor.close()
        self.dish_tableView.setItemDelegateForColumn(
            4,
            DishTableDelegateCell(self.show_modify_dish_popup,
                                  self.delete_dish, self.dish_tableView))

    def load_dish_data_table(self):
        sql_select_query = """
            SELECT dish_data.dish_id, dish_data.date, dish.name, dish.price, dish_data.sell_num
            FROM dish_data LEFT JOIN dish  
            ON dish_data.dish_id = dish.id
            WHERE dish_data.date IS NOT NULL
            ORDER BY dish_data.date DESC, dish.name, dish.price, dish_data.sell_num;"""
        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        for row_idx, record in enumerate(records):
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(*record))
        cursor.close()
        self.lower_data_dateEdit.setDate(QDate.currentDate().addDays(-7))
        self.higher_data_dateEdit.setDate(QDate.currentDate())
        self.data_tableView.setItemDelegateForColumn(
            5, DishDataTableDelegateCell(self.data_tableView))

    def data_table_check_state(self, state, col):
        for row in range(self.dish_data_table_proxy.rowCount()):
            index = self.dish_data_table_proxy.mapToSource(
                self.dish_data_table_proxy.index(row, col))
            if index.isValid():
                self.dish_data_table_model.setData(index, str(state),
                                                   Qt.DisplayRole)

    def show_new_dish_popup(self):
        # Move popup to center
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.new_dish_popup.move(
            global_point - QtCore.QPoint(self.new_dish_popup.width() // 2,
                                         self.new_dish_popup.height() // 2))
        self.new_dish_popup.show()

    def show_new_dish_multi_popup(self):
        file_name = QFileDialog().getOpenFileName(None, "选择文件", "",
                                                  self.tr("CSV文件 (*.csv)"))[0]
        self.new_dish_multi_popup.tableWidget.setRowCount(0)
        if file_name:
            with open(file_name, "r") as file:
                csv_reader = csv.reader(file, delimiter=",")
                for idx, row_data in enumerate(csv_reader):
                    if len(row_data) == 2:
                        name, price = row_data
                        remark = ""
                    elif len(row_data) == 3:
                        name, price, remark = row_data
                    else:
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('格式为"菜品 价格"或者"菜品 价格 备注"\n第{}行输入有误'.format(
                                idx)))
                        return
                    self.new_dish_multi_popup.tableWidget.insertRow(
                        self.new_dish_multi_popup.tableWidget.rowCount())
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 0, QTableWidgetItem(name))
                    price_type = str_type(price)
                    if price_type == str or (isinstance(
                            price_type, (float, int)) and float(price) < 0):
                        QMessageBox.warning(
                            self, "格式错误",
                            self.tr('第{}行价格输入有误'.format(idx + 1)))
                        return
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 1,
                        QTableWidgetItem("{:.2f}".format(float(price))))
                    self.new_dish_multi_popup.tableWidget.setItem(
                        idx, 2, QTableWidgetItem(remark))
            self.new_dish_multi_popup.show()

    def modify_new_dish_data_popup_table(self, *args, show=False):
        sql_select_query = """
                    SELECT id, name, price, dish_data.sell_num
                    FROM dish LEFT JOIN dish_data
                    ON dish.id=dish_data.dish_id
                    WHERE dish_data.date IS NULL OR dish_data.date = date('{}')
                    GROUP BY id, name, price
                    ORDER BY dish.name, dish.price;""".format(
            self.new_dish_data_popup.dateEdit.date().toString("yyyy-MM-dd"))

        cursor = self.db_connection.cursor()
        cursor.execute(sql_select_query)
        records = cursor.fetchall()
        self.new_dish_data_popup.tableWidget.setRowCount(len(records))
        self.new_dish_data_popup.tableWidget.setColumnHidden(0, True)
        for row_idx, record in enumerate(records):
            dish_id, name, price, sell_num = record
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 0, QTableWidgetItem(str(dish_id)))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 1, QTableWidgetItem(name))
            self.new_dish_data_popup.tableWidget.setItem(
                row_idx, 2, QTableWidgetItem("{:.2f}".format(price)))
            spin_box = QSpinBox()
            spin_box.setMaximum(9999)
            spin_box.setValue(sell_num)
            self.new_dish_data_popup.tableWidget.setCellWidget(
                row_idx, 3, spin_box)
        cursor.close()
        if show:
            self.new_dish_data_popup.show()

    def create_new_dish(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ INSERT INTO dish(name, price, remarks)
                         VALUES(?,?,?)"""
        dish_name = self.new_dish_popup.dish_name.text()
        dish_price = self.new_dish_popup.dish_price.value()
        dish_remark = self.new_dish_popup.dish_remark.toPlainText()
        try:
            cursor.execute(sql_insert, (dish_name, dish_price, dish_remark))
            new_dish_id = cursor.lastrowid
            cursor.close()
            self.db_connection.commit()
            # Update dish table and dish comboBox in UI
            self.dish_table_model.appendRow(
                create_dish_table_row(new_dish_id, dish_name, dish_price, 0,
                                      dish_remark))
            self.new_dish_popup.hide()
        except sqlite3.Error:
            cursor.close()
            QMessageBox.warning(self, "菜品价格重复", self.tr('菜品价格组合重复,请检查'))

    def create_new_dish_multi(self):
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT INTO dish(name, price, remarks)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_multi_popup.tableWidget.rowCount()):
            dish_name = self.new_dish_multi_popup.tableWidget.item(row,
                                                                   0).text()
            dish_price = float(
                self.new_dish_multi_popup.tableWidget.item(row, 1).text())
            dish_remark = self.new_dish_multi_popup.tableWidget.item(row,
                                                                     2).text()
            try:
                cursor.execute(sql_insert,
                               (dish_name, dish_price, dish_remark))
                new_dish_id = cursor.lastrowid
                self.dish_table_model.appendRow(
                    create_dish_table_row(new_dish_id, dish_name, dish_price,
                                          0, dish_remark))
            except sqlite3.Error:
                cursor.close()
                QMessageBox.warning(
                    self, "菜品价格重复",
                    self.tr('前{}行已插入。\n第{}行菜品价格组合重复,请检查'.format(row, row + 1)))
                return
        cursor.close()
        self.db_connection.commit()
        self.new_dish_multi_popup.hide()

    def create_new_dish_data(self):
        current_date = self.new_dish_data_popup.dateEdit.date().toString(
            "yyyy-MM-dd")
        table_filter = TableFilter()
        table_filter.setSourceModel(self.dish_data_table_model)
        table_filter.set_col_regex_filter(1, current_date)
        for row in range(table_filter.rowCount()):
            index = table_filter.mapToSource(table_filter.index(0, 1))
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())
        del table_filter
        cursor = self.db_connection.cursor()
        sql_insert = """ 
            INSERT OR REPLACE INTO dish_data(dish_id, date, sell_num)     
            VALUES (?, ?, ?)"""
        for row in range(self.new_dish_data_popup.tableWidget.rowCount()):
            dish_id = int(
                self.new_dish_data_popup.tableWidget.item(row, 0).text())
            name = self.new_dish_data_popup.tableWidget.item(row, 1).text()
            price = float(
                self.new_dish_data_popup.tableWidget.item(row, 2).text())
            sell_num = self.new_dish_data_popup.tableWidget.cellWidget(
                row, 3).value()
            cursor.execute(sql_insert, (dish_id, current_date, sell_num))
            self.dish_data_table_model.appendRow(
                create_dish_data_table_row(dish_id, current_date, name, price,
                                           sell_num))
        cursor.close()
        self.db_connection.commit()
        self.new_dish_data_popup.hide()

    def delete_dish(self, dish_id):
        cursor = self.db_connection.cursor()
        sql_delete = """ DELETE FROM dish WHERE id=?"""
        cursor.execute(sql_delete, tuple([dish_id]))
        cursor.close()
        self.db_connection.commit()

        # Update dish table and dish comboBox in UI
        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.removeRow(index.row())

        for row in self.dish_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_table_model.removeRow(index.row())

    def show_modify_dish_popup(self, dish_id):
        point = self.rect().center()
        global_point = self.mapToGlobal(point)
        self.modify_dish_popup.move(
            global_point - QtCore.QPoint(self.modify_dish_popup.width() // 2,
                                         self.modify_dish_popup.height() // 2))
        # Find the row and get necessary info
        index = self.dish_table_model.match(self.dish_table_model.index(0, 0),
                                            Qt.DisplayRole, str(dish_id))
        if index:
            row_idx = index[0]
            dish_name = self.dish_table_model.data(row_idx.siblingAtColumn(1))
            dish_price = self.dish_table_model.data(row_idx.siblingAtColumn(2))
            dish_remark = self.dish_table_model.data(
                row_idx.siblingAtColumn(5))
            self.modify_dish_popup.dish_name.setText(dish_name)
            self.modify_dish_popup.dish_price.setValue(float(dish_price))
            self.modify_dish_popup.dish_remark.setText(dish_remark)

            try:
                self.modify_dish_popup.modify_dish_btn.clicked.disconnect()
            except TypeError:
                pass
            self.modify_dish_popup.modify_dish_btn.clicked.connect(
                lambda: self.modify_dish(row_idx, dish_id))
            self.modify_dish_popup.show()

    def modify_dish(self, row, dish_id):
        cursor = self.db_connection.cursor()
        sql_update = """ UPDATE dish
                         SET name = ?, price = ?, remarks = ?
                         WHERE id=?"""
        dish_name = self.modify_dish_popup.dish_name.text()
        dish_price = self.modify_dish_popup.dish_price.value()
        dish_remark = self.modify_dish_popup.dish_remark.toPlainText()
        cursor.execute(sql_update,
                       (dish_name, dish_price, dish_remark, dish_id))
        cursor.close()
        self.db_connection.commit()
        self.modify_dish_popup.hide()

        # Update dish table and dish comboBox in UI
        old_name = self.dish_table_model.data(row.siblingAtColumn(1))
        old_price = self.dish_table_model.data(row.siblingAtColumn(2))
        sell_num = self.dish_table_model.data(row.siblingAtColumn(3))
        row_idx = row.row()
        self.dish_table_model.removeRow(row_idx)
        self.dish_table_model.insertRow(
            row_idx,
            create_dish_table_row(dish_id, dish_name, dish_price, sell_num,
                                  dish_remark))

        for row in self.dish_data_table_model.findItems(str(dish_id)):
            index = row.index()
            if index.isValid():
                self.dish_data_table_model.setData(index.siblingAtColumn(2),
                                                   dish_name)
                self.dish_data_table_model.setData(index.siblingAtColumn(3),
                                                   "{:.2f}".format(dish_price))
        old_key = old_name + '(' + old_price + ')'
        if old_key in self.graph_line_series:
            self.graph_line_series[dish_name + '(' + str(dish_price) +
                                   ')'] = self.graph_line_series[old_key]
            del self.graph_line_series[old_key]

    def update_series(self, item: QStandardItem):
        if item.column() == 5:  # check for checkbox column
            item_idx = item.index()
            date = self.dish_data_table_model.data(item_idx.siblingAtColumn(1))
            dish_name = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(2))
            dish_price = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(3))
            sell_num = self.dish_data_table_model.data(
                item_idx.siblingAtColumn(4))
            set_name = dish_name + "(" + dish_price + ")"
            key = str(
                QDateTime(QDate.fromString(date,
                                           "yyyy-MM-dd")).toSecsSinceEpoch())
            if key not in self.graph_series:
                self.graph_series[key] = {}

            if int(item.text()) == 0:
                if set_name in self.graph_series[key]:
                    del self.graph_series[key][set_name]
                if not self.graph_series[key]:
                    del self.graph_series[key]
            else:
                self.graph_series[key][set_name] = int(sell_num)

    def update_graph(self, index):
        if index == 2:
            self.graph_chart.removeAllSeries()

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

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

            max_num = 0
            total_date = 0
            set_dict = {}
            for key, data in sorted(self.graph_series.items(),
                                    key=lambda i: int(i[0])):
                axis_x.append(
                    QDateTime.fromSecsSinceEpoch(
                        int(key)).toString("yyyy年MM月dd日"))
                for set_name, value in data.items():
                    if set_name not in set_dict:
                        set_dict[set_name] = QBarSet(set_name)
                        for _ in range(total_date):
                            set_dict[set_name].append(0)
                    set_dict[set_name].append(value)
                    max_num = max(max_num, value)
                total_date += 1
                for _, bar_set in set_dict.items():
                    if bar_set.count() < total_date:
                        bar_set.append(0)
            bar_series = QBarSeries()
            for _, bar_set in set_dict.items():
                bar_series.append(bar_set)
            bar_series.hovered.connect(self.graph_tooltip)
            axis_y.setMax(max_num + 1)
            axis_y.setMin(0)
            self.graph_chart.addSeries(bar_series)
            bar_series.attachAxis(axis_x)
            bar_series.attachAxis(axis_y)

    def graph_tooltip(self, status, index, bar_set: QBarSet):
        if status:
            QToolTip.showText(
                QCursor.pos(),
                "{}\n日期: {}\n售出: {}".format(bar_set.label(),
                                            self.graph_chart.axisX().at(index),
                                            int(bar_set.at(index))))
示例#30
0
class Graph(QChartView):
	def __init__(self, parent=None):
		super().__init__(parent=parent)

		self.setpoint_temperature = None

		self.chart = QChart()
		self.chart.legend().hide()
		self.setChart( self.chart )
		self.setRenderHint(QPainter.Antialiasing)
		self.chart.setPlotAreaBackgroundBrush( QBrush(Qt.black) )
		self.chart.setPlotAreaBackgroundVisible( True )

		self.setpointTemperatureSeries = QLineSeries( self.chart )
		pen = self.setpointTemperatureSeries.pen()
		pen.setWidthF(2.)
		pen.setColor( Qt.green )
		self.setpointTemperatureSeries.setPen( pen )
		#self.setpointTemperatureSeries.setUseOpenGL( True )
		self.chart.addSeries( self.setpointTemperatureSeries )

		self.temperatureSeries = QLineSeries( self.chart )
		pen = self.temperatureSeries.pen()
		pen.setWidthF(2.)
		pen.setColor( Qt.red )
		self.temperatureSeries.setPen( pen )
		#self.temperatureSeries.setUseOpenGL( True )
		self.chart.addSeries( self.temperatureSeries )

		self.number_of_samples_to_keep = 2 * 5 * 60

		self.xMin = QDateTime.currentDateTime().toMSecsSinceEpoch()
		self.xMax = QDateTime.currentDateTime().toMSecsSinceEpoch()
		self.yMin = 400
		self.yMax = 0

		#self.chart.createDefaultAxes()
		#x_axis = QValueAxis()
		x_axis = QDateTimeAxis()
		x_axis.setTitleText( "Time" )
		x_axis.setFormat("HH:mm:ss")
		self.chart.addAxis( x_axis, Qt.AlignBottom )
		self.temperatureSeries.attachAxis( x_axis )
		self.setpointTemperatureSeries.attachAxis( x_axis )
		startDate = QDateTime.currentDateTime().addSecs( -5 * 60 )
		endDate = QDateTime.currentDateTime().addSecs( 5 * 60 )
		#startDate = QDateTime(QDate(2017, 1, 9), QTime(17, 25, 0))
		#endDate = QDateTime(QDate(2017, 1, 9), QTime(17, 50, 0))
		#self.chart.axisX().setRange( startDate, endDate )
		#self.chart.axisX().setRange( 0, 100 )

		y_axis = QValueAxis()
		y_axis.setTitleText( "Temperature (K)" )
		self.chart.addAxis( y_axis, Qt.AlignLeft )
		self.temperatureSeries.attachAxis( y_axis )
		self.setpointTemperatureSeries.attachAxis( y_axis )
		self.chart.axisY().setRange( 0, 400 )
		#self.chart.axisY().setRange( 260., 290. )

		self.temperatureSeries.pointAdded.connect( self.Rescale_Axes )
		#self.setpointTemperatureSeries.pointAdded.connect( self.Rescale_Axes )

		self.setRubberBand( QChartView.HorizontalRubberBand )

		# Customize chart title
		font = QFont()
		font.setPixelSize(24);
		self.chart.setTitleFont(font);
		self.chart.setTitleBrush(QBrush(Qt.white));

		## Customize chart background
		#backgroundGradient = QLinearGradient()
		#backgroundGradient.setStart(QPointF(0, 0));
		#backgroundGradient.setFinalStop(QPointF(0, 1));
		#backgroundGradient.setColorAt(0.0, QColor(0x000147));
		#backgroundGradient.setColorAt(1.0, QColor(0x000117));
		#backgroundGradient.setCoordinateMode(QGradient.ObjectBoundingMode);
		#self.chart.setBackgroundBrush(backgroundGradient);
		transparent_background = QBrush(QColor(0,0,0,0))
		self.chart.setBackgroundBrush( transparent_background )

		# Customize axis label font
		labelsFont = QFont()
		labelsFont.setPixelSize(16);
		x_axis.setLabelsFont(labelsFont)
		y_axis.setLabelsFont(labelsFont)
		x_axis.setTitleFont(labelsFont)
		y_axis.setTitleFont(labelsFont)

		# Customize axis colors
		axisPen = QPen(QColor(0xd18952))
		axisPen.setWidth(2)
		x_axis.setLinePen(axisPen)
		y_axis.setLinePen(axisPen)

		# Customize axis label colors
		axisBrush = QBrush(Qt.white)
		x_axis.setLabelsBrush(axisBrush)
		y_axis.setLabelsBrush(axisBrush)
		x_axis.setTitleBrush(axisBrush)
		y_axis.setTitleBrush(axisBrush)

	def set_title(self, title):
		self.chart.setTitle(title)

	def add_new_data_point( self, x, y ):
		x_as_millisecs = x.toMSecsSinceEpoch()
		self.temperatureSeries.append( x_as_millisecs, y )
		if( self.setpoint_temperature ):
			self.setpointTemperatureSeries.append( x_as_millisecs, self.setpoint_temperature )

		num_of_datapoints = self.temperatureSeries.count()
		#if( num_of_datapoints > self.number_of_samples_to_keep ):
		#	self.number_of_samples_to_keep.
		#print( x_as_millisecs, y )
		#self.chart.scroll( x_as_millisecs - 5 * 60 * 1000, x_as_millisecs )
		#self.temperatureSeries.append( x, float(y) )
		#self.repaint()

	def Rescale_Axes( self, index ):
		x = self.temperatureSeries.at( index ).x()
		x_rescaled = False
		if( x < self.xMin ):
			self.xMin = x
			x_rescaled = True
		if( x > self.xMax ):
			self.xMax = x
			x_rescaled = True
		if( x_rescaled ):
			full_range = min( self.xMax - self.xMin, 5 * 60 * 1000 )
			margin = full_range * 0.05

			self.chart.axisX().setRange( QDateTime.fromMSecsSinceEpoch(self.xMax - full_range - margin), QDateTime.fromMSecsSinceEpoch(self.xMax + margin) )
			
		y = self.temperatureSeries.at( index ).y()
		y_rescaled = False
		if( y < self.yMin ):
			self.yMin = y
			y_rescaled = True
		if( y > self.yMax ):
			self.yMax = y
			y_rescaled = True
		if( y_rescaled ):
			full_range = self.yMax - self.yMin
			margin = full_range * 0.05
			self.chart.axisY().setRange( self.yMin - margin, self.yMax + margin )