示例#1
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)
示例#2
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)
示例#3
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)
示例#4
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)
示例#5
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()
class MultiPlot(QtWidgets.QMainWindow):
    def __init__(self, _parent):

        QtWidgets.QMainWindow.__init__(self, _parent)
        self.setWindowTitle("Production rates")
        self.resize(1020, 752)
        frameGm = self.frameGeometry()
        centerPoint = QtWidgets.QDesktopWidget().availableGeometry().center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

        self.fig = None
        self.canvas = None
        self.parent = _parent
        self.prod_rates_df = _parent.simulation_thread.prod_rates_df
        self.prev_dir_path = ""
        self.create_menu()
        self.create_main_frame()
        self.on_draw()

    def create_menu(self):
        self.file_menu = self.menuBar().addMenu("File")
        quit_action = QtWidgets.QAction("Quit", self)
        quit_action.setIcon(QtGui.QIcon(":quit.png"))
        quit_action.triggered.connect(self.close)
        quit_action.setToolTip("Quit")
        quit_action.setStatusTip("Quit")
        quit_action.setShortcut('Ctrl+Q')

        self.file_menu.addAction(quit_action)

    def create_main_frame(self):
        self.main_frame = QtWidgets.QWidget()

        # Create the mpl Figure and FigCanvas objects
        self.dpi = 100

        self.fig = Figure((10.0, 10.0), dpi=self.dpi, facecolor='White')

        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        save_button = QtWidgets.QPushButton()
        save_button.clicked.connect(self.save_production_data)
        save_button.setIcon(QtGui.QIcon(":save.png"))
        save_button.setToolTip("Save production data")
        save_button.setStatusTip("Save production data")

        show_button = QtWidgets.QPushButton()
        show_button.clicked.connect(self.plot_settings_view)
        show_button.setIcon(QtGui.QIcon(":gear.png"))
        show_button.setToolTip("Edit settings")
        show_button.setStatusTip("Edit settings")

        buttonbox0 = QtWidgets.QDialogButtonBox()
        buttonbox0.addButton(save_button,
                             QtWidgets.QDialogButtonBox.ActionRole)
        buttonbox0.addButton(show_button,
                             QtWidgets.QDialogButtonBox.ActionRole)

        self.mpl_toolbar.addWidget(buttonbox0)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.canvas)

        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

        self.status_text = QtWidgets.QLabel("")
        self.statusBar().addWidget(self.status_text, 1)

    def save_production_data(self):
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self, self.tr("Save file"), self.prev_dir_path,
            "CSV files (*.csv)")
        filename = filename[0]

        if not filename:
            return

        self.prev_dir_path = ntpath.dirname(filename[0])
        self.prod_rates_df.to_csv(filename)
        self.statusBar().showMessage(self.tr("File saved"), 3000)

    def plot_settings_view(self):
        settings_dialog = PlotSettingsDialog(self)
        settings_dialog.setModal(True)
        settings_dialog.show()

    def on_draw(self):

        cl = [
            '#4F81BD', '#C0504D', '#9BBB59', '#F79646', '#8064A2', '#4BACC6',
            '0', '0.5'
        ]  # colour

        # add subplot purely for the axis labels
        axes = self.fig.add_subplot(111)
        axes.spines['top'].set_color('none')
        axes.spines['bottom'].set_color('none')
        axes.spines['left'].set_color('none')
        axes.spines['right'].set_color('none')
        axes.tick_params(labelcolor='w',
                         top='off',
                         bottom='off',
                         left='off',
                         right='off')
        axes.set_xlabel(r'$\mathrm{\mathsf{Time\ [hours]}}$',
                        fontsize=24,
                        weight='black')
        axes.set_ylabel(r'$\mathrm{\mathsf{Production\ rate\ [a.u.]}}$',
                        fontsize=24,
                        weight='black')

        # define grid for all the subplots
        gs = gridspec.GridSpec(len(self.parent.plot_selection), 1)
        gs.update(wspace=0,
                  hspace=0)  # set the spacing between the plots to zero

        num0 = 0  # for all data sets
        num1 = 0  # for selected data sets

        self.parent.plot_selection.sort(
        )  # sort to be sure we make axes for only the last element

        for i in self.prod_rates_df.columns:

            if num0 in self.parent.plot_selection:

                axes = self.fig.add_subplot(gs[num1])
                axes.plot(self.prod_rates_df.index,
                          self.prod_rates_df.iloc[:, num0],
                          c=cl[num1 % len(cl)]
                          )  # need iloc to avoid columns with the same name
                axes.text(0.01,
                          0.5,
                          i,
                          horizontalalignment='left',
                          verticalalignment='center',
                          transform=axes.transAxes)
                axes.title.set_visible(False)
                axes.set_yticklabels(())
                if (not num0 == self.parent.plot_selection[-1]):
                    axes.set_xticklabels(())
                axes.tick_params(pad=8)
                num1 += 1

            num0 += 1

        self.canvas.draw()

    def on_redraw(self):

        self.parent.plot_production_rates()
        self.close()
示例#7
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)
示例#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 IVMainPlot(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        pass

    def on_draw(self):
        pass

    def create_main_frame(self, two_axes=False):
        self.main_frame = QtWidgets.QWidget()

        # Create the mpl Figure and FigCanvas objects
        self.dpi = 100
        self.fig = Figure((10.0, 10.0), dpi=self.dpi, facecolor='White')
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        self.axes = self.fig.add_subplot(111, facecolor='White')

        if two_axes:
            self.axes2 = self.axes.twinx()

        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        # Other GUI controls
        show_button = QtWidgets.QPushButton()
        show_button.clicked.connect(self.plot_settings_view)
        show_button.setIcon(QtGui.QIcon(":gear.png"))
        show_button.setToolTip(self.tr("Plot settings"))
        show_button.setStatusTip(self.tr("Plot settings"))

        buttonbox0 = QtWidgets.QDialogButtonBox()
        buttonbox0.addButton(show_button,
                             QtWidgets.QDialogButtonBox.ActionRole)

        self.mpl_toolbar.addWidget(show_button)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.canvas)

        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

        self.status_text = QtWidgets.QLabel("")
        self.statusBar().addWidget(self.status_text, 1)

    def create_menu(self):

        self.file_menu = self.menuBar().addMenu(self.tr("File"))
        tip = self.tr("Quit")
        quit_action = QtWidgets.QAction(tip, self)
        quit_action.setIcon(QtGui.QIcon(":quit.png"))
        quit_action.triggered.connect(self.close)
        quit_action.setToolTip(tip)
        quit_action.setStatusTip(tip)
        quit_action.setShortcut('Ctrl+Q')

        self.file_menu.addAction(quit_action)

    def plot_settings_view(self):
        settings_dialog = PlotSettingsDialog(self)
        settings_dialog.setModal(True)
        settings_dialog.show()
class MultiPlot(QtWidgets.QMainWindow):
    
    def __init__(self, _parent):
        
        QtWidgets.QMainWindow.__init__(self, _parent)
        self.setWindowTitle("Production rates")
        self.resize(1020, 752)
        frameGm = self.frameGeometry()
        centerPoint = QtWidgets.QDesktopWidget().availableGeometry().center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())
        
        self.fig = None
        self.canvas = None
        self.parent = _parent
        self.prod_rates_df = _parent.simulation_thread.prod_rates_df
        self.prev_dir_path = ""
        self.create_menu()
        self.create_main_frame()       
        self.on_draw()        

    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("File")
        quit_action = QtWidgets.QAction("Quit", self)
        quit_action.setIcon(QtGui.QIcon(":quit.png"))
        quit_action.triggered.connect(self.close) 
        quit_action.setToolTip("Quit")
        quit_action.setStatusTip("Quit")
        quit_action.setShortcut('Ctrl+Q')
       
        self.file_menu.addAction(quit_action)

    def create_main_frame(self):
        self.main_frame = QtWidgets.QWidget()
        
        # Create the mpl Figure and FigCanvas objects
        self.dpi = 100
        
        self.fig = Figure((10.0, 10.0), dpi=self.dpi, facecolor='White')        

        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)       
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        save_button = QtWidgets.QPushButton()
        save_button.clicked.connect(self.save_production_data)
        save_button.setIcon(QtGui.QIcon(":save.png"))
        save_button.setToolTip("Save production data")
        save_button.setStatusTip("Save production data")
        
        show_button = QtWidgets.QPushButton()
        show_button.clicked.connect(self.plot_settings_view)
        show_button.setIcon(QtGui.QIcon(":gear.png"))
        show_button.setToolTip("Edit settings")
        show_button.setStatusTip("Edit settings")

        buttonbox0 = QtWidgets.QDialogButtonBox()
        buttonbox0.addButton(save_button, QtWidgets.QDialogButtonBox.ActionRole)
        buttonbox0.addButton(show_button, QtWidgets.QDialogButtonBox.ActionRole)

        self.mpl_toolbar.addWidget(buttonbox0)                      
                                
        vbox = QtWidgets.QVBoxLayout()        
        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.canvas)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
        
        self.status_text = QtWidgets.QLabel("")        
        self.statusBar().addWidget(self.status_text,1)

    def save_production_data(self):
        filename = QtWidgets.QFileDialog.getSaveFileName(self,self.tr("Save file"), self.prev_dir_path, "CSV files (*.csv)")
        filename = filename[0]
        
        if not filename:
            return

        self.prev_dir_path = ntpath.dirname(filename[0])
        self.prod_rates_df.to_csv(filename)        
        self.statusBar().showMessage(self.tr("File saved"),3000)

    def plot_settings_view(self):
        settings_dialog = PlotSettingsDialog(self)
        settings_dialog.setModal(True)
        settings_dialog.show()
        
    def on_draw(self):

        cl = ['#4F81BD', '#C0504D', '#9BBB59','#F79646','#8064A2','#4BACC6','0','0.5'] # colour

        # add subplot purely for the axis labels
        axes = self.fig.add_subplot(111)  
        axes.spines['top'].set_color('none')
        axes.spines['bottom'].set_color('none')
        axes.spines['left'].set_color('none')
        axes.spines['right'].set_color('none')
        axes.tick_params(labelcolor='w', top='off', bottom='off', left='off', right='off')
        axes.set_xlabel(r'$\mathrm{\mathsf{Time\ [hours]}}$', fontsize=24, weight='black')
        axes.set_ylabel(r'$\mathrm{\mathsf{Production\ rate\ [a.u.]}}$', fontsize=24, weight='black')

        # define grid for all the subplots
        gs = gridspec.GridSpec(len(self.parent.plot_selection),1)
        gs.update(wspace=0, hspace=0) # set the spacing between the plots to zero

        num0 = 0 # for all data sets
        num1 = 0 # for selected data sets
        
        self.parent.plot_selection.sort() # sort to be sure we make axes for only the last element
        
        for i in self.prod_rates_df.columns:

            if num0 in self.parent.plot_selection:
                
                axes = self.fig.add_subplot(gs[num1])
                axes.plot(self.prod_rates_df.index, self.prod_rates_df.iloc[:,num0], c=cl[num1 % len(cl)]) # need iloc to avoid columns with the same name
                axes.text(0.01,0.5,i, horizontalalignment='left', verticalalignment='center', transform=axes.transAxes)
                axes.title.set_visible(False)               
                axes.set_yticklabels(())
                if (not num0 == self.parent.plot_selection[-1]):
                    axes.set_xticklabels(()) 
                axes.tick_params(pad=8)
                num1 += 1

            num0 += 1

        self.canvas.draw()    
        
    def on_redraw(self):
        
        self.parent.plot_production_rates()
        self.close()    
                
class IVMainPlot(QtWidgets.QMainWindow):  
    
    def __init__(self, parent=None):
        pass          
        
    def on_draw(self):
        pass
    
    def create_main_frame(self,two_axes=False):
        self.main_frame = QtWidgets.QWidget()
        
        # Create the mpl Figure and FigCanvas objects
        self.dpi = 100
        self.fig = Figure((10.0, 10.0), dpi=self.dpi, facecolor='White')
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        
        self.axes = self.fig.add_subplot(111, facecolor='White')
        
        if two_axes:
            self.axes2 = self.axes.twinx()        
 
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Other GUI controls               
        show_button = QtWidgets.QPushButton()
        show_button.clicked.connect(self.plot_settings_view)
        show_button.setIcon(QtGui.QIcon(":gear.png"))
        show_button.setToolTip(self.tr("Plot settings"))
        show_button.setStatusTip(self.tr("Plot settings"))

        buttonbox0 = QtWidgets.QDialogButtonBox()
        buttonbox0.addButton(show_button, QtWidgets.QDialogButtonBox.ActionRole)               

        self.mpl_toolbar.addWidget(show_button)                      
                                
        vbox = QtWidgets.QVBoxLayout()        
        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.canvas)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
        
        self.status_text = QtWidgets.QLabel("")        
        self.statusBar().addWidget(self.status_text,1)       
        
    def create_menu(self):

        self.file_menu = self.menuBar().addMenu(self.tr("File"))
        tip = self.tr("Quit")
        quit_action = QtWidgets.QAction(tip, self)
        quit_action.setIcon(QtGui.QIcon(":quit.png"))
        quit_action.triggered.connect(self.close) 
        quit_action.setToolTip(tip)
        quit_action.setStatusTip(tip)
        quit_action.setShortcut('Ctrl+Q')
       
        self.file_menu.addAction(quit_action)        

    def plot_settings_view(self):
        settings_dialog = PlotSettingsDialog(self)
        settings_dialog.setModal(True)
        settings_dialog.show()