示例#1
1
    class Window(QDialog):
        def __init__(self):
            QDialog.__init__(self)
            self.setWindowTitle("Printen grafiek magazijnvoorraad bedragen")
            self.setWindowIcon(QIcon('./images/logos/logo.jpg'))
            self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint
                                | Qt.WindowMinMaxButtonsHint)
            self.chart = QChart()
            self.chart_view = QChartView(self.chart)
            self.chart_view.setRenderHint(QPainter.Antialiasing)
            self.buttonPreview = QPushButton('Afdrukvoorbeeld', self)
            self.buttonPreview.setStyleSheet(
                "color: black;  background-color: gainsboro")
            self.buttonPreview.clicked.connect(self.handle_preview)
            self.buttonPrint = QPushButton('Printen', self)
            self.buttonPrint.setStyleSheet(
                "color: black;  background-color: gainsboro")
            self.buttonPrint.clicked.connect(self.handle_print)
            self.sluiten = QPushButton('Sluiten', self)
            self.sluiten.setStyleSheet(
                "color: black;  background-color: gainsboro")
            self.sluiten.clicked.connect(lambda: sluiten(self, m_email))
            layout = QGridLayout(self)
            layout.addWidget(self.buttonPrint, 1, 1)
            layout.addWidget(self.sluiten, 1, 0)
            layout.addWidget(self.chart_view, 0, 0, 1, 3)
            layout.addWidget(self.buttonPreview, 1, 2)
            self.create_chart()

        def create_chart(self):
            self.chart.setTitle('Grafiek financieën magazijnvoorraad')
            font = QFont("Sans Serif", 10)
            font.setWeight(QFont.Bold)
            self.chart.setTitleFont(font)

            set0 = QBarSet('Totaal')
            set1 = QBarSet('Courant')
            set2 = QBarSet('Incourant')

            set0 << rpvrd[0][1] << rpvrd[1][1] << rpvrd[2][1] << rpvrd[3][
                1] << rpvrd[4][1] << rpvrd[5][1] << rpvrd[6][1] << rpvrd[7][
                    1] << rpvrd[8][1] << rpvrd[9][1] << rpvrd[10][1] << rpvrd[
                        11][1]
            set1 << rpvrd[0][2] << rpvrd[1][2] << rpvrd[2][2] << rpvrd[3][
                2] << rpvrd[4][2] << rpvrd[5][2] << rpvrd[6][2] << rpvrd[7][
                    2] << rpvrd[8][2] << rpvrd[9][2] << rpvrd[10][2] << rpvrd[
                        11][2]
            set2 << rpvrd[0][3] << rpvrd[1][3] << rpvrd[2][3] << rpvrd[3][
                3] << rpvrd[4][3] << rpvrd[5][3] << rpvrd[6][3] << rpvrd[7][
                    3] << rpvrd[8][3] << rpvrd[9][3] << rpvrd[10][3] << rpvrd[
                        11][3]

            barseries = QBarSeries()
            barseries.append(set0)
            barseries.append(set1)
            barseries.append(set2)

            categories = [rpvrd[0][0],rpvrd[1][0],rpvrd[2][0],rpvrd[3][0],rpvrd[4][0],\
                          rpvrd[5][0],rpvrd[6][0],rpvrd[7][0],rpvrd[8][0],rpvrd[9][0],\
                          rpvrd[10][0],rpvrd[11][0]]

            self.chart.addSeries(barseries)
            self.chart.axisX()
            self.chart.createDefaultAxes()
            axisX = QBarCategoryAxis()
            axisX.append(categories)
            axisX.setTitleText('Voortschrijdende periode over 12 maanden')
            self.chart.setAxisX(axisX, barseries)
            axisX.setRange(rpvrd[0][0], rpvrd[11][0])
            axisX.setLabelsAngle(-90)

        def handle_print(self):
            printer = QPrinter(QPrinter.HighResolution)
            printer.setOrientation(QPrinter.Landscape)
            dialog = QPrintDialog(printer, self)
            if dialog.exec_() == QPrintDialog.Accepted:
                self.handle_paint_request(printer)

        def handle_preview(self):
            dialog = QPrintPreviewDialog()
            dialog.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint
                                  | Qt.WindowMinMaxButtonsHint)
            dialog.setWindowIcon(QIcon('./images/logos/logo.jpg'))
            dialog.setWindowFlags(dialog.windowFlags()
                                  | Qt.WindowSystemMenuHint
                                  | Qt.WindowMinMaxButtonsHint)
            dialog.resize(1200, 800)
            #dialog.setMinimumSize(1200, 800)
            dialog.paintRequested.connect(self.handle_paint_request)
            dialog.exec_()

        def handle_paint_request(self, printer):
            printer.setPageOrientation(QPageLayout.Landscape)
            painter = QPainter(printer)
            painter.setViewport(self.chart_view.rect())
            painter.setWindow(self.chart_view.rect())
            self.chart_view.render(painter)
            painter.end()
示例#2
1
    class Window(QDialog):
        def __init__(self):
            QDialog.__init__(self)
            self.setWindowTitle(
                "Printen grafiek aantal externe werken per status over jaar " +
                jrwk[0:4])
            self.setWindowIcon(QIcon('./images/logos/logo.jpg'))
            self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint
                                | Qt.WindowMinMaxButtonsHint)
            self.chart = QChart()
            self.chart_view = QChartView(self.chart)
            self.chart_view.setRenderHint(QPainter.Antialiasing)
            self.buttonPreview = QPushButton('Afdrukvoorbeeld', self)
            self.buttonPreview.clicked.connect(self.handle_preview)
            self.buttonPreview.setStyleSheet(
                "color: navy;  background-color: gainsboro")
            self.buttonPrint = QPushButton('Printen', self)
            self.buttonPrint.clicked.connect(self.handle_print)
            self.buttonPrint.setStyleSheet(
                "color: navy;  background-color: gainsboro")
            self.buttonSluit = QPushButton('Sluiten', self)
            self.buttonSluit.clicked.connect(lambda: sluit(self, m_email))
            self.buttonSluit.setStyleSheet(
                "color: navy;  background-color: gainsboro")
            self.buttonInfo = QPushButton('Info', self)
            self.buttonInfo.clicked.connect(lambda: info(self))
            self.buttonInfo.setStyleSheet(
                "color: navy;  background-color: gainsboro")

            layout = QGridLayout(self)
            layout.addWidget(self.chart_view, 0, 0, 1, 4)
            layout.addWidget(self.buttonInfo, 1, 0)
            layout.addWidget(self.buttonSluit, 1, 1)
            layout.addWidget(self.buttonPrint, 1, 2)
            layout.addWidget(self.buttonPreview, 1, 3)
            self.create_chart()

        def create_chart(self):
            self.chart.setTitle(
                'Grafiek aantal externe werken per status - opnameweek ' +
                jrwk)
            font = QFont("Sans Serif", 10)
            font.setWeight(QFont.Bold)
            self.chart.setTitleFont(font)
            set0 = QBarSet('Aantal externe werken per status')

            set0 << rpr[0][2] << rpr[1][2] << rpr[2][2] << rpr[3][2] << rpr[4][
                2] << rpr[5][2] << rpr[6][2] << rpr[7][2]

            barseries = QBarSeries()
            barseries.append(set0)
            barseries.append

            categories = [
                "Status A", "Status B", "Status C", "Status D", "Status E",
                "Status F", "Status G", "Status H"
            ]

            self.chart.addSeries(barseries)
            self.chart.axisX()
            self.chart.createDefaultAxes()
            axisX = QBarCategoryAxis()
            axisX.append(categories)
            self.chart.setAxisX(axisX, barseries)
            axisX.setRange(str("Status A"), str("Status H"))

        def handle_print(self):
            printer = QPrinter(QPrinter.HighResolution)
            printer.setOrientation(QPrinter.Landscape)
            dialog = QPrintDialog(printer, self)
            if dialog.exec_() == QPrintDialog.Accepted:
                self.handle_paint_request(printer)

        def handle_preview(self):
            dialog = QPrintPreviewDialog()
            dialog.setWindowIcon(QIcon('./images/logos/logo.jpg'))
            dialog.setWindowFlags(dialog.windowFlags()
                                  | Qt.WindowSystemMenuHint
                                  | Qt.WindowMinMaxButtonsHint)
            dialog.resize(1485, 990)
            #dialog.setMinimumSize(1485, 990)
            dialog.paintRequested.connect(self.handle_paint_request)
            dialog.exec_()

        def handle_paint_request(self, printer):
            painter = QPainter(printer)
            painter.setViewport(self.chart_view.rect())
            painter.setWindow(self.chart_view.rect())
            printer.setPageOrientation(QPageLayout.Landscape)
            self.chart_view.render(painter)
            painter.end()
示例#3
0
    def addSeries(
            self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart,
            _axis_x: QValueAxis, _axis_y: QValueAxis
    ):
        series = QLineSeries()
        series.setName(self.name)
        for x, y in zip(self.x_list, self.y_list):
            series.append(_x2idx[x], y)
        if self.color is not None:
            series.setColor(self.color)

        _chart.addSeries(series)
        _chart.setAxisX(_axis_x, series)
        _chart.setAxisY(_axis_y, series)

        if self.show_value:
            self.createShow()
示例#4
0
    def addSeries(
            self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart,
            _axis_x: QValueAxis, _axis_y: QValueAxis
    ):
        bar_set = QBarSet(self.name)
        tmp_dict = dict(zip(self.x_list, self.y_list))
        for k in _idx2x:
            if k in tmp_dict.keys():
                bar_set.append(tmp_dict[k])
            else:
                bar_set.append(0)

        if self.color is not None:
            bar_set.setColor(self.color)

        bar_series = QBarSeries()
        bar_series.append(bar_set)
        _chart.addSeries(bar_series)
        _chart.setAxisX(_axis_x, bar_series)
        _chart.setAxisY(_axis_y, bar_series)

        if self.show_value:
            self.createShow()
示例#5
0
    def addSeries(
            self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart,
            _axis_x: QValueAxis, _axis_y: QValueAxis
    ):
        series = QCandlestickSeries()
        series.setName(self.name)

        for x, y in zip(self.x_list, self.y_list):
            series.append(QCandlestickSet(*y, _x2idx[x]))
        if self.inc_color is not None:
            series.setIncreasingColor(self.inc_color)
        else:
            series.setIncreasingColor(QColor('#c41919'))
        if self.dec_color is not None:
            series.setDecreasingColor(self.dec_color)
        else:
            series.setDecreasingColor(QColor('#009f9f'))

        _chart.addSeries(series)
        _chart.setAxisX(_axis_x, series)
        _chart.setAxisY(_axis_y, series)

        if self.show_value:
            self.createShow()
示例#6
0
class LineChartView(QChartView):
    def __init__(self):
        super(LineChartView, self).__init__()
        self.resize(800, 600)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
        # 自定义x轴label

    def CreatePlot(self, NumSection, Alltime, PlotData, type, name='列车调度'):
        if type == 1:
            self.initChart(NumSection, Alltime, PlotData, name)
        else:
            self.initProgressChart(NumSection, Alltime, PlotData, name)

        # 提示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(998)
        #self.lineItem.hide()
        self.lineItem.show()
        # 一些固定计算,减少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(LineChartView, self).resizeEvent(event)
        # 当窗口大小改变时需要重新计算
        # 坐标系中左上角顶点
        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) / (self._chart.axisX().tickCount() - 1)

    def mouseMoveEvent(self, event):
        super(LineChartView, self).mouseMoveEvent(event)
        pos = event.pos()
        # 把鼠标位置所在点转换为对应的xy值
        x = self._chart.mapToValue(pos).x()
        y = self._chart.mapToValue(pos).y()
        index = round(int(x / self.step_x) * self.step_x) + round(
            x % self.step_x) - 1
        #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.x(), self.point_top.y(), pos_x.x(),
                                  self.point_bottom.y())
            self.lineItem.show()
            try:
                title = ""
            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()

    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 initProgressChart(self, MaxTime, Allgen, PlotData, name):
        MinTime = 100000
        for k in PlotData:
            if min(k[1]) < MinTime:
                MinTime = min(k[1])
        self._chart = QChart(title=name)
        self._chart.setAcceptHoverEvents(True)
        # Series动画

        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        # dataTable = [
        #     ["邮件营销", [120, 132, 101, 134, 90, 230]],
        #     ["联盟广告", [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, label_list in PlotData:
            series = QLineSeries(self._chart)
            for j, v in zip(label_list, 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(11)  # x轴设置7个刻度
        axisX.setGridLineVisible(False)  # 隐藏从x轴往上的线条
        axisY = self._chart.axisY()
        axisY.setTickCount(10)  # y轴设置7个刻度
        #axisY.setRange(0, MaxTime)  # 设置y轴范围
        # 自定义x轴
        # axis_x = QCategoryAxis(
        #     self._chart, labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
        # axis_x.setTickCount(Allgen)
        # axis_x.setGridLineVisible(False)
        # min_x = axisX.min()
        # for i in range(0, Allgen + 1):
        #     axis_x.append(str(i), min_x + i)
        # self._chart.setAxisX(axis_x, self._chart.series()[-1])

        # 自定义y轴
        # axis_y = QCategoryAxis(
        #     self._chart, labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
        # axis_y.setTickCount(round(MaxTime)-max(round(MinTime)-10,0))
        # axis_y.setRange(max(round(MinTime)-10,0), round(MaxTime))
        # for i in range(max(round(MinTime)-10,0), round(MaxTime) + 1):
        #     axis_y.append('%i' % i, i)
        # self._chart.setAxisY(axis_y, self._chart.series()[-1])
        # 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)

    def initChart(self, NumSection, Alltime, PlotData, name):
        self._chart = QChart(title=name)
        self._chart.setAcceptHoverEvents(True)
        # Series动画
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        # dataTable = [
        #     ["邮件营销", [120, 132, 101, 134, 90, 230]],
        #     ["联盟广告", [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, label_list in PlotData:
            series = QLineSeries(self._chart)
            for j, v in zip(label_list, 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(Alltime)  # x轴设置7个刻度
        axisX.setGridLineVisible(False)  # 隐藏从x轴往上的线条
        axisY = self._chart.axisY()
        axisY.setTickCount(NumSection)  # y轴设置7个刻度
        axisY.setRange(0, NumSection)  # 设置y轴范围
        # 自定义x轴
        axis_x = QCategoryAxis(
            self._chart,
            labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue)
        axis_x.setTickCount(Alltime + 1)
        axis_x.setGridLineVisible(False)
        min_x = axisX.min()
        for i in range(0, Alltime + 1):
            axis_x.append(str(i), min_x + i)
        self._chart.setAxisX(axis_x, self._chart.series()[-1])

        # 自定义y轴
        axis_y = QCategoryAxis(
            self._chart, labelsPosition=QCategoryAxis.AxisLabelsPositionCenter)
        axis_y.setTickCount(NumSection)
        axis_y.setRange(0, NumSection)
        for i in range(0, NumSection + 1):
            axis_y.append('section%i' % (NumSection - i + 1), i)
        self._chart.setAxisY(axis_y, self._chart.series()[-1])
        # 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)
示例#7
0
class PlotterPane(QChartView):
    """
    This plotter widget makes viewing sensor data easy!

    This widget represents a chart that will look for tuple data from
    the MicroPython REPL, Python 3 REPL or Python 3 code runner and will
    auto-generate a graph.
    """

    data_flood = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        # Holds the raw input to be checked for actionable data to display.
        self.input_buffer = []
        # Holds the raw actionable data detected while plotting.
        self.raw_data = []
        self.setObjectName("plotterpane")
        self.max_x = 100  # Maximum value along x axis
        self.max_y = 1000  # Maximum value +/- along y axis
        self.flooded = False  # Flag to indicate if data flooding is happening.

        # Holds deques for each slot of incoming data (assumes 1 to start with)
        self.data = [deque([0] * self.max_x)]
        # Holds line series for each slot of incoming data (assumes 1 to start
        # with).
        self.series = [QLineSeries()]

        # Ranges used for the Y axis (up to 1000, after which we just double
        # the range).
        self.y_ranges = [1, 5, 10, 25, 50, 100, 250, 500, 1000]

        # Set up the chart with sensible defaults.
        self.chart = QChart()
        self.chart.legend().hide()
        self.chart.addSeries(self.series[0])
        self.axis_x = QValueAxis()
        self.axis_y = QValueAxis()
        self.axis_x.setRange(0, self.max_x)
        self.axis_y.setRange(-self.max_y, self.max_y)
        self.axis_x.setLabelFormat("time")
        self.axis_y.setLabelFormat("%d")
        self.chart.setAxisX(self.axis_x, self.series[0])
        self.chart.setAxisY(self.axis_y, self.series[0])
        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)

    def process_tty_data(self, data):
        """
        Takes raw bytes and, if a valid tuple is detected, adds the data to
        the plotter.

        The the length of the bytes data > 1024 then a data_flood signal is
        emitted to ensure Mu can take action to remain responsive.
        """
        # Data flooding guards.
        if self.flooded:
            return
        if len(data) > 1024:
            self.flooded = True
            self.data_flood.emit()
            return
        data = data.replace(b"\r\n", b"\n")
        self.input_buffer.append(data)
        # Check if the data contains a Python tuple, containing numbers, on a
        # single line (i.e. ends with \n).
        input_bytes = b"".join(self.input_buffer)
        lines = input_bytes.split(b"\n")
        for line in lines:
            if line.startswith(b"(") and line.endswith(b")"):
                # Candidate tuple. Extract the raw bytes into a numeric tuple.
                raw_values = [val.strip() for val in line[1:-1].split(b",")]
                numeric_values = []
                for raw in raw_values:
                    try:
                        numeric_values.append(int(raw))
                        # It worked, so move onto the next value.
                        continue
                    except ValueError:
                        # Try again as a float.
                        pass
                    try:
                        numeric_values.append(float(raw))
                    except ValueError:
                        # Not an int or float, so ignore this value.
                        continue
                if numeric_values:
                    # There were numeric values in the tuple, so use them!
                    self.add_data(tuple(numeric_values))
        # Reset the input buffer.
        self.input_buffer = []
        if lines[-1]:
            # Append any bytes that are not yet at the end of a line, for
            # processing next time we read data from self.connection.
            self.input_buffer.append(lines[-1])

    def add_data(self, values):
        """
        Given a tuple of values, ensures there are the required number of line
        series, add the data to the line series, update the range of the chart
        so the chart displays nicely.
        """
        # Store incoming data to dump as CSV at the end of the session.
        self.raw_data.append(values)
        # Check the number of incoming values.
        if len(values) != len(self.series):
            # Adjust the number of line series.
            value_len = len(values)
            series_len = len(self.series)
            if value_len > series_len:
                # Add new line series.
                for i in range(value_len - series_len):
                    new_series = QLineSeries()
                    self.chart.addSeries(new_series)
                    self.chart.setAxisX(self.axis_x, new_series)
                    self.chart.setAxisY(self.axis_y, new_series)
                    self.series.append(new_series)
                    self.data.append(deque([0] * self.max_x))
            else:
                # Remove old line series.
                for old_series in self.series[value_len:]:
                    self.chart.removeSeries(old_series)
                self.series = self.series[:value_len]
                self.data = self.data[:value_len]

        # Add the incoming values to the data to be displayed, and compute
        # max range.
        max_ranges = []
        for i, value in enumerate(values):
            self.data[i].appendleft(value)
            max_ranges.append(max([max(self.data[i]), abs(min(self.data[i]))]))
            if len(self.data[i]) > self.max_x:
                self.data[i].pop()

        # Re-scale y-axis.
        max_y_range = max(max_ranges)
        y_range = bisect.bisect_left(self.y_ranges, max_y_range)
        if y_range < len(self.y_ranges):
            self.max_y = self.y_ranges[y_range]
        elif max_y_range > self.max_y:
            self.max_y += self.max_y
        elif max_y_range < self.max_y / 2:
            self.max_y = self.max_y / 2
        self.axis_y.setRange(-self.max_y, self.max_y)

        # Ensure floats are used to label y axis if the range is small.
        if self.max_y <= 5:
            self.axis_y.setLabelFormat("%2.2f")
        else:
            self.axis_y.setLabelFormat("%d")

        # Update the line series with the data.
        for i, line_series in enumerate(self.series):
            line_series.clear()
            xy_vals = []
            for j in range(self.max_x):
                val = self.data[i][self.max_x - 1 - j]
                xy_vals.append((j, val))
            for point in xy_vals:
                line_series.append(*point)

    def set_theme(self, theme):
        """
        Sets the theme / look for the plotter pane.
        """
        if theme == "day":
            self.chart.setTheme(QChart.ChartThemeLight)
        elif theme == "night":
            self.chart.setTheme(QChart.ChartThemeDark)
        else:
            self.chart.setTheme(QChart.ChartThemeHighContrast)
示例#8
0
class Chart(QChartView):
    def __init__(self):
        self.chart = QChart()

        QChartView.__init__(self, self.chart)

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

        self.xRange = [0, 100]
        self.yRange = [-100, 100]

        self.curve = []
        self.scatterCurve = []

        self.setBackgroundBrush(QColor('#D8D8D8'))

        self.setRenderHint(QPainter.Antialiasing)
        self.chart.setAnimationOptions(QChart.NoAnimation)
        self.chart.legend().setVisible(True)
        self.chart.legend().setAlignment(Qt.AlignBottom)
        self.chart.legend().setLabelColor(Qt.white)
        self.chart.legend().setMarkerShape(QLegend.MarkerShapeFromSeries)
        self.chart.setBackgroundBrush(QColor('#00004D'))

        penAxisGrid = QPen(QColor('#F2F2F2'))
        penAxisGrid.setWidthF(0.5)
        penAxisMinorGrid = QPen(QColor('#A4A4A4'))
        penAxisMinorGrid.setWidthF(0.3)

        self.axisX.setGridLinePen(penAxisGrid)
        self.axisX.setLinePen(penAxisGrid)
        self.axisY.setGridLinePen(penAxisGrid)
        self.axisY.setLinePen(penAxisGrid)

        self.axisX.setMinorGridLinePen(penAxisMinorGrid)
        self.axisY.setMinorGridLinePen(penAxisMinorGrid)

        self.axisX.setLabelsColor(Qt.white)
        self.axisY.setLabelsColor(Qt.white)

        self.axisX.setMinorTickCount(4)
        self.axisY.setMinorTickCount(4)

        self.axisX.setTitleBrush(Qt.white)
        self.axisY.setTitleBrush(Qt.white)

        self.axisX.setTitleText('Time')
        self.axisY.setTitleText('Signal Amplitude')

        self.axisX.setTickCount(11)
        self.axisY.setTickCount(11)
        self.axisX.setRange(self.xRange[0], self.xRange[1])
        self.axisY.setRange(self.yRange[0], self.yRange[1])

    def setAddSerie(self, name, color):
        self.curve.append(QLineSeries())
        pen = self.curve[len(self.curve) - 1].pen()

        pen.setColor(QColor(color))
        pen.setWidthF(2)
        self.curve[len(self.curve) - 1].setPen(pen)

        self.curve[len(self.curve) - 1].setName(name)

        self.chart.addSeries(self.curve[len(self.curve) - 1])

        self.chart.setAxisX(self.axisX, self.curve[len(self.curve) - 1])
        self.chart.setAxisY(self.axisY, self.curve[len(self.curve) - 1])

    def setAddScatterSerie(self, color):
        self.scatterCurve.append(QScatterSeries())

        pen = self.scatterCurve[len(self.scatterCurve) - 1].pen()
        pen.setColor(QColor(color))
        pen.setWidthF(1)
        self.scatterCurve[len(self.scatterCurve) - 1].setPen(pen)
        self.scatterCurve[len(self.scatterCurve) - 1].setColor(QColor(color))
        self.scatterCurve[len(self.scatterCurve) - 1].setMarkerSize(10)

        self.chart.addSeries(self.scatterCurve[len(self.scatterCurve) - 1])

        self.chart.setAxisX(self.axisX,
                            self.scatterCurve[len(self.scatterCurve) - 1])
        self.chart.setAxisY(self.axisY,
                            self.scatterCurve[len(self.scatterCurve) - 1])

    def setDataChartScatter(self, xData, yData1, yData2):
        if xData > self.xRange[1]:
            addValue = xData - self.xRange[1]

            if self.xRange[0] is not 0:
                self.xRange[0] = self.xRange[0] + addValue

            self.xRange[1] = self.xRange[1] + addValue
            self.axisX.setRange(self.xRange[0], self.xRange[1])

        self.curve[0].append(xData, yData1)
        self.curve[1].append(xData, yData2)
        self.scatterCurve[0].append(xData, yData1)
        self.scatterCurve[1].append(xData, yData2)

    def setDataChart(self, xData, yData1, yData2):
        if xData > self.xRange[1]:
            addValue = xData - self.xRange[1]

            if self.xRange[0] is not 0:
                self.xRange[0] = self.xRange[0] + addValue

            self.xRange[1] = self.xRange[1] + addValue
            self.axisX.setRange(self.xRange[0], self.xRange[1])

        self.curve[0].append(xData, yData1)
        self.curve[1].append(xData, yData2)

    def setRangeY(self, yRange, autoscale):
        if autoscale:

            if yRange[0] == 0 and yRange[1] == 0:
                yRange[0] = -0.50
                yRange[1] = 0.50

            elif yRange[0] == 0:
                yRange[0] = -0.10
                yRange[1] = yRange[1] * 1.10

            elif yRange[1] == 0:
                yRange[0] = yRange[0] * 1.10
                yRange[1] = 0.10

            else:

                if yRange[0] < 0:
                    yRange[0] = yRange[0] * 1.10

                else:
                    yRange[0] = yRange[0] - (yRange[0] * 0.10)

                if yRange[1] < 0:
                    yRange[1] = yRange[1] - (yRange[1] * 0.10)

                else:
                    yRange[1] = yRange[1] * 1.10

            self.axisY.setRange(yRange[0], yRange[1])

        else:
            self.axisY.setRange(yRange[0], yRange[1])

    def setRangeX(self, xRange):
        self.axisX.setRange(xRange[0], xRange[1])

    def getRangeX(self):
        return self.xRange

    def setAxisXName(self, name):
        self.axisX.setTitleText(name)

    def setAxisYName(self, name):
        self.axisY.setTitleText(name)

    def setAxisXTickCount(self, tick):
        self.axisX.setTickCount(tick)

    def setAxisYTickCount(self, tick):
        self.axisY.setTickCount(tick)

    def initSerie(self):
        self.curve.clear()

    def initSeries(self):
        self.curve[0].clear()
        self.curve[1].clear()
示例#9
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 = np.fft.rfftfreq(250, 2 * (1 / 512))[2:50]
        y_axis = data
        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']))
    def plotgraph(self):
        print(self.button_group.checkedButton().text())
        collection_name = self.button_group.checkedButton().text()
        mycol = mydb[collection_name]
        font = QtGui.QFont()
        font.setPointSize(9)

        ############### Query from the SKU(collection) for total number of good/bad count ##############

        global y1,y2,y3,y4,y5,y6,y7,y8,z1,z2,z3,z4,z5,z6,z7,z8
        ls0 =[]
        myquery0 = {"Status": "Bad", "SKU id":"S1" }
        for x in mycol.find(myquery0):
            ls0.append(x)
        y1 = len(ls0)

        ls1 =[]
        myquery1 = {"Status": "Good", "SKU id":"S1" }
        for x in mycol.find(myquery1):
            ls1.append(x)
        z1 = len(ls1)


        ls2 =[]
        myquery2 = {"Status": "Bad", "SKU id":"S2" }
        for x in mycol.find(myquery2):
            ls2.append(x)
        y2 = len(ls2)

        ls3 =[]
        myquery3 = {"Status": "Good", "SKU id":"S2" }
        for x in mycol.find(myquery3):
            ls3.append(x)
        z2 = len(ls3)


        ls4 =[]
        myquery4 = {"Status": "Bad", "SKU id":"S3" }
        for x in mycol.find(myquery4):
            ls4.append(x)
        y3 = len(ls4)

        ls5 =[]
        myquery5 = {"Status": "Good", "SKU id":"S3" }
        for x in mycol.find(myquery5):
            ls5.append(x)
        z3 = len(ls5)


        ls6 =[]
        myquery6 = {"Status": "Bad", "SKU id":"S4" }
        for x in mycol.find(myquery6):
            ls6.append(x)
        y4 = len(ls6)

        ls7 =[]
        myquery7 = {"Status": "Good", "SKU id":"S4" }
        for x in mycol.find(myquery7):
            ls7.append(x)
        z4 = len(ls7)


        ls8 =[]
        myquery8 = {"Status": "Bad", "SKU id":"S5" }
        for x in mycol.find(myquery8):
            ls8.append(x)
        y5 = len(ls8)

        ls9 =[]
        myquery9 = {"Status": "Good", "SKU id":"S5" }
        for x in mycol.find(myquery9):
            ls9.append(x)
        z5 = len(ls9)


        ls10 =[]
        myquery10 = {"Status": "Bad", "SKU id":"S6" }
        for x in mycol.find(myquery10):
            ls10.append(x)
        y6 = len(ls10)

        ls11 =[]
        myquery11 = {"Status": "Good", "SKU id":"S6" }
        for x in mycol.find(myquery11):
            ls11.append(x)
        z6 = len(ls11)


        ls12 =[]
        myquery12 = {"Status": "Bad", "SKU id":"S7" }
        for x in mycol.find(myquery12):
            ls12.append(x)
        y7 = len(ls12)

        ls13 =[]
        myquery13 = {"Status": "Good", "SKU id":"S7" }
        for x in mycol.find(myquery13):
            ls13.append(x)
        z7 = len(ls13)


        ls14 =[]
        myquery14 = {"Status": "Bad", "SKU id":"S8" }
        for x in mycol.find(myquery14):
            ls14.append(x)
        y8 = len(ls14)

        ls15 =[]
        myquery15 = {"Status": "Good", "SKU id":"S8" }
        for x in mycol.find(myquery15):
            ls15.append(x)
        z8 = len(ls15)

        self.clearLayout(lay)
        #########################################################################
        set0 = QBarSet("Good")
        set1 = QBarSet("Bad")
            
        # set0.append([5400, 4900, 5100, 5400, 5000, 4800, 4500, 3000])
        # set1.append([600, 800, 900, 600, 1000, 1200, 1500, 3000])
        set0.append([z1,z2,z3,z4,z5,z6,z7,z8])
        set1.append([y1,y2,y3,y4,y5,y6,y7,y8])

        series = QStackedBarSeries()
        series.append(set0)
        series.append(set1)
        
        chart = QChart()
        chart.addSeries(series)
        chart.setTitle("Production Count")
        chart.setAnimationOptions(QChart.SeriesAnimations)
            
        categories = ["12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00"]
        axis = QBarCategoryAxis()
        axis.append(categories)
        chart.createDefaultAxes()
        chart.setAxisX(axis, series)

        axisY = QValueAxis()
        axisY.setRange(0, 6000)
        axisY.setTitleText("Units")
        chart.setAxisY(axisY)

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

        chartView = QChartView(chart)
        chartView.setRenderHint(QPainter.Antialiasing)
        chartView.setToolTip('Good Units v/s Bad Units')

        comboBox = QtWidgets.QComboBox()
        comboBox.setGeometry(QtCore.QRect(20, 20, 171, 31))
        comboBox.setObjectName("comboBox")
        comboBox.addItem("SKU Selection")
        comboBox.addItem("Analytics View")
        comboBox.activated[str].connect(self.bargraph)
        comboBox.setToolTip("Select an Option!")    # Message to show when mouse hover
        comboBox.setFont(font)

        lay.addWidget(comboBox,0)
        lay.addWidget(chartView,1)
示例#11
0
class widgetFDChart(QtWidgets.QWidget, qdesignFDChart.Ui_Form):
    def __init__(self, parent=None):
        super(widgetFDChart, self).__init__(parent)
        self.setupUi(self)
        tribchartmenustyle(self)
        # SetUp for Chart to Display Distribution curves and inputs.
        self.chart = QChart()
        self.chart.legend().setVisible(False)

        self.chart.axisX = QValueAxis()
        self.chart.axisY = QValueAxis()
        self.chart.axisX.setTickCount(10)
        self.chart.axisY.setTickCount(10)
        self.chart.axisX.setTitleText("Value")
        self.chart.axisY.setTitleText("Probability")

        self.chartview = QChartView(self.chart)
        self.verticalLayout.addWidget(self.chartview)
        #        self.setAxesMinMax(-3,3,0.01,1.5)
        self.chartview.setRenderHint(QPainter.Antialiasing)
        # self.legend().setVisible(True)
        # self.setAnimationOptions(QChart.SeriesAnimations)
        # self.legend().setAlignment(Qt.AlignBottom)

        # Connect Buttons
        self.pushButtonExportPNG.pressed.connect(self._onActionSavePNG)

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

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

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

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

    def addDistrLine(self, type, n, kstats):
        data = distr.distrpdf(type, n, **kstats)
        xmin = min(data['X'])
        xmax = max(data['X'])
        ymin = min(data['Y'])
        ymax = max(data['Y'])
        self.lineDist = XLineSeries(data, xkey='X')[0]
        self.chart.addSeries(self.lineDist)
        self.setAxes(self.lineDist)
        xscal = 0.1 * (xmax - xmin)
        yscal = 0.1 * (ymax - ymin)
        self.setAxesMinMax(xmin - xscal, xmax + xscal, ymin, ymax + yscal)

    def updateChart(self, tabledata):
        self.activeDist = tabledata[0]
        self.kstats = tabledata[1]
        self.chart.removeAllSeries()
        self.addDistrLine(self.activeDist, 100, self.kstats)

    @pyqtSlot(str)
    def paintChart(self, filename):
        #pixmap = QPixmap()
        pixmap = self.chartview.grab()
        pixmap.save(filename)

    def _onActionSavePNG(self):
        pngfile = QtWidgets.QFileDialog.getSaveFileName(
            self, caption='Export PNG As', directory='~', filter='*.png')
        #try:
        self.paintChart(pngfile[0])
示例#12
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(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()

    def resizeEvent(self, event):
        super(ChartView, self).resizeEvent(event)
        # 当窗口大小改变时需要重新计算
        # 坐标系中左上角顶点
        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) / \
                      (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.x(), self.point_top.y(),
                                  pos_x.x(), self.point_bottom.y())
            self.lineItem.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()

    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])
        # 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)
示例#13
0
文件: panes.py 项目: martinohanlon/mu
class PlotterPane(QChartView):
    """
    This plotter widget makes viewing sensor data easy!

    This widget represents a chart that will look for tuple data from
    the MicroPython REPL, Python 3 REPL or Python 3 code runner and will
    auto-generate a graph.
    """

    data_flood = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        # Holds the raw input to be checked for actionable data to display.
        self.input_buffer = []
        # Holds the raw actionable data detected while plotting.
        self.raw_data = []
        self.setObjectName('plotterpane')
        self.max_x = 100  # Maximum value along x axis
        self.max_y = 1000  # Maximum value +/- along y axis
        self.flooded = False  # Flag to indicate if data flooding is happening.

        # Holds deques for each slot of incoming data (assumes 1 to start with)
        self.data = [deque([0] * self.max_x), ]
        # Holds line series for each slot of incoming data (assumes 1 to start
        # with).
        self.series = [QLineSeries(), ]

        # Ranges used for the Y axis (up to 1000, after which we just double
        # the range).
        self.y_ranges = [1, 5, 10, 25, 50, 100, 250, 500, 1000]

        # Set up the chart with sensible defaults.
        self.chart = QChart()
        self.chart.legend().hide()
        self.chart.addSeries(self.series[0])
        self.axis_x = QValueAxis()
        self.axis_y = QValueAxis()
        self.axis_x.setRange(0, self.max_x)
        self.axis_y.setRange(-self.max_y, self.max_y)
        self.axis_x.setLabelFormat("time")
        self.axis_y.setLabelFormat("%d")
        self.chart.setAxisX(self.axis_x, self.series[0])
        self.chart.setAxisY(self.axis_y, self.series[0])
        self.setChart(self.chart)
        self.setRenderHint(QPainter.Antialiasing)

    def process_bytes(self, data):
        """
        Takes raw bytes and, if a valid tuple is detected, adds the data to
        the plotter.

        The the length of the bytes data > 1024 then a data_flood signal is
        emitted to ensure Mu can take action to remain responsive.
        """
        # Data flooding guards.
        if self.flooded:
            return
        if len(data) > 1024:
            self.flooded = True
            self.data_flood.emit()
            return
        data = data.replace(b'\r\n', b'\n')
        self.input_buffer.append(data)
        # Check if the data contains a Python tuple, containing numbers, on a
        # single line (i.e. ends with \n).
        input_bytes = b''.join(self.input_buffer)
        lines = input_bytes.split(b'\n')
        for line in lines:
            if line.startswith(b'(') and line.endswith(b')'):
                # Candidate tuple. Extract the raw bytes into a numeric tuple.
                raw_values = [val.strip() for val in line[1:-1].split(b',')]
                numeric_values = []
                for raw in raw_values:
                    try:
                        numeric_values.append(int(raw))
                        # It worked, so move onto the next value.
                        continue
                    except ValueError:
                        # Try again as a float.
                        pass
                    try:
                        numeric_values.append(float(raw))
                    except ValueError:
                        # Not an int or float, so ignore this value.
                        continue
                if numeric_values:
                    # There were numeric values in the tuple, so use them!
                    self.add_data(tuple(numeric_values))
        # Reset the input buffer.
        self.input_buffer = []
        if lines[-1]:
            # Append any bytes that are not yet at the end of a line, for
            # processing next time we read data from self.serial.
            self.input_buffer.append(lines[-1])

    def add_data(self, values):
        """
        Given a tuple of values, ensures there are the required number of line
        series, add the data to the line series, update the range of the chart
        so the chart displays nicely.
        """
        # Store incoming data to dump as CSV at the end of the session.
        self.raw_data.append(values)
        # Check the number of incoming values.
        if len(values) != len(self.series):
            # Adjust the number of line series.
            value_len = len(values)
            series_len = len(self.series)
            if value_len > series_len:
                # Add new line series.
                for i in range(value_len - series_len):
                    new_series = QLineSeries()
                    self.chart.addSeries(new_series)
                    self.chart.setAxisX(self.axis_x, new_series)
                    self.chart.setAxisY(self.axis_y, new_series)
                    self.series.append(new_series)
                    self.data.append(deque([0] * self.max_x))
            else:
                # Remove old line series.
                for old_series in self.series[value_len:]:
                    self.chart.removeSeries(old_series)
                self.series = self.series[:value_len]
                self.data = self.data[:value_len]

        # Add the incoming values to the data to be displayed, and compute
        # max range.
        max_ranges = []
        for i, value in enumerate(values):
            self.data[i].appendleft(value)
            max_ranges.append(max([max(self.data[i]), abs(min(self.data[i]))]))
            if len(self.data[i]) > self.max_x:
                self.data[i].pop()

        # Re-scale y-axis.
        max_y_range = max(max_ranges)
        y_range = bisect.bisect_left(self.y_ranges, max_y_range)
        if y_range < len(self.y_ranges):
            self.max_y = self.y_ranges[y_range]
        elif max_y_range > self.max_y:
            self.max_y += self.max_y
        elif max_y_range < self.max_y / 2:
            self.max_y = self.max_y / 2
        self.axis_y.setRange(-self.max_y, self.max_y)

        # Ensure floats are used to label y axis if the range is small.
        if self.max_y <= 5:
            self.axis_y.setLabelFormat("%2.2f")
        else:
            self.axis_y.setLabelFormat("%d")

        # Update the line series with the data.
        for i, line_series in enumerate(self.series):
            line_series.clear()
            xy_vals = []
            for j in range(self.max_x):
                val = self.data[i][self.max_x - 1 - j]
                xy_vals.append((j, val))
            for point in xy_vals:
                line_series.append(*point)

    def set_theme(self, theme):
        """
        Sets the theme / look for the plotter pane.
        """
        if theme == 'day':
            self.chart.setTheme(QChart.ChartThemeLight)
        elif theme == 'night':
            self.chart.setTheme(QChart.ChartThemeDark)
        else:
            self.chart.setTheme(QChart.ChartThemeHighContrast)
示例#14
0
class widgetIDChart(QtWidgets.QWidget, qdesignFDChart.Ui_Form):

    actionRequestFromTable = pyqtSignal()

    def __init__(self, parent=None):
        super(widgetIDChart, self).__init__(parent)
        self.setupUi(self)
        tribchartmenustyle(self)
        # Default Settings
        self.nbins = 10

        # Extra Menu Items
        # Distribution Type Selection
        self.comboBoxDistr = XComboBoxDict(self)
        self.comboBoxDistr.setMinimumSize(QtCore.QSize(100, 30))

        self.knowndistr = distr._distrnames()
        self.comboBoxDistr.addItem({'None': 'None'})
        self.comboBoxDistr.addItems(self.knowndistr)
        self.comboBoxDistr.setObjectName("comboBoxDistr")
        self.horizontalLayout.insertWidget(3, self.comboBoxDistr)
        self.comboBoxDistr.currentTextChanged.connect(
            self.onComboBoxDistrChanged)
        self.activeDist = str(
            self.distrfromname(self.comboBoxDistr.currentText()))

        # Spinbox Label
        self.spinBoxLab = QtWidgets.QLabel(self)
        self.spinBoxLab.setText('  Bins: ')
        self.horizontalLayout.insertWidget(4, self.spinBoxLab)

        # Histogram N columns quick select spin box
        self.spinBoxDistr = QtWidgets.QSpinBox(self)
        self.spinBoxDistr.setMinimumSize(QtCore.QSize(50, 30))
        self.spinBoxDistr.setRange(2, 100)
        self.spinBoxDistr.setSingleStep(1)
        self.spinBoxDistr.setValue(self.nbins)
        self.spinBoxDistr.setObjectName("spinBoxDistr")
        self.horizontalLayout.insertWidget(5, self.spinBoxDistr)
        self.spinBoxDistr.valueChanged.connect(self.onSpinBoxChanged)

        # SetUp for Chart to Display Distribution curves and inputs.
        self.chart = QChart()
        self.chart.legend().setVisible(False)

        # SetUp Visible Chart Axes
        self.chart.axisX = QValueAxis()
        self.chart.axisY = QValueAxis()
        self.chart.axisX.setTickCount(10)
        self.chart.axisY.setTickCount(2)
        self.chart.axisX.setTitleText("Value")
        self.chart.axisY.setTitleText("Probability")

        # HistogramAxis
        self.chart.axisHist = QValueAxis()
        self.chart.addAxis(self.chart.axisHist, Qt.AlignRight)
        self.chart.axisHist.setTickCount(10)
        self.chart.axisHist.setTitleText("Count")
        self.chart.axisBins = QValueAxis()
        self.chart.addAxis(self.chart.axisBins, Qt.AlignBottom)
        self.chart.axisBins.setVisible(False)

        # Add Chart to Chartview and Chartview to Widget
        self.chartview = QChartView(self.chart)
        self.verticalLayout.addWidget(self.chartview)
        self.chartview.setRenderHint(QPainter.Antialiasing)

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

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

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

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

    def setRawData(self, datar):
        self.datar = datar
        self.ndata = len(self.datar)

    def addDistrLine(self, n, kstats):
        self.kstats = kstats
        data = distr.distrpdf(self.activeDist, n, **kstats)
        xmin = min(data['X'])
        xmax = max(data['X'])
        ymin = min(data['Y'])
        ymax = max(data['Y'])
        xscal = 0.1 * (xmax - xmin)
        yscal = 0.1 * (ymax - 0)
        self.chart.axisY.setRange(0, ymax + yscal)
        self.lineDist = XLineSeries(data, xkey='X')[0]

    def addHistLine(self):
        # fits a distribution to the histogram and draws a line
        self.kstats = distr.distrfit(self.activeDist, self.datar)  #hist[0])
        self.addDistrLine(1000, self.kstats)

    def addHistogram(self, nbins):
        # accepts a data array datar and int nbins to calculate a histogram
        self.nbins = nbins
        self.spinBoxDistr.setValue(nbins)
        try:
            self.hist = np.histogram(self.datar, bins=nbins)
        except:
            pass
            # create a function which displays a msg in the middle of the chart by raising a data error of sorts
        self.histseries = XDictSet({'Hist': self.hist[0]})
        # return barsets
        self.histsets = self.histseries.findChildren(QBarSet)

    def updateChart(self):
        self.chart.removeAllSeries()
        hmin = self.hist[1][0]
        hmax = self.hist[1][-1]
        cmax = max(self.hist[0]) + 1
        binwidth = self.hist[1][1] - self.hist[1][0]
        binscale = 1 / binwidth

        if self.activeDist == 'None':
            self.chart.axisY.setVisible(False)
            self.chart.axisX.setMin(hmin)
            self.chart.axisX.setMax(hmax)
        else:
            self.chart.axisY.setVisible(True)

        try:  # Add histogram bars
            self.chart.axisBins.setRange(-1, self.nbins)
            self.chart.axisHist.setRange(0, cmax)
            self.chart.addSeries(self.histseries)
            self.histseries.setBarWidth(1)

            # Set Colours
            self.histsets[0].setColor(tribColours.tribBlue)

            # Update Axes
            self.chart.setAxisX(self.chart.axisBins, self.histseries)
            self.chart.setAxisY(self.chart.axisHist, self.histseries)
        except NameError:
            pass

        if self.activeDist != 'None':
            try:  # Add distribution line
                self.addHistLine()

                # Fit Line Formatting
                linepen = QPen()
                linepen.setWidth(2.5)
                linepen.setColor(tribColours.tribCoral)
                self.lineDist.setPen(linepen)

                self.chart.addSeries(self.lineDist)
                self.setAxes(self.lineDist)
                self.chart.axisX.setRange(hmin - binwidth, hmax + binwidth)

            except AttributeError:
                pass

    @pyqtSlot(int)
    def onSpinBoxChanged(self, n):
        self.nbins = n
        self.addHistogram(self.nbins)
        self.updateChart()

    def distrfromname(self, search):
        for key, name in self.knowndistr.items():
            if name == search:
                return key

    @pyqtSlot(str)
    def onComboBoxDistrChanged(self, name):
        self.activeDist = self.comboBoxDistr.currentKey()
        self.addHistogram(self.nbins)
        self.updateChart()

    @pyqtSlot(dict)
    def receiveFromTable(self, datadict):
        self.setRawData(datadict['Value'])
        self.addHistogram(self.nbins)
        self.updateChart()
示例#15
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.pixelRow = QLabel()
        self.pixelRow.setFixedSize(20, nbPixels)

        self.matrixDisplay = QTextEdit()
        self.matrixDisplay.setFixedSize(165, 180)

        self.valuesDisplay = QTextEdit()
        self.valuesDisplay.setFixedSize(50, nbPixels)

        # CHART
        self.serie = QLineSeries()

        self.chart = QChart()
        self.chart.addSeries(self.serie)
        self.chart.legend().hide()
        self.chart.layout().setContentsMargins(0, 0, 0, 0)

        self.xAxis = QValueAxis()
        self.xAxis.setTitleText("Height")
        self.xAxis.setLabelFormat("%d")
        self.xAxis.setRange(0, nbPixels)

        self.yAxis = QValueAxis()
        self.yAxis.setLabelFormat("%d")
        self.yAxis.setTitleText("Distance ")
        self.yAxis.setRange(0, couleurMax)

        self.chart.setAxisX(self.xAxis)
        self.chart.setAxisY(self.yAxis)

        self.serie.attachAxis(self.xAxis)
        self.serie.attachAxis(self.yAxis)

        self.chart.setTitle("Profile line")

        self.chartView = QChartView(self)
        self.chartView.setChart(self.chart)
        self.chartView.rotate(90)
        self.chartView.setGeometry(20, 195, 450, 400)
        #end CHART

        self.timer = QTimer(self)
        self.timer.setInterval(periode)
        self.timer.start
        self.timer.timeout.connect(self.refresh)

        self.startButton = QPushButton("START")
        self.startButton.setDefault(True)
        self.startButton.clicked.connect(self.startTimer)
        self.startButton.setFixedSize(100, 50)

        self.stopButton = QPushButton("STOP")
        self.stopButton.setDefault(True)
        self.stopButton.clicked.connect(self.stopTimer)
        self.stopButton.setFixedSize(100, 50)

        topLayout = QGridLayout()
        topLayout.addWidget(self.startButton, 0, 0)
        topLayout.addWidget(self.stopButton, 1, 0)
        topLayout.addWidget(self.matrixDisplay, 0, 1, 2, 1)

        mainLayout = QGridLayout()
        mainLayout.addLayout(topLayout, 0, 0)
        mainLayout.addWidget(self.pixelRow, 0, 1, 2, 1)
        mainLayout.addWidget(self.valuesDisplay, 0, 2, 2, 1)
        mainLayout.addWidget(self.chartView, 1, 0)

        mainwidget = QWidget()
        mainwidget.setLayout(mainLayout)
        self.setCentralWidget(mainwidget)

        self.setWindowTitle("Minecraft Depth Map")

    def startTimer(self):
        self.timer.start()

    def stopTimer(self):
        self.timer.stop()

    def refresh(self):
        self.serie.clear()
        self.valuesDisplay.clear()
        screen = app.primaryScreen()
        #grabWindow(wID, x, y, w, h)
        pix = QPixmap(
            screen.grabWindow(0,
                              int((screenW * 3) / 4) - 10,
                              int((screenH - nbPixels) / 2), 20, nbPixels))
        self.pixelRow.setPixmap(pix)
        img = QImage(pix.toImage())

        array = [0 for i in range(nbBlocsH)]

        for i in range(nbBlocsH):
            y = nbPixels - (i * (nbPixels / nbBlocsH) + (nbPixels /
                                                         (2 * nbBlocsH)))
            colorvalue = 255 - QColor(img.pixel(10, y)).black()
            self.valuesDisplay.append(str(colorvalue))
            self.valuesDisplay.append("\n")
            self.serie.append(y, colorvalue)

            #convert colors from 0->couleurMax to 0->nbBlocsD
            if colorvalue > couleurMax:
                colorvalue = nbBlocsD
            elif colorvalue < couleurMin:
                colorvalue = 0
            else:
                colorvalue = int(colorvalue / (couleurMax / nbBlocsD))
            array[i] = colorvalue

        self.convertToMatrix(array)

    def convertToMatrix(self, array):

        matrix = [[0 for j in range(nbBlocsD)] for i in range(nbBlocsH)]

        for i in range(nbBlocsH):
            if array[i] < nbBlocsD:
                matrix[i][array[i]] = 1
                if i < (nbBlocsH - 1):
                    if array[i + 1] > (array[i] + 1):
                        for j in range(array[i] + 1,
                                       min(nbBlocsD, array[i + 1])):
                            matrix[i][j] = 1
                if i > 0:
                    if array[i - 1] > (array[i] + 1):
                        for j in range(array[i] + 1,
                                       min(nbBlocsD, array[i - 1])):
                            matrix[i][j] = 1

        #test1Scalable.convertToHexa(motifF,nbBlocsD,nbBlocsH)  # es-ce bien la fonction a utiliser pour l'affichage ?
        self.displayMatrix(matrix)

    def displayMatrix(self, matrix):
        self.matrixDisplay.clear()
        for j in range(nbBlocsD - 1, -1, -1):
            line = ""
            for i in range(nbBlocsH):
                line = line + str(matrix[i][j]) + "  "
                #self.matrixDisplay.append( line)
                #self.matrixDisplay.append( str(matrix[i][j]) + "  ")
                #self.matrixDisplay.moveCursor( QTextCursor.EndOfLine )
            self.matrixDisplay.append(line)
示例#16
0
class MicroPythonGraphWidget(QWidget):
    """
    Class implementing the MicroPython graph widget.
    
    @signal dataFlood emitted to indicate, that too much data is received
    """
    dataFlood = pyqtSignal()

    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(MicroPythonGraphWidget, self).__init__(parent)

        self.__layout = QHBoxLayout()
        self.__layout.setContentsMargins(2, 2, 2, 2)
        self.setLayout(self.__layout)

        self.__chartView = QChartView(self)
        self.__chartView.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)
        self.__layout.addWidget(self.__chartView)

        self.__verticalLayout = QVBoxLayout()
        self.__verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.__layout.addLayout(self.__verticalLayout)

        self.__saveButton = QToolButton(self)
        self.__saveButton.setIcon(UI.PixmapCache.getIcon("fileSave"))
        self.__saveButton.setToolTip(self.tr("Press to save the raw data"))
        self.__saveButton.clicked.connect(self.on_saveButton_clicked)
        self.__verticalLayout.addWidget(self.__saveButton)
        self.__verticalLayout.setAlignment(self.__saveButton, Qt.AlignHCenter)

        spacerItem = QSpacerItem(20, 20, QSizePolicy.Minimum,
                                 QSizePolicy.Expanding)
        self.__verticalLayout.addItem(spacerItem)

        label = QLabel(self.tr("max. X:"))
        self.__verticalLayout.addWidget(label)
        self.__verticalLayout.setAlignment(label, Qt.AlignHCenter)

        self.__maxX = 100
        self.__maxXSpinBox = QSpinBox()
        self.__maxXSpinBox.setMinimum(100)
        self.__maxXSpinBox.setMaximum(1000)
        self.__maxXSpinBox.setSingleStep(100)
        self.__maxXSpinBox.setToolTip(
            self.tr("Enter the maximum number of data points to be plotted."))
        self.__maxXSpinBox.setValue(self.__maxX)
        self.__maxXSpinBox.setAlignment(Qt.AlignRight)
        self.__verticalLayout.addWidget(self.__maxXSpinBox)

        # holds the data to be checked for plotable data
        self.__inputBuffer = []
        # holds the raw data
        self.__rawData = []
        self.__dirty = False

        self.__maxY = 1000
        self.__flooded = False  # flag indicating a data flood

        self.__data = [deque([0] * self.__maxX)]
        self.__series = [QLineSeries()]

        # Y-axis ranges
        self.__yRanges = [1, 5, 10, 25, 50, 100, 250, 500, 1000]

        # setup the chart
        self.__chart = QChart()
        self.__chart.legend().hide()
        self.__chart.addSeries(self.__series[0])
        self.__axisX = QValueAxis()
        self.__axisX.setRange(0, self.__maxX)
        self.__axisX.setLabelFormat("time")
        self.__axisY = QValueAxis()
        self.__axisY.setRange(-self.__maxY, self.__maxY)
        self.__axisY.setLabelFormat("%d")
        self.__chart.setAxisX(self.__axisX, self.__series[0])
        self.__chart.setAxisY(self.__axisY, self.__series[0])
        self.__chartView.setChart(self.__chart)
        self.__chartView.setRenderHint(QPainter.Antialiasing)

        self.__maxXSpinBox.valueChanged.connect(self.__handleMaxXChanged)

    @pyqtSlot(bytes)
    def processData(self, data):
        """
        Public slot to process the raw data.
        
        It takes raw bytes, checks the data for a valid tuple of ints or
        floats and adds the data to the graph. If the the length of the bytes
        data is greater than 1024 then a dataFlood signal is emitted to ensure
        eric can take action to remain responsive.
        
        @param data raw data received from the connected device via the main
            device widget
        @type bytes
        """
        # flooding guard
        if self.__flooded:
            return

        if len(data) > 1024:
            self.__flooded = True
            self.dataFlood.emit()
            return

        # disable the inputs while processing data
        self.__saveButton.setEnabled(False)
        self.__maxXSpinBox.setEnabled(False)

        data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
        self.__inputBuffer.append(data)

        # check if the data contains a Python tuple containing numbers (int
        # or float) on a single line
        inputBytes = b"".join(self.__inputBuffer)
        lines = inputBytes.splitlines(True)
        for line in lines:
            if not line.endswith(b"\n"):
                # incomplete line (last line); skip it
                break

            line = line.strip()
            if line.startswith(b"(") and line.endswith(b")"):
                # it may be a tuple we are interested in
                rawValues = [val.strip() for val in line[1:-1].split(b",")]
                values = []
                for raw in rawValues:
                    try:
                        values.append(int(raw))
                        # ok, it is an integer
                        continue
                    except ValueError:
                        # test for a float
                        pass
                    try:
                        values.append(float(raw))
                    except ValueError:
                        # it is not an int or float, ignore it
                        continue
                if values:
                    self.__addData(tuple(values))

        self.__inputBuffer = []
        if lines[-1] and not lines[-1].endswith(b"\n"):
            # Append any left over bytes for processing next time data is
            # received.
            self.__inputBuffer.append(lines[-1])

        # re-enable the inputs
        self.__saveButton.setEnabled(True)
        self.__maxXSpinBox.setEnabled(True)

    def __addData(self, values):
        """
        Private method to add a tuple of values to the graph.
        
        It ensures there are the required number of line series, adds the data
        to the line series and updates the range of the chart so the chart
        displays nicely.
        
        @param values tuple containing the data to be added
        @type tuple of int or float
        """
        # store incoming data to be able to dump it as CSV upon request
        self.__rawData.append(values)
        self.__dirty = True

        # check number of incoming values and adjust line series accordingly
        if len(values) != len(self.__series):
            valuesLen = len(values)
            seriesLen = len(self.__series)
            if valuesLen > seriesLen:
                # add a nwe line series
                for _index in range(valuesLen - seriesLen):
                    newSeries = QLineSeries()
                    self.__chart.addSeries(newSeries)
                    self.__chart.setAxisX(self.__axisX, newSeries)
                    self.__chart.setAxisY(self.__axisY, newSeries)
                    self.__series.append(newSeries)
                    self.__data.append(deque([0] * self.__maxX))
            else:
                # remove obsolete line series
                for oldSeries in self.__series[valuesLen:]:
                    self.__chart.removeSeries(oldSeries)
                self.__series = self.__series[:valuesLen]
                self.__data = self.__data[:valuesLen]

        # add the new values to the display and compute the maximum range
        maxRanges = []
        for index, value in enumerate(values):
            self.__data[index].appendleft(value)
            maxRanges.append(
                max([max(self.__data[index]),
                     abs(min(self.__data[index]))]))
            if len(self.__data[index]) > self.__maxX:
                self.__data[index].pop()

        # re-scale the y-axis
        maxYRange = max(maxRanges)
        yRange = bisect.bisect_left(self.__yRanges, maxYRange)
        if yRange < len(self.__yRanges):
            self.__maxY = self.__yRanges[yRange]
        elif maxYRange > self.__maxY:
            self.__maxY += self.__maxY
        elif maxYRange < self.__maxY / 2:
            self.__maxY /= 2
        self.__axisY.setRange(-self.__maxY, self.__maxY)

        # ensure that floats are used to label the y-axis if the range is small
        if self.__maxY <= 5:
            self.__axisY.setLabelFormat("%2.2f")
        else:
            self.__axisY.setLabelFormat("%d")

        # update the line series
        for index, series in enumerate(self.__series):
            series.clear()
            xyValues = []
            for x in range(self.__maxX):
                value = self.__data[index][self.__maxX - 1 - x]
                xyValues.append((x, value))
            for xy in xyValues:
                series.append(*xy)

    @pyqtSlot()
    def on_saveButton_clicked(self):
        """
        Private slot to save the raw data to a CSV file.
        """
        self.saveData()

    def hasData(self):
        """
        Public method to check, if the chart contains some valid data.
        
        @return flag indicating valid data
        @rtype bool
        """
        return len(self.__rawData) > 0

    def isDirty(self):
        """
        Public method to check, if the chart contains unsaved data.
        
        @return flag indicating unsaved data
        @rtype bool
        """
        return self.hasData() and self.__dirty

    def saveData(self):
        """
        Public method to save the dialog's raw data.
        
        @return flag indicating success
        @rtype bool
        """
        baseDir = (Preferences.getMultiProject("Workspace")
                   or os.path.expanduser("~"))
        dataDir = os.path.join(baseDir, "data_capture")

        if not os.path.exists(dataDir):
            os.makedirs(dataDir)

        # save the raw data as a CSV file
        fileName = "{0}.csv".format(time.strftime("%Y%m%d-%H%M%S"))
        fullPath = os.path.join(dataDir, fileName)
        try:
            csvFile = open(fullPath, "w")
            csvWriter = csv.writer(csvFile)
            csvWriter.writerows(self.__rawData)
            csvFile.close()

            self.__dirty = False
            return True
        except (IOError, OSError) as err:
            E5MessageBox.critical(
                self, self.tr("Save Chart Data"),
                self.tr("""<p>The chart data could not be saved into file"""
                        """ <b>{0}</b>.</p><p>Reason: {1}</p>""").format(
                            fullPath, str(err)))
            return False

    @pyqtSlot(int)
    def __handleMaxXChanged(self, value):
        """
        Private slot handling a change of the max. X spin box.
        
        @param value value of the spin box
        @type int
        """
        delta = value - self.__maxX
        if delta == 0:
            # nothing to change
            return
        elif delta > 0:
            # range must be increased
            for deq in self.__data:
                deq.extend([0] * delta)
        else:
            # range must be decreased
            data = []
            for deq in self.__data:
                data.append(deque(list(deq)[:value]))
            self.__data = data

        self.__maxX = value
        self.__axisX.setRange(0, self.__maxX)
示例#17
0
    def createBar(self):
        print("in create bar")
        min_num, max_num = 0, 100
        max_count = 0
        linked_bag_list = []
        try:
            df = self.linked['Beam Diff'].dropna()
            linked_bag_list = df.values.tolist()
            min_num = int(min(linked_bag_list))
            if min_num > 0:                 # check if greater than 0, set to 0
                min_num = 0
            max_num = int(max(linked_bag_list))

        except AttributeError:
            self.statusbar.showMessage('Data not ready')


        count = linked_bag_list
        count = [0] * (max_num + 1)        # choose the largest num as length of count
        
        for num in linked_bag_list:
            count[int(num)] += 1            # update every number's count

        max_count = max(count)

        setBar = QBarSet('Beam Difference Occurrence')
        setBar.append(count)
        brush = QBrush(QColor(0x57B1FD))
        pen = QPen(QColor(0x57B1FD))
        pen.setWidth(2)
        setBar.setPen(pen)  
        setBar.setBrush(brush)

        series = QBarSeries()
        series.append(setBar)

        chart = QChart()
        font = QFont()
        font.setPixelSize(18)
        chart.setTitleFont(font)

        chart.setTitle('Linked Bags Histogram')
        chart.addSeries(series)
        chart.setAnimationOptions(QChart.SeriesAnimations)

        axisX = QValueAxis()
        axisX.setRange(min_num, max_num+20)
        chart.setAxisX(axisX, series)

        axisY = QValueAxis()
        axisY.setRange(0, max_count+20)
        chart.setAxisY(axisY, series)

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

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

        # MainWindow.setCentralWidget(chartView)
        return chartView
示例#18
0
class ChartView(QChartView):
    def __init__(self, file, parent=None):
        super(ChartView, self).__init__(parent)
        self._chart = QChart()
        self._chart.setAcceptHoverEvents(True)
        self.setChart(self._chart)
        self.initUi(file)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def __analysis(self, datas):
        '''
        analysis json data
        :param datas: json data
        '''
        # 标题
        self.__setTitle(datas.get("title", None))
        # 抗锯齿
        if (datas.get("antialiasing", False) or False):
            self.setRenderHint(QPainter.Antialiasing)
        # 主题
        self._chart.setTheme(datas.get("theme", 0) or 0)
        # 动画
        self.__setAnimation(datas.get("animation", None))
        # 背景设置
        self.__setBackground(datas.get("background", None))
        # 边距设置
        self.__setMargins(datas.get("margins", None))
        # 设置图例
        self.__setLegend(datas.get("legend", None))
        # 设置series
        self.__setSeries(datas.get("series", None))
        # 自定义的x轴
        self.__setAxisX(datas.get("axisx", None))
class ContentView(QWidget):
    def __init__(self):
        super().__init__()

        self.m_chart_1 = QChart()
        self.m_chart_2 = QChart()
        self.m_chart_3 = QChart()
        self.m_chart_4 = QChart()
        self.m_series_1 = QLineSeries()
        self.m_series_2 = QLineSeries()
        self.m_series_3 = QLineSeries()
        self.m_series_4 = QLineSeries()

        self.y_original = []
        self.x_data = []
        self.y_processed = []
        self.sampling_rate = 0

        self.pathForVocalMute = ""

        self.select_action_drop = QComboBox()

        self.echo_shift = 0.4
        self.echo_alpha = 0.5

        self.init_ui()

    def init_ui(self):
        main_layout = QVBoxLayout()

        # Drag&Drop area
        drag_drop = DragDropArea(parent=self)
        main_layout.addWidget(drag_drop)

        # Chart layout
        chart_layout_1 = QHBoxLayout()
        chart_layout_2 = QHBoxLayout()

        # Chart 1
        chart_view_1 = QChartView(self.m_chart_1)
        chart_view_1.setMinimumSize(400, 300)

        self.m_chart_1.addSeries(self.m_series_1)

        pen = self.m_series_1.pen()
        pen.setColor(Qt.red)
        pen.setWidthF(.1)
        self.m_series_1.setPen(pen)
        self.m_series_1.setUseOpenGL(True)

        axis_x = QValueAxis()
        axis_x.setRange(0, 100)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Samples")

        axis_y = QValueAxis()
        axis_y.setRange(-10, 10)
        axis_y.setTitleText("Audio level")

        self.m_chart_1.setAxisX(axis_x, self.m_series_1)
        self.m_chart_1.setAxisY(axis_y, self.m_series_1)
        self.m_chart_1.setTitle("Original signal time domain")

        chart_layout_1.addWidget(chart_view_1)

        # Chart 2
        chart_view_2 = QChartView(self.m_chart_2)
        chart_view_2.setMinimumSize(400, 300)

        self.m_chart_2.setTitle("Original signal frequency domain")

        pen = self.m_series_2.pen()
        pen.setColor(Qt.blue)
        pen.setWidthF(.1)
        self.m_series_2.setPen(pen)
        self.m_series_2.setUseOpenGL(True)

        self.m_chart_2.addSeries(self.m_series_2)

        chart_layout_1.addWidget(chart_view_2)

        # Chart 3
        chart_view_3 = QChartView(self.m_chart_3)
        chart_view_3.setMinimumSize(400, 300)

        self.m_chart_3.addSeries(self.m_series_3)

        pen = self.m_series_3.pen()
        pen.setColor(Qt.green)
        pen.setWidthF(.1)
        self.m_series_3.setPen(pen)
        self.m_series_3.setUseOpenGL(True)

        axis_x = QValueAxis()
        axis_x.setRange(0, 100)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Samples")

        axis_y = QValueAxis()
        axis_y.setRange(-10, 10)
        axis_y.setTitleText("Audio level")

        self.m_chart_3.setAxisX(axis_x, self.m_series_3)
        self.m_chart_3.setAxisY(axis_y, self.m_series_3)
        self.m_chart_3.setTitle("Processed signal time domain")

        chart_layout_2.addWidget(chart_view_3)

        # Chart 4
        chart_view_4 = QChartView(self.m_chart_4)
        chart_view_4.setMinimumSize(400, 300)

        self.m_chart_4.setTitle("Processed signal frequency domain")

        pen = self.m_series_4.pen()
        pen.setColor(Qt.magenta)
        pen.setWidthF(.1)
        self.m_series_4.setPen(pen)
        self.m_series_4.setUseOpenGL(True)

        self.m_chart_4.addSeries(self.m_series_4)

        chart_layout_2.addWidget(chart_view_4)

        main_layout.addLayout(chart_layout_1)
        main_layout.addLayout(chart_layout_2)

        # Action buttons
        player_layout = QHBoxLayout()

        self.select_action_drop.addItems([
            "Add noise", "Filter", "Mute equipment", "Mute vocal", "Add echo",
            "Filter echo"
        ])

        player_layout.addWidget(self.select_action_drop)

        noise_jc = QIcon('rate_ic.png')
        noise_btn = QPushButton('Process')
        noise_btn.setIcon(noise_jc)
        noise_btn.clicked.connect(self.on_action)

        player_layout.addWidget(noise_btn)

        play_jc = QIcon('play_ic.png')
        play_orig_btn = QPushButton('Play Original')
        play_orig_btn.setIcon(play_jc)
        play_orig_btn.clicked.connect(self.on_play_orig)

        player_layout.addWidget(play_orig_btn)

        play_jc = QIcon('play_ic.png')
        play_btn = QPushButton('Play Processed')
        play_btn.setIcon(play_jc)
        play_btn.clicked.connect(self.on_play)

        player_layout.addWidget(play_btn)

        stop_jc = QIcon('stop_ic.png')
        stop_btn = QPushButton('Stop')
        stop_btn.setIcon(stop_jc)
        stop_btn.clicked.connect(self.on_stop)

        player_layout.addWidget(stop_btn)

        main_layout.addLayout(player_layout)

        self.setLayout(main_layout)

    ''''
        Toolbar actions
    '''

    def browse_file(self):
        path1 = QFileDialog.getOpenFileName(self, 'Open File',
                                            os.getenv('HOME'), '*.wav')
        print(path1[0])

        rate, data = wavfile.read(path1[0])

        self.sampling_rate = rate
        self.y_original = data[:, 0]

        self.show_original_data()

    def on_file_upload(self, file_url):
        print(file_url[7:])

        self.pathForVocalMute = file_url[7:]

        rate, data = wavfile.read(file_url[7:])

        self.sampling_rate = rate
        self.y_original = data[:, 0]

        self.show_original_data()

    def on_save(self):
        print("on_save")
        if len(self.y_processed) > 0:
            path = QFileDialog.getSaveFileName(self, 'Save File',
                                               os.getenv('HOME'), 'audio/wav')
            if path[0] != '':
                data2 = np.asarray([self.y_processed,
                                    self.y_processed]).transpose()
                wavfile.write(path[0], self.sampling_rate, data2)
            else:
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Critical)
                msg.setText("No path")
                msg.setInformativeText("You should define path to save file")
                msg.setWindowTitle("Error")
                msg.exec_()
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("No data")
            msg.setInformativeText(
                "No data to save, you should upload and process sound file")
            msg.setWindowTitle("Error")
            msg.exec_()

    ''''
        Action selection
    '''

    def on_action(self):
        if self.select_action_drop.currentText() == "Add noise":
            self.on_add_noise()
        elif self.select_action_drop.currentText() == "Filter":
            self.on_filter()
        elif self.select_action_drop.currentText() == "Mute equipment":
            self.on_mute_equipment()
        elif self.select_action_drop.currentText() == "Mute vocal":
            self.on_mute_voice()
        elif self.select_action_drop.currentText() == "Add echo":
            self.on_add_echo()
        elif self.select_action_drop.currentText() == "Filter echo":
            self.on_filter_echo()

    '''
        Noise addition
    '''

    def on_add_noise(self):
        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        noise = np.random.normal(0,
                                 self.y_original.max() / 30,
                                 len(self.y_original))
        arr1 = np.array(self.y_original)
        self.y_processed = arr1 + noise
        self.show_processed_data()

    def on_filter(self):
        print("on_filter")

        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        filter1, filter2, limit1, limit2, extra, max_ripple, min_attenuation, ok = FilterSelectionDialog.show_dialog(
            parent=self)
        print(filter1, filter2, limit1, limit2, extra, max_ripple,
              min_attenuation, ok)

        if ok:
            if filter1 == "FIR filter":
                self.on_fir_filter(filter2, limit1, limit2, extra)
            elif filter1 == "IIR filter":
                self.on_iir_filter(filter2, limit1, limit2, extra, max_ripple,
                                   min_attenuation)

    def on_mute_equipment(self):
        print("on_mute_equipment")

        check_piano, check_organ, check_flute, check_french_horn, check_trumpet, check_violin, \
        check_guitar_acoustic, check_guitar_bass, check_clarinet, \
        check_saxophone, ok = MuteInstrumentsDialog.show_dialog(parent=self)

        print(check_piano, check_organ, check_flute, check_french_horn,
              check_trumpet, check_violin, check_guitar_acoustic,
              check_guitar_bass, check_clarinet, check_saxophone, ok)
        '''
        Piano	A0 (28 Hz) to C8 (4,186 Hz or 4.1 KHz)
        Organ	C0 (16 Hz) to A9 (7,040 KHz)	
        Concert Flute	C4 (262 Hz) to B6 (1,976 Hz)	
        French Horn	A2 (110 Hz) to A5 (880 Hz)
        Trumpet	E3 (165 Hz) to B5 (988 Hz)
        Violin	G3 (196 Hz) - G7 (3,136 Hz) (G-D-E-A) (or C8 (4,186 Hz?)
        Guitar (Acoustic)	E2 (82 Hz) to F6 (1,397 Hz)
        Guitar (Bass)	4 string E1 (41 Hz) to C4 (262 Hz)
        Clarinet	E3 (165 Hz) to G6 (1,568 Hz)	
        Saxaphone Eb 138-830 (880)
        '''
        if ok:
            print(check_piano)

        limit1 = 0.1
        limit2 = 0.2
        if check_piano:
            pass
        elif check_organ:
            pass
        elif check_flute:
            limit1 = 262 / self.sampling_rate
            limit2 = 1976 / self.sampling_rate
            pass
        elif check_french_horn:
            limit1 = 110 / self.sampling_rate
            limit2 = 880 / self.sampling_rate
            pass
        elif check_trumpet:
            limit1 = 165 / self.sampling_rate
            limit2 = 988 / self.sampling_rate
            pass
        elif check_violin:
            limit1 = 196 / self.sampling_rate
            limit2 = 3136 / self.sampling_rate
            pass
        elif check_guitar_acoustic:
            limit1 = 82 / self.sampling_rate
            limit2 = 1397 / self.sampling_rate
            pass
        elif check_guitar_bass:
            limit1 = 41 / self.sampling_rate
            limit2 = 262 / self.sampling_rate
            pass
        elif check_clarinet:
            limit1 = 165 / self.sampling_rate
            limit2 = 1568 / self.sampling_rate
            pass
        elif check_saxophone:
            limit1 = 138 / self.sampling_rate
            limit2 = 880 / self.sampling_rate
            pass

        print(limit1, limit2)

        print([
            0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001,
            0.9991, 1.0
        ], [0, 1, 1, 0, 0, 1, 1, 0])
        design_filter = signal.firwin2(1000000, [
            0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001,
            0.9991, 1.0
        ], [0, 1, 1, 0, 0, 1, 1, 0])

        self.y_processed = signal.convolve(self.y_original,
                                           design_filter,
                                           mode='same')

        w1, h1 = signal.freqz(design_filter)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    def on_mute_voice(self):
        y, sr = librosa.load(self.pathForVocalMute, sr=self.sampling_rate)

        S_full, phase = librosa.magphase(librosa.stft(y))

        S_filter = librosa.decompose.nn_filter(
            S_full,
            aggregate=np.median,
            metric='cosine',
            width=int(librosa.time_to_frames(2, sr=sr)))

        S_filter = np.minimum(S_full, S_filter)

        margin_i, margin_v = 2, 10
        power = 2

        mask_i = librosa.util.softmask(S_filter,
                                       margin_i * (S_full - S_filter),
                                       power=power)

        mask_v = librosa.util.softmask(S_full - S_filter,
                                       margin_v * S_filter,
                                       power=power)

        S_foreground = mask_v * S_full
        S_background = mask_i * S_full

        self.y_processed = librosa.istft(S_background)

        self.show_processed_data()

    def on_add_echo(self):
        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        num_shift = int(self.sampling_rate * self.echo_shift)
        zeros = np.zeros(num_shift)

        original = np.append(self.y_original, zeros)
        echo = np.append(zeros, self.y_original) * self.echo_alpha

        self.y_processed = original + echo

        np.delete(
            self.y_processed,
            np.arange(
                len(self.y_processed) - len(zeros), len(self.y_processed)))

        self.show_processed_data()

    def on_filter_echo(self):
        ceps = cepstrum.real_cepstrum(np.array(self.y_original))

        index, result = CepstrumDialog.show_dialog(self, ceps)

        if result:
            print(index)

            b = np.array([1])

            a = np.zeros(index + 1)
            a[0] = 1
            a[len(a) - 1] = self.echo_alpha

            zi = signal.lfilter_zi(b, a)

            self.y_processed, _ = signal.lfilter(b,
                                                 a,
                                                 self.y_original,
                                                 axis=0,
                                                 zi=zi * self.y_original[0])

            w1, h1 = signal.freqz(b, a)

            result = FilterResponseDialog.show_dialog(parent=self,
                                                      w1=w1,
                                                      h1=h1)

            if result:
                self.show_processed_data()

    '''
        Filters
    '''

    def on_fir_filter(self, filter_type, limit1, limit2, extra):
        if filter_type == "Low-pass":
            design_filter = signal.firwin(41, limit1, window=extra)
        elif filter_type == "High-pass":
            temp = np.zeros(41)
            temp[20] = 1
            design_filter = temp - np.array(
                signal.firwin(41, limit1, window=extra))
        elif filter_type == "Band-pass":
            temp = np.zeros(41)
            temp[20] = 1
            design_filter = temp - np.array(
                signal.firwin(41, [limit1, limit2], window=extra))
        elif filter_type == "Band-reject":
            design_filter = signal.firwin(41, [limit1, limit2], window=extra)

        self.y_processed = signal.convolve(self.y_original,
                                           design_filter,
                                           mode='same')

        w1, h1 = signal.freqz(design_filter)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    def on_iir_filter(self, filter_type, limit1, limit2, extra, max_ripple,
                      min_attenuation):
        if filter_type == "Low-pass":
            b, a = signal.iirfilter(4,
                                    limit1,
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='lowpass',
                                    ftype=extra)
        elif filter_type == "High-pass":
            b, a = signal.iirfilter(4,
                                    limit1,
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='highpass',
                                    ftype=extra)
        elif filter_type == "Band-pass":
            b, a = signal.iirfilter(4, [limit1, limit2],
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='bandpass',
                                    ftype=extra)
        elif filter_type == "Band-reject":
            b, a = signal.iirfilter(4, [limit1, limit2],
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='bandstop',
                                    ftype=extra)

        self.y_processed = signal.lfilter(b, a, self.y_original)

        w1, h1 = signal.freqz(b, a)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    '''
        Audio controls
    '''

    def on_play(self):
        print("on_play")

        if len(self.y_processed) > 0:
            data2 = np.asarray(self.y_processed)
            sd.play(data2, self.sampling_rate)
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should upload and process sound file to play")
            msg.setWindowTitle("Error")
            msg.exec_()

    def on_stop(self):
        sd.stop()

    def on_play_orig(self):
        print("on_play_orig")

        if len(self.y_original) > 0:
            data = np.asarray(self.y_original)
            sd.play(data, self.sampling_rate)
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText("First you should add sound file to play")
            msg.setWindowTitle("Error")
            msg.exec_()

    '''
        Signal plots
    '''

    def show_original_data(self):
        # Time domain
        y_data_scaled = np.interp(
            self.y_original, (self.y_original.min(), self.y_original.max()),
            (-10, +10))

        sample_size = len(self.y_original)
        self.x_data = np.linspace(0., 100., sample_size)

        points_1 = []

        for k in range(len(y_data_scaled)):
            points_1.append(QPointF(self.x_data[k], y_data_scaled[k]))

        self.m_series_1.replace(points_1)

        # Frequency domain
        y_freq_data = np.abs(fftpack.fft(self.y_original))
        y_freq_data = np.interp(y_freq_data,
                                (y_freq_data.min(), y_freq_data.max()),
                                (0, +10))
        x_freq_data = fftpack.fftfreq(len(
            self.y_original)) * self.sampling_rate

        axis_x = QValueAxis()
        axis_x.setRange(0, self.sampling_rate / 2)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Frequency [Hz]")

        axis_y = QValueAxis()
        axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data))
        axis_y.setTitleText("Magnitude")

        self.m_chart_2.setAxisX(axis_x, self.m_series_2)
        self.m_chart_2.setAxisY(axis_y, self.m_series_2)

        points_2 = []

        for k in range(len(y_freq_data)):
            points_2.append(QPointF(x_freq_data[k], y_freq_data[k]))

        self.m_series_2.replace(points_2)

        self.m_series_3.clear()
        self.m_series_4.clear()

    def show_processed_data(self):
        # Time domain
        y_data_scaled = np.interp(
            self.y_processed, (self.y_processed.min(), self.y_processed.max()),
            (-10, +10))

        points_3 = []

        sample_size = len(self.y_processed)
        x_data = np.linspace(0., 100., sample_size)

        for k in range(len(y_data_scaled)):
            points_3.append(QPointF(x_data[k], y_data_scaled[k]))

        self.m_series_3.replace(points_3)

        # Frequency domain
        y_freq_data = np.abs(fftpack.fft(self.y_processed))
        y_freq_data = np.interp(y_freq_data,
                                (y_freq_data.min(), y_freq_data.max()),
                                (0, +10))
        x_freq_data = fftpack.fftfreq(len(
            self.y_processed)) * self.sampling_rate

        axis_x = QValueAxis()
        axis_x.setRange(0, self.sampling_rate / 2)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Frequency [Hz]")

        axis_y = QValueAxis()
        axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data))
        axis_y.setTitleText("Magnitude")

        self.m_chart_4.setAxisX(axis_x, self.m_series_4)
        self.m_chart_4.setAxisY(axis_y, self.m_series_4)

        points_4 = []

        for k in range(len(y_freq_data)):
            points_4.append(QPointF(x_freq_data[k], y_freq_data[k]))

        self.m_series_4.replace(points_4)
示例#20
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()

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

        # line 宽度需要调整
        self.lineItem = QGraphicsLineItem(self._chart)
        pen = QPen(Qt.gray)
        self.lineItem.setPen(pen)
        self.lineItem.setZValue(998)
        self.lineItem.hide()

        # 一些固定计算,减少mouseMoveEvent中的计算量
        # 获取x和y轴的最小最大值
        axisX, axisY = self._chart.axisX(), self._chart.axisY()
        self.category_len = len(axisX.categories())
        self.min_x, self.max_x = -0.5, self.category_len - 0.5
        self.min_y, self.max_y = axisY.min(), axisY.max()
        # 坐标系中左上角顶点
        self.point_top = self._chart.mapToPosition(
            QPointF(self.min_x, self.max_y))

    def 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)
        # 得到在坐标系中的所有bar的类型和点
        serie = self._chart.series()[0]
        bars = [
            (bar, bar.at(index)) for bar in serie.barSets()
            if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y
        ]
        #         print(bars)
        if bars:
            right_top = self._chart.mapToPosition(
                QPointF(self.max_x, self.max_y))
            # 等分距离比例
            step_x = round(
                (right_top.x() - self.point_top.x()) / self.category_len)
            posx = self._chart.mapToPosition(QPointF(x, self.min_y))
            self.lineItem.setLine(posx.x(), self.point_top.y(), posx.x(),
                                  posx.y())
            self.lineItem.show()
            try:
                title = self.categories[index]
            except:
                title = ""
            t_width = self.toolTipWidget.width()
            t_height = self.toolTipWidget.height()
            # 如果鼠标位置离右侧的距离小于tip宽度
            x = pos.x() - t_width if self.width() - \
                pos.x() - 20 < t_width else pos.x()
            # 如果鼠标位置离底部的高度小于tip高度
            y = pos.y() - t_height if self.height() - \
                pos.y() - 20 < t_height else pos.y()
            self.toolTipWidget.show(title, bars, QPoint(x, y))
        else:
            self.toolTipWidget.hide()
            self.lineItem.hide()

    def handleMarkerClicked(self):
        marker = self.sender()  # 信号发送者
        if not marker:
            return
        bar = marker.barset()
        if not bar:
            return
        # bar透明度
        brush = bar.brush()
        color = brush.color()
        alpha = 0.0 if color.alphaF() == 1.0 else 1.0
        color.setAlphaF(alpha)
        brush.setColor(color)
        bar.setBrush(brush)
        # marker
        brush = marker.labelBrush()
        color = brush.color()
        alpha = 0.4 if color.alphaF() == 1.0 else 1.0
        # 设置label的透明度
        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)

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

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

    def initChart(self):
        self._chart = QChart(title="柱状图堆叠")
        self._chart.setAcceptHoverEvents(True)
        # Series动画
        self._chart.setAnimationOptions(QChart.SeriesAnimations)
        self.categories = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        names = ["邮件营销", "联盟广告", "视频广告", "直接访问", "搜索引擎"]
        series = QBarSeries(self._chart)
        for name in names:
            bar = QBarSet(name)
            # 随机数据
            for _ in range(7):
                bar.append(randint(0, 10))
            series.append(bar)
            bar.hovered.connect(self.handleBarHoverd)  # 鼠标悬停
        self._chart.addSeries(series)
        self._chart.createDefaultAxes()  # 创建默认的轴
        # x轴
        axis_x = QBarCategoryAxis(self._chart)
        axis_x.append(self.categories)
        self._chart.setAxisX(axis_x, series)
        # chart的图例
        legend = self._chart.legend()
        legend.setVisible(True)
        # 遍历图例上的标记并绑定信号
        for marker in legend.markers():
            # 点击事件
            marker.clicked.connect(self.handleMarkerClicked)
            # 鼠标悬停事件
            marker.hovered.connect(self.handleMarkerHovered)
        self.setChart(self._chart)
    def bargraph(self, text):
        if text == "SKU Selection":
            # print("sku")
            self.clearLayout(lay)
            font = QtGui.QFont()
            font.setPointSize(9)

            comboBox = QtWidgets.QComboBox()
            comboBox.setGeometry(QtCore.QRect(20, 20, 171, 31))
            comboBox.setObjectName("comboBox")
            comboBox.addItem("SKU Selection")
            comboBox.addItem("Analytics View")
            comboBox.activated[str].connect(self.bargraph)
            comboBox.setToolTip("Select an Option!")    # Message to show when mouse hover
            comboBox.setFont(font)
            lay.addWidget(comboBox,0,Qt.AlignTop)

            self.dynamicaly_created_radiobtns()

        else:
            # print("analytics")
            try:
                self.clearLayout(lay)
                font = QtGui.QFont()
                font.setPointSize(9)
                
                set0 = QBarSet("Good")
                set1 = QBarSet("Bad")
                # set0.append([5400, 4900, 5100, 5400, 5000, 4800, 4500, 3000])
                # set1.append([600, 800, 900, 600, 1000, 1200, 1500, 3000])

                set0.append([z1,z2,z3,z4,z5,z6,z7,z8])
                set1.append([y1,y2,y3,y4,y5,y6,y7,y8])

                series = QStackedBarSeries()
                series.append(set0)
                series.append(set1)

                chart = QChart()
                chart.addSeries(series)
                chart.setTitle("Production Count")
                chart.setAnimationOptions(QChart.SeriesAnimations)

                categories = ["12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00"]
                axis = QBarCategoryAxis()
                axis.append(categories)
                chart.createDefaultAxes()
                chart.setAxisX(axis, series)

                axisY = QValueAxis()
                axisY.setRange(0, 6000)
                axisY.setTitleText("Units")
                chart.setAxisY(axisY)

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

                chartView = QChartView(chart)
                chartView.setRenderHint(QPainter.Antialiasing)
                chartView.setToolTip('Good Units v/s Bad Units')

                comboBox = QtWidgets.QComboBox()
                comboBox.setGeometry(QtCore.QRect(20, 20, 171, 31))
                comboBox.setObjectName("comboBox")
                comboBox.addItem("SKU Selection")
                comboBox.addItem("Analytics View")
                comboBox.activated[str].connect(self.bargraph)
                comboBox.setToolTip("Select an Option!")    # Message to show when mouse hover
                comboBox.setFont(font)

                lay.addWidget(comboBox,0)
                lay.addWidget(chartView,1)
            
            except:

                self.clearLayout(lay)
                font = QtGui.QFont()
                font.setPointSize(9)
                
                set0 = QBarSet("Good")
                set1 = QBarSet("Bad")           
                # set0.append([5400, 4900, 5100, 5400, 5000, 4800, 4500, 3000])
                # set1.append([600, 800, 900, 600, 1000, 1200, 1500, 3000])

                set0.append([0,0,0,0,0,0,0,0])
                set1.append([0,0,0,0,0,0,0,0])

                series = QStackedBarSeries()
                series.append(set0)
                series.append(set1)
        
                chart = QChart()
                chart.addSeries(series)
                chart.setTitle("Production Count")
                chart.setAnimationOptions(QChart.SeriesAnimations)
                
                categories = ["12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00"]
                axis = QBarCategoryAxis()
                axis.append(categories)
                chart.createDefaultAxes()
                chart.setAxisX(axis, series)

                axisY = QValueAxis()
                axisY.setRange(0, 6000)
                axisY.setTitleText("Units")
                chart.setAxisY(axisY)

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

                chartView = QChartView(chart)
                chartView.setRenderHint(QPainter.Antialiasing)
                chartView.setToolTip('Good Units v/s Bad Units')
                
                comboBox = QtWidgets.QComboBox()
                comboBox.setGeometry(QtCore.QRect(20, 20, 171, 31))
                comboBox.setObjectName("comboBox")
                comboBox.addItem("SKU Selection")
                comboBox.addItem("Analytics View")
                comboBox.activated[str].connect(self.bargraph)
                comboBox.setToolTip("Select an Option!")    # Message to show when mouse hover
                comboBox.setFont(font)

                lay.addWidget(comboBox,0)
                lay.addWidget(chartView,1)

                msgBox = QMessageBox(self)
                msgBox.setIcon(QMessageBox.Information)
                msgBox.setText("Please Select a SKU!")
                msgBox.setWindowTitle("Application Info")
                msgBox.setStandardButtons(QMessageBox.Ok)
                returnValue = msgBox.exec()
                if returnValue == QMessageBox.Ok:
                    print('OK clicked')
class Ui(mainwindow.Ui_MainWindow):
    def __init__(self, MainWindow):
        super(Ui, self).setupUi(MainWindow)
        self.MainWindow = MainWindow
        self.stix_tctm_parser = stix_parser.StixTCTMParser()
        self.initialize()

    def close(self):
        self.MainWindow.close()

    def style(self):
        return self.MainWindow.style()

    def initialize(self):
        self.tabWidget.setCurrentIndex(0)
        self.actionExit.triggered.connect(self.close)
        self.actionPlot.setEnabled(False)

        self.actionNext.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowForward))
        self.actionPrevious.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_ArrowBack))
        self.actionOpen.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DialogOpenButton))
        self.actionSave.setIcon(self.style().standardIcon(
            QtWidgets.QStyle.SP_DriveFDIcon))

        self.actionSave.triggered.connect(self.save)

        self.actionOpen.triggered.connect(self.getOpenFilename)

        self.actionNext.triggered.connect(self.nextPacket)
        self.actionPrevious.triggered.connect(self.previousPacket)
        self.actionAbout.triggered.connect(self.about)

        self.actionPrevious.setEnabled(False)
        self.actionNext.setEnabled(False)
        self.actionSave.setEnabled(False)
        self.actionPlot.setEnabled(False)
        self.actionCopy.triggered.connect(self.onCopyTriggered)

        self.packetTreeWidget.currentItemChanged.connect(self.onPacketSelected)

        self.actionCopy.setEnabled(False)
        self.actionPaste.triggered.connect(self.onPasteTriggered)
        self.actionLog.triggered.connect(self.dockWidget.show)
        self.actionSetIDB.triggered.connect(self.onSetIDBClicked)
        self.plotButton.clicked.connect(self.onPlotButtonClicked)
        self.exportButton.clicked.connect(self.onExportButtonClicked)
        self.actionPlot.triggered.connect(self.onPlotActionClicked)
        self.actionLoadMongodb.triggered.connect(self.onLoadMongoDBTriggered)
        self.actionConnectTSC.triggered.connect(self.onConnectTSCTriggered)
        self.actionPacketFilter.triggered.connect(self.onPacketFilterTriggered)
        self.actionPlugins.triggered.connect(self.onPluginTriggered)
        self.actionOnlineHelp.triggered.connect(self.onOnlineHelpTriggered)
        self.actionViewBinary.triggered.connect(self.onViewBinaryTriggered)

        self.packetTreeWidget.customContextMenuRequested.connect(
            self.packetTreeContextMenuEvent)

        self.mdb = None

        self.current_row = 0
        self.data = []
        self.x = []
        self.y = []
        self.xlabel = 'x'
        self.ylabel = 'y'

        self.buttons_enabled = False

        self.chart = QChart()
        self.chart.layout().setContentsMargins(0, 0, 0, 0)
        self.chart.setBackgroundRoundness(0)
        self.savePlotButton.clicked.connect(self.savePlot)

        self.chartView = QChartView(self.chart)
        self.gridLayout.addWidget(self.chartView, 1, 0, 1, 15)
        #self.packetTreeWidget.itemDoubleClicked.connect(self.onPacketTreeItemDoubleClicked)
        self.selected_services = SELECTED_SERVICES
        self.selected_SPID = []

        # IDB location

        self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.idb_filename = self.settings.value('idb_filename', [], str)
        if self.idb_filename:
            idb._stix_idb.reload(self.idb_filename)
        if not idb._stix_idb.is_connected():
            self.showMessage('IDB has not been set!')
        else:
            self.showMessage(
                'IDB location: {} '.format(idb._stix_idb.get_idb_filename()),
                1)

    def packetTreeContextMenuEvent(self, pos):
        menu = QtWidgets.QMenu()
        rawDataAction = menu.addAction('Show raw data')
        menu.addSeparator()
        filterAction = menu.addAction('Filter packets')
        copyPacketAction = menu.addAction('Copy packet')
        menu.addSeparator()
        deleteAllAction = menu.addAction('Delete all packets')
        self.current_row = self.packetTreeWidget.currentIndex().row()

        rawDataAction.triggered.connect(self.onViewBinaryTriggered)
        filterAction.triggered.connect(self.onPacketFilterTriggered)
        copyPacketAction.triggered.connect(self.onCopyTriggered)
        deleteAllAction.triggered.connect(self.onDeleteAllTriggered)
        action = menu.exec_(self.packetTreeWidget.viewport().mapToGlobal(pos))

    def onDeleteAllTriggered(self):
        self.data.clear()
        self.packetTreeWidget.clear()
        self.paramTreeWidget.clear()

    #def onPacketTreeItemDoubleClicked(self):
    #    self.onViewBinaryTriggered()

    def onViewBinaryTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = raw_viewer.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.data:
            try:
                raw = self.data[self.current_row]['bin']
                header = self.data[self.current_row]['header']
                diag_ui.setPacketInfo('{}({},{})  {}'.format(
                    header['TMTC'], header['service_type'],
                    header['service_subtype'], header['DESCR']))
                diag_ui.displayRaw(raw)
            except (IndexError, KeyError):
                diag_ui.setText('Raw data not available.')
        diag.exec_()

    def onOnlineHelpTriggered(self):
        webbrowser.open('https://github.com/i4Ds/STIX-dataviewer', new=2)

    def onPluginTriggered(self):
        self.plugin_location = self.settings.value('plugin_location', [], str)
        diag = QtWidgets.QDialog()
        diag_ui = plugin.Ui_Dialog()
        diag_ui.setupUi(diag)
        if self.plugin_location:
            diag_ui.setPluginLocation(self.plugin_location)

        diag_ui.setData(self.data, self.current_row)
        diag.exec_()
        location = diag_ui.getPluginLocation()
        if location != self.plugin_location:
            self.settings.setValue('plugin_location', location)

    def onPacketFilterTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = packet_filter.Ui_Dialog()
        diag_ui.setupUi(diag)
        diag_ui.setSelectedServices(self.selected_services)
        diag_ui.buttonBox.accepted.connect(
            partial(self.applyServiceFilter, diag_ui))
        diag.exec_()

    def applyServiceFilter(self, diag_ui):
        self.selected_SPID = diag_ui.getSelectedSPID()
        self.selected_services = diag_ui.getSelectedServices()
        self.showMessage('Applying filter...')

        self.addPacketsToView(self.data, True, show_stat=False)

    def onExportButtonClicked(self):
        if self.y:
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(None,
                                                      "Save data to file", "",
                                                      "CSV(*.csv)")[0])
            if filename:
                with open(filename, 'w') as f:
                    f.write('{},{}\n'.format(self.xlabel, self.ylabel))
                    for xx, yy in zip(self.x, self.y):
                        f.write('{},{}\n'.format(xx, yy))
                    self.showMessage(
                        'The data has been written to {}'.format(filename))
        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('Plot first!')
            msgBox.setWindowTitle("Warning")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def savePlot(self):
        # if self.figure.get_axes():
        if self.chart:
            filetypes = "PNG (*.png);;JPEG (*.jpg)"
            filename = str(
                QtWidgets.QFileDialog.getSaveFileName(None,
                                                      "Save plot to file", "",
                                                      filetypes)[0])
            if filename:
                if not filename.endswith(('.png', '.jpg')):
                    filename += '.png'
                # self.figure.savefig(filename)
                p = self.chartView.grab()
                p.save(filename)
                self.showMessage(('Saved to %s.' % filename))

        else:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setIcon(QtWidgets.QMessageBox.Information)
            msgBox.setText('No figure to save')
            msgBox.setWindowTitle("STIX raw data viewer")
            msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            msgBox.exec_()

    def onCopyTriggered(self):
        packet_id = self.current_row
        try:
            packet = self.data[packet_id]
            ss = pprint.pformat(packet)
            cb = QtWidgets.QApplication.clipboard()
            cb.clear(mode=cb.Clipboard)
            cb.setText(ss, mode=cb.Clipboard)
            msg = QtWidgets.QMessageBox()
            msg.setIcon(QtWidgets.QMessageBox.Information)
            msg.setText(
                "The data of the selected packet has been copied to the clipboard."
            )
            msg.setWindowTitle("Information")
            msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
            retval = msg.exec_()

        except Exception as e:
            self.showMessage(str(e), 0)

    def onPasteTriggered(self):
        raw_hex = QtWidgets.QApplication.clipboard().text()
        if len(raw_hex) < 16:
            self.showMessage('No data in the clipboard.')
            return
        data_hex = re.sub(r"\s+", "", raw_hex)
        try:
            data_binary = binascii.unhexlify(data_hex)
            packets = self.stix_tctm_parser.parse_binary(data_binary,
                                                         0,
                                                         store_binary=True)
            if not packets:
                return
            self.showMessage('%d packets read from the clipboard' %
                             len(packets))
            self.onDataReady(packets, clear=False, show_stat=False)
        except Exception as e:
            self.showMessageBox(str(e), data_hex)

    def showMessageBox(self, message, content):
        msg = QtWidgets.QMessageBox()
        msg.setIcon(QtWidgets.QMessageBox.Critical)
        msg.setText("Error")
        msg.setInformativeText(message)
        msg.setWindowTitle("Error")
        msg.setDetailedText(content)
        msg.setStandardButtons(QtWidgets.QMessageBox.Ok
                               | QtWidgets.QMessageBox.Cancel)
        retval = msg.exec_()

    def showMessage(self, msg, where=0):
        if where != 1:
            self.statusbar.showMessage(msg)
        if where != 0:
            self.statusListWidget.addItem(msg)
        # if destination !=0 :
        #    self.listWidget_2.addItem(msg)

    def onSetIDBClicked(self):
        self.idb_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', '.', 'IDB file(*.db *.sqlite *.sqlite3)')[0]

        if not self.idb_filename:
            return

        idb._stix_idb.reload(self.idb_filename)
        if idb._stix_idb.is_connected():
            #settings = QtCore.QSettings('FHNW', 'stix_parser')
            self.settings.setValue('idb_filename', self.idb_filename)
        self.showMessage(
            'IDB location: {} '.format(idb._stix_idb.get_idb_filename()), 1)

    def save(self):
        filetypes = 'python compressed pickle (*.pklz);; python pickle file (*.pkl);; binary data (*.dat)'
        self.output_filename = str(
            QtWidgets.QFileDialog.getSaveFileName(None, "Save packets to", "",
                                                  filetypes)[0])

        if not self.output_filename.endswith(('.pklz', '.pkl', '.dat')):
            msg = 'unsupported file format !'
            self.showMessage(msg)
            return

        msg = 'Writing data to file %s' % self.output_filename
        self.showMessage(msg)

        if self.output_filename.endswith(('.pklz', '.pkl')):
            stw = stix_writer.StixPickleWriter(self.output_filename)
            stw.register_run(str(self.input_filename))
            stw.write_all(self.data)
            #stw.done()
        elif self.output_filename.endswith('.dat'):
            stw = stix_writer.StixBinaryWriter(self.output_filename)
            stw.write_all(self.data)
            num_ok = stw.get_num_sucess()
            msg = (
                'The binary data of {} packets written to file {}, total packets {}'
                .format(num_ok, self.output_filename, len(self.data)))
            self.showMessage(msg)

    def setListViewSelected(self, row):
        #index = self.model.createIndex(row, 0);
        # if index.isValid():
        #    self.model.selectionModel().select( index, QtGui.QItemSelectionModel.Select)
        pass

    def about(self):
        msgBox = QtWidgets.QMessageBox()
        msgBox.setIcon(QtWidgets.QMessageBox.Information)
        msgBox.setText("STIX raw data parser and viewer, [email protected]")
        msgBox.setWindowTitle("Stix data viewer")

        msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
        msgBox.exec_()

    def nextPacket(self):
        self.current_row += 1
        length = len(self.data)

        if self.current_row >= length:
            self.current_row = length - 1
            self.showMessage('No more packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def previousPacket(self):
        self.current_row -= 1
        if self.current_row < 0:
            self.current_row = 0
            self.showMessage('Reach the first packet!')

        self.showPacket(self.current_row)
        self.setListViewSelected(self.current_row)

    def getOpenFilename(self):
        filetypes = (
            'STIX raw data(*.dat *.bin *.binary);; python pickle files (*.pkl *pklz);;'
            'ESA xml files (*xml);;'
            'ESA ascii files(*.ascii);; CMDVS archive files (*.BDF);; All(*)')
        self.input_filename = QtWidgets.QFileDialog.getOpenFileName(
            None, 'Select file', '.', filetypes)[0]
        if not self.input_filename:
            return
        self.openFile(self.input_filename)

    def openFile(self, filename):
        self.packetTreeWidget.clear()
        msg = 'Loading file %s ...' % filename
        self.showMessage(msg)
        self.dataReader = StixFileReader(filename)
        #self.dataReader.dataLoaded.connect(self.onDataReady)
        self.dataReader.packetArrival.connect(self.onPacketArrival)
        self.dataReader.error.connect(self.onDataReaderError)
        self.dataReader.info.connect(self.onDataReaderInfo)
        self.dataReader.warn.connect(self.onDataReaderWarn)
        self.dataReader.start()

    def onDataReaderInfo(self, msg):
        self.showMessage(msg, 0)

    def onDataReaderWarn(self, msg):
        self.showMessage(msg, 1)

    def onDataReaderError(self, msg):
        self.showMessage(msg, 1)

    def onDataReady(self, data, clear=True, show_stat=True):
        if not clear:
            self.data.extend(data)
        else:
            self.data = data
        if data:
            self.addPacketsToView(data, clear=clear, show_stat=show_stat)
            self.enableButtons()

    def enableButtons(self):
        if not self.buttons_enabled:
            self.actionPrevious.setEnabled(True)
            self.actionNext.setEnabled(True)
            self.actionSave.setEnabled(True)
            self.actionCopy.setEnabled(True)
            self.actionPlot.setEnabled(True)
            self.actionViewBinary.setEnabled(True)
            self.buttons_enabled = True

    def addPacketsToView(self, data, clear=True, show_stat=True):
        if clear:
            self.packetTreeWidget.clear()
        #t0 = 0
        for p in data:
            if type(p) is not dict:
                continue
            header = p['header']

            root = QtWidgets.QTreeWidgetItem(self.packetTreeWidget)
            # if t0 == 0:
            #    t0 = header['time']
            timestamp_str = ''
            try:
                timestamp_str = header['utc']
            except KeyError:
                timestamp_str = '{:.2f}'.format(header['time'])
                #- t0)

            root.setText(0, timestamp_str)
            root.setText(
                1,
                '{}({},{}) - {}'.format(header['TMTC'], header['service_type'],
                                        header['service_subtype'],
                                        header['DESCR']))

            if not self.selected_SPID:
                #not set then apply service
                if header['service_type'] not in self.selected_services:
                    root.setHidden(True)
            else:
                if header['SPID'] not in self.selected_SPID:
                    root.setHidden(True)

        if show_stat:
            total_packets = len(self.data)
            self.showMessage(('Total packet(s): %d' % total_packets))

    def onConnectTSCTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = tsc_connection.Ui_Dialog()
        diag_ui.setupUi(diag)
        self.tsc_host = self.settings.value('tsc_host', [], str)
        self.tsc_port = self.settings.value('tsc_port', [], str)
        if self.tsc_host:
            diag_ui.serverLineEdit.setText(self.tsc_host)
        if self.tsc_port:
            diag_ui.portLineEdit.setText(self.tsc_port)
        diag_ui.buttonBox.accepted.connect(partial(self.connectToTSC, diag_ui))
        diag.exec_()

    def connectToTSC(self, dui):
        host = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        self.showMessage('Connecting to TSC...')
        self.socketPacketReceiver = StixSocketPacketReceiver(host, int(port))
        self.socketPacketReceiver.packetArrival.connect(self.onPacketArrival)
        self.socketPacketReceiver.error.connect(self.onDataReaderError)
        self.socketPacketReceiver.info.connect(self.onDataReaderInfo)
        self.socketPacketReceiver.warn.connect(self.onDataReaderWarn)
        self.socketPacketReceiver.start()

    def onPacketArrival(self, packets):
        if packets:
            self.onDataReady(packets, clear=False, show_stat=True)

    def onLoadMongoDBTriggered(self):
        diag = QtWidgets.QDialog()
        diag_ui = mongo_dialog.Ui_Dialog()
        diag_ui.setupUi(diag)
        #self.settings = QtCore.QSettings('FHNW', 'stix_parser')
        self.mongo_server = self.settings.value('mongo_server', [], str)
        self.mongo_port = self.settings.value('mongo_port', [], str)
        self.mongo_user = self.settings.value('mongo_user', [], str)
        self.mongo_pwd = self.settings.value('mongo_pwd', [], str)

        if self.mongo_server:
            diag_ui.serverLineEdit.setText(self.mongo_server)
        if self.mongo_port:
            diag_ui.portLineEdit.setText(self.mongo_port)

        if self.mongo_user:
            diag_ui.userLineEdit.setText(self.mongo_user)
        if self.mongo_pwd:
            diag_ui.pwdLineEdit.setText(self.mongo_pwd)

        diag_ui.pushButton.clicked.connect(
            partial(self.loadRunsFromMongoDB, diag_ui))
        diag_ui.buttonBox.accepted.connect(
            partial(self.loadDataFromMongoDB, diag_ui, diag))
        diag.exec_()

    def loadRunsFromMongoDB(self, dui):
        server = dui.serverLineEdit.text()
        port = dui.portLineEdit.text()
        user = dui.userLineEdit.text()
        pwd = dui.pwdLineEdit.text()

        self.showMessage('saving setting...')
        if self.mongo_server != server:
            self.settings.setValue('mongo_server', server)
        if self.mongo_port != port:
            self.settings.setValue('mongo_port', port)

        if self.mongo_user != user:
            self.settings.setValue('mongo_user', user)
        if self.mongo_pwd != pwd:
            self.settings.setValue('mongo_pwd', pwd)

        self.showMessage('connecting Mongo database ...')
        self.mdb = mgdb.MongoDB(server, int(port), user, pwd)
        if not self.mdb.is_connected():
            return

        dui.treeWidget.clear()
        self.showMessage('Fetching data...')
        for run in self.mdb.get_runs():
            root = QtWidgets.QTreeWidgetItem(dui.treeWidget)
            root.setText(0, str(run['_id']))
            root.setText(1, run['filename'])
            root.setText(2, run['date'])
            root.setText(3, str(run['start']))
            root.setText(4, str(run['end']))

    def loadDataFromMongoDB(self, dui, diag):
        self.showMessage('Loading packets ...')
        selected_runs = []
        for item in dui.treeWidget.selectedItems():
            selected_runs.append(item.text(0))
        if not selected_runs:
            self.showMessage('Run not selected!')
        if selected_runs:
            diag.done(0)
            self.showMessage('Loading data ...!')
            data = self.mdb.get_packets(selected_runs[0])
            if data:
                self.onDataReady(data, clear=True)
            else:
                self.showMessage('No packets found!')
        # close

    def onPacketSelected(self, cur, pre):
        self.current_row = self.packetTreeWidget.currentIndex().row()
        self.showMessage(('Packet #%d selected' % self.current_row))
        self.showPacket(self.current_row)

    def showPacket(self, row):
        if not self.data:
            return
        header = self.data[row]['header']
        total_packets = len(self.data)
        self.showMessage(
            ('Packet %d / %d  %s ' % (row, total_packets, header['DESCR'])))
        self.paramTreeWidget.clear()
        header_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        header_root.setText(0, "Header")
        rows = len(header)
        for key, val in header.items():
            root = QtWidgets.QTreeWidgetItem(header_root)
            root.setText(0, key)
            root.setText(1, str(val))

        params = self.data[row]['parameters']
        param_root = QtWidgets.QTreeWidgetItem(self.paramTreeWidget)
        param_root.setText(0, "Parameters")
        self.showParameterTree(params, param_root)
        self.paramTreeWidget.expandItem(param_root)
        self.paramTreeWidget.expandItem(header_root)
        self.current_row = row

    def showParameterTree(self, params, parent):
        if not params:
            return
        for p in params:
            root = QtWidgets.QTreeWidgetItem(parent)
            if not p:
                continue
            try:
                param_name = p['name']
                desc = ''  #description of parameter
                if 'desc' in p:
                    desc = p['desc']
                if not desc:
                    desc = idb._stix_idb.get_PCF_description(param_name)
                scos_desc = idb._stix_idb.get_scos_description(param_name)
                if scos_desc:
                    root.setToolTip(1, scos_desc)
                root.setText(0, param_name)
                root.setText(1, desc)
                root.setText(2, str(p['raw']))
                try:
                    root.setToolTip(2, hex(p['raw'][0]))
                except:
                    pass
                root.setText(3, str(p['eng']))
                if 'children' in p:
                    if p['children']:
                        self.showParameterTree(p['children'], root)
            except KeyError:
                self.showMessage(
                    '[Error  ]: keyError occurred when adding parameter')
        self.paramTreeWidget.itemDoubleClicked.connect(self.onTreeItemClicked)

    def walk(self, name, params, header, ret_x, ret_y, xaxis=0, data_type=0):
        if not params:
            return
        timestamp = header['time']
        for p in params:
            if type(p) is not dict:
                continue
            if name == p['name']:
                values = None
                #print('data type:{}'.format(data_type))
                if data_type == 0:
                    values = p['raw']
                else:
                    values = p['eng']
                try:
                    yvalue = None
                    if (type(values) is tuple) or (type(values) is list):
                        yvalue = float(values[0])
                    else:
                        yvalue = float(values)
                    ret_y.append(yvalue)
                    if xaxis == 1:
                        ret_x.append(timestamp)
                    else:
                        self.showMessage(('Can not plot %s  ' % str(yvalue)))
                except Exception as e:
                    self.showMessage(('%s ' % str(e)))

            if 'children' in p:
                if p['children']:
                    self.walk(name, p['children'], header, ret_x, ret_y, xaxis,
                              data_type)

    def onPlotButtonClicked(self):
        if self.chart:
            self.chart.removeAllSeries()
        if not self.data:
            return
        self.showMessage('Preparing plot ...')
        name = self.paramNameEdit.text()
        packet_selection = self.comboBox.currentIndex()
        xaxis_type = self.xaxisComboBox.currentIndex()
        data_type = self.dataTypeComboBox.currentIndex()

        timestamp = []
        self.y = []
        packet_id = self.current_row
        params = self.data[packet_id]['parameters']
        header = self.data[packet_id]['header']
        current_spid = header['SPID']
        if packet_selection == 0:
            self.walk(name, params, header, timestamp, self.y, xaxis_type,
                      data_type)
        elif packet_selection == 1:
            for packet in self.data:
                header = packet['header']
                if packet['header']['SPID'] != current_spid:
                    continue
                params = packet['parameters']
                self.walk(name, params, header, timestamp, self.y, xaxis_type,
                          data_type)

        self.x = []

        if not self.y:
            self.showMessage('No data points')
        elif self.y:
            style = self.styleEdit.text()
            if not style:
                style = '-'
            title = '%s' % str(name)
            desc = self.descLabel.text()
            if desc:
                title += '- %s' % desc

            self.chart.setTitle(title)

            ylabel = 'Raw value'
            xlabel = name
            if data_type == 1:
                ylabel = 'Engineering  value'
            if xaxis_type == 0:
                if packet_selection == 1:
                    xlabel = "Packet #"
                else:
                    xlabel = "Repeat #"
                self.x = range(0, len(self.y))
            if xaxis_type == 1:
                self.x = [t - timestamp[0] for t in timestamp]
                xlabel = 'Time -T0 (s)'

            if xaxis_type != 2:
                series = QLineSeries()
                series2 = None
                for xx, yy in zip(self.x, self.y):
                    series.append(xx, yy)
                if 'o' in style:
                    series2 = QScatterSeries()
                    for xx, yy in zip(self.x, self.y):
                        series2.append(xx, yy)
                    self.chart.addSeries(series2)
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(xlabel)
                axisY = QValueAxis()
                axisY.setTitleText(ylabel)

                self.chart.setAxisX(axisX)
                self.chart.setAxisY(axisY)
                series.attachAxis(axisX)
                series.attachAxis(axisY)
            else:
                nbins = len(set(self.y))
                ycounts, xedges = np.histogram(self.y, bins=nbins)
                series = QLineSeries()
                for i in range(0, nbins):
                    meanx = (xedges[i] + xedges[i + 1]) / 2.
                    series.append(meanx, ycounts[i])
                self.chart.addSeries(series)
                axisX = QValueAxis()
                axisX.setTitleText(name)
                axisY = QValueAxis()
                axisY.setTitleText("Counts")

                self.chart.setAxisY(axisY)
                self.chart.setAxisX(axisX)
                series.attachAxis(axisX)
                series.attachAxis(axisY)

            self.xlabel = xlabel
            self.ylabel = ylabel
            self.chartView.setRubberBand(QChartView.RectangleRubberBand)
            self.chartView.setRenderHint(QtGui.QPainter.Antialiasing)
            msg = 'Y length: {}, min-Y:  {}, max-Y: {}'.format(
                len(self.y), min(self.y), max(self.y))

            self.showMessage(msg, 1)

            self.showMessage('The canvas updated!')

    def plotParameter(self, name=None, desc=None):
        self.tabWidget.setCurrentIndex(1)
        if name:
            self.paramNameEdit.setText(name)
        if desc:
            self.descLabel.setText(desc)

    def onPlotActionClicked(self):
        self.tabWidget.setCurrentIndex(1)
        self.plotParameter()

    def onTreeItemClicked(self, it, col):
        self.plotParameter(it.text(0), it.text(1))