def main(dataSrc):
    plottrlog.LEVEL = logging.INFO

    app = QtWidgets.QApplication([])
    fc, win = autoplot(plotWidgetClass=plotWidgetClass)

    dataThread = QtCore.QThread()
    dataSrc.moveToThread(dataThread)
    dataSrc.dataready.connect(
        lambda d: win.setInput(data=d, resetDefaults=False))
    dataSrc.nomoredata.connect(dataThread.quit)
    dataThread.started.connect(dataSrc.gimmesomedata)
    win.windowClosed.connect(dataThread.quit)

    dataThread.start()

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtWidgets.QApplication.instance().exec_()
Exemple #2
0
    def setImage(self, x: np.ndarray, y: np.ndarray, z: np.ndarray) -> None:
        """Set data to be plotted as image.

        Clears the plot before creating a new image item that gets places in the
        plot and linked to the colorscale.

        :param x: x coordinates (as 2D meshgrid)
        :param y: y coordinates (as 2D meshgrid)
        :param z: data values (as 2D meshgrid)
        :return: None
        """
        self.clearPlot()

        self.img = pg.ImageItem()
        self.plot.addItem(self.img)
        self.img.setImage(z)
        self.img.setRect(QtCore.QRectF(x.min(), y.min(), x.max() - x.min(), y.max() - y.min()))

        self.colorbar.setImageItem(self.img)
        self.colorbar.rounding = (z.max() - z.min()) * 1e-2
        self.colorbar.setLevels((z.min(), z.max()))
Exemple #3
0
    def __init__(self, parent: Optional[QtWidgets.QWidget] = None):
        super().__init__(parent=parent)

        self.plotDataType = PlotDataType.unknown
        self.plotType = PlotType.empty

        # The default complex behavior is set here.
        self.complexRepresentation = ComplexRepresentation.realAndImag

        # A toolbar for configuring the plot
        self.plotOptionsToolBar = AutoPlotToolBar('Plot options', self)
        self.layout().insertWidget(1, self.plotOptionsToolBar)

        self.plotOptionsToolBar.plotTypeSelected.connect(
            self._plotTypeFromToolBar)
        self.plotOptionsToolBar.complexRepresentationSelected.connect(
            self._complexPreferenceFromToolBar)

        scaling = dpiScalingFactor(self)
        iconSize = int(36 + 8 * (scaling - 1))
        self.plotOptionsToolBar.setIconSize(QtCore.QSize(iconSize, iconSize))
        self.setMinimumSize(int(640 * scaling), int(480 * scaling))
Exemple #4
0
class MonitorIntervalInput(QtGui.QWidget):
    """
    Simple form-like widget for entering a monitor/refresh interval.
    Only has a label and a spin-box as input.

    It's signal `intervalChanged(int)' is emitted when the value
    of the spinbox has changed.
    """

    intervalChanged = QtCore.pyqtSignal(int)

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

        self.spin = QtGui.QSpinBox()
        layout = QtGui.QFormLayout()
        layout.addRow('Refresh interval (s)', self.spin)
        self.setLayout(layout)

        self.spin.valueChanged.connect(self.spinValueChanged)

    @QtCore.pyqtSlot(int)
    def spinValueChanged(self, val):
        self.intervalChanged.emit(val)
def image_test():
    app = QtWidgets.QApplication([])

    # create data
    x = np.linspace(0, 10, 51)
    y = np.linspace(-4, 4, 51)
    xx, yy = np.meshgrid(x, y, indexing='ij')
    zz = np.cos(xx)*np.exp(-(yy-1.)**2)

    # layout widget
    pgWidget = pg.GraphicsLayoutWidget()

    # main plot
    imgPlot = pgWidget.addPlot(title='my image', row=0, col=0)
    img = pg.ImageItem()
    imgPlot.addItem(img)

    # histogram and colorbar
    hist = pg.HistogramLUTItem()
    hist.setImageItem(img)
    pgWidget.addItem(hist)
    hist.gradient.loadPreset('viridis')

    # cut elements
    pgWidget2 = pg.GraphicsLayoutWidget()

    # plots for x and y cuts
    xplot = pgWidget2.addPlot(row=1, col=0)
    yplot = pgWidget2.addPlot(row=0, col=0)

    xplot.addLegend()
    yplot.addLegend()

    # add crosshair to main plot
    vline = pg.InfiniteLine(angle=90, movable=False, pen='r')
    hline = pg.InfiniteLine(angle=0, movable=False, pen='b')
    imgPlot.addItem(vline, ignoreBounds=True)
    imgPlot.addItem(hline, ignoreBounds=True)

    def crossMoved(event):
        pos = event[0].scenePos()
        if imgPlot.sceneBoundingRect().contains(pos):
            origin = imgPlot.vb.mapSceneToView(pos)
            vline.setPos(origin.x())
            hline.setPos(origin.y())
            vidx = np.argmin(np.abs(origin.x()-x))
            hidx = np.argmin(np.abs(origin.y()-y))
            yplot.clear()
            yplot.plot(zz[vidx, :], y, name='vertical cut',
                       pen=pg.mkPen('r', width=2),
                       symbol='o', symbolBrush='r', symbolPen=None)
            xplot.clear()
            xplot.plot(x, zz[:, hidx], name='horizontal cut',
                       pen=pg.mkPen('b', width=2),
                       symbol='o', symbolBrush='b', symbolPen=None)

    proxy = pg.SignalProxy(imgPlot.scene().sigMouseClicked, slot=crossMoved)

    dg = widgetDialog(pgWidget, title='pyqtgraph image test')
    dg2 = widgetDialog(pgWidget2, title='line cuts')

    # setting the data
    img.setImage(zz)
    img.setRect(QtCore.QRectF(0, -4, 10, 8.))
    hist.setLevels(zz.min(), zz.max())

    # formatting
    imgPlot.setLabel('left', "Y", units='T')
    imgPlot.setLabel('bottom', "X", units='A')
    xplot.setLabel('left', 'Z')
    xplot.setLabel('bottom', "X", units='A')
    yplot.setLabel('left', "Y", units='T')
    yplot.setLabel('bottom', "Z")

    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtWidgets.QApplication.instance().exec_()
Exemple #6
0
class GridOptionWidget(QtGui.QWidget):
    optionSelected = QtCore.pyqtSignal(object)

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

        self._emitUpdate = True

        #  make radio buttons and layout ##
        self.buttons = {
            GridOption.noGrid: QtGui.QRadioButton('No grid'),
            GridOption.guessShape: QtGui.QRadioButton('Guess shape'),
            GridOption.specifyShape: QtGui.QRadioButton('Specify shape'),
        }

        btnLayout = QtGui.QVBoxLayout()
        self.btnGroup = QtGui.QButtonGroup(self)

        for opt in GridOption:
            btn = self.buttons[opt]
            self.btnGroup.addButton(btn, opt.value)
            btnLayout.addWidget(btn)

        btnBox = QtGui.QGroupBox('Grid')
        btnBox.setLayout(btnLayout)

        # make shape spec widget
        self.shapeSpec = ShapeSpecificationWidget()
        shapeLayout = QtGui.QVBoxLayout()
        shapeLayout.addWidget(self.shapeSpec)
        shapeBox = QtGui.QGroupBox('Shape')
        shapeBox.setLayout(shapeLayout)

        # Widget layout
        layout = QtGui.QHBoxLayout()
        layout.addWidget(btnBox)
        layout.addWidget(shapeBox)
        layout.addStretch()
        self.setLayout(layout)

        # Connect signals/slots #
        self.btnGroup.buttonToggled.connect(self.gridButtonSelected)
        self.shapeSpec.confirm.clicked.connect(self.shapeSpecified)

        # Default settings
        self.buttons[GridOption.noGrid].setChecked(True)
        self.enableShapeEdit(False)

    def getGrid(self):
        activeBtn = self.btnGroup.checkedButton()
        activeId = self.btnGroup.id(activeBtn)
        opts = {}

        if GridOption(activeId) == GridOption.specifyShape:
            opts['shape'] = self.shapeSpec.getShape()

        return GridOption(activeId), opts

    def setGrid(self, grid):
        # This function should not trigger an emission for an update.
        # We only want that when the user sets the grid in the UI,
        # to avoid recursive calls
        self._emitUpdate = False

        method, opts = grid
        for k, btn in self.buttons.items():
            if k == method:
                btn.setChecked(True)

        if method == GridOption.specifyShape:
            self.setShape(opts['shape'])

    @QtCore.pyqtSlot(QtGui.QAbstractButton, bool)
    def gridButtonSelected(self, btn, checked):
        if checked:

            # only emit the signal when the update is from the UI
            if self._emitUpdate:
                self.signalGridOption(self.getGrid())

            if GridOption(self.btnGroup.id(btn)) == GridOption.specifyShape:
                self.enableShapeEdit(True)
            else:
                self.enableShapeEdit(False)

            self._emitUpdate = True

    @QtCore.pyqtSlot()
    def shapeSpecified(self):
        self.signalGridOption(self.getGrid())

    def signalGridOption(self, grid):
        self.optionSelected.emit(grid)

    def setAxes(self, axes):
        self.shapeSpec.setAxes(axes)
        if self.getGrid()[0] == GridOption.specifyShape:
            self.enableShapeEdit(True)
        else:
            self.enableShapeEdit(False)

    def setShape(self, shape):
        self.shapeSpec.setShape(shape)

    def enableShapeEdit(self, enable):
        self.shapeSpec.enableEditing(enable)
Exemple #7
0
class DataGridder(Node):
    """
    A node that can put data onto or off a grid.
    Has one property: grid. That can have the following values:
    * ...
    """

    nodeName = "Gridder"
    uiClass = DataGridderNodeWidget

    shapeDetermined = QtCore.pyqtSignal(tuple)
    axesList = QtCore.pyqtSignal(list)

    def __init__(self, *arg, **kw):

        self._grid = GridOption.noGrid, {}
        self._shape = None
        self._invalid = False

        super().__init__(*arg, **kw)

    # Properties

    @property
    def grid(self):
        return self._grid

    @grid.setter
    @updateOption('grid')
    def grid(self, val: Tuple[GridOption, Dict[str, Any]]):
        try:
            method, opts = val
        except TypeError:
            raise ValueError(f"Invalid grid specification.")

        if not method in GridOption:
            raise ValueError(f"Invalid grid method specification.")

        if not isinstance(opts, dict):
            raise ValueError(f"Invalid grid options specification.")

        self._grid = val

    # Processing

    def validateOptions(self, data: Any):
        if not super().validateOptions(data):
            return False

        return True

    def process(self, **kw):
        data = kw['dataIn']
        if data is None:
            return None

        data = super().process(**kw)
        if data is None:
            return None
        data = data['dataOut'].copy()
        self.axesList.emit(data.axes())

        dout = None
        method, opts = self._grid

        if isinstance(data, DataDict):
            if method is GridOption.noGrid:
                dout = data.expand()
            elif method is GridOption.guessShape:
                dout = dd.datadict_to_meshgrid(data)
            elif method is GridOption.specifyShape:
                dout = dd.datadict_to_meshgrid(data, target_shape=opts['shape'])

        elif isinstance(data, MeshgridDataDict):
            if method is GridOption.noGrid:
                dout = dd.meshgrid_to_datadict(data)
            elif method is GridOption.guessShape:
                dout = data
            elif method is GridOption.specifyShape:
                self.logger().warning(
                    f"Data is already on grid. Ignore shape.")
                dout = data

        else:
            self.logger().error(
                f"Unknown data type {type(data)}.")
            return None

        if dout is None:
            return None

        if hasattr(dout, 'shape'):
            self.shapeDetermined.emit(dout.shape())
        else:
            self.shapeDetermined.emit(tuple())

        return dict(dataOut=dout)

    ### Setup UI

    def setupUi(self):
        super().setupUi()
        self.axesList.connect(self.ui.setAxes)
        self.shapeDetermined.connect(self.ui.setShape)
Exemple #8
0
    def __init__(self,
                 parent: Optional[QtWidgets.QWidget] = None,
                 dbPath: Optional[str] = None):
        """Constructor for :class:`QCodesDBInspector`."""
        super().__init__(parent)

        self._plotWindows: Dict[int, WindowDict] = {}

        self.filepath = dbPath
        self.dbdf = None
        self.monitor = QtCore.QTimer()

        # flag for determining what has been loaded so far.
        # * None: nothing opened yet.
        # * -1: empty DS open.
        # * any value > 0: run ID from the most recent loading.
        self.latestRunId = None

        self.setWindowTitle('Plottr | QCoDeS dataset inspectr')

        ### GUI elements

        # Main Selection widgets
        self.dateList = DateList()
        self._selected_dates: Tuple[str, ...] = ()
        self.runList = RunList()
        self.runInfo = RunInfo()

        rightSplitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
        rightSplitter.addWidget(self.runList)
        rightSplitter.addWidget(self.runInfo)
        rightSplitter.setSizes([400, 200])

        splitter = QtWidgets.QSplitter()
        splitter.addWidget(self.dateList)
        splitter.addWidget(rightSplitter)
        splitter.setSizes([100, 500])

        self.setCentralWidget(splitter)

        # status bar
        self.status = QtWidgets.QStatusBar()
        self.setStatusBar(self.status)

        # toolbar
        self.toolbar = self.addToolBar('Data monitoring')

        # toolbar item: monitor interval
        self.monitorInput = MonitorIntervalInput()
        self.monitorInput.setToolTip('Set to 0 for disabling')
        self.monitorInput.intervalChanged.connect(self.setMonitorInterval)
        self.toolbar.addWidget(self.monitorInput)

        self.toolbar.addSeparator()

        # toolbar item: auto-launch plotting
        self.autoLaunchPlots = FormLayoutWrapper([('Auto-plot new',
                                                   QtWidgets.QCheckBox())])
        tt = "If checked, and automatic refresh is running, "
        tt += " launch plotting window for new datasets automatically."
        self.autoLaunchPlots.setToolTip(tt)
        self.toolbar.addWidget(self.autoLaunchPlots)

        # menu bar
        menu = self.menuBar()
        fileMenu = menu.addMenu('&File')

        # action: load db file
        loadAction = QtWidgets.QAction('&Load', self)
        loadAction.setShortcut('Ctrl+L')
        loadAction.triggered.connect(self.loadDB)
        fileMenu.addAction(loadAction)

        # action: updates from the db file
        refreshAction = QtWidgets.QAction('&Refresh', self)
        refreshAction.setShortcut('R')
        refreshAction.triggered.connect(self.refreshDB)
        fileMenu.addAction(refreshAction)

        # sizing
        scaledSize = 640 * rint(self.logicalDpiX() / 96.0)
        self.resize(scaledSize, scaledSize)

        ### Thread workers

        # DB loading. can be slow, so nice to have in a thread.
        self.loadDBProcess = LoadDBProcess()
        self.loadDBThread = QtCore.QThread()
        self.loadDBProcess.moveToThread(self.loadDBThread)
        self.loadDBProcess.pathSet.connect(self.loadDBThread.start)
        self.loadDBProcess.dbdfLoaded.connect(self.DBLoaded)
        self.loadDBProcess.dbdfLoaded.connect(self.loadDBThread.quit)
        self.loadDBThread.started.connect(
            self.loadDBProcess.loadDB)  # type: ignore[attr-defined]

        ### connect signals/slots

        self.dbdfUpdated.connect(self.updateDates)
        self.dbdfUpdated.connect(self.showDBPath)

        self.dateList.datesSelected.connect(self.setDateSelection)
        self.dateList.fileDropped.connect(self.loadFullDB)
        self.runList.runSelected.connect(self.setRunSelection)
        self.runList.runActivated.connect(self.plotRun)
        self._sendInfo.connect(self.runInfo.setInfo)
        self.monitor.timeout.connect(self.monitorTriggered)

        if self.filepath is not None:
            self.loadFullDB(self.filepath)
Exemple #9
0
    def setupUi(self, MainWindow: QtWidgets.QMainWindow) -> None:
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(935, 569)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName("splitter")
        self.fileList = DataFileList(self.splitter)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.fileList.sizePolicy().hasHeightForWidth())
        self.fileList.setSizePolicy(sizePolicy)
        self.fileList.setAlternatingRowColors(False)
        self.fileList.setUniformRowHeights(True)
        self.fileList.setObjectName("fileList")
        self.fileContents = DataFileContent(self.splitter)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.fileContents.sizePolicy().hasHeightForWidth())
        self.fileContents.setSizePolicy(sizePolicy)
        self.fileContents.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.fileContents.setUniformRowHeights(True)
        self.fileContents.setAllColumnsShowFocus(False)
        self.fileContents.setObjectName("fileContents")
        self.verticalLayout.addWidget(self.splitter)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 935, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.monitorToolBar = MonitorToolBar(MainWindow)
        self.monitorToolBar.setObjectName("monitorToolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.monitorToolBar)
        self.autoPlotNewAction = QtWidgets.QAction(MainWindow)
        self.autoPlotNewAction.setCheckable(True)
        self.autoPlotNewAction.setObjectName("autoPlotNewAction")
        self.monitorToolBar.addAction(self.autoPlotNewAction)

        self.retranslateUi(MainWindow)
        MainWindow.dataFileSelected.connect(self.fileContents.setData)
        self.fileList.dataFileSelected.connect(MainWindow.processFileSelection)
        self.fileContents.customContextMenuRequested['QPoint'].connect(
            self.fileContents.onCustomContextMenuRequested
        )  #  type: ignore[index]
        self.fileContents.plotRequested.connect(MainWindow.plotSelected)
        self.fileList.itemSelectionChanged.connect(
            self.fileList.processSelection)
        self.fileList.newDataFilesFound.connect(MainWindow.onNewDataFilesFound)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)