示例#1
0
文件: widgets.py 项目: wpfff/plottr
class MPLPlotWidget(PlotWidget):
    """
    Base class for matplotlib-based plot widgets.
    Per default, add a canvas and the matplotlib NavBar.
    """
    def __init__(self, parent: Optional[QtWidgets.QWidget] = None):
        super().__init__(parent=parent)

        #: the plot widget
        self.plot = MPLPlot()

        #: the matplotlib toolbar
        self.mplBar = NavBar(self.plot, self)

        self.addMplBarOptions()
        defaultIconSize = int(16 * dpiScalingFactor(self))
        self.mplBar.setIconSize(QtCore.QSize(defaultIconSize, defaultIconSize))
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.plot)
        layout.addWidget(self.mplBar)
        self.setLayout(layout)

    def setMeta(self, data: DataDictBase) -> None:
        """Add meta info contained in the data to the figure.

        :param data: data object containing the meta information
            if meta field ``title`` or ``info`` are in the data object, then
            they will be added as text info to the figure.
        """
        if data.has_meta('title'):
            self.plot.setFigureTitle(data.meta_val('title'))

        if data.has_meta('info'):
            self.plot.setFigureInfo(data.meta_val('info'))

        all_meta = {}
        for k, v in sorted(data.meta_items()):
            this_meta = str(v)
            if len(this_meta) > 200:
                this_meta = this_meta[:200] + "..."
            all_meta[k] = this_meta
        self.plot.setMetaInfo(all_meta)

    def addMplBarOptions(self) -> None:
        """Add options for displaying ``info`` meta data and copying the figure to the clipboard to the
        plot toolbar."""
        self.mplBar.addSeparator()
        infoAction = self.mplBar.addAction('Show Info')
        infoAction.setCheckable(True)
        infoAction.toggled.connect(self.plot.setShowInfo)

        self.mplBar.addSeparator()
        self.mplBar.addAction('Copy Figure', self.plot.toClipboard)
        self.mplBar.addAction('Copy Meta', self.plot.metaToClipboard)
示例#2
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._molecule = nx.Graph()
        self._mapping = MappingModel(self._molecule)

        layout = QHBoxLayout()
        canvas_layout = QVBoxLayout()
        self.embeddings_box = QComboBox()
        self.embeddings_box.addItems(EMBEDDINGS.keys())
        self.embeddings_box.setEditable(False)
        self.embeddings_box.currentTextChanged.connect(self._set_embedding)

        canvas_layout.addWidget(self.embeddings_box)

        self.figure = Figure()
        self.canvas = MappingView(self.figure)
        canvas_layout.addWidget(self.canvas)

        canvas_toolbar = NavigationToolbar(self.canvas, self.canvas, False)
        canvas_toolbar.addSeparator()
        hide_mapping = QAction('Hide Mapping',
                               self,
                               icon=self.style().standardIcon(
                                   QStyle.SP_DesktopIcon))
        hide_mapping.triggered.connect(self.canvas.hide_mapping)
        canvas_toolbar.addAction(hide_mapping)

        remove_mapping = QAction('Remove Mapping',
                                 self,
                                 icon=self.style().standardIcon(
                                     QStyle.SP_DialogDiscardButton))
        remove_mapping.triggered.connect(self.canvas.remove_mapping)
        canvas_toolbar.addAction(remove_mapping)

        canvas_layout.addWidget(canvas_toolbar, alignment=Qt.AlignBottom)

        layout.addLayout(canvas_layout)

        self._table = QTableView()
        self._table.horizontalHeader().setStretchLastSection(True)
        layout.addWidget(self._table)

        self.setLayout(layout)
        self._set_embedding(self.embeddings_box.currentText())
示例#3
0
class PlotWidget(QtWidgets.QWidget):
    """ Qt widget to hold the matplotlib canvas and the tools for interacting with the plots """
    def __init__(self, data, xlabel, ylabel):
        QtWidgets.QWidget.__init__(self)

        self.setLayout(QtWidgets.QVBoxLayout())
        self.canvas = PlotCanvas(data, xlabel, ylabel)        
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.addSeparator()
        
        self.ACshowselector = QtWidgets.QAction('Activate/Clear RangeSelector')
        self.ACshowselector.setIconText('RANGE SELECTOR')
        self.ACshowselector.setFont(QtGui.QFont("Times", 12, QtGui.QFont.Bold))
        self.ACshowselector.triggered.connect(self.toggle_showselector)

        self.toolbar.addAction(self.ACshowselector)
        self.toolbar.addSeparator()
        self.layout().addWidget(self.toolbar)
        self.layout().addWidget(self.canvas)

    def toggle_showselector(self):
        self.canvas.toggle_rangeselector()
示例#4
0
class _MPLPlotWidget(PlotWidget):
    """
    Base class for matplotlib-based plot widgets.
    Per default, add a canvas and the matplotlib NavBar.
    """
    def __init__(self, parent: Optional[QtWidgets.QWidget] = None):
        super().__init__(parent=parent)

        setMplDefaults(self)
        scaling = np.rint(self.logicalDpiX() / 96.0)
        defaultIconSize = 16 * scaling

        self.plot = MPLPlot()
        self.mplBar = NavBar(self.plot, self)
        self.addMplBarOptions()
        self.mplBar.setIconSize(QtCore.QSize(defaultIconSize, defaultIconSize))

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.plot)
        layout.addWidget(self.mplBar)
        self.setLayout(layout)

    def setMeta(self, data: DataDictBase) -> None:
        if data.has_meta('title'):
            self.plot.setFigureTitle(data.meta_val('title'))

        if data.has_meta('info'):
            self.plot.setFigureInfo(data.meta_val('info'))

        meta_info = {}
        for meta_key in ('qcodes_guid', 'qcodes_sample_name',
                         'qcodes_experiment_name', 'qcodes_dataset_name',
                         'qcodes_runId', 'qcodes_db', 'qcodes_completedTS',
                         'qcodes_runTS'):
            if data.has_meta(meta_key):
                key_without_prefix = (meta_key.replace("qcodes_", "")
                                      if meta_key.startswith("qcodes_") else
                                      meta_key)
                meta_info[key_without_prefix] = data.meta_val(meta_key)

        self.plot.setMetaInfo(meta_info=meta_info)

    def addMplBarOptions(self) -> None:
        tlCheck = QtWidgets.QCheckBox('Tight layout')
        tlCheck.toggled.connect(self.plot.setTightLayout)

        infoCheck = QtWidgets.QCheckBox('Info')
        infoCheck.toggled.connect(self.plot.setShowInfo)

        self.mplBar.addSeparator()
        self.mplBar.addWidget(tlCheck)
        self.mplBar.addSeparator()
        self.mplBar.addWidget(infoCheck)
        self.mplBar.addSeparator()
        self.mplBar.addAction('Copy plot', self.plot.toClipboard)
        self.mplBar.addAction('Copy metadata', self.plot.metaToClipboard)
示例#5
0
文件: mpl.py 项目: neildick/plottr
class MPLPlotWidget(QtGui.QWidget):
    """
    Base class for matplotlib-based plot widgets.
    Per default, add a canvas and the matplotlib NavBar.
    """
    def __init__(self, parent=None):
        super().__init__(parent=parent)

        setMplDefaults()

        self.plot = MPLPlot()
        self.mplBar = NavBar(self.plot, self)
        self.addMplBarOptions()

        self.toolLayout = QtGui.QHBoxLayout()

        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addLayout(self.toolLayout)
        self.layout.addWidget(self.plot)
        self.layout.addWidget(self.mplBar)

    def setData(self, data: DataDictBase):
        raise NotImplementedError

    def setMeta(self, data: DataDictBase):
        if data.has_meta('title'):
            self.plot.setFigureTitle(data.meta_val('title'))

        if data.has_meta('info'):
            self.plot.setFigureInfo(data.meta_val('info'))

    def addMplBarOptions(self):
        tlCheck = QtGui.QCheckBox('Tight layout')
        tlCheck.toggled.connect(self.plot.setTightLayout)

        infoCheck = QtGui.QCheckBox('Info')
        infoCheck.toggled.connect(self.plot.setShowInfo)

        self.mplBar.addSeparator()
        self.mplBar.addWidget(tlCheck)
        self.mplBar.addSeparator()
        self.mplBar.addWidget(infoCheck)
        self.mplBar.addSeparator()
        self.mplBar.addAction('Copy', self.plot.toClipboard)
示例#6
0
文件: mpl.py 项目: labist/plottr
class _MPLPlotWidget(PlotWidget):
    """
    Base class for matplotlib-based plot widgets.
    Per default, add a canvas and the matplotlib NavBar.
    """
    def __init__(self, parent: Optional[QtWidgets.QWidget] = None):
        super().__init__(parent=parent)

        setMplDefaults(self)
        scaling = np.rint(self.logicalDpiX() / 96.0)
        defaultIconSize = 16 * scaling

        self.plot = MPLPlot()
        self.mplBar = NavBar(self.plot, self)
        self.addMplBarOptions()
        self.mplBar.setIconSize(QtCore.QSize(defaultIconSize, defaultIconSize))

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.plot)
        layout.addWidget(self.mplBar)
        self.setLayout(layout)

    def setMeta(self, data: DataDictBase) -> None:
        if data.has_meta('title'):
            self.plot.setFigureTitle(data.meta_val('title'))

        if data.has_meta('info'):
            self.plot.setFigureInfo(data.meta_val('info'))

    def addMplBarOptions(self) -> None:
        tlCheck = QtWidgets.QCheckBox('Tight layout')
        tlCheck.toggled.connect(self.plot.setTightLayout)

        infoCheck = QtWidgets.QCheckBox('Info')
        infoCheck.toggled.connect(self.plot.setShowInfo)

        self.mplBar.addSeparator()
        self.mplBar.addWidget(tlCheck)
        self.mplBar.addSeparator()
        self.mplBar.addWidget(infoCheck)
        self.mplBar.addSeparator()
        self.mplBar.addAction('Copy', self.plot.toClipboard)
示例#7
0
    def _create_window(self):
        '''
        Create the QT window and all widgets
        '''
        self.setWindowTitle("Our QT Plot")
        
        if self.settings.value("geometry") == None: # First launch on this computer
            self.left = 200
            self.top = 400
            self.width = 1240
            self.height = 960
            self.setGeometry(self.left, self.top, self.width, self.height)
        else:   # restored saved windows position
            self.restoreGeometry(self.settings.value("geometry"))
        
        nav_toolbar_home = NavigationToolbar.home
        
        def new_home(self, *args, **kwargs):
            print ('new home')
            nav_toolbar_home(self, *args, **kwargs)

        NavigationToolbar.home = new_home

        
        self.tab_widget = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        #self.tabs.resize(300,200)
        
        # Add tabs
        self.tab_widget.addTab(self.tab1,"Timeseries Plot")
        self.tab_widget.addTab(self.tab2,"XY Plot")
        
        # Create first timeseries tab
        self.tab1.layout = QHBoxLayout()
        timeseries_canvas = FigureCanvas(Figure())
        self.main_figure = timeseries_canvas.figure
        self.tab1.layout.addWidget(timeseries_canvas)
        timeseries_nav_tb = NavigationToolbar(timeseries_canvas, self)
        timeseries_nav_tb.setOrientation(Qt.Vertical)
        
        # Relove last plot button
        timeseries_removePlotButton = QToolButton()
        timeseries_removePlotButton.setIcon(QApplication.style().standardIcon(QStyle.SP_DialogOkButton))
        timeseries_removePlotButton.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        timeseries_removePlotButton.setToolTip('Remove Last Plot')
        timeseries_nav_tb.addSeparator()
        timeseries_nav_tb.addWidget(timeseries_removePlotButton)
        timeseries_removePlotButton.clicked.connect(self._remove_last_subplot)
        
        # Clear plot button
        timeseries_clear_button = QToolButton()
        timeseries_clear_button.setIcon(QApplication.style().standardIcon(QStyle.SP_BrowserStop))
        timeseries_clear_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        timeseries_clear_button.setToolTip('Clear All Plots')
        timeseries_nav_tb.addWidget(timeseries_clear_button)
        timeseries_clear_button.clicked.connect(self._remove_all_timeseries_subplots)
        
        timeseries_nav_tb.setFixedWidth(36)
        self.tab1.layout.addWidget(timeseries_nav_tb)
        self.tab1.setLayout(self.tab1.layout)

        # Create XY figure tab
        self.tab2.layout = QHBoxLayout()
        xy_canvas = FigureCanvas(Figure())
        self.xy_figure = xy_canvas.figure
        self.xy_axes = self.xy_figure.subplots(1, 1)
        self.tab2.layout.addWidget(xy_canvas)
        
        xy_nav_tb = NavigationToolbar(xy_canvas, self)
        xy_nav_tb.setOrientation(Qt.Vertical)
        xy_clear_button = QToolButton()
        xy_clear_button.setIcon(QApplication.style().standardIcon(QStyle.SP_BrowserStop))
        xy_clear_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        xy_clear_button.setToolTip('Clear All Plots') 
        xy_nav_tb.addSeparator()
        xy_nav_tb.addWidget(xy_clear_button)
        xy_clear_button.clicked.connect(self._clear_xy_axes)
        xy_nav_tb.setFixedWidth(36)
        #xy_nav_tb.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.tab2.layout.addWidget(xy_nav_tb)
        self.tab2.setLayout(self.tab2.layout)
        
        self.setCentralWidget(self.tab_widget)
        
        #self.addToolBar(NavigationToolbar(timeseries_canvas, self))

        # Add time series plot buttons
        self.tsp_widget = QDockWidget("Select Timeseries Plot", self)
        self.tsp_button_Group = QGroupBox()
        self.tsp_button_Group.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)

        tsp_button_GroupLayout = QVBoxLayout()
        
        tsplotButtonList = []
        
        for time_series_buttons_dict_key, time_series_buttons_dict_value in sorted(self.time_series_buttons_dict.iteritems()):
            buttonwidget = QPushButton(time_series_buttons_dict_key)
            #buttonwidget.clicked.connect(lambda: self._add_new_plot(time_series_buttons_dict_value))
            buttonwidget.clicked.connect(partial(self._add_new_plot, time_series_buttons_dict_value))
            tsp_button_GroupLayout.addWidget(buttonwidget)
            tsplotButtonList.append(buttonwidget)
        

        tsp_button_GroupLayout.addStretch(1)
        self.tsp_button_Group.setLayout(tsp_button_GroupLayout)
        
        self.tsp_widget.setWidget(self.tsp_button_Group)
        self.tsp_widget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.tsp_widget.setFloating(False)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.tsp_widget)
        
        # Add xy plot buttons
        self.xyp_widget = QDockWidget("Select XY Plot", self)
        self.xyp_button_Group = QGroupBox()
        self.xyp_button_Group.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)

        xyp_button_GroupLayout = QVBoxLayout()
        
        xyplotButtonList = []
        
        for xy_buttons_dict_key, xy_buttons_dict_value in self.xy_buttons_dict.items():
            buttonwidget = QPushButton(xy_buttons_dict_key)
            #buttonwidget.clicked.connect(lambda: self._add_new_plot(xy_buttons_dict_value))
            buttonwidget.clicked.connect(partial(self._add_new_xy_plot, xy_buttons_dict_value))
            xyp_button_GroupLayout.addWidget(buttonwidget)
            xyplotButtonList.append(buttonwidget)
        
        #xyp_button_GroupLayout.addWidget(xy_clear_button)
        
        xyp_button_GroupLayout.addStretch(1)
        self.xyp_button_Group.setLayout(xyp_button_GroupLayout)
        
        self.xyp_widget.setWidget(self.xyp_button_Group)
        self.xyp_widget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.xyp_widget.setFloating(False)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.xyp_widget)

        # Add load data button
        self.openDataWidget = QDockWidget("Open Data File", self)
        self.openDataGroup = QGroupBox()
        self.openDataGroup.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        openDataGroupLayout = QHBoxLayout()
        openDataButton = QPushButton("Load Datafile")
        openDataButton.setDefault(False)
        #openDataButton.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
        openDataButton.clicked.connect(self._load_datafile)
        openDataGroupLayout.addWidget(openDataButton)
        self.openDataGroup.setLayout(openDataGroupLayout)
        self.openDataWidget.setWidget(self.openDataGroup)
        self.openDataWidget.setFloating(False)
        self.addDockWidget(Qt.TopDockWidgetArea, self.openDataWidget)
        
        self.memory_status_qlabel = QLabel("Memory: {:.1f}%".format(0))
        self.statusBar().addPermanentWidget(self.memory_status_qlabel)
示例#8
0
class FigureTab:
    cursors = [15000, 45000]
    colors = ['orange', 'violet']

    def __init__(self, layout, vna):
        # create figure
        self.figure = Figure()
        if sys.platform != 'win32':
            self.figure.set_facecolor('none')
        self.canvas = FigureCanvas(self.figure)
        layout.addWidget(self.canvas)
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, None, False)
        self.toolbar.layout().setSpacing(6)
        # remove subplots action
        actions = self.toolbar.actions()
        if int(matplotlib.__version__[0]) < 2:
            self.toolbar.removeAction(actions[7])
        else:
            self.toolbar.removeAction(actions[6])
        self.toolbar.addSeparator()
        self.cursorLabels = {}
        self.cursorValues = {}
        self.cursorMarkers = {}
        self.cursorPressed = {}
        for i in range(len(self.cursors)):
            self.cursorMarkers[i] = None
            self.cursorPressed[i] = False
            self.cursorLabels[i] = QLabel('Cursor %d, kHz' % (i + 1))
            self.cursorLabels[i].setStyleSheet('color: %s' % self.colors[i])
            self.cursorValues[i] = QSpinBox()
            self.cursorValues[i].setMinimumSize(90, 0)
            self.cursorValues[i].setSingleStep(10)
            self.cursorValues[i].setAlignment(Qt.AlignRight | Qt.AlignTrailing
                                              | Qt.AlignVCenter)
            self.toolbar.addWidget(self.cursorLabels[i])
            self.toolbar.addWidget(self.cursorValues[i])
            self.cursorValues[i].valueChanged.connect(
                partial(self.set_cursor, i))
            self.canvas.mpl_connect('button_press_event',
                                    partial(self.press_marker, i))
            self.canvas.mpl_connect('motion_notify_event',
                                    partial(self.move_marker, i))
            self.canvas.mpl_connect('button_release_event',
                                    partial(self.release_marker, i))
        self.toolbar.addSeparator()
        self.plotButton = QPushButton('Rescale')
        self.toolbar.addWidget(self.plotButton)
        layout.addWidget(self.toolbar)
        self.plotButton.clicked.connect(self.plot)
        self.mode = None
        self.vna = vna

    def add_cursors(self, axes):
        if self.mode == 'gain_short' or self.mode == 'gain_open':
            columns = ['Freq., kHz', 'G, dB', r'$\angle$ G, deg']
        else:
            columns = [
                'Freq., kHz', 'Re(Z), \u03A9', 'Im(Z), \u03A9', '|Z|, \u03A9',
                r'$\angle$ Z, deg', 'SWR', r'|$\Gamma$|',
                r'$\angle$ $\Gamma$, deg', 'RL, dB'
            ]
        y = len(self.cursors) * 0.04 + 0.01
        for i in range(len(columns)):
            self.figure.text(0.19 + 0.1 * i,
                             y,
                             columns[i],
                             horizontalalignment='right')
        self.cursorRows = {}
        for i in range(len(self.cursors)):
            y = len(self.cursors) * 0.04 - 0.03 - 0.04 * i
            self.figure.text(0.01,
                             y,
                             'Cursor %d' % (i + 1),
                             color=self.colors[i])
            self.cursorRows[i] = {}
            for j in range(len(columns)):
                self.cursorRows[i][j] = self.figure.text(
                    0.19 + 0.1 * j, y, '', horizontalalignment='right')
            if self.mode == 'smith':
                self.cursorMarkers[i], = axes.plot(0.0,
                                                   0.0,
                                                   marker='o',
                                                   color=self.colors[i])
            else:
                self.cursorMarkers[i] = axes.axvline(0.0,
                                                     color=self.colors[i],
                                                     linewidth=2)
            self.set_cursor(i, self.cursorValues[i].value())

    def set_cursor(self, index, value):
        FigureTab.cursors[index] = value
        marker = self.cursorMarkers[index]
        if marker is None: return
        row = self.cursorRows[index]
        freq = value
        gamma = self.vna.gamma(freq)
        if self.mode == 'smith':
            marker.set_xdata(gamma.real)
            marker.set_ydata(gamma.imag)
        else:
            marker.set_xdata(freq)
        row[0].set_text('%d' % freq)
        if self.mode == 'gain_short':
            gain = self.vna.gain_short(freq)
            magnitude = 20.0 * np.log10(np.absolute(gain))
            angle = np.angle(gain, deg=True)
            row[1].set_text(unicode_minus('%.1f' % magnitude))
            row[2].set_text(unicode_minus('%.1f' % angle))
        elif self.mode == 'gain_open':
            gain = self.vna.gain_open(freq)
            magnitude = 20.0 * np.log10(np.absolute(gain))
            angle = np.angle(gain, deg=True)
            row[1].set_text(unicode_minus('%.1f' % magnitude))
            row[2].set_text(unicode_minus('%.1f' % angle))
        else:
            swr = self.vna.swr(freq)
            z = self.vna.impedance(freq)
            rl = 20.0 * np.log10(np.absolute(gamma))
            if rl > -0.01: rl = 0.0
            row[1].set_text(metric_prefix(z.real))
            row[2].set_text(metric_prefix(z.imag))
            row[3].set_text(metric_prefix(np.absolute(z)))
            angle = np.angle(z, deg=True)
            if np.abs(angle) < 0.1: angle = 0.0
            row[4].set_text(unicode_minus('%.1f' % angle))
            row[5].set_text(unicode_minus('%.2f' % swr))
            row[6].set_text(unicode_minus('%.2f' % np.absolute(gamma)))
            angle = np.angle(gamma, deg=True)
            if np.abs(angle) < 0.1: angle = 0.0
            row[7].set_text(unicode_minus('%.1f' % angle))
            row[8].set_text(unicode_minus('%.2f' % rl))
        self.canvas.draw()

    def press_marker(self, index, event):
        if not event.inaxes: return
        if self.mode == 'smith': return
        marker = self.cursorMarkers[index]
        if marker is None: return
        contains, misc = marker.contains(event)
        if not contains: return
        self.cursorPressed[index] = True

    def move_marker(self, index, event):
        if not event.inaxes: return
        if self.mode == 'smith': return
        if not self.cursorPressed[index]: return
        self.cursorValues[index].setValue(event.xdata)

    def release_marker(self, index, event):
        self.cursorPressed[index] = False

    def xlim(self, freq):
        start = freq[0]
        stop = freq[-1]
        min = np.minimum(start, stop)
        max = np.maximum(start, stop)
        margin = (max - min) / 50
        return (min - margin, max + margin)

    def plot(self):
        getattr(self, 'plot_%s' % self.mode)()

    def update(self, mode):
        start = self.vna.dut.freq[0]
        stop = self.vna.dut.freq[-1]
        min = np.minimum(start, stop)
        max = np.maximum(start, stop)
        for i in range(len(self.cursors)):
            value = self.cursors[i]
            self.cursorValues[i].setRange(min, max)
            self.cursorValues[i].setValue(value)
            self.set_cursor(i, value)
        getattr(self, 'update_%s' % mode)()

    def plot_curves(self, freq, data1, label1, limit1, data2, label2, limit2):
        matplotlib.rcdefaults()
        matplotlib.rcParams['axes.formatter.use_mathtext'] = True
        self.figure.clf()
        bottom = len(self.cursors) * 0.04 + 0.13
        self.figure.subplots_adjust(left=0.16,
                                    bottom=bottom,
                                    right=0.84,
                                    top=0.96)
        axes1 = self.figure.add_subplot(111)
        axes1.cla()
        axes1.xaxis.grid()
        axes1.set_xlabel('kHz')
        axes1.set_ylabel(label1)
        xlim = self.xlim(freq)
        axes1.set_xlim(xlim)
        if limit1 is not None: axes1.set_ylim(limit1)
        self.curve1, = axes1.plot(freq, data1, color='blue', label=label1)
        self.add_cursors(axes1)
        if data2 is None:
            self.canvas.draw()
            return
        axes1.tick_params('y', color='blue', labelcolor='blue')
        axes1.yaxis.label.set_color('blue')
        axes2 = axes1.twinx()
        axes2.spines['left'].set_color('blue')
        axes2.spines['right'].set_color('red')
        axes2.set_ylabel(label2)
        axes2.set_xlim(xlim)
        if limit2 is not None: axes2.set_ylim(limit2)
        axes2.tick_params('y', color='red', labelcolor='red')
        axes2.yaxis.label.set_color('red')
        self.curve2, = axes2.plot(freq, data2, color='red', label=label2)
        self.canvas.draw()

    def plot_gain(self, gain):
        freq = self.vna.dut.freq
        data1 = 20.0 * np.log10(np.absolute(gain))
        data2 = np.angle(gain, deg=True)
        self.plot_curves(freq, data1, 'G, dB', (-110, 110.0), data2,
                         r'$\angle$ G, deg', (-198, 198))

    def plot_gain_short(self):
        self.mode = 'gain_short'
        self.plot_gain(self.vna.gain_short(self.vna.dut.freq))

    def plot_gain_open(self):
        self.mode = 'gain_open'
        self.plot_gain(self.vna.gain_open(self.vna.dut.freq))

    def update_gain(self, gain, mode):
        if self.mode == mode:
            self.curve1.set_xdata(self.vna.dut.freq)
            self.curve1.set_ydata(20.0 * np.log10(np.absolute(gain)))
            self.curve2.set_xdata(self.vna.dut.freq)
            self.curve2.set_ydata(np.angle(gain, deg=True))
            self.canvas.draw()
        else:
            self.mode = mode
            self.plot_gain(gain)

    def update_gain_short(self):
        self.update_gain(self.vna.gain_short(self.vna.dut.freq), 'gain_short')

    def update_gain_open(self):
        self.update_gain(self.vna.gain_open(self.vna.dut.freq), 'gain_open')

    def plot_magphase(self, freq, data, label, mode):
        self.mode = mode
        data1 = np.absolute(data)
        data2 = np.angle(data, deg=True)
        max = np.fmax(0.01, data1.max())
        label1 = r'|%s|' % label
        label2 = r'$\angle$ %s, deg' % label
        self.plot_curves(freq, data1, label1, (-0.05 * max, 1.05 * max), data2,
                         label2, (-198, 198))

    def update_magphase(self, freq, data, label, mode):
        if self.mode == mode:
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(np.absolute(data))
            self.curve2.set_xdata(freq)
            self.curve2.set_ydata(np.angle(data, deg=True))
            self.canvas.draw()
        else:
            self.plot_magphase(freq, data, label, mode)

    def plot_open(self):
        self.plot_magphase(self.vna.open.freq, self.vna.open.data, 'open',
                           'open')

    def update_open(self):
        self.update_magphase(self.vna.open.freq, self.vna.open.data, 'open',
                             'open')

    def plot_short(self):
        self.plot_magphase(self.vna.short.freq, self.vna.short.data, 'short',
                           'short')

    def update_short(self):
        self.update_magphase(self.vna.short.freq, self.vna.short.data, 'short',
                             'short')

    def plot_load(self):
        self.plot_magphase(self.vna.load.freq, self.vna.load.data, 'load',
                           'load')

    def update_load(self):
        self.update_magphase(self.vna.load.freq, self.vna.load.data, 'load',
                             'load')

    def plot_dut(self):
        self.plot_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

    def update_dut(self):
        self.update_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut',
                             'dut')

    def plot_smith_grid(self, axes, color):
        load = 50.0
        ticks = np.array([0.0, 0.2, 0.5, 1.0, 2.0, 5.0])
        for tick in ticks * load:
            axis = np.logspace(-4, np.log10(1.0e3), 200) * load
            z = tick + 1.0j * axis
            gamma = (z - load) / (z + load)
            axes.plot(gamma.real,
                      gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            axes.plot(gamma.real,
                      -gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            z = axis + 1.0j * tick
            gamma = (z - load) / (z + load)
            axes.plot(gamma.real,
                      gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            axes.plot(gamma.real,
                      -gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            if tick == 0.0:
                axes.text(1.0,
                          0.0,
                          u'\u221E',
                          color=color,
                          ha='left',
                          va='center',
                          clip_on=True,
                          fontsize='x-large')
                axes.text(-1.0,
                          0.0,
                          u'0\u03A9',
                          color=color,
                          ha='left',
                          va='bottom',
                          clip_on=True)
                continue
            lab = u'%d\u03A9' % tick
            x = (tick - load) / (tick + load)
            axes.text(x,
                      0.0,
                      lab,
                      color=color,
                      ha='left',
                      va='bottom',
                      clip_on=True)
            lab = u'j%d\u03A9' % tick
            z = 1.0j * tick
            gamma = (z - load) / (z + load) * 1.05
            x = gamma.real
            y = gamma.imag
            angle = np.angle(gamma) * 180.0 / np.pi - 90.0
            axes.text(x,
                      y,
                      lab,
                      color=color,
                      ha='center',
                      va='center',
                      clip_on=True,
                      rotation=angle)
            lab = u'\u2212j%d\u03A9' % tick
            axes.text(x,
                      -y,
                      lab,
                      color=color,
                      ha='center',
                      va='center',
                      clip_on=True,
                      rotation=-angle)

    def plot_smith(self):
        self.mode = 'smith'
        matplotlib.rcdefaults()
        self.figure.clf()
        bottom = len(self.cursors) * 0.04 + 0.05
        self.figure.subplots_adjust(left=0.0,
                                    bottom=bottom,
                                    right=1.0,
                                    top=1.0)
        axes1 = self.figure.add_subplot(111)
        self.plot_smith_grid(axes1, 'blue')
        gamma = self.vna.gamma(self.vna.dut.freq)
        self.curve1, = axes1.plot(gamma.real, gamma.imag, color='red')
        axes1.axis('equal')
        axes1.set_xlim(-1.12, 1.12)
        axes1.set_ylim(-1.12, 1.12)
        axes1.xaxis.set_visible(False)
        axes1.yaxis.set_visible(False)
        for loc, spine in axes1.spines.items():
            spine.set_visible(False)
        self.add_cursors(axes1)
        self.canvas.draw()

    def update_smith(self):
        if self.mode == 'smith':
            gamma = self.vna.gamma(self.vna.dut.freq)
            self.curve1.set_xdata(gamma.real)
            self.curve1.set_ydata(gamma.imag)
            self.canvas.draw()
        else:
            self.plot_smith()

    def plot_imp(self):
        self.mode = 'imp'
        freq = self.vna.dut.freq
        z = self.vna.impedance(freq)
        data1 = np.fmin(9.99e4, np.absolute(z))
        data2 = np.angle(z, deg=True)
        max = np.fmax(0.01, data1.max())
        self.plot_curves(freq, data1, '|Z|, \u03A9', (-0.05 * max, 1.05 * max),
                         data2, r'$\angle$ Z, deg', (-198, 198))

    def update_imp(self):
        if self.mode == 'imp':
            freq = self.vna.dut.freq
            z = self.vna.impedance(freq)
            data1 = np.fmin(9.99e4, np.absolute(z))
            data2 = np.angle(z, deg=True)
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(data1)
            self.curve2.set_xdata(freq)
            self.curve2.set_ydata(data2)
            self.canvas.draw()
        else:
            self.plot_imp()

    def plot_swr(self):
        self.mode = 'swr'
        freq = self.vna.dut.freq
        data1 = self.vna.swr(freq)
        self.plot_curves(freq, data1, 'SWR', (0.9, 3.1), None, None, None)

    def update_swr(self):
        if self.mode == 'swr':
            self.curve1.set_xdata(self.vna.dut.freq)
            self.curve1.set_ydata(self.vna.swr(self.vna.dut.freq))
            self.canvas.draw()
        else:
            self.plot_swr()

    def plot_gamma(self):
        self.plot_magphase(self.vna.dut.freq,
                           self.vna.gamma(self.vna.dut.freq), r'$\Gamma$',
                           'gamma')

    def update_gamma(self):
        self.update_magphase(self.vna.dut.freq,
                             self.vna.gamma(self.vna.dut.freq), r'$\Gamma$',
                             'gamma')

    def plot_rl(self):
        self.mode = 'rl'
        freq = self.vna.dut.freq
        gamma = self.vna.gamma(freq)
        data1 = 20.0 * np.log10(np.absolute(gamma))
        self.plot_curves(freq, data1, 'RL, dB', (-105, 5.0), None, None, None)

    def update_rl(self):
        if self.mode == 'rl':
            freq = self.vna.dut.freq
            gamma = self.vna.gamma(freq)
            data1 = 20.0 * np.log10(np.absolute(gamma))
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(data1)
            self.canvas.draw()
        else:
            self.plot_rl()
示例#9
0
class dae2DPlot(QtWidgets.QDialog):
    plotDefaults = [
        daePlot2dDefaults('black', 0.5, 'solid', 'o', 6, 'black', 'black'),
        daePlot2dDefaults('blue', 0.5, 'solid', 's', 6, 'blue', 'black'),
        daePlot2dDefaults('red', 0.5, 'solid', '^', 6, 'red', 'black'),
        daePlot2dDefaults('green', 0.5, 'solid', 'p', 6, 'green', 'black'),
        daePlot2dDefaults('c', 0.5, 'solid', 'h', 6, 'c', 'black'),
        daePlot2dDefaults('m', 0.5, 'solid', '*', 6, 'm', 'black'),
        daePlot2dDefaults('k', 0.5, 'solid', 'd', 6, 'k', 'black'),
        daePlot2dDefaults('y', 0.5, 'solid', 'x', 6, 'y', 'black'),
        daePlot2dDefaults('black', 0.5, 'dashed', 'o', 6, 'black', 'black'),
        daePlot2dDefaults('blue', 0.5, 'dashed', 's', 6, 'blue', 'black'),
        daePlot2dDefaults('red', 0.5, 'dashed', '^', 6, 'red', 'black'),
        daePlot2dDefaults('green', 0.5, 'dashed', 'p', 6, 'green', 'black'),
        daePlot2dDefaults('c', 0.5, 'dashed', 'h', 6, 'c', 'black'),
        daePlot2dDefaults('m', 0.5, 'dashed', '*', 6, 'm', 'black'),
        daePlot2dDefaults('k', 0.5, 'dashed', 'd', 6, 'k', 'black'),
        daePlot2dDefaults('y', 0.5, 'dashed', 'x', 6, 'y', 'black'),
        daePlot2dDefaults('black', 0.5, 'dotted', 'o', 6, 'black', 'black'),
        daePlot2dDefaults('blue', 0.5, 'dotted', 's', 6, 'blue', 'black'),
        daePlot2dDefaults('red', 0.5, 'dotted', '^', 6, 'red', 'black'),
        daePlot2dDefaults('green', 0.5, 'dotted', 'p', 6, 'green', 'black'),
        daePlot2dDefaults('c', 0.5, 'dotted', 'h', 6, 'c', 'black'),
        daePlot2dDefaults('m', 0.5, 'dotted', '*', 6, 'm', 'black'),
        daePlot2dDefaults('k', 0.5, 'dotted', 'd', 6, 'k', 'black'),
        daePlot2dDefaults('y', 0.5, 'dotted', 'x', 6, 'y', 'black')
    ]

    def __init__(self, parent, updateInterval=0, animated=False):
        QtWidgets.QDialog.__init__(self, parent, QtCore.Qt.Window)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

        self.plotter = parent

        self.legendOn = True
        self.gridOn = True
        self.curves = []
        self.funcAnimation = None
        self._isAnimating = False
        self._timer = None
        self._cv_dlg = None
        self.xmin_policy = 0
        self.xmax_policy = 0
        self.ymin_policy = 1
        self.ymax_policy = 1

        if animated == True:
            self.updateInterval = updateInterval
            self.plotType = daeChooseVariable.plot2DAnimated
        elif updateInterval == 0:
            self.updateInterval = 0
            self.plotType = daeChooseVariable.plot2D
        else:
            self.updateInterval = int(updateInterval)
            self.plotType = daeChooseVariable.plot2DAutoUpdated

        self.setWindowTitle("2D plot")
        self.setWindowIcon(QtGui.QIcon(join(images_dir, 'line-chart.png')))

        exit = QtWidgets.QAction(QtGui.QIcon(join(images_dir, 'close.png')),
                                 'Exit', self)
        exit.setShortcut('Ctrl+Q')
        exit.setStatusTip('Exit application')
        exit.triggered.connect(self.close)

        export = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'template.png')), 'Export template',
            self)
        export.setShortcut('Ctrl+X')
        export.setStatusTip('Export template')
        export.triggered.connect(self.slotExportTemplate)

        properties = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'preferences.png')), 'Options', self)
        properties.setShortcut('Ctrl+P')
        properties.setStatusTip('Options')
        properties.triggered.connect(self.slotProperties)

        grid = QtWidgets.QAction(QtGui.QIcon(join(images_dir, 'grid.png')),
                                 'Grid on/off', self)
        grid.setShortcut('Ctrl+G')
        grid.setStatusTip('Grid on/off')
        grid.triggered.connect(self.slotToggleGrid)

        legend = QtWidgets.QAction(QtGui.QIcon(join(images_dir, 'legend.png')),
                                   'Legend on/off', self)
        legend.setShortcut('Ctrl+L')
        legend.setStatusTip('Legend on/off')
        legend.triggered.connect(self.slotToggleLegend)

        viewdata = QtWidgets.QAction(QtGui.QIcon(join(images_dir, 'data.png')),
                                     'View tabular data', self)
        viewdata.setShortcut('Ctrl+T')
        viewdata.setStatusTip('View tabular data')
        viewdata.triggered.connect(self.slotViewTabularData)

        export_csv = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'csv.png')), 'Export CSV', self)
        export_csv.setShortcut('Ctrl+S')
        export_csv.setStatusTip('Export CSV')
        export_csv.triggered.connect(self.slotExportCSV)

        fromUserData = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'add-user-data.png')),
            'Add line from the user-provided data...', self)
        fromUserData.setShortcut('Ctrl+D')
        fromUserData.setStatusTip('Add line from the user-provided data')
        fromUserData.triggered.connect(self.slotFromUserData)

        remove_line = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'remove.png')), 'Remove line', self)
        remove_line.setShortcut('Ctrl+R')
        remove_line.setStatusTip('Remove line')
        remove_line.triggered.connect(self.slotRemoveLine)

        new_line = QtWidgets.QAction(QtGui.QIcon(join(images_dir, 'add.png')),
                                     'Add line', self)
        new_line.setShortcut('Ctrl+A')
        new_line.setStatusTip('Add line')
        if animated == True:
            new_line.triggered.connect(self.newAnimatedCurve)
        else:
            new_line.triggered.connect(self.newCurve)

        play_animation = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'media-playback-start.png')),
            'Start animation', self)
        play_animation.setShortcut('Ctrl+S')
        play_animation.setStatusTip('Start animation')
        play_animation.triggered.connect(self.playAnimation)
        self.play_animation = play_animation  # save it

        stop_animation = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'media-playback-stop.png')),
            'Stop animation', self)
        stop_animation.setShortcut('Ctrl+E')
        stop_animation.setStatusTip('Stop animation')
        stop_animation.triggered.connect(self.stopAnimation)
        self.stop_animation = stop_animation  # save it

        export_video = QtWidgets.QAction(
            QtGui.QIcon(join(images_dir, 'save-video.png')),
            'Export video/sequence of images', self)
        export_video.setShortcut('Ctrl+V')
        export_video.setStatusTip('Export video/sequence of images')
        export_video.triggered.connect(self.exportVideo)

        self.actions_to_disable = [
            export, viewdata, export_csv, grid, legend, properties
        ]
        self.actions_to_disable_permanently = [
            fromUserData
        ]  #[new_line, fromUserData, remove_line]

        self.toolbar_widget = QtWidgets.QWidget(self)
        layoutToolbar = QtWidgets.QVBoxLayout(self.toolbar_widget)
        layoutToolbar.setContentsMargins(0, 0, 0, 0)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum,
                                           QtWidgets.QSizePolicy.Fixed)
        self.toolbar_widget.setSizePolicy(sizePolicy)

        layoutPlot = QtWidgets.QVBoxLayout(self)
        layoutPlot.setContentsMargins(2, 2, 2, 2)
        self.figure = Figure((8, 6.5), dpi=100, facecolor='white')  #"#E5E5E5")
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setParent(self)
        self.canvas.axes = self.figure.add_subplot(111)

        self.mpl_toolbar = NavigationToolbar(self.canvas, self.toolbar_widget,
                                             False)

        #self.mpl_toolbar.addSeparator()
        self.mpl_toolbar.addAction(export)
        self.mpl_toolbar.addAction(export_csv)
        self.mpl_toolbar.addAction(viewdata)
        self.mpl_toolbar.addSeparator()
        self.mpl_toolbar.addAction(grid)
        self.mpl_toolbar.addAction(legend)
        self.mpl_toolbar.addSeparator()
        self.mpl_toolbar.addAction(new_line)
        self.mpl_toolbar.addAction(fromUserData)
        self.mpl_toolbar.addAction(remove_line)
        self.mpl_toolbar.addSeparator()
        #self.mpl_toolbar.addAction(properties)
        #self.mpl_toolbar.addSeparator()
        #self.mpl_toolbar.addAction(exit)
        if self.plotType == daeChooseVariable.plot2DAnimated:
            self.mpl_toolbar.addSeparator()
            self.mpl_toolbar.addAction(play_animation)
            self.mpl_toolbar.addAction(stop_animation)
            self.mpl_toolbar.addAction(export_video)

        self.fp9 = matplotlib.font_manager.FontProperties(family='sans-serif',
                                                          style='normal',
                                                          variant='normal',
                                                          weight='normal',
                                                          size=9)
        self.fp10 = matplotlib.font_manager.FontProperties(family='sans-serif',
                                                           style='normal',
                                                           variant='normal',
                                                           weight='normal',
                                                           size=10)
        self.fp12 = matplotlib.font_manager.FontProperties(family='sans-serif',
                                                           style='normal',
                                                           variant='normal',
                                                           weight='normal',
                                                           size=12)

        self.textTime = self.figure.text(0.01,
                                         0.01,
                                         '',
                                         fontproperties=self.fp10)

        self.xtransform = 1.0
        self.ytransform = 1.0

        for xlabel in self.canvas.axes.get_xticklabels():
            xlabel.set_fontproperties(self.fp10)
        for ylabel in self.canvas.axes.get_yticklabels():
            ylabel.set_fontproperties(self.fp10)

        layoutToolbar.addWidget(self.mpl_toolbar)
        layoutPlot.addWidget(self.canvas)
        layoutPlot.addWidget(self.toolbar_widget)

        if animated == False and self.updateInterval > 0:
            self._timer = QtCore.QTimer()
            self._timer.timeout.connect(self.updateCurves)
            self._timer.start(self.updateInterval)

    def closeEvent(self, event):
        #print("dae2DPlot.closeEvent")
        if self.funcAnimation:
            self.funcAnimation.event_source.stop()

        if self._timer:
            self._timer.stop()

        return QtWidgets.QDialog.closeEvent(self, event)

    def updateCurves(self):
        try:
            #                                                      these three not used
            for (line, variable, domainIndexes, domainPoints, fun, times,
                 xPoints, yPoints_2D) in self.curves:
                results = fun(variable, domainIndexes, domainPoints)
                if self.xtransform != 1:
                    xPoints = numpy.array(results[5]) * self.xtransform
                else:
                    xPoints = results[5]

                if self.ytransform != 1:
                    yPoints = numpy.array(results[6]) * self.ytransform
                else:
                    yPoints = results[6]

                currentTime = results[7]

                line.set_xdata(xPoints)
                line.set_ydata(yPoints)

                if self.textTime:
                    t = 'Time = {0} s'.format(currentTime)
                    self.textTime.set_text(t)

            #self.reformatPlot()

        except Exception as e:
            print((str(e)))

    #@QtCore.pyqtSlot()
    def slotExportTemplate(self):
        try:
            curves = []
            template = {
                'curves': curves,
                'plotType': self.plotType,
                'updateInterval': self.updateInterval,
                'xlabel': self.canvas.axes.get_xlabel(),
                'xmin': self.canvas.axes.get_xlim()[0],
                'xmax': self.canvas.axes.get_xlim()[1],
                'xscale': self.canvas.axes.get_xscale(),
                'xtransform': 1.0,
                'ylabel': self.canvas.axes.get_ylabel(),
                'ymin': self.canvas.axes.get_ylim()[0],
                'ymax': self.canvas.axes.get_ylim()[1],
                'yscale': self.canvas.axes.get_yscale(),
                'ytransform': 1.0,
                'legendOn': self.legendOn,
                'gridOn': self.gridOn,
                'plotTitle': self.canvas.axes.get_title(),
                'windowTitle': str(self.windowTitle()),
                'xmin_policy': int(self.xmin_policy),
                'xmax_policy': int(self.xmax_policy),
                'ymin_policy': int(self.ymin_policy),
                'ymax_policy': int(self.ymax_policy)
            }

            for (line, variable, domainIndexes, domainPoints, fun, times,
                 xPoints, yPoints_2D) in self.curves:
                # variableName, indexes, points, linelabel, style = {linecolor, linewidth, linestyle, marker, markersize, markerfacecolor, markeredgecolor}
                style = daePlot2dDefaults(line.get_color(),
                                          line.get_linewidth(),
                                          line.get_linestyle(),
                                          line.get_marker(),
                                          line.get_markersize(),
                                          line.get_markerfacecolor(),
                                          line.get_markeredgecolor())
                curves.append((variable.Name, domainIndexes, domainPoints,
                               line.get_label(), style.to_dict()))

            s = json.dumps(template, indent=2, sort_keys=True)

            filename, ok = QtWidgets.QFileDialog.getSaveFileName(
                self, "Save 2D plot template", "template.pt",
                "Templates (*.pt)")
            if not ok:
                return

            f = open(filename, 'w')
            f.write(s)
            f.close()

        except Exception as e:
            print((str(e)))

    #@QtCore.pyqtSlot()
    def slotProperties(self):
        figure_edit(self.canvas, self)

    #@QtCore.pyqtSlot()
    def slotToggleLegend(self):
        self.legendOn = not self.legendOn
        self.updateLegend()

    #@QtCore.pyqtSlot()
    def slotToggleGrid(self):
        self.gridOn = not self.gridOn
        self.updateGrid()

    def updateLegend(self):
        if self.legendOn:
            self.canvas.axes.legend(loc=0,
                                    prop=self.fp9,
                                    numpoints=1,
                                    fancybox=True)
        else:
            self.canvas.axes.legend_ = None
        self.canvas.draw()
        #self.reformatPlot()

    def updateGrid(self):
        self.canvas.axes.grid(self.gridOn)
        self.canvas.draw()
        #self.reformatPlot()

    #@QtCore.pyqtSlot()
    def slotExportCSV(self):
        strInitialFilename = QtCore.QDir.current().path()
        strInitialFilename += "/untitled.csv"
        strExt = "Comma separated files (*.csv)"
        strCaption = "Save file"
        fileName, ok = QtWidgets.QFileDialog.getSaveFileName(
            self, strCaption, strInitialFilename, strExt)
        if not ok:
            return

        datafile = open(str(fileName), 'w')
        lines = self.canvas.axes.get_lines()

        for line in lines:
            xlabel = self.canvas.axes.get_xlabel()
            ylabel = line.get_label()
            x = line.get_xdata()
            y = line.get_ydata()
            datafile.write('\"' + xlabel + '\",\"' + ylabel + '\"\n')
            for i in range(0, len(x)):
                datafile.write('%.14e,%.14e\n' % (x[i], y[i]))
            datafile.write('\n')

    #@QtCore.pyqtSlot()
    def slotViewTabularData(self):
        lines = self.canvas.axes.get_lines()

        tableDialog = daeTableDialog(self)
        tableDialog.setWindowTitle('Raw data')
        table = tableDialog.ui.tableWidget
        nr = 0
        ncol = len(lines)
        for line in lines:
            n = len(line.get_xdata())
            if nr < n:
                nr = n

        xlabel = self.canvas.axes.get_xlabel()
        table.setRowCount(nr)
        table.setColumnCount(ncol)
        horHeader = []
        verHeader = []
        for i, line in enumerate(lines):
            xlabel = self.canvas.axes.get_xlabel()
            ylabel = line.get_label()
            x = line.get_xdata()
            y = line.get_ydata()
            horHeader.append(ylabel)
            for k in range(0, len(x)):
                newItem = QtWidgets.QTableWidgetItem('%.14f' % y[k])
                table.setItem(k, i, newItem)
            for k in range(0, len(x)):
                verHeader.append('%.14f' % x[k])

        table.setHorizontalHeaderLabels(horHeader)
        table.setVerticalHeaderLabels(verHeader)
        table.resizeRowsToContents()
        tableDialog.exec_()

    #@QtCore.pyqtSlot()
    def slotRemoveLine(self):
        lines = self.canvas.axes.get_lines()
        items = []
        for line in lines:
            label = line.get_label()
            items.append(label)

        nameToRemove, ok = QtWidgets.QInputDialog.getItem(
            self, "Choose line to remove", "Lines:", items, 0, False)
        if ok:
            for i, line in enumerate(lines):
                label = line.get_label()
                if label == str(nameToRemove):
                    self.canvas.axes.lines.pop(i)
                    #self.reformatPlot()
                    # updateLegend will also call canvas.draw()
                    self.updateLegend()
                    return

    def newFromTemplate(self, template):
        """
        template is a dictionary:

        .. code-block:: javascript

           {
            "curves": [
                [
                "variableName", 
                [
                    1, 
                    -1
                ], 
                [
                    "0.05", 
                    "*"
                ], 
                "variableName(0.05, *)", 
                {
                    "color": [
                    0.0, 
                    0.0, 
                    0.0, 
                    1.0
                    ], 
                    "linestyle": "-", 
                    "linewidth": 1.0, 
                    "marker": "o", 
                    "markeredgecolor": "#000000ff", 
                    "markerfacecolor": "#000000ff", 
                    "markersize": 0.0
                }
                ]
            ], 
            "gridOn": true, 
            "legendOn": true, 
            "plotTitle": "", 
            "plotType": 0, 
            "updateInterval": 0, 
            "windowTitle": "tutorial_dealii_8.ActiveSurface.cs(2.0, *)", 
            "xlabel": "y-cordinate", 
            "xmax": 31.45, 
            "xmax_policy": 0, 
            "xmin": -0.4500000000000002, 
            "xmin_policy": 0, 
            "xscale": "linear", 
            "xtransform": 1.0, 
            "ylabel": "cs (mol/m**2)", 
            "ymax": 0.34935417753491, 
            "ymax_policy": 1, 
            "ymin": -0.00938086024107475, 
            "ymin_policy": 1, 
            "yscale": "linear", 
            "ytransform": 1.0
           }
        """
        processes = {}
        for process in self.plotter.getProcesses():
            processes[process.Name] = process

        if len(processes) == 0:
            return

        if len(template) == 0:
            return False

        curves = template['curves']

        if 'plotType' in template:
            self.plotType = int(template['plotType'])

        if 'xtransform' in template:
            self.xtransform = template['xtransform']
        if 'ytransform' in template:
            self.ytransform = template['ytransform']

        for i, curve in enumerate(curves):
            variableName = curve[0]
            domainIndexes = curve[1]
            domainPoints = curve[2]
            label = None
            pd = None
            if len(curve) > 3:
                label = curve[3]
            if len(curve) > 4:
                pd = daePlot2dDefaults.from_dict(curve[4])

            windowTitle = "Select process for variable {0} (of {1})".format(
                i + 1, len(curves))
            var_to_look_for = "Variable: {0}({1})".format(
                variableName, ','.join(domainPoints))
            items = sorted(processes.keys())
            processName, ok = self.showSelectProcessDialog(
                windowTitle, var_to_look_for, items)
            if not ok:
                return False

            process = processes[str(processName)]
            for variable in process.Variables:
                if variableName == variable.Name:
                    if self.plotType == daeChooseVariable.plot2D or self.plotType == daeChooseVariable.plot2DAutoUpdated:
                        variable, domainIndexes, domainPoints, xAxisLabel, yAxisLabel, xPoints, yPoints, currentTime = daeChooseVariable.get2DData(
                            variable, domainIndexes, domainPoints)
                        self._addNewCurve(variable, domainIndexes,
                                          domainPoints, xAxisLabel, yAxisLabel,
                                          xPoints, yPoints, currentTime, label,
                                          pd)
                        break

                    elif self.plotType == daeChooseVariable.plot2DAnimated:
                        variable, domainIndexes, domainPoints, xAxisLabel, yAxisLabel, xPoints, yPoints, times = daeChooseVariable.get2DAnimatedData(
                            variable, domainIndexes, domainPoints)
                        self._addNewAnimatedCurve(variable, domainIndexes,
                                                  domainPoints, xAxisLabel,
                                                  yAxisLabel, xPoints, yPoints,
                                                  times, None, None)
                        for action in self.actions_to_disable_permanently:
                            action.setEnabled(False)
                        break

                    else:
                        raise RuntimeError('Invalid plot type')

        if 'xlabel' in template:
            self.canvas.axes.set_xlabel(template['xlabel'],
                                        fontproperties=self.fp12)
        if 'xmin' in template and 'xmax' in template:
            self.canvas.axes.set_xlim(float(template['xmin']),
                                      float(template['xmax']))
        if 'xscale' in template:
            self.canvas.axes.set_xscale(template['xscale'])

        if 'ylabel' in template:
            self.canvas.axes.set_ylabel(template['ylabel'],
                                        fontproperties=self.fp12)
        if 'ymin' in template and 'ymax' in template:
            self.canvas.axes.set_ylim(float(template['ymin']),
                                      float(template['ymax']))
        if 'yscale' in template:
            self.canvas.axes.set_yscale(template['yscale'])

        if 'gridOn' in template:
            self.gridOn = template['gridOn']
            self.canvas.axes.grid(self.gridOn)

        if 'legendOn' in template:
            self.legendOn = template['legendOn']
            if self.legendOn:
                self.canvas.axes.legend(loc=0,
                                        prop=self.fp9,
                                        numpoints=1,
                                        fancybox=True)
            else:
                self.canvas.axes.legend_ = None

        if 'plotTitle' in template:
            self.canvas.axes.set_title(template['plotTitle'])

        if 'windowTitle' in template:
            self.setWindowTitle(template['windowTitle'])

        if 'xmin_policy' in template:
            self.xmin_policy = int(template['xmin_policy'])
        if 'xmax_policy' in template:
            self.xmax_policy = int(template['xmax_policy'])
        if 'ymin_policy' in template:
            self.ymin_policy = int(template['ymin_policy'])
        if 'ymax_policy' in template:
            self.ymax_policy = int(template['ymax_policy'])

        #fmt = matplotlib.ticker.ScalarFormatter(useOffset = False)
        #fmt.set_scientific(False)
        #fmt.set_powerlimits((-3, 4))
        #self.canvas.axes.xaxis.set_major_formatter(fmt)
        #self.canvas.axes.yaxis.set_major_formatter(fmt)

        self.figure.tight_layout()
        self.canvas.draw()

        return True

    def showSelectProcessDialog(self, windowTitle, label, items):
        dlg = QtWidgets.QInputDialog(self)
        dlg.resize(500, 300)
        dlg.setWindowTitle(windowTitle)
        dlg.setLabelText(label)
        dlg.setComboBoxItems(items)

        dlg.setComboBoxEditable(False)
        dlg.setOption(QtWidgets.QInputDialog.UseListViewForComboBoxItems)

        if dlg.exec_() == QtWidgets.QDialog.Accepted:
            return str(dlg.textValue()), True
        else:
            return '', False

    def _updateFrame(self, frame):
        lines = []
        for curve in self.curves:
            line = curve[0]
            lines.append(line)

            times = curve[5]
            xPoints = curve[6]
            yPoints = curve[7]
            yData = yPoints[frame]
            line.set_ydata(yData)
            time = times[frame]

            if self.xmin_policy == 0:  # From 1st frame
                xmin = numpy.min(xPoints)
            elif self.xmin_policy == 1:  # Overall min value
                xmin = numpy.min(xPoints)
            elif self.xmin_policy == 2:  # Adaptive
                xmin = numpy.min(xPoints)
            else:  # Do not change it
                xmin = self.canvas.axes.get_xlim()[0]

            if self.xmax_policy == 0:  # From 1st frame
                xmax = numpy.max(xPoints)
                dx = 0.5 * (xmax - xmin) * 0.05
            elif self.xmax_policy == 1:  # Overall max value
                xmax = numpy.max(xPoints)
                dx = 0.5 * (xmax - xmin) * 0.05
            elif self.xmax_policy == 2:  # Adaptive
                xmax = numpy.max(xPoints)
                dx = 0.5 * (xmax - xmin) * 0.05
            else:  # Do not change it
                xmax = self.canvas.axes.get_xlim()[1]
                dx = 0.0

            if self.ymin_policy == 0:  # From 1st frame
                ymin = numpy.min(yPoints[0])
            elif self.ymin_policy == 1:  # Overall min value
                ymin = numpy.min(yPoints)
            elif self.ymin_policy == 2:  # Adaptive
                ymin = numpy.min(yPoints[frame])
            else:  # Do not change it
                ymin = self.canvas.axes.get_ylim()[0]

            if self.ymax_policy == 0:  # From 1st frame
                ymax = numpy.max(yPoints[0])
                dy = 0.5 * (ymax - ymin) * 0.05
            elif self.ymax_policy == 1:  # Overall max value
                ymax = numpy.max(yPoints)
                dy = 0.5 * (ymax - ymin) * 0.05
            elif self.ymax_policy == 2:  # Adaptive
                ymax = numpy.max(yPoints[frame])
                dy = 0.5 * (ymax - ymin) * 0.05
            else:  # Do not change it
                ymax = self.canvas.axes.get_ylim()[1]
                dy = 0.0

        self.canvas.axes.set_xlim(xmin - dx, xmax + dx)
        self.canvas.axes.set_ylim(ymin - dy, ymax + dy)

        self.canvas.axes.set_title('time = %f s' % time,
                                   fontproperties=self.fp10)

        if frame == len(times) - 1:  # the last frame
            for action in self.actions_to_disable:
                action.setEnabled(True)

            del self.funcAnimation
            self.funcAnimation = None

            self.play_animation.setIcon(
                QtGui.QIcon(join(images_dir, 'media-playback-start.png')))
            self.play_animation.setStatusTip('Start animation')
            self.play_animation.setText('Start animation')
            self._isAnimating = False

        return lines

    def _startAnimation(self):
        #if len(self.curves) != 1:
        #    return

        # Set properties for the frame 0
        curve = self.curves[0]
        times = curve[5]
        frames = numpy.arange(0, len(times))

        self.canvas.axes.set_title('time = %f s' % times[0],
                                   fontproperties=self.fp10)
        self.funcAnimation = animation.FuncAnimation(
            self.figure,
            self._updateFrame,
            frames,
            interval=self.updateInterval,
            blit=False,
            repeat=False)
        self.play_animation.setIcon(
            QtGui.QIcon(join(images_dir, 'media-playback-pause.png')))
        self.play_animation.setStatusTip('Pause animation')
        self.play_animation.setText('Pause animation')
        self._isAnimating = True
        #At the end do not call show() nor save(), they will be ran by a caller

    #@QtCore.pyqtSlot()
    def playAnimation(self):
        if self.funcAnimation:  # animation started - pause/resume it
            if self._isAnimating:  # pause it
                for action in self.actions_to_disable:
                    action.setEnabled(True)
                self.funcAnimation.event_source.stop()
                self.play_animation.setIcon(
                    QtGui.QIcon(join(images_dir, 'media-playback-start.png')))
                self.play_animation.setStatusTip('Start animation')
                self.play_animation.setText('Start animation')
                self._isAnimating = False
                self.canvas.draw()
            else:  # restart it
                for action in self.actions_to_disable:
                    action.setEnabled(False)
                self.funcAnimation.event_source.start()
                self.play_animation.setIcon(
                    QtGui.QIcon(join(images_dir, 'media-playback-pause.png')))
                self.play_animation.setStatusTip('Pause animation')
                self.play_animation.setText('Pause animation')
                self._isAnimating = True
                self.canvas.draw()

        else:  # start animation
            for action in self.actions_to_disable:
                action.setEnabled(False)
            self._startAnimation()
            self.canvas.draw()

    #@QtCore.pyqtSlot()
    def stopAnimation(self):
        if self.funcAnimation:  # animated started - stop it
            for action in self.actions_to_disable:
                action.setEnabled(True)

            self.funcAnimation.event_source.stop()
            del self.funcAnimation
            self.funcAnimation = None

            self.play_animation.setIcon(
                QtGui.QIcon(join(images_dir, 'media-playback-start.png')))
            self.play_animation.setStatusTip('Start animation')
            self.play_animation.setText('Start animation')
            self._isAnimating = False

        # Go back to frame 0
        self._updateFrame(0)
        self.canvas.draw()

    #@QtCore.pyqtSlot()
    def exportVideo(self):
        dlg = daeSavePlot2DVideo()
        for enc in sorted(animation.writers.list()):
            dlg.ui.comboEncoders.addItem(str(enc))
        dlg.ui.lineeditCodec.setText('')
        dlg.ui.lineeditFilename.setText(
            os.path.join(os.path.expanduser('~'), 'video.avi'))
        dlg.ui.spinFPS.setValue(10)
        dlg.ui.lineeditExtraArgs.setText(json.dumps(
            []))  # ['-pix_fmt', 'yuv420p']
        dlg.ui.spinBitrate.setValue(-1)

        if dlg.exec_() != QtWidgets.QDialog.Accepted:
            return False

        filename = str(dlg.ui.lineeditFilename.text())
        fps = int(dlg.ui.spinFPS.value())
        encoder = str(dlg.ui.comboEncoders.currentText())
        codec = str(dlg.ui.lineeditCodec.text())
        bitrate = int(dlg.ui.spinBitrate.value())
        extra_args = []
        try:
            extra_args = list(json.loads(str(dlg.ui.lineeditExtraArgs.text())))
        except:
            pass
        if bitrate == -1:
            bitrate = None
        if codec == '':
            codec = None
        if not extra_args:
            extra_args = None

        print('%s(fps = %s, codec = %s, bitrate = %s, extra_args = %s) -> %s' %
              (encoder, fps, codec, bitrate, extra_args, filename))

        # First stop the existing animation, if already started
        self.stopAnimation()
        Writer = animation.writers[encoder]
        writer = Writer(fps=fps,
                        codec=codec,
                        bitrate=bitrate,
                        extra_args=extra_args)
        self._startAnimation()
        self.funcAnimation.save(filename, writer=writer)

    def slotFromUserData(self):
        dlg = daeUserData()
        if dlg.exec_() != QtWidgets.QDialog.Accepted:
            return

        self.newCurveFromUserData(dlg.xLabel, dlg.yLabel, dlg.lineLabel,
                                  dlg.xPoints, dlg.yPoints)

    def newCurveFromUserData(self, xAxisLabel, yAxisLabel, lineLabel, xPoints,
                             yPoints):
        class dummyVariable(object):
            def __init__(self, name='', units=''):
                self.Name = name
                self.Units = units

        self._addNewCurve(dummyVariable(lineLabel), [], [], xAxisLabel,
                          yAxisLabel, xPoints, yPoints, None, lineLabel, None)
        return True

    #@QtCore.pyqtSlot()
    def newCurve(self):
        processes = self.plotter.getProcesses()

        if not self._cv_dlg:
            self._cv_dlg = daeChooseVariable(self.plotType)
        self._cv_dlg.updateProcessesList(processes)
        self._cv_dlg.setWindowTitle('Choose variable for 2D plot')
        if self._cv_dlg.exec_() != QtWidgets.QDialog.Accepted:
            return False

        variable, domainIndexes, domainPoints, xAxisLabel, yAxisLabel, xPoints, yPoints, currentTime = self._cv_dlg.getPlot2DData(
        )
        self._addNewCurve(variable, domainIndexes, domainPoints, xAxisLabel,
                          yAxisLabel, xPoints, yPoints, currentTime, None,
                          None)

        return True

    def newVar1_vs_Var2Curve(self):
        processes = self.plotter.getProcesses()

        if not self._cv_dlg:
            self._cv_dlg = daeChooseVariable(self.plotType)
        self._cv_dlg.updateProcessesList(processes)

        self._cv_dlg.setWindowTitle(
            'Choose the 1st variable (x axis) for 2D plot')
        if self._cv_dlg.exec_() != QtWidgets.QDialog.Accepted:
            return False

        variable1, domainIndexes1, domainPoints1, xAxisLabel1, yAxisLabel1, xPoints1, yPoints1, currentTime1 = self._cv_dlg.getPlot2DData(
        )

        self._cv_dlg.setWindowTitle(
            'Choose the 2nd variable (y axis) for 2D plot')
        if self._cv_dlg.exec_() != QtWidgets.QDialog.Accepted:
            return False

        variable2, domainIndexes2, domainPoints2, xAxisLabel2, yAxisLabel2, xPoints2, yPoints2, currentTime2 = self._cv_dlg.getPlot2DData(
        )

        if len(yPoints1) != len(yPoints2):
            QtWidgets.QMessageBox.warning(
                None, 'Variable1 vs. variable2 2D plot',
                'The number of points in variables do not match')
            return False

        self._addNewCurve(variable2, domainIndexes2, domainPoints2,
                          yAxisLabel1, yAxisLabel2, yPoints1, yPoints2,
                          currentTime2, None, None)

        return True

    #@QtCore.pyqtSlot()
    def newAnimatedCurve(self):
        processes = self.plotter.getProcesses()

        if not self._cv_dlg:
            self._cv_dlg = daeChooseVariable(self.plotType)
        self._cv_dlg.updateProcessesList(processes)
        self._cv_dlg.setWindowTitle('Choose variable for animated 2D plot')
        if self._cv_dlg.exec_() != QtWidgets.QDialog.Accepted:
            return False

        dlg = daeAnimationParameters()
        if dlg.exec_() != QtWidgets.QDialog.Accepted:
            return

        self.updateInterval = int(dlg.ui.spinUpdateInterval.value())
        self.xmin_policy = dlg.ui.comboXmin.currentIndex()
        self.xmax_policy = dlg.ui.comboXmax.currentIndex()
        self.ymin_policy = dlg.ui.comboYmin.currentIndex()
        self.ymax_policy = dlg.ui.comboYmax.currentIndex()

        variable, domainIndexes, domainPoints, xAxisLabel, yAxisLabel, xPoints, yPoints, times = self._cv_dlg.getPlot2DAnimatedData(
        )
        self._addNewAnimatedCurve(variable, domainIndexes, domainPoints,
                                  xAxisLabel, yAxisLabel, xPoints, yPoints,
                                  times, None, None)

        for action in self.actions_to_disable_permanently:
            action.setEnabled(False)

        self._updateFrame(0)

        return True

    def _addNewAnimatedCurve(self,
                             variable,
                             domainIndexes,
                             domainPoints,
                             xAxisLabel,
                             yAxisLabel,
                             xPoints,
                             yPoints_2D,
                             times,
                             label=None,
                             pd=None):
        domains = '(' + ', '.join(domainPoints) + ')'

        if not label:
            label = variable.Name.replace("&", "").replace(";", "") + domains

        line = self.addLine(xAxisLabel, yAxisLabel, xPoints, yPoints_2D[0],
                            label, pd)
        self.setWindowTitle(label)

        #                                                                 update fun is None
        self.curves.append((line, variable, domainIndexes, domainPoints, None,
                            times, xPoints, yPoints_2D))

    def _addNewCurve(self,
                     variable,
                     domainIndexes,
                     domainPoints,
                     xAxisLabel,
                     yAxisLabel,
                     xPoints,
                     yPoints,
                     currentTime,
                     label=None,
                     pd=None):
        domains = "("
        for i in range(0, len(domainPoints)):
            if i != 0:
                domains += ", "
            domains += domainPoints[i]
        domains += ")"

        if not label:
            label = variable.Name.replace("&", "").replace(";", "") + domains

        line = self.addLine(xAxisLabel, yAxisLabel, xPoints, yPoints, label,
                            pd)
        self.setWindowTitle(label)
        #                                                                                              everything after update fun is none
        self.curves.append((line, variable, domainIndexes, domainPoints,
                            daeChooseVariable.get2DData, None, None, None))

    def addLine(self, xAxisLabel, yAxisLabel, xPoints, yPoints, label, pd):
        no_lines = len(self.canvas.axes.get_lines())
        if not pd:
            n = no_lines % len(dae2DPlot.plotDefaults)
            pd = dae2DPlot.plotDefaults[n]

        xPoints_ = numpy.array(xPoints) * self.xtransform
        yPoints_ = numpy.array(yPoints) * self.ytransform

        line, = self.canvas.axes.plot(xPoints_, yPoints_, label=label, color=pd.color, linewidth=pd.linewidth, \
                                      linestyle=pd.linestyle, marker=pd.marker, markersize=pd.markersize, \
                                      markerfacecolor=pd.markerfacecolor, markeredgecolor=pd.markeredgecolor)

        if no_lines == 0:
            # Set labels, fonts, gridlines and limits only when adding the first line
            self.canvas.axes.set_xlabel(xAxisLabel, fontproperties=self.fp12)
            self.canvas.axes.set_ylabel(yAxisLabel, fontproperties=self.fp12)
            t = self.canvas.axes.xaxis.get_offset_text()
            t.set_fontproperties(self.fp10)
            t = self.canvas.axes.yaxis.get_offset_text()
            t.set_fontproperties(self.fp10)
            self.updateGrid()

        # Update the legend and (x,y) limits after every addition
        self.updateLegend()
        self.reformatPlot()

        return line

    def reformatPlot(self):
        lines = self.canvas.axes.get_lines()
        xmin = 1e20
        xmax = -1e20
        ymin = 1e20
        ymax = -1e20
        for line in lines:
            if numpy.min(line.get_xdata()) < xmin:
                xmin = numpy.min(line.get_xdata())
            if numpy.max(line.get_xdata()) > xmax:
                xmax = numpy.max(line.get_xdata())

            if numpy.min(line.get_ydata()) < ymin:
                ymin = numpy.min(line.get_ydata())
            if numpy.max(line.get_ydata()) > ymax:
                ymax = numpy.max(line.get_ydata())

        dx = (xmax - xmin) * 0.05
        dy = (ymax - ymin) * 0.05
        xmin -= dx
        xmax += dx
        ymin -= dy
        ymax += dy

        self.canvas.axes.set_xlim(xmin, xmax)
        self.canvas.axes.set_ylim(ymin, ymax)

        #self.canvas.axes.grid(self.gridOn)

        #if self.legendOn:
        #    self.canvas.axes.legend(loc = 0, prop=self.fp9, numpoints = 1, fancybox=True)
        #else:
        #    self.canvas.axes.legend_ = None

        self.figure.tight_layout()
        self.canvas.draw()
示例#10
0
class PlotWindow(QtWidgets.QMainWindow):
    def __init__(self, nrows=1, ncols=1, **kwargs):
        matplotlib.use('Qt5Agg')

        qapp = QtWidgets.QApplication.instance()
        if qapp is None:
            qapp = QtWidgets.QApplication(sys.argv)

        self.qapp = qapp

        super().__init__()

        self._main = QtWidgets.QWidget()

        self.setStyle(QStyleFactory.create('Fusion'))

        self.setCentralWidget(self._main)
        self.layout = QGridLayout(self._main)

        marker_kw = {}
        for k in marker_default_params.keys():
            if k in kwargs.keys():
                marker_kw[k] = kwargs.pop(k)

        title = kwargs.pop('title', None)
        icon = kwargs.pop('icon', None)

        if icon != None:
            self.setWindowIcon(QtGui.QIcon(str(icon)))

        marker_kw['interactive'] = kwargs.pop('interactive', True)
        marker_kw['top_axes'] = kwargs.pop('top_axes', None)
        marker_kw['link_all'] = kwargs.pop('link_all', False)

        self.single_trace = kwargs.pop('single_trace', False)

        subplot_kw = kwargs.pop('subplot_kw', {})
        sharex = kwargs.pop('sharex', False)
        sharey = kwargs.pop('sharey', False)
        gridspec_kw = kwargs.pop('gridspec_kw', None)

        self.fig = plt.figure(**kwargs)

        self.axes_grid = self.fig.subplots(nrows,
                                           ncols,
                                           squeeze=False,
                                           sharex=False,
                                           sharey=False,
                                           subplot_kw=subplot_kw,
                                           gridspec_kw=gridspec_kw)

        self.axes = self.axes_grid.flatten()

        self.nrows = nrows
        self.ncols = ncols

        self.canvas = self.fig.canvas
        self.canvas.mpl_disconnect(self.canvas.manager.key_press_handler_id)

        self.canvas.manager.show = self._show
        self.layout.addWidget(self.canvas, 0, 0, (self.nrows * self.ncols) + 1,
                              1)

        self.toolbar = NavigationToolbar(self.canvas, self, coordinates=False)
        self.build_toolbar()

        self.addToolBar(self.toolbar)
        self.fig.canvas.toolbar = self.toolbar
        self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas.setFocus()

        p = self.palette()
        p.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(p)

        title = 'Figure {}'.format(
            self.fig.canvas.manager.num) if title == None else title
        self.setWindowTitle(title)
        self._drop_event_handler = None

        self.fig.marker_enable(**marker_kw)
        self.fig.qapp = self.qapp
        self.fig.app = self
        self.draw_updates = False
        self.axes_cb_group = []
        self.current_data_format = None

        self.data_format_options = None

        for i, ax in enumerate(self.axes):
            ax_cb = AxesCheckBoxGroup(
                self, ax, "Axes {},{}".format(i // self.nrows, i % self.nrows))
            self.axes_cb_group.append(ax_cb)

    def keyPressEvent(self, event):
        if event.key() in (QtCore.Qt.Key_F5, ):
            self.fig.canvas.draw()
        super().keyPressEvent(event)

    def set_draw_updates(self, state):
        prev = self.draw_updates
        self.draw_updates = state
        return prev

    def add_toolbar_actions(self, *widgets, end=True):
        for icon_path, name, tooltip, action in widgets:

            icon = QtGui.QPixmap(str(icon_path))
            icon.setDevicePixelRatio(self.canvas._dpi_ratio)
            a = self.toolbar.addAction(QtGui.QIcon(icon), name, action)
            a.setToolTip(tooltip)

        if end:
            locLabel = QLabel("", self.toolbar)
            locLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
            locLabel.setSizePolicy(
                QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                      QtWidgets.QSizePolicy.Ignored))
            self.toolbar.addWidget(locLabel)

    def build_toolbar(self):

        self.toolbar.removeAction(self.toolbar._actions['configure_subplots'])
        self.toolbar.removeAction(self.toolbar._actions['forward'])
        self.toolbar.removeAction(self.toolbar._actions['back'])

        widgets = [
            (str(dir_ / 'icons/layout_large.png'), 'Layout',
             'Apply Tight Layout', self.set_tight_layout),
            (str(dir_ / 'icons/copy_large.png'), 'Copy', 'Copy To Clipboard',
             self.copy_figure),
            (str(dir_ / 'icons/erase_large.png'), 'Delete',
             'Remove All Markers', self.remove_all),
            (str(dir_ / 'icons/autoscale_y.png'), 'Autoscale',
             'Autoscale Y-Axis', self.autoscale_y),
            (str(dir_ / 'icons/autoscale_x.png'), 'Autoscale',
             'Autoscale X-Axis', self.autoscale_x),
            (str(dir_ / 'icons/set_format_large.png'), 'Set Data Format',
             'Set Data Format', self.set_data_format),
        ]

        self.add_toolbar_actions(*widgets, end=False)
        self.toolbar.addSeparator()

    def add_drop_event_handler(self, handler):
        self._drop_event_handler = handler

        if self._drop_event_handler != None:
            self.setAcceptDrops(True)

    def dragEnterEvent(self, e):

        if e.mimeData().hasText():
            text = e.mimeData().text()
            m = re.search(r's\d+p$', text)
            if m != None:
                e.accept()
            else:
                e.ignore()
        else:
            e.ignore()

    def dropEvent(self, e):
        text = e.mimeData().text()
        self._drop_event_handler(text)
        self.change_data_format(self.current_data_format)
        self.update_axes_groups()
        self.autoscale_x()
        self.remove_all()
        self.fig.canvas.draw()

    def set_data_format(self):
        dialog = DataFormatDialog(self, self.change_data_format,
                                  self.data_format_options)
        dialog.show()

    def change_data_format(self, options):
        self.current_data_format = options
        for i, ax in enumerate(self.axes):
            self._data_format_handler(ax, options[i])
        self.autoscale_y()

    def add_data_format_handler(self, func, format_options, initial=None):
        self._data_format_handler = func
        self.data_format_options = format_options
        self.current_data_format = [initial] * len(self.axes)

    def autoscale_x(self):
        for ax_cb in self.axes_cb_group:
            ax_cb.scale_visible(yscale=False)
        self.fig.canvas.draw()

    def autoscale_y(self):
        for ax_cb in self.axes_cb_group:
            ax_cb.scale_visible(xscale=False)
        self.fig.canvas.draw()

    def remove_all(self):
        for ax in self.fig._top_axes:
            ax.marker_delete_all()
            ax.draw_lines_markers()
            for l_ax in ax.marker_linked_axes:
                l_ax.marker_delete_all()
                l_ax.draw_lines_markers()

    def set_tight_layout(self):
        self.fig.tight_layout()
        self.canvas.draw()

    def copy_figure(self):

        buf = io.BytesIO()
        self.fig.savefig(buf)

        image = Image.open(buf)
        output = io.BytesIO()
        image.convert("RGB").save(output, "BMP")
        data = output.getvalue()[14:]
        output.close()

        win32clipboard.OpenClipboard()
        win32clipboard.EmptyClipboard()
        win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
        win32clipboard.CloseClipboard()
        buf.close()

    def update_axes_groups(self):
        for i, ax_cb in enumerate(self.axes_cb_group):
            ax_cb.update_checkboxes()

    def create_axes_groups(self):
        for i, ax_cb in enumerate(self.axes_cb_group):
            ax_cb.add_to_layout(self.layout, i, 1)

        self.layout.addWidget(QGroupBox(), i + 1, 1)
        self.layout.setColumnStretch(0, 1)
        self.layout.setRowStretch(i + 1, 1)

    def _show(self):

        self.create_axes_groups()
        self.set_draw_updates(True)

        self.show()

        plt.close(self.fig)
示例#11
0
class FigureTab:
  cursors = [15000, 45000]
  colors = ['orange', 'violet']

  def __init__(self, layout, vna):
    # create figure
    self.figure = Figure()
    if sys.platform != 'win32':
      self.figure.set_facecolor('none')
    self.canvas = FigureCanvas(self.figure)
    layout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, None, False)
    self.toolbar.layout().setSpacing(6)
    # remove subplots action
    actions = self.toolbar.actions()
    if int(matplotlib.__version__[0]) < 2:
      self.toolbar.removeAction(actions[7])
    else:
      self.toolbar.removeAction(actions[6])
    self.toolbar.addSeparator()
    self.cursorLabels = {}
    self.cursorValues = {}
    self.cursorMarkers = {}
    self.cursorPressed = {}
    for i in range(len(self.cursors)):
      self.cursorMarkers[i] = None
      self.cursorPressed[i] = False
      self.cursorLabels[i] = QLabel('Cursor %d, kHz' % (i + 1))
      self.cursorLabels[i].setStyleSheet('color: %s' % self.colors[i])
      self.cursorValues[i] = QSpinBox()
      self.cursorValues[i].setMinimumSize(90, 0)
      self.cursorValues[i].setSingleStep(10)
      self.cursorValues[i].setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter)
      self.toolbar.addWidget(self.cursorLabels[i])
      self.toolbar.addWidget(self.cursorValues[i])
      self.cursorValues[i].valueChanged.connect(partial(self.set_cursor, i))
      self.canvas.mpl_connect('button_press_event', partial(self.press_marker, i))
      self.canvas.mpl_connect('motion_notify_event', partial(self.move_marker, i))
      self.canvas.mpl_connect('button_release_event', partial(self.release_marker, i))
    self.toolbar.addSeparator()
    self.plotButton = QPushButton('Rescale')
    self.toolbar.addWidget(self.plotButton)
    layout.addWidget(self.toolbar)
    self.plotButton.clicked.connect(self.plot)
    self.mode = None
    self.vna = vna

  def add_cursors(self, axes):
    if self.mode == 'gain_short' or self.mode == 'gain_open':
      columns = ['Freq., kHz', 'G, dB', r'$\angle$ G, deg']
    else:
      columns = ['Freq., kHz', 'Re(Z), \u03A9', 'Im(Z), \u03A9', '|Z|, \u03A9', r'$\angle$ Z, deg', 'SWR', r'|$\Gamma$|', r'$\angle$ $\Gamma$, deg', 'RL, dB']
    y = len(self.cursors) * 0.04 + 0.01
    for i in range(len(columns)):
      self.figure.text(0.19 + 0.1 * i, y, columns[i], horizontalalignment = 'right')
    self.cursorRows = {}
    for i in range(len(self.cursors)):
      y = len(self.cursors) * 0.04 - 0.03 - 0.04 * i
      self.figure.text(0.01, y, 'Cursor %d' % (i + 1), color = self.colors[i])
      self.cursorRows[i] = {}
      for j in range(len(columns)):
        self.cursorRows[i][j] = self.figure.text(0.19 + 0.1 * j, y, '', horizontalalignment = 'right')
      if self.mode == 'smith':
        self.cursorMarkers[i], = axes.plot(0.0, 0.0, marker = 'o', color = self.colors[i])
      else:
        self.cursorMarkers[i] = axes.axvline(0.0, color = self.colors[i], linewidth = 2)
      self.set_cursor(i, self.cursorValues[i].value())

  def set_cursor(self, index, value):
    FigureTab.cursors[index] = value
    marker = self.cursorMarkers[index]
    if marker is None: return
    row = self.cursorRows[index]
    freq = value
    gamma = self.vna.gamma(freq)
    if self.mode == 'smith':
      marker.set_xdata(gamma.real)
      marker.set_ydata(gamma.imag)
    else:
      marker.set_xdata(freq)
    row[0].set_text('%d' % freq)
    if self.mode == 'gain_short':
      gain = self.vna.gain_short(freq)
      magnitude = 20.0 * np.log10(np.absolute(gain))
      angle = np.angle(gain, deg = True)
      row[1].set_text(unicode_minus('%.1f' % magnitude))
      row[2].set_text(unicode_minus('%.1f' % angle))
    elif self.mode == 'gain_open':
      gain = self.vna.gain_open(freq)
      magnitude = 20.0 * np.log10(np.absolute(gain))
      angle = np.angle(gain, deg = True)
      row[1].set_text(unicode_minus('%.1f' % magnitude))
      row[2].set_text(unicode_minus('%.1f' % angle))
    else:
      swr = self.vna.swr(freq)
      z = self.vna.impedance(freq)
      rl = 20.0 * np.log10(np.absolute(gamma))
      if rl > -0.01: rl = 0.0
      row[1].set_text(metric_prefix(z.real))
      row[2].set_text(metric_prefix(z.imag))
      row[3].set_text(metric_prefix(np.absolute(z)))
      angle = np.angle(z, deg = True)
      if np.abs(angle) < 0.1: angle = 0.0
      row[4].set_text(unicode_minus('%.1f' % angle))
      row[5].set_text(unicode_minus('%.2f' % swr))
      row[6].set_text(unicode_minus('%.2f' % np.absolute(gamma)))
      angle = np.angle(gamma, deg = True)
      if np.abs(angle) < 0.1: angle = 0.0
      row[7].set_text(unicode_minus('%.1f' % angle))
      row[8].set_text(unicode_minus('%.2f' % rl))
    self.canvas.draw()

  def press_marker(self, index, event):
    if not event.inaxes: return
    if self.mode == 'smith': return
    marker = self.cursorMarkers[index]
    if marker is None: return
    contains, misc = marker.contains(event)
    if not contains: return
    self.cursorPressed[index] = True

  def move_marker(self, index, event):
    if not event.inaxes: return
    if self.mode == 'smith': return
    if not self.cursorPressed[index]: return
    self.cursorValues[index].setValue(event.xdata)

  def release_marker(self, index, event):
    self.cursorPressed[index] = False

  def xlim(self, freq):
    start = freq[0]
    stop = freq[-1]
    min = np.minimum(start, stop)
    max = np.maximum(start, stop)
    margin = (max - min) / 50
    return (min - margin, max + margin)

  def plot(self):
    getattr(self, 'plot_%s' % self.mode)()

  def update(self, mode):
    start = self.vna.dut.freq[0]
    stop = self.vna.dut.freq[-1]
    min = np.minimum(start, stop)
    max = np.maximum(start, stop)
    for i in range(len(self.cursors)):
      value = self.cursors[i]
      self.cursorValues[i].setRange(min, max)
      self.cursorValues[i].setValue(value)
      self.set_cursor(i, value)
    getattr(self, 'update_%s' % mode)()

  def plot_curves(self, freq, data1, label1, limit1, data2, label2, limit2):
    matplotlib.rcdefaults()
    matplotlib.rcParams['axes.formatter.use_mathtext'] = True
    self.figure.clf()
    bottom = len(self.cursors) * 0.04 + 0.13
    self.figure.subplots_adjust(left = 0.16, bottom = bottom, right = 0.84, top = 0.96)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.grid()
    axes1.set_xlabel('kHz')
    axes1.set_ylabel(label1)
    xlim = self.xlim(freq)
    axes1.set_xlim(xlim)
    if limit1 is not None: axes1.set_ylim(limit1)
    self.curve1, = axes1.plot(freq, data1, color = 'blue', label = label1)
    self.add_cursors(axes1)
    if data2 is None:
      self.canvas.draw()
      return
    axes1.tick_params('y', color = 'blue', labelcolor = 'blue')
    axes1.yaxis.label.set_color('blue')
    axes2 = axes1.twinx()
    axes2.spines['left'].set_color('blue')
    axes2.spines['right'].set_color('red')
    axes2.set_ylabel(label2)
    axes2.set_xlim(xlim)
    if limit2 is not None: axes2.set_ylim(limit2)
    axes2.tick_params('y', color = 'red', labelcolor = 'red')
    axes2.yaxis.label.set_color('red')
    self.curve2, = axes2.plot(freq, data2, color = 'red', label = label2)
    self.canvas.draw()

  def plot_gain(self, gain):
    freq = self.vna.dut.freq
    data1 = 20.0 * np.log10(np.absolute(gain))
    data2 = np.angle(gain, deg = True)
    self.plot_curves(freq, data1, 'G, dB', (-110, 110.0), data2, r'$\angle$ G, deg', (-198, 198))

  def plot_gain_short(self):
    self.mode = 'gain_short'
    self.plot_gain(self.vna.gain_short(self.vna.dut.freq))

  def plot_gain_open(self):
    self.mode = 'gain_open'
    self.plot_gain(self.vna.gain_open(self.vna.dut.freq))

  def update_gain(self, gain, mode):
    if self.mode == mode:
      self.curve1.set_xdata(self.vna.dut.freq)
      self.curve1.set_ydata(20.0 * np.log10(np.absolute(gain)))
      self.curve2.set_xdata(self.vna.dut.freq)
      self.curve2.set_ydata(np.angle(gain, deg = True))
      self.canvas.draw()
    else:
      self.mode = mode
      self.plot_gain(gain)

  def update_gain_short(self):
    self.update_gain(self.vna.gain_short(self.vna.dut.freq), 'gain_short')

  def update_gain_open(self):
    self.update_gain(self.vna.gain_open(self.vna.dut.freq), 'gain_open')

  def plot_magphase(self, freq, data, label, mode):
    self.mode = mode
    data1 = np.absolute(data)
    data2 = np.angle(data, deg = True)
    max = np.fmax(0.01, data1.max())
    label1 = r'|%s|' % label
    label2 = r'$\angle$ %s, deg' % label
    self.plot_curves(freq, data1, label1, (-0.05 * max, 1.05 * max), data2, label2, (-198, 198))

  def update_magphase(self, freq, data, label, mode):
    if self.mode == mode:
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(np.absolute(data))
      self.curve2.set_xdata(freq)
      self.curve2.set_ydata(np.angle(data, deg = True))
      self.canvas.draw()
    else:
      self.plot_magphase(freq, data, label, mode)

  def plot_open(self):
    self.plot_magphase(self.vna.open.freq, self.vna.open.data, 'open', 'open')

  def update_open(self):
    self.update_magphase(self.vna.open.freq, self.vna.open.data, 'open', 'open')

  def plot_short(self):
    self.plot_magphase(self.vna.short.freq, self.vna.short.data, 'short', 'short')

  def update_short(self):
    self.update_magphase(self.vna.short.freq, self.vna.short.data, 'short', 'short')

  def plot_load(self):
    self.plot_magphase(self.vna.load.freq, self.vna.load.data, 'load', 'load')

  def update_load(self):
    self.update_magphase(self.vna.load.freq, self.vna.load.data, 'load', 'load')

  def plot_dut(self):
    self.plot_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

  def update_dut(self):
    self.update_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

  def plot_smith_grid(self, axes, color):
    load = 50.0
    ticks = np.array([0.0, 0.2, 0.5, 1.0, 2.0, 5.0])
    for tick in ticks * load:
      axis = np.logspace(-4, np.log10(1.0e3), 200) * load
      z = tick + 1.0j * axis
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      z = axis + 1.0j * tick
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      if tick == 0.0:
        axes.text(1.0, 0.0, u'\u221E', color = color, ha = 'left', va = 'center', clip_on = True, fontsize = 'x-large')
        axes.text(-1.0, 0.0, u'0\u03A9', color = color, ha = 'left', va = 'bottom', clip_on = True)
        continue
      lab = u'%d\u03A9' % tick
      x = (tick - load) / (tick + load)
      axes.text(x, 0.0, lab, color = color, ha = 'left', va = 'bottom', clip_on = True)
      lab = u'j%d\u03A9' % tick
      z =  1.0j * tick
      gamma = (z - load)/(z + load) * 1.05
      x = gamma.real
      y = gamma.imag
      angle = np.angle(gamma) * 180.0 / np.pi - 90.0
      axes.text(x, y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = angle)
      lab = u'\u2212j%d\u03A9' % tick
      axes.text(x, -y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = -angle)

  def plot_smith(self):
    self.mode = 'smith'
    matplotlib.rcdefaults()
    self.figure.clf()
    bottom = len(self.cursors) * 0.04 + 0.05
    self.figure.subplots_adjust(left = 0.0, bottom = bottom, right = 1.0, top = 1.0)
    axes1 = self.figure.add_subplot(111)
    self.plot_smith_grid(axes1, 'blue')
    gamma = self.vna.gamma(self.vna.dut.freq)
    self.curve1, = axes1.plot(gamma.real, gamma.imag, color = 'red')
    axes1.axis('equal')
    axes1.set_xlim(-1.12, 1.12)
    axes1.set_ylim(-1.12, 1.12)
    axes1.xaxis.set_visible(False)
    axes1.yaxis.set_visible(False)
    for loc, spine in axes1.spines.items():
      spine.set_visible(False)
    self.add_cursors(axes1)
    self.canvas.draw()

  def update_smith(self):
    if self.mode == 'smith':
      gamma = self.vna.gamma(self.vna.dut.freq)
      self.curve1.set_xdata(gamma.real)
      self.curve1.set_ydata(gamma.imag)
      self.canvas.draw()
    else:
      self.plot_smith()

  def plot_imp(self):
    self.mode = 'imp'
    freq = self.vna.dut.freq
    z = self.vna.impedance(freq)
    data1 = np.fmin(9.99e4, np.absolute(z))
    data2 = np.angle(z, deg = True)
    max = np.fmax(0.01, data1.max())
    self.plot_curves(freq, data1, '|Z|, \u03A9', (-0.05 * max, 1.05 * max), data2, r'$\angle$ Z, deg', (-198, 198))

  def update_imp(self):
    if self.mode == 'imp':
      freq = self.vna.dut.freq
      z = self.vna.impedance(freq)
      data1 = np.fmin(9.99e4, np.absolute(z))
      data2 = np.angle(z, deg = True)
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(data1)
      self.curve2.set_xdata(freq)
      self.curve2.set_ydata(data2)
      self.canvas.draw()
    else:
      self.plot_imp()

  def plot_swr(self):
    self.mode = 'swr'
    freq = self.vna.dut.freq
    data1 = self.vna.swr(freq)
    self.plot_curves(freq, data1, 'SWR', (0.9, 3.1), None, None, None)

  def update_swr(self):
    if self.mode == 'swr':
      self.curve1.set_xdata(self.vna.dut.freq)
      self.curve1.set_ydata(self.vna.swr(self.vna.dut.freq))
      self.canvas.draw()
    else:
      self.plot_swr()

  def plot_gamma(self):
    self.plot_magphase(self.vna.dut.freq, self.vna.gamma(self.vna.dut.freq), r'$\Gamma$', 'gamma')

  def update_gamma(self):
    self.update_magphase(self.vna.dut.freq, self.vna.gamma(self.vna.dut.freq), r'$\Gamma$', 'gamma')

  def plot_rl(self):
    self.mode = 'rl'
    freq = self.vna.dut.freq
    gamma = self.vna.gamma(freq)
    data1 = 20.0 * np.log10(np.absolute(gamma))
    self.plot_curves(freq, data1, 'RL, dB', (-105, 5.0), None, None, None)

  def update_rl(self):
    if self.mode == 'rl':
      freq = self.vna.dut.freq
      gamma = self.vna.gamma(freq)
      data1 = 20.0 * np.log10(np.absolute(gamma))
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(data1)
      self.canvas.draw()
    else:
      self.plot_rl()
示例#12
0
class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1900, 980)
        MainWindow.setMaximumSize(1900, 980)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        ######################################        Creating Table Widget       ######################################
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(50, 540, 850, 300))
        font = QtGui.QFont()
        font.setBold(True)
        font.setItalic(True)
        font.setWeight(75)
        self.tableWidget.setFont(font)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(4)
        # self.tableWidget.setRowCount(0)
        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.tableWidget.setHorizontalHeaderLabels(
            ("PW", " PA ", " PRI ", " Classification "))
        self.tableWidget.setStatusTip("Table widget")
        #self.tableWidget.setRowCount(0)
        #######################################       Creating Pushbutton   ############################################
        self.pushButton_Start = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_Start.setGeometry(QtCore.QRect(400, 870, 180, 51))
        font = QtGui.QFont()
        font.setPointSize(14)
        font.setBold(True)
        font.setItalic(False)
        font.setUnderline(False)
        font.setWeight(75)
        self.pushButton_Start.setFont(font)
        self.pushButton_Start.setStyleSheet(
            "border-top-color: rgb(144, 255, 248);\n"
            "border-bottom-color: rgb(157, 255, 121);")
        self.pushButton_Start.setObjectName("pushButton_Start")
        ######################################## Creating Widgets(Plotting Graphs) ####################################
        self.Graph1 = pg.PlotWidget(self.centralwidget)
        self.Graph1.setGeometry(QtCore.QRect(50, 80, 850, 410))
        self.Graph1.setLabel('left', 'PRI')
        self.Graph1.setLabel('bottom', 'Pulse Count')

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)

        self.Graph2 = pg.LayoutWidget(self.centralwidget)
        self.Graph2.setGeometry(QtCore.QRect(1000, 80, 850, 410))
        self.Graph2.addWidget(self.canvas)
        self.Graph2.addWidget(self.toolbar)

        self.Dialer = QtWidgets.QDial(self.centralwidget)
        self.Dialer.setGeometry(QtCore.QRect(1640, 300, 150, 150))
        self.Dialer.setNotchesVisible(True)
        # self.Dialer.setWrapping(True)
        self.Dialer.setMinimum(1)
        self.Dialer.setMaximum(100)

        self.Graph3 = pg.PlotWidget(self.centralwidget)
        self.Graph3.setGeometry(QtCore.QRect(1000, 520, 850, 410))
        self.Graph3.setObjectName("Graph3")
        self.Graph3.setLabel('left', 'Count')
        self.Graph3.setLabel('bottom', 'TOA')

        ## Set Graph background colour ( White-'w',Black-'k',Green-'g',Red-'r',Yellow-'y',Blue-'b',cyan (bright blue-green)-'c',magenta (bright pink)-'m' ) ###########
        self.Graph1.setBackground('k')
        #self.Graph2.setBackground('k')
        self.Graph3.setBackground('k')

        MainWindow.setCentralWidget(self.centralwidget)
        ############################################## Status Bar  ####################################################
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        ##############################################   Tool Bar  ####################################################
        self.toolbar = QtWidgets.QToolBar(MainWindow)
        self.toolbar.setObjectName("toolbar")
        self.toolbar.setMovable(False)
        self.toolbar.setGeometry(QtCore.QRect(0, 0, 1900, 50))
        self.toolbar.setIconSize(QtCore.QSize(60, 60))
        self.toolbar.addSeparator()
        ######################################    Creating Tool Bar Icons #################################################
        self.btn1 = QtWidgets.QAction(MainWindow)
        self.btn1.setIcon(QtGui.QIcon("IP.png"))
        self.btn1.setObjectName("btn1")
        self.toolbar.addAction(self.btn1)

        self.btn2 = QtWidgets.QAction(MainWindow)
        self.btn2.setIcon(QtGui.QIcon("pulse1.png"))
        self.btn2.setObjectName("btn2")
        self.toolbar.addAction(self.btn2)

        self.btn3 = QtWidgets.QAction(MainWindow)
        self.btn3.setIcon(QtGui.QIcon(""))
        self.btn3.setObjectName("btn3")
        self.toolbar.addAction(self.btn3)

        self.btn4 = QtWidgets.QAction(MainWindow)
        self.btn4.setIcon(QtGui.QIcon(""))
        self.btn4.setObjectName("btn4")
        self.toolbar.addAction(self.btn4)

        self.pushButton_Start.clicked.connect(self.StartPA)
        self.Dialer.valueChanged.connect(self.Plot_DTOA)
        self.btn1.triggered.connect(self.Window1)
        self.btn2.triggered.connect(self.Window2)
        self.tableWidget.rowCount()
        self.df = pd.read_csv("pdw.csv")

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

        self.thread = MyThread()
        # self.thread.change_value.connect(self.setProgressVal)
        self.thread.StopFlag = False
        self.thread.start()
        self.thread.StartPulseAnalysis = False
        self.thread.pd_PDW_Update.connect(self.updateGraphs)
        self.thread.Track_Update.connect(self.updateTrackTable)

    # Track_Update = pyqtSignal(bytearray)

    def StartPA(self):
        if self.thread.StartPulseAnalysis == False:
            self.pushButton_Start.setText("Stop PA")
            self.thread.StartPulseAnalysis = True

        elif self.thread.StartPulseAnalysis == True:
            self.pushButton_Start.setText("Start PA")
            self.thread.StartPulseAnalysis = False

    def updateGraphs(self, df_Pdw):
        print('Update Graphs')
        print(df_Pdw.head())
#Munny write here for Graphs updation

    def updateTrackTable(self, TrackData):
        print('Update Table')
        print(TrackData)
        #Munny Write here for Tbale updation

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_Start.setText(_translate("MainWindow", "Start PA"))

    def Window1(self):
        self.Wd1 = Tool1_Window()
        self.Wd1.show()

    def Window2(self):
        self.Wd2 = Tool2_Window()
        self.Wd2.show()

    def Plot_DTOA(self):
        pen1 = pg.mkPen(color=(0, 150, 0), width=3, style=QtCore.Qt.SolidLine)
        TOA = self.df['TOA']
        PW = self.df['PW']
        PA = self.df['PA']
        PC = self.df['PC']
        DTOA = self.df['DTOA']
        #print(PA)
        self.Graph1.plot(PC, DTOA, pen=pen1)
        #self.Graph1.setYRange()

        x_lim = self.Dialer.value() * 1000
        #print("count", x_lim)
        y = []
        #for index in range(10):
        cur_TOA = 0
        index = 0
        while cur_TOA < x_lim:
            for t in range(TOA[index], TOA[index] + PW[index]):
                y.append(1)
            for t in range(TOA[index] + PW[index], TOA[index + 1]):
                y.append(0)
            cur_TOA = TOA[index + 1]
            index = index + 1
        x = [*range(0, len(y), 1)]
        plt.plot(x, y, "g")
        plt.title('DTOA vs Pulse Count')
        plt.ylabel('DTOA (micro sec)')
        plt.xlabel('Pulse Count->')
        plt.xlim(0, x_lim)
        plt.ylim(-1, +5)
        # plt.hlines(y=0, xmin=0, xmax=4000, linewidth=1, color='k', linestyles="--")
        self.canvas.draw()

    def Exit(self):
        reply = QMessageBox.question(
            self, 'Confirm Exit',
            'Are you sure you want to exit Hub Configuration?',
            QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            quit()
示例#13
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.setWindowTitle("Demo14_3, 交互操作")
        self.__labMove = QLabel("Mouse Move:")
        self.__labMove.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labMove)

        self.__labPick = QLabel("Mouse Pick:")
        self.__labPick.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labPick)

        mpl.rcParams['font.sans-serif'] = ['SimHei']  #显示汉字为 楷体, 汉字不支持 粗体,斜体等设置
        mpl.rcParams['font.size'] = 11
        ##  Windows自带的一些字体
        ##  黑体:SimHei 宋体:SimSun 新宋体:NSimSun 仿宋:FangSong  楷体:KaiTi
        mpl.rcParams['axes.unicode_minus'] = False  #减号unicode编码

        self.__fig = None  #Figue对象
        self.__createFigure()  #创建Figure和FigureCanvas对象,初始化界面
        self.__drawFig1X2()

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

    def __createFigure(self):  ##创建绘图系统
        self.__fig = mpl.figure.Figure(figsize=(8, 5))  #单位英寸
        figCanvas = FigureCanvas(self.__fig)  #创建FigureCanvas对象,必须传递一个Figure对象
        self.__naviBar = NavigationToolbar(figCanvas,
                                           self)  #创建NavigationToolbar工具栏

        actList = self.__naviBar.actions()  #关联的Action列表
        for act in actList:  #获得每个Action的标题和tooltip,可注释掉
            print("text=%s,\ttoolTip=%s" % (act.text(), act.toolTip()))
        self.__changeActionLanguage()  #改工具栏的语言为汉语
        ##工具栏改造
        actList[6].setVisible(False)  #隐藏Subplots 按钮
        actList[7].setVisible(False)  #隐藏Customize按钮
        act8 = actList[8]  #分隔条
        self.__naviBar.insertAction(act8, self.ui.actTightLayout)  #"紧凑布局"按钮
        self.__naviBar.insertAction(act8, self.ui.actSetCursor)  #"十字光标"按钮

        count = len(actList)  #Action的个数
        lastAction = actList[count - 1]  #最后一个Action
        self.__naviBar.insertAction(lastAction,
                                    self.ui.actScatterAgain)  #"重绘散点"按钮

        lastAction.setVisible(False)  #隐藏其原有的坐标提示
        self.__naviBar.addSeparator()
        self.__naviBar.addAction(self.ui.actQuit)  #"退出"按钮
        self.__naviBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  #显示方式

        self.addToolBar(self.__naviBar)  #添加作为主窗口工具栏
        self.setCentralWidget(figCanvas)

        figCanvas.setCursor(Qt.CrossCursor)
        ## 必须保留变量cid,否则可能被垃圾回收
        self._cid1 = figCanvas.mpl_connect("motion_notify_event",
                                           self.do_canvas_mouseMove)
        self._cid2 = figCanvas.mpl_connect("axes_enter_event",
                                           self.do_axes_mouseEnter)
        self._cid3 = figCanvas.mpl_connect("axes_leave_event",
                                           self.do_axes_mouseLeave)
        self._cid4 = figCanvas.mpl_connect("pick_event", self.do_series_pick)
        self._cid5 = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)

    def __changeActionLanguage(self):
        actList = self.__naviBar.actions()  #关联的Action列表
        actList[0].setText("复位")  #Home
        actList[0].setToolTip("复位到原始视图")  #Reset original view

        actList[1].setText("回退")  #Back
        actList[1].setToolTip("回到前一视图")  #Back to previous view

        actList[2].setText("前进")  #Forward
        actList[2].setToolTip("前进到下一视图")  #Forward to next view

        actList[4].setText("平动")  #Pan
        actList[4].setToolTip(
            "左键平移坐标轴,右键缩放坐标轴")  #Pan axes with left mouse, zoom with right

        actList[5].setText("缩放")  #Zoom
        actList[5].setToolTip("框选矩形框缩放")  #Zoom to rectangle

        actList[6].setText("子图")  #Subplots
        actList[6].setToolTip("设置子图")  #Configure subplots

        actList[7].setText("定制")  #Customize
        actList[7].setToolTip("定制图表参数")  #Edit axis, curve and image parameters

        actList[9].setText("保存")  #Save
        actList[9].setToolTip("保存图表")  #Save the figure

    def __drawScatters(self, N=15):
        x = range(N)  #序列0,1,....N-1
        ##      x=np.random.rand(N)
        y = np.random.rand(N)
        colors = np.random.rand(N)  #0~1之间随机数
        self.__markerSize = (
            40 * (0.2 + np.random.rand(N)))**2  #0 to 15 point radius
        self.__axScatter.scatter(x,
                                 y,
                                 s=self.__markerSize,
                                 c=colors,
                                 marker='*',
                                 alpha=0.5,
                                 label="scatter series",
                                 picker=True)  #允许被拾取pick
        #s=The marker size in points**2
        #c=color, sequence, or sequence of color, optional, default: 'b'
        ## marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
        self.__axScatter.set_title("散点图")
        self.__axScatter.set_xlabel('序号')  # X轴标题

    def __drawFig1X2(self):  #初始化绘图
        gs = self.__fig.add_gridspec(1, 2)  #1行,2列
        ##      ax1=self.__fig.add_subplot(1,1,1) #添加一个Axes对象,并返回此对象,不支持constrained_layout
        ax1 = self.__fig.add_subplot(gs[0, 0], label="Line2D plot")

        t = np.linspace(0, 10, 40)
        y1 = np.sin(t)
        y2 = np.cos(2 * t)
        ax1.plot(t,
                 y1,
                 'r-o',
                 label="sin series",
                 linewidth=1,
                 markersize=5,
                 picker=True)  #绘制一条曲线
        ax1.plot(t, y2, 'b:', label="cos series", linewidth=2)  #绘制一条曲线
        ax1.set_xlabel('X 轴')
        ax1.set_ylabel('Y 轴')
        ax1.set_xlim([0, 10])
        ax1.set_ylim([-1.5, 1.5])
        ax1.set_title("曲线")
        ax1.legend()  #自动创建Axes的图例

        self.__axScatter = self.__fig.add_subplot(gs[0, 1],
                                                  label="scatter plot")  #创建子图
        self.__drawScatters(N=15)  #绘制散点图

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

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ## 紧凑布局
    def on_actTightLayout_triggered(self):
        self.__fig.tight_layout()  # 对所有子图 进行一次tight_layout
        self.__fig.canvas.draw()

    @pyqtSlot()  ## 设置鼠标光标
    def on_actSetCursor_triggered(self):
        self.__fig.canvas.setCursor(Qt.CrossCursor)

    @pyqtSlot()  ## 重新绘制散点图
    def on_actScatterAgain_triggered(self):
        self.__axScatter.clear()  #清除子图
        self.__drawScatters(N=15)
        self.__fig.canvas.draw()  #刷新

##  =================自定义槽函数==========
#event类型 matplotlib.backend_bases.MouseEvent

    def do_canvas_mouseMove(self, event):
        if event.inaxes == None:
            return
        info = "%s: xdata=%.2f,ydata=%.2f  " % (event.inaxes.get_label(),
                                                event.xdata, event.ydata)
        self.__labMove.setText(info)

## event类型:matplotlib.backend_bases.LocationEvent

    def do_axes_mouseEnter(self, event):
        event.inaxes.patch.set_facecolor('g')  #设置背景颜色
        event.inaxes.patch.set_alpha(0.2)  #透明度
        event.canvas.draw()

    def do_axes_mouseLeave(self, event):
        event.inaxes.patch.set_facecolor('w')  #设置背景颜色
        event.canvas.draw()

##event 类型: matplotlib.backend_bases.PickEvent

    def do_series_pick(self, event):
        series = event.artist  # 产生事件的对象
        index = event.ind[0]  #索引号,是array([int32])类型,可能有多个对象被pick,只取第1个
        #是否有ind属性与具体的对象有关

        if isinstance(series, mpl.collections.PathCollection):  #scatter()生成的序列
            markerSize = self.__markerSize[index]
            info = "%s: index=%d, marker size=%d " % (
                event.mouseevent.inaxes.get_label(), index, markerSize)
        elif isinstance(series, mpl.lines.Line2D):  #plot()生成的序列
            ##         xdata=series.get_xdata() #两种方法都可以
            ##         x=xdata[index]
            ##         ydata=series.get_ydata()
            ##         y=ydata[index]
            x = event.mouseevent.xdata  #标量数据点
            y = event.mouseevent.ydata  #标量数据点
            info = "%s: index=%d, data_xy=(%.2f, %.2f) " % (series.get_label(),
                                                            index, x, y)

        self.__labPick.setText(info)

#event类型 matplotlib.backend_bases.MouseEvent

    def do_scrollZoom(self, event):  #通过鼠标滚轮缩放
        ax = event.inaxes  # 产生事件的axes对象
        if ax == None:
            return

        self.__naviBar.push_current(
        )  #Push the current view limits and position onto the stack,这样才可以还原
        xmin, xmax = ax.get_xbound()  #获取范围
        xlen = xmax - xmin

        ymin, ymax = ax.get_ybound()  #获取范围
        ylen = ymax - ymin

        xchg = event.step * xlen / 20  #step [scalar],positive = ’up’, negative ='down'
        xmin = xmin + xchg
        xmax = xmax - xchg

        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)

        event.canvas.draw()