def setUp(self):
     super(TestConsole, self).setUp()
     self.console = IPythonDockWidget(
         available_vars={"a": _a, "f": _f},
         custom_banner="Welcome!\n")
     self.console.show()
     self.qWaitForWindowExposed(self.console)
Ejemplo n.º 2
0
class TestConsole(TestCaseQt):
    """Basic test for ``module.IPythonDockWidget``"""
    def setUp(self):
        super(TestConsole, self).setUp()
        self.console = IPythonDockWidget(available_vars={
            "a": _a,
            "f": _f
        },
                                         custom_banner="Welcome!\n")
        self.console.show()
        self.qWaitForWindowExposed(self.console)

    def tearDown(self):
        self.console.setAttribute(qt.Qt.WA_DeleteOnClose)
        self.console.close()
        del self.console
        super(TestConsole, self).tearDown()

    def testShow(self):
        pass

    def testInteract(self):
        self.mouseClick(self.console, qt.Qt.LeftButton)
        self.keyClicks(self.console, 'import silx')
        self.keyClick(self.console, qt.Qt.Key_Enter)
        self.qapp.processEvents()
Ejemplo n.º 3
0
class TestConsole(TestCaseQt):
    """Basic test for ``module.IPythonDockWidget``"""

    def setUp(self):
        super(TestConsole, self).setUp()
        self.console = IPythonDockWidget(
            available_vars={"a": _a, "f": _f},
            custom_banner="Welcome!\n")
        self.console.show()
        self.qWaitForWindowExposed(self.console)

    def tearDown(self):
        self.console.setAttribute(qt.Qt.WA_DeleteOnClose)
        self.console.close()
        del self.console
        super(TestConsole, self).tearDown()

    def testShow(self):
        pass

    def testInteract(self):
        self.mouseClick(self.console, qt.Qt.LeftButton)
        self.keyClicks(self.console, 'import silx')
        self.keyClick(self.console, qt.Qt.Key_Enter)
        self.qapp.processEvents()
Ejemplo n.º 4
0
def console(qapp_utils):
    """Create a console widget"""
    # Console tests disabled due to corruption of python environment
    pytest.skip("Disabled (see issue #538)")
    try:
        from silx.gui.console import IPythonDockWidget
    except ImportError:
        pytest.skip("IPythonDockWidget is not available")

    console = IPythonDockWidget(available_vars={
        "a": _a,
        "f": _f
    },
                                custom_banner="Welcome!\n")
    console.show()
    qapp_utils.qWaitForWindowExposed(console)
    yield console
    console.setAttribute(qt.Qt.WA_DeleteOnClose)
    console.close()
    console = None
Ejemplo n.º 5
0
    def __init__(self, filename=None):

        # Qt base class constructor
        super(ScanViewer, self).__init__()

        # instantiate the form class and set it up in the current QMainWindow
        self.ui = design.Ui_MainWindow()
        self.ui.setupUi(self)

        # possibly set initial values
        self.guessPath()
        if filename:
            self.ui.filenameBox.setText(filename)

        # set up default plot settings
        self.diffCmap = {
            'name': 'temperature',
            'autoscale': True,
            'normalization': 'log'
        }
        self.mapCmap = {
            'name': 'gray',
            'autoscale': True,
            'normalization': 'linear'
        }

        # populate the scan class list
        self.ui.scanClassBox.addItem('select scan type')
        default_text = 'contrast_scan'
        default_index = 0
        for subclass in nmutils.core.Scan.__subclasses__():
            self.ui.scanClassBox.addItem(subclass.__name__)
            if subclass.__name__ == default_text:
                default_index = self.ui.scanClassBox.count() - 1
            for subclass_ in subclass.__subclasses__():
                self.ui.scanClassBox.addItem(subclass_.__name__)

        # connect browse button
        def wrap():
            old = self.ui.filenameBox.text()
            result = qt.QFileDialog.getOpenFileName(directory=old)
            # PyQt5 gives a tuple here...
            if type(result) == tuple:
                result = result[0]
            if result:
                self.ui.filenameBox.setText(result)

        self.ui.browseButton.clicked.connect(wrap)

        # populate the options tab
        self.ui.scanClassBox.currentIndexChanged.connect(self.populateOptions)

        # set the default and emit a signal
        self.ui.scanClassBox.setCurrentIndex(default_index)

        # connect load button
        self.ui.loadButton.clicked.connect(self.load)

        # connect the PyMCA button to the slot on that widget
        self.ui.pymcaButton.clicked.connect(self.ui.xrfWidget.exportPyMCA)

        # dummy scan
        self._scan = None

        # the ipython button
        self.ui.ipythonButton.setCheckable(True)
        self.ui.ipythonButton.setChecked(False)
        self.ui.ipythonButton.clicked.connect(self._toggle_ipython)
        if HAS_QTCONSOLE:
            self.console = IPythonDockWidget(
                parent=self,
                available_vars={
                    'self': self,
                    'ui': self.ui,
                    'update': self._update
                },
                custom_banner=
                ('Nanomax Scan Viewer console.\n' +
                 '"self" refers to the ScanViewer instance.\n' +
                 '"self.scan" refers to the current Scan object.\n' +
                 '"update()" refreshes all plots and images after modifying data.'
                 + '\n\n'))
            self.console.hide()
            self.addDockWidget(qt.Qt.BottomDockWidgetArea, self.console)
        else:
            self.ui.ipythonButton.setEnabled(False)
Ejemplo n.º 6
0
class ScanViewer(qt.QMainWindow):
    def __init__(self, filename=None):

        # Qt base class constructor
        super(ScanViewer, self).__init__()

        # instantiate the form class and set it up in the current QMainWindow
        self.ui = design.Ui_MainWindow()
        self.ui.setupUi(self)

        # possibly set initial values
        self.guessPath()
        if filename:
            self.ui.filenameBox.setText(filename)

        # set up default plot settings
        self.diffCmap = {
            'name': 'temperature',
            'autoscale': True,
            'normalization': 'log'
        }
        self.mapCmap = {
            'name': 'gray',
            'autoscale': True,
            'normalization': 'linear'
        }

        # populate the scan class list
        self.ui.scanClassBox.addItem('select scan type')
        default_text = 'contrast_scan'
        default_index = 0
        for subclass in nmutils.core.Scan.__subclasses__():
            self.ui.scanClassBox.addItem(subclass.__name__)
            if subclass.__name__ == default_text:
                default_index = self.ui.scanClassBox.count() - 1
            for subclass_ in subclass.__subclasses__():
                self.ui.scanClassBox.addItem(subclass_.__name__)

        # connect browse button
        def wrap():
            old = self.ui.filenameBox.text()
            result = qt.QFileDialog.getOpenFileName(directory=old)
            # PyQt5 gives a tuple here...
            if type(result) == tuple:
                result = result[0]
            if result:
                self.ui.filenameBox.setText(result)

        self.ui.browseButton.clicked.connect(wrap)

        # populate the options tab
        self.ui.scanClassBox.currentIndexChanged.connect(self.populateOptions)

        # set the default and emit a signal
        self.ui.scanClassBox.setCurrentIndex(default_index)

        # connect load button
        self.ui.loadButton.clicked.connect(self.load)

        # connect the PyMCA button to the slot on that widget
        self.ui.pymcaButton.clicked.connect(self.ui.xrfWidget.exportPyMCA)

        # dummy scan
        self._scan = None

        # the ipython button
        self.ui.ipythonButton.setCheckable(True)
        self.ui.ipythonButton.setChecked(False)
        self.ui.ipythonButton.clicked.connect(self._toggle_ipython)
        if HAS_QTCONSOLE:
            self.console = IPythonDockWidget(
                parent=self,
                available_vars={
                    'self': self,
                    'ui': self.ui,
                    'update': self._update
                },
                custom_banner=
                ('Nanomax Scan Viewer console.\n' +
                 '"self" refers to the ScanViewer instance.\n' +
                 '"self.scan" refers to the current Scan object.\n' +
                 '"update()" refreshes all plots and images after modifying data.'
                 + '\n\n'))
            self.console.hide()
            self.addDockWidget(qt.Qt.BottomDockWidgetArea, self.console)
        else:
            self.ui.ipythonButton.setEnabled(False)

    def _toggle_ipython(self):
        if self.ui.ipythonButton.isChecked():
            self.console.show()
        else:
            self.console.hide()

    def _current_subclass_opts(self):
        subclass_ = str(self.ui.scanClassBox.currentText())
        try:
            subclass = getattr(nmutils.core, subclass_)
            opts = subclass.default_opts.copy()
        except AttributeError:
            opts = {}
        return opts

    def guessPath(self):
        """
        As a beamline convenience, sees if there's an SDM path available
        to start with.
        """
        try:
            import tango, os
            dev = tango.DeviceProxy('b303a/ctl/sdm-01')
            path = dev.path
            if os.path.exists(path):
                self.ui.filenameBox.setText(path)
        except Exception as e:
            print("couldn't find path from tango - but that's ok")

    def gatherOptions(self):
        # collect options from the options tab:
        opts = {}
        for name, w in self.formWidgets.items():
            if isinstance(w, qt.QCheckBox):
                val = bool(w.isChecked())
            elif isinstance(w, qt.QComboBox):
                val = str(w.currentText())
            elif isinstance(w, qt.QLineEdit) and not w.evaluate_me:
                val = str(w.text())
            elif isinstance(w, qt.QLineEdit) and w.evaluate_me:
                val = eval(str(w.text()))
            else:
                val = w.value()
            opts[name] = val

        # collect special options from the top of the GUI:
        subclass_opts = self._current_subclass_opts()
        if 'path' in subclass_opts.keys():
            opts['path'] = str(self.ui.filenameBox.text())
        if 'fileName' in subclass_opts.keys():
            opts['fileName'] = str(self.ui.filenameBox.text())
        if 'scanNr' in subclass_opts.keys():
            opts['scanNr'] = self.ui.scanNumberBox.value()

        return opts

    def populateOptions(self):
        grid = self.ui.optionsGrid
        # remove all old options
        for i in reversed(range(grid.count())):
            grid.itemAt(i).widget().setParent(None)

        # add new ones
        opts = self._current_subclass_opts()
        self.formWidgets = {}
        i = 0
        for name, opt in opts.items():
            # special: the options scanNr and fileName (or path) have their input
            # widgets at the top of the GUI for convenience, while dataSource is
            # handled per tab.
            if name in ('dataSource', 'scanNr', 'path', 'fileName'):
                continue
            grid.addWidget(qt.QLabel(name), i, 0)
            grid.addWidget(qt.QLabel(opt['doc']), i, 2)
            if opt['type'] == int:
                w = qt.QSpinBox()
                w.setMaximum(9999)
                w.setValue(opt['value'])
            elif opt['type'] == float:
                w = qt.QDoubleSpinBox()
                w.setValue(opt['value'])
            elif opt['type'] == bool:
                w = qt.QCheckBox()
                w.setChecked(opt['value'])
            elif opt['type'] in (list, tuple):
                w = qt.QLineEdit()
                w.setText(str(opt['value']))
                w.evaluate_me = True
            elif type(opt['type']) in (list, tuple):
                w = qt.QComboBox()
                defaultindex = 0
                for j, item in enumerate(opt['type']):
                    w.addItem(item)
                    if item == opt['value']:
                        defaultindex = j
                w.setCurrentIndex(defaultindex)
            else:
                w = qt.QLineEdit()
                w.setText(opt['value'])
                w.evaluate_me = False
            grid.addWidget(w, i, 1)
            # save a dict of the options widgets, to parse when loading
            self.formWidgets[name] = w
            i += 1

        # add a vertical spacer on the last line to make the table more compact
        grid.setRowStretch(i, 1)

        # special treatment
        oldtext = str(self.ui.filenameBox.text())
        if 'path' in opts.keys() and oldtext.startswith('<'):
            self.ui.filenameBox.setText('<data path>')
        elif 'fileName' in opts.keys() and oldtext.startswith('<'):
            self.ui.filenameBox.setText('<input file>')
        self.ui.filenameBox.setDisabled(not (
            'path' in opts.keys() or 'fileName' in opts.keys()))
        self.ui.browseButton.setDisabled(not (
            'path' in opts.keys() or 'fileName' in opts.keys()))
        self.ui.scanNumberBox.setDisabled('scanNr' not in opts.keys())

        # per-tab dataSource option
        boxes = {
            self.ui.dataSource2dBox: 2,
            self.ui.dataSource1dBox: 1,
            self.ui.dataSource0dBox: 0
        }
        subclass_ = str(self.ui.scanClassBox.currentText())
        try:
            subclass = getattr(nmutils.core, subclass_)
        except AttributeError:
            subclass = None

        for box, dim in boxes.items():
            box.clear()
            if subclass is not None:
                for name in opts['dataSource']['type']:
                    if hasattr(subclass, 'sourceDims'
                               ) and not subclass.sourceDims[name] == dim:
                        continue
                    box.addItem(name)
                box.addItem('')

    def statusOutput(self, msg):
        self.ui.statusbar.showMessage(msg)
        self.ui.statusbar.showMessage(msg)

    def _update(self):
        """
        Dummy property for use with the ipython console, makes the plots
        update by activating the self.scan setter method.
        """
        self.scan = self.scan

    @property
    def scan(self):
        return self._scan

    @scan.setter
    def scan(self, scn):
        self._scan = scn
        if scn is None:
            # clear all the widgets' references
            self.ui.xrdWidget.setScan(None)
            self.ui.comWidget.setScan(None)
            self.ui.xrfWidget.setScan(None)
            self.ui.pymcaButton.setEnabled(False)
            self.ui.scalarWidget.setScan(None)
            # do this just to be sure
            del (self._scan)
            self._scan = None
            # enforce garbage collection for good measure
            gc.collect()
        else:
            if '2d' in scn.data.keys():
                self.ui.xrdWidget.setScan(scn)
                self.ui.comWidget.setScan(scn)
            if '1d' in scn.data.keys():
                self.ui.xrfWidget.setScan(scn)
                self.ui.pymcaButton.setEnabled(True)
            if '0d' in scn.data.keys():
                self.ui.scalarWidget.setScan(scn)

    def load(self):
        try:
            self.statusOutput("Loading data...")

            if self.scan and not self.ui.appendBox.isChecked():
                print("Deleting previous scan from memory")
                self.scan = None

            # construct a scan
            try:
                subclass = str(self.ui.scanClassBox.currentText())
                scan_ = getattr(nmutils.core, subclass)()
            except AttributeError:
                self.statusOutput("Invalid subclass!")
                return

            # get options
            opts = self.gatherOptions()

            # add 2D data:
            try:
                source = self.ui.dataSource2dBox.currentText()
                if not source:
                    raise nmutils.NoDataException
                scan_.addData(dataSource=source, name='2d', **opts)
                dim = len(scan_.data['2d'].shape[1:])
                if not dim == 2:
                    scan_.removeData(name='2d')
                    print("loaded 2D was %uD, discarding" % dim)
                    raise nmutils.NoDataException
                print("loaded 2D data: %d positions, %d x %d pixels" %
                      (scan_.data['2d'].shape))
            except MemoryError:
                print(
                    "Out of memory! Consider cropping or binning your images")
            except nmutils.NoDataException:
                print("no 2D data found")
            except KeyboardInterrupt:
                print("cancelled")
                self.statusOutput("")
                return

            # add 1D data:
            try:
                source = self.ui.dataSource1dBox.currentText()
                if not source:
                    raise nmutils.NoDataException
                scan_.addData(dataSource=source, name='1d', **opts)
                dim = len(scan_.data['1d'].shape[1:])
                if not dim == 1:
                    scan_.removeData(name='1d')
                    print("loaded 1D was %uD, discarding" % dim)
                    raise nmutils.NoDataException
                print("loaded 1D data: %d positions, %d channels" %
                      (scan_.data['1d'].shape))
            except nmutils.NoDataException:
                print("no 1D data found")
            except KeyboardInterrupt:
                print("cancelled")
                self.statusOutput("")
                return

            # add 0D data:
            try:
                source = self.ui.dataSource0dBox.currentText()
                if not source:
                    raise nmutils.NoDataException
                scan_.addData(dataSource=source, name='0d', **opts)
                dim = len(scan_.data['0d'].shape[1:])
                if not dim == 0:
                    scan_.removeData(name='0d')
                    print("loaded 0D was %uD, discarding" % dim)
                    raise nmutils.NoDataException
                print("loaded 0D data: %d positions" %
                      (scan_.data['0d'].shape))
            except nmutils.NoDataException:
                print("no 0D data found")
            except KeyboardInterrupt:
                print("cancelled")
                self.statusOutput("")
                return

            # maybe there was no data at all
            if scan_.positions is None:
                self.statusOutput("No data found")
                return

            # append or store loaded scan as it is
            if self.scan is None:
                merged = scan_
            else:
                merged = self.scan
                merged.merge(scan_)

            # update the widgets
            if merged.nPositions > 1:
                self.scan = merged
            self.statusOutput("")
        except:
            self.statusOutput(
                "Loading failed. See terminal output for details.")
            raise