Exemple #1
0
    def __init__(self, parent, settings):
        super(GeneralTab, self).__init__(parent)

        self.settings = settings

        self.getParams().addChildren(
            [
                {
                    "name": "Project Folder",
                    "type": "file",
                    "filter": "dir",
                    "get": lambda: self.settings.value("project-home-dir"),
                    "set": lambda v: self.settings.setValue("project-home-dir", v),
                    "psync": False,
                }
            ]
        )

        parameterTree = ParameterTree()
        parameterTree.addParameters(self.getParams()._PyQtGraphParameter)

        defdirLayout = QHBoxLayout()
        defdirLayout.addWidget(parameterTree)
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(defdirLayout)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)
 def addSettings(self, param):
     """Adds a dockwidget designed to store a ParameterTree, also adds to 'Windows' menu"""
     parameterTree = ParameterTree()
     parameterTree.addParameters(param._PyQtGraphParameter)
     dock = self.addDock(parameterTree, name=param.getName(), area=Qt.TopDockWidgetArea)
     dock.setMaximumWidth(560)
     return dock
Exemple #3
0
    def __init__(self, parent, settings):
        super(GeneralTab, self).__init__(parent)

        self.settings = settings

        self.getParams().addChildren([{
            'name':
            "Project Folder",
            'type':
            "file",
            "filter":
            "dir",
            "get":
            lambda: self.settings.value("project-home-dir"),
            "set":
            lambda v: self.settings.setValue("project-home-dir", v),
            'psync':
            False
        }])

        parameterTree = ParameterTree()
        parameterTree.addParameters(self.getParams()._PyQtGraphParameter)

        defdirLayout = QHBoxLayout()
        defdirLayout.addWidget(parameterTree)
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(defdirLayout)
        mainLayout.addStretch(1)
        self.setLayout(mainLayout)
Exemple #4
0
 def addSettings(self, param):
     """Adds a dockwidget designed to store a ParameterTree, also adds to 'Windows' menu"""
     parameterTree = ParameterTree()
     parameterTree.addParameters(param._PyQtGraphParameter)
     dock = self.addDock(parameterTree, name=param.getName(), area=Qt.TopDockWidgetArea)
     dock.setMaximumWidth(560)
     return dock
Exemple #5
0
    class maintest(Parameterized):
        def __init__(self):
            super(maintest, self).__init__()
            self.values = {'module 1': module(1), 'module 2': module(2), 'module 3': module(3)}
            self.module = self.values['module 2']
            p = [
                {'name': 'Module', 'type': 'list',
                 'values': self.values,
                 'set': self.setmodule,
                 'get': self.getmodule,
                 'childmode': "root",
                 'help': '%namehdr%Boatload of text is possible here. Can use markup too with external help window.'},
                {'name': 'Rocks to Skips', 'type': 'int', 'value': 0, 'help': 'Another help example', 'helpwnd': None,
                 'linked': ['1/Rocks to Skips']},
                {'name': '1/Rocks to Skips', 'type': 'float', 'help': 'Another help example', 'helpwnd': None,
                 'get': self.getLinked}
            ]
            self.params = Parameter(name='Root', type='group', children=p).register()
            self.params.init()

            self.t = ParameterTree()
            self.t.addParameters(self.params.getPyQtGraphParameter())

            self.test = Parameter(name='Test', type='group')
            self.test.addChildren([
                {'name': 'baud', 'type': 'int', 'key': 'baud', 'limits': (500, 2000000), 'value': 38400}
            ])

            self.params.append(self.test)
            self.test.remove()
            self.test.getChild("baud").setValue(500)
            self.params.append(self.test)

            self.t2 = ParameterTree()
            self.params2 = Parameter(name='Root', type='group')
            self.params.getChild("Module").stealDynamicParameters(self.params2)
            self.t2.addParameters(self.params2._PyQtGraphParameter)
            self.params.save("abcde.txt")
            self.params.load("abcde.txt")

        def printhelp(self, msg, obj):
            print msg

        def getmodule(self):
            return self.module

        @setupSetParam("Module")
        def setmodule(self, module):
            print "Changing Module"
            self.module = module

        def getLinked(self):
            try:
                return 1.0 / float(self.params.getChild('Rocks to Skips').getValue())
            except:
                return 0
Exemple #6
0
    class maintest(Parameterized):
        def __init__(self):
            super(maintest, self).__init__()
            self.values = {'module 1': module(1), 'module 2': module(2), 'module 3': module(3)}
            self.module = self.values['module 2']
            p = [
                {'name': 'Module', 'type': 'list',
                 'values': self.values,
                 'set': self.setmodule,
                 'get': self.getmodule,
                 'childmode': "root",
                 'help': '%namehdr%Boatload of text is possible here. Can use markup too with external help window.'},
                {'name': 'Rocks to Skips', 'type': 'int', 'value': 0, 'help': 'Another help example', 'helpwnd': None,
                 'linked': ['1/Rocks to Skips']},
                {'name': '1/Rocks to Skips', 'type': 'float', 'help': 'Another help example', 'helpwnd': None,
                 'get': self.getLinked}
            ]
            self.params = Parameter(name='Root', type='group', children=p).register()
            self.params.init()

            self.t = ParameterTree()
            self.t.addParameters(self.params.getPyQtGraphParameter())

            self.test = Parameter(name='Test', type='group')
            self.test.addChildren([
                {'name': 'baud', 'type': 'int', 'key': 'baud', 'limits': (500, 2000000), 'value': 38400}
            ])

            self.params.append(self.test)
            self.test.remove()
            self.test.getChild("baud").setValue(500)
            self.params.append(self.test)

            self.t2 = ParameterTree()
            self.params2 = Parameter(name='Root', type='group')
            self.params.getChild("Module").stealDynamicParameters(self.params2)
            self.t2.addParameters(self.params2._PyQtGraphParameter)
            self.params.save("abcde.txt")
            self.params.load("abcde.txt")

        def printhelp(self, msg, obj):
            print msg

        def getmodule(self):
            return self.module

        @setupSetParam("Module")
        def setmodule(self, module):
            print "Changing Module"
            self.module = module

        def getLinked(self):
            try:
                return 1.0 / float(self.params.getChild('Rocks to Skips').getValue())
            except:
                return 0
Exemple #7
0
class _EZPlugin(GUIPlugin):
    def __init__(self,
                 name,
                 toolbuttons=None,
                 parameters=None,
                 appendheadertest=None,
                 centerwidget=None,
                 bottomwidget=None):
        self.name = name

        self.centerwidget = centerwidget() if callable(
            centerwidget) else centerwidget
        self.bottomwidget = bottomwidget() if callable(
            bottomwidget) else bottomwidget
        self.rightwidget = ParameterTree()
        self.toolbar = QToolBar()

        if parameters:
            self.parameters = Parameter(name="Params",
                                        type="group",
                                        children=parameters)
            self.rightwidget.setParameters(self.parameters, showTop=False)

        if toolbuttons:
            for toolbutton in toolbuttons:
                self.addToolButton(*toolbutton)

        if appendheadertest:
            self.appendHeader = appendheadertest

        self.stages = {
            "EZPlugin":
            GUILayout(self.centerwidget,
                      right=self.rightwidget,
                      bottom=self.bottomwidget,
                      top=self.toolbar)
        }

        super(_EZPlugin, self).__init__()
        _EZPlugin.instance = self

    def setImage(self, data):
        self.centerwidget.setImage(data)

    def plot(self, *args, **kwargs):
        self.bottomwidget.plot(*args, **kwargs)

    def addParameter(self, **kwargs):
        self.rightwidget.addParameters(Parameter(**kwargs))

    def addToolButton(self, icon, method, text=None):
        tb = QAction(QIcon(icon), text, self.toolbar)
        tb.triggered.connect(method)
        self.toolbar.addAction(tb)
Exemple #8
0
def test_device_parameter_tree(qtbot, motor, device):
    tree = ParameterTree(showHeader=False)
    devices = ptypes.GroupParameter(name='Devices')
    tree.addParameters(devices)
    qtbot.addWidget(tree)
    # Device with no subdevices
    motor_param = DeviceParameter(motor, embeddable=False)
    assert len(motor_param.childs) == 0
    devices.addChild(motor_param)
    # Device with subdevices
    dev_param = DeviceParameter(device, emeddable=True)
    assert len(dev_param.childs) == len(device._sub_devices)
    devices.addChild(dev_param)
Exemple #9
0
class EZplugin(plugin):
    def __init__(self,
                 name='TestPlugin',
                 toolbuttons=[],
                 parameters=[],
                 openfileshandler=None):
        self.name = name

        self.parameters = Parameter(name='Params',
                                    type='group',
                                    children=parameters)

        self.centerwidget = pg.ImageView()
        self.bottomwidget = pg.PlotWidget()
        self.rightwidget = ParameterTree()
        self.toolbar = QtGui.QToolBar()

        self.rightwidget.setParameters(self.parameters, showTop=False)

        for toolbutton in toolbuttons:
            self.addToolButton(*toolbutton)

        if openfileshandler: self.openfiles = openfileshandler

        super(EZplugin, self).__init__([])

    def setImage(self, data):
        self.centerwidget.setImage(data)

    def plot(self, *args, **kwargs):
        self.bottomwidget.plot(*args, **kwargs)

    def addParameter(self, **kwargs):
        self.rightwidget.addParameters(Parameter(**kwargs))

    def addToolButton(self, icon, method, text=None):
        tb = QtGui.QAction(QtGui.QIcon(icon), text, self.toolbar)
        tb.triggered.connect(method)
        self.toolbar.addAction(tb)
Exemple #10
0
    def __init__(self, *args, **kwargs):
        self.models_tree = load_models()
        self.categories = self.models_tree.keys()
        super().__init__(self, *args, *kwargs)

        # verticle layout
        vlayout = QVBoxLayout()

        # add a dropdown list of fitting routines
        self.fitterbox = QComboBox()
        self.fitterox.addItems(list(self.fitters.keys()))
        vlayout.addWidget(self.fitterbox)

        # add a dropdown list of categories
        self.catbox = QComboBox()
        self.catbox.addItems(self.categories)
        vlayout.addWidget(self.catbox)

        # add list of models in category
        cat = self.catbox.currentText()
        self.modelsbox = QComboBox()
        self.modelsbox.addItems(list(self.models_tree[cat]))
        vlayout.addWidget(self.modelsbox)

        # add parameter tree
        modelname = self.modelsbox.currentText()
        parameters = self.models_tree[cat][modelname]['params']
        param_tree = ParameterTree(showTop=False)
        param_tree.addParameters(self.parameters)
        vlayout.addWidget(param_tree)
        self.fittable = XicamSASModel(modelname, parameters)

        # add fit-button
        fit_button = QPushButton('Fit')
        fit_button.setToolTip('Fit model to the data')
        vlayout.addWidget(fit_button)
        fit_button.clicked.connect(self.run)
Exemple #11
0
class TyphosSuite(TyphosBase):
    """
    This suite combines tools and devices into a single widget.

    A :class:`ParameterTree` is contained in a :class:`~pcdsutils.qt.QPopBar`
    which shows tools and the hierarchy of a device along with options to
    show or hide them.

    Parameters
    ----------
    parent : QWidget, optional

    pin : bool, optional
        Pin the parameter tree on startup.

    Attributes
    ----------
    default_tools : dict
        The default tools to use in the suite.  In the form of
        ``{'tool_name': ToolClass}``.
    """

    DEFAULT_TITLE = 'Typhos Suite'
    DEFAULT_TITLE_DEVICE = 'Typhos Suite - {device.name}'

    default_tools = {
        'Log': TyphosLogDisplay,
        'StripTool': TyphosTimePlot,
        'Console': TyphosConsole
    }

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

        self._update_title()

        self._tree = ParameterTree(parent=self, showHeader=False)
        self._tree.setAlternatingRowColors(False)
        self._save_action = ptypes.ActionParameter(name='Save Suite')
        self._tree.addParameters(self._save_action)
        self._save_action.sigActivated.connect(self.save)

        self._bar = pcdsutils.qt.QPopBar(title='Suite',
                                         parent=self,
                                         widget=self._tree,
                                         pin=pin)

        self._content_frame = QtWidgets.QFrame(self)
        self._content_frame.setObjectName("content")
        self._content_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self._content_frame.setLayout(QtWidgets.QHBoxLayout())

        # Horizontal box layout: [PopBar] [Content Frame]
        layout = QtWidgets.QHBoxLayout()
        self.setLayout(layout)
        layout.setSpacing(1)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._bar)
        layout.addWidget(self._content_frame)

        self.embedded_dock = None

    def add_subdisplay(self, name, display, category):
        """
        Add an arbitrary widget to the tree of available widgets and tools.

        Parameters
        ----------
        name : str
            Name to be displayed in the tree

        display : QWidget
            QWidget to show in the dock when expanded.

        category : str
            The top level group to place the controls under in the tree. If the
            category does not exist, a new one will be made
        """
        logger.debug("Adding widget %r with %r to %r ...", name, display,
                     category)
        # Create our parameter
        parameter = SidebarParameter(value=display, name=name)
        self._add_to_sidebar(parameter, category)

    @property
    def top_level_groups(self):
        """
        Get top-level groups.

        This is of the form:

        .. code:: python

            {'name': QGroupParameterItem}
        """
        root = self._tree.invisibleRootItem()
        return dict((root.child(idx).param.name(), root.child(idx).param)
                    for idx in range(root.childCount()))

    def add_tool(self, name, tool):
        """
        Add a widget to the toolbar.

        Shortcut for:

        .. code:: python

           suite.add_subdisplay(name, tool, category='Tools')

        Parameters
        ----------
        name :str
            Name of tool to be displayed in sidebar

        tool: QWidget
            Widget to be added to ``.ui.subdisplay``
        """
        self.add_subdisplay(name, tool, 'Tools')

    def get_subdisplay(self, display):
        """
        Get a subdisplay by name or contained device.

        Parameters
        ----------
        display :str or Device
            Name of screen or device

        Returns
        -------
        widget : QWidget
            Widget that is a member of the :attr:`.ui.subdisplay`

        Example
        -------
        .. code:: python

            suite.get_subdisplay(my_device.x)
            suite.get_subdisplay('My Tool')
        """
        if not isinstance(display, SidebarParameter):
            for group in self.top_level_groups.values():
                tree = flatten_tree(group)
                matches = [
                    param for param in tree if hasattr(param, 'has_device')
                    and param.has_device(display)
                ]

                if matches:
                    display = matches[0]
                    break

        if not isinstance(display, SidebarParameter):
            # If we got here we can't find the subdisplay
            raise ValueError(f"Unable to find subdisplay {display}")

        subdisplay = display.value()
        if isinstance(subdisplay, partial):
            subdisplay = subdisplay()
            display.setValue(subdisplay)
        return subdisplay

    @QtCore.Slot(str)
    @QtCore.Slot(object)
    def show_subdisplay(self, widget):
        """
        Open a display in the dock system.

        Parameters
        ----------
        widget: QWidget, SidebarParameter or str
            If given a ``SidebarParameter`` from the tree, the widget will be
            shown and the sidebar item update. Otherwise, the information is
            passed to :meth:`.get_subdisplay`
        """
        # Grab true widget
        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        # Setup the dock
        dock = widgets.SubDisplay(self)
        # Set sidebar properly
        self._show_sidebar(widget, dock)
        # Add the widget to the dock
        logger.debug("Showing widget %r ...", widget)
        if hasattr(widget, 'display_type'):
            widget.display_type = widget.detailed_screen
        widget.setVisible(True)
        dock.setWidget(widget)
        # Add to layout
        self._content_frame.layout().addWidget(dock)

    @QtCore.Slot(str)
    @QtCore.Slot(object)
    def embed_subdisplay(self, widget):
        """Embed a display in the dock system."""
        # Grab the relevant display
        if not self.embedded_dock:
            self.embedded_dock = widgets.SubDisplay()
            self.embedded_dock.setWidget(QtWidgets.QWidget())
            self.embedded_dock.widget().setLayout(QtWidgets.QVBoxLayout())
            self.embedded_dock.widget().layout().addStretch(1)
            self._content_frame.layout().addWidget(self.embedded_dock)

        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        # Set sidebar properly
        self._show_sidebar(widget, self.embedded_dock)
        # Set our widget to be embedded
        widget.setVisible(True)
        widget.display_type = widget.embedded_screen
        widget_count = self.embedded_dock.widget().layout().count()
        self.embedded_dock.widget().layout().insertWidget(
            widget_count - 1, widget)

    @QtCore.Slot()
    @QtCore.Slot(object)
    def hide_subdisplay(self, widget):
        """
        Hide a visible subdisplay.

        Parameters
        ----------
        widget: SidebarParameter or Subdisplay
            If you give a SidebarParameter, we will find the corresponding
            widget and hide it. If the widget provided to us is inside a
            DockWidget we will close that, otherwise the widget is just hidden.
        """
        if not isinstance(widget, QtWidgets.QWidget):
            widget = self.get_subdisplay(widget)
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_hidden()
        else:
            logger.warning("Unable to find sidebar item for %r", widget)
        # Make sure the actual widget is hidden
        logger.debug("Hiding widget %r ...", widget)
        if isinstance(widget.parent(), QtWidgets.QDockWidget):
            logger.debug("Closing dock ...")
            widget.parent().close()
        # Hide the full dock if this is the last widget
        elif (self.embedded_dock
              and widget.parent() == self.embedded_dock.widget()):
            logger.debug("Removing %r from embedded widget layout ...", widget)
            self.embedded_dock.widget().layout().removeWidget(widget)
            widget.hide()
            if self.embedded_dock.widget().layout().count() == 1:
                logger.debug("Closing embedded layout ...")
                self.embedded_dock.close()
                self.embedded_dock = None
        else:
            widget.hide()

    @QtCore.Slot()
    def hide_subdisplays(self):
        """Hide all open displays."""
        # Grab children from devices
        for group in self.top_level_groups.values():
            for param in flatten_tree(group)[1:]:
                self.hide_subdisplay(param)

    @property
    def tools(self):
        """Tools loaded into the suite."""
        if 'Tools' in self.top_level_groups:
            return [
                param.value()
                for param in self.top_level_groups['Tools'].childs
            ]
        return []

    def _update_title(self, device=None):
        """
        Update the window title, optionally with a device.

        Parameters
        ----------
        device : ophyd.Device, optional
            Device to indicate in the title.
        """
        title_fmt = (self.DEFAULT_TITLE
                     if device is None else self.DEFAULT_TITLE_DEVICE)

        self.setWindowTitle(title_fmt.format(self=self, device=device))

    def add_device(self, device, children=True, category='Devices'):
        """
        Add a device to the suite.

        Parameters
        ----------
        device: ophyd.Device
            The device to add.

        children: bool, optional
            Also add any ``subdevices`` of this device to the suite as well.

        category: str, optional
            Category of device. By default, all devices will just be added to
            the "Devices" group
        """
        super().add_device(device)
        self._update_title(device)
        # Create DeviceParameter and add to top level category
        dev_param = DeviceParameter(device, subdevices=children)
        self._add_to_sidebar(dev_param, category)
        # Grab children
        for child in flatten_tree(dev_param)[1:]:
            self._add_to_sidebar(child)
        # Add a device to all the tool displays
        for tool in self.tools:
            try:
                tool.add_device(device)
            except Exception:
                logger.exception("Unable to add %s to tool %s", device.name,
                                 type(tool))

    @classmethod
    def from_device(cls,
                    device,
                    parent=None,
                    tools=DEFAULT_TOOLS,
                    pin=False,
                    **kwargs):
        """
        Create a new :class:`TyphosSuite` from an :class:`ophyd.Device`.

        Parameters
        ----------
        device : ophyd.Device
            The device to use.

        children : bool, optional
            Choice to include child Device components

        parent : QWidget

        tools : dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        **kwargs :
            Passed to :meth:`TyphosSuite.add_device`
        """
        return cls.from_devices([device],
                                parent=parent,
                                tools=tools,
                                pin=pin,
                                **kwargs)

    @classmethod
    def from_devices(cls,
                     devices,
                     parent=None,
                     tools=DEFAULT_TOOLS,
                     pin=False,
                     **kwargs):
        """
        Create a new TyphosSuite from an iterator of :class:`ophyd.Device`

        Parameters
        ----------
        device : ophyd.Device

        children : bool, optional
            Choice to include child Device components

        parent : QWidget

        tools : dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        **kwargs :
            Passed to :meth:`TyphosSuite.add_device`
        """
        suite = cls(parent=parent, pin=pin)
        if tools is not None:
            logger.info("Loading Tools ...")
            if tools is DEFAULT_TOOLS:
                logger.debug("Using default TyphosSuite tools ...")
                tools = cls.default_tools
            for name, tool in tools.items():
                try:
                    suite.add_tool(name, tool())
                except Exception:
                    logger.exception("Unable to load %s", type(tool))
        logger.info("Adding devices ...")
        for device in devices:
            try:
                suite.add_device(device, **kwargs)
                suite.show_subdisplay(device)
            except Exception:
                logger.exception("Unable to add %r to TyphosSuite",
                                 device.name)
        return suite

    def save(self):
        """
        Save suite settings to a file using :meth:`typhos.utils.save_suite`.

        A ``QFileDialog`` will be used to query the user for the desired
        location of the created Python file

        The template will be of the form:

        .. code::
        """
        # Note: the above docstring is appended below

        logger.debug("Requesting file location for saved TyphosSuite")
        root_dir = os.getcwd()
        filename = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save TyphosSuite', root_dir, "Python (*.py)")
        if filename:
            try:
                with open(filename[0], 'w+') as handle:
                    save_suite(self, handle)
            except Exception as exc:
                logger.exception("Failed to save TyphosSuite")
                utils.raise_to_operator(exc)
        else:
            logger.debug("No filename chosen")

    # Add the template to the docstring
    save.__doc__ += textwrap.indent('\n' + utils.saved_template, '\t\t')

    def _get_sidebar(self, widget):
        items = {}
        for group in self.top_level_groups.values():
            for item in flatten_tree(group):
                items[item.value()] = item
        return items.get(widget)

    def _show_sidebar(self, widget, dock):
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_shown()
            # Make sure we react if the dock is closed outside of our menu
            dock.closing.connect(partial(self.hide_subdisplay, sidebar))
        else:
            logger.warning("Unable to find sidebar item for %r", widget)

    def _add_to_sidebar(self, parameter, category=None):
        """Add an item to the sidebar, connecting necessary signals."""
        if category:
            # Create or grab our category
            if category in self.top_level_groups:
                group = self.top_level_groups[category]
            else:
                logger.debug("Creating new category %r ...", category)
                group = ptypes.GroupParameter(name=category)
                self._tree.addParameters(group)
                self._tree.sortItems(0, QtCore.Qt.AscendingOrder)
            logger.debug("Adding %r to category %r ...", parameter.name(),
                         group.name())
            group.addChild(parameter)

        widget = parameter.value()
        if isinstance(widget, QtWidgets.QWidget):
            # Setup window to have a parent
            widget.setParent(self)
            widget.setHidden(True)

        logger.debug("Connecting parameter signals ...")
        parameter.sigOpen.connect(partial(self.show_subdisplay, parameter),
                                  QtCore.Qt.QueuedConnection)
        parameter.sigHide.connect(partial(self.hide_subdisplay, parameter),
                                  QtCore.Qt.QueuedConnection)
        if parameter.embeddable:
            parameter.sigEmbed.connect(
                partial(self.embed_subdisplay, parameter),
                QtCore.Qt.QueuedConnection)
        return parameter
Exemple #12
0
class RosBagWidget(QtGui.QWidget):

    ##
    # @brief
    #
    # @return

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.file_name = ''
        self.bag = None
        self.data = {}
        self.plot_data = {}
        self.gridLayout = None
        self.label1 = None
        self.loadBtn = None
        self.tree = None
        self.addBtn = None
        self.editBtn = None
        self.removeBtn = None
        self.plotBtn = None
        self.plotTree = None
        self.plotData = None
        self.plotwin = None
        self.plot_num = 1
        self.params = [{
            'type':
            'group',
            'name':
            u'plot params',
            'children': [{
                'type': 'str',
                'name': 'x axis name',
                'value': u'time(s)'
            }, {
                'type': 'str',
                'name': 'y axis name',
                'value': u'position(m)'
            }, {
                'type': 'str',
                'name': 'plot name',
                'value': u'plot name'
            }]
        }]
        self.line_mark_list = [
            '+-', '*-', 'o-', '^-', 's-', 'x-', '.-', 'p-', 'h-', 'd-'
        ]
        self.msg_types = []
        self.topics = {}
        self.topics_data = {}
        self.msg_types_blacklist = [
            'sensor_msgs/PointCloud', 'sensor_msgs/Image'
        ]
        self.setup_ui(self)

    ##
    # @brief
    #
    # @param Form
    #
    # @return
    def setup_ui(self, Form):
        self.setObjectName("Form")
        self.resize(217, 499)
        self.gridLayout = QtGui.QGridLayout(self)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setVerticalSpacing(0)
        self.gridLayout.setObjectName("gridLayout")
        self.label1 = QtGui.QLabel("")
        self.label1.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
        self.label1.setStyleSheet("border:1px solid black;")
        self.gridLayout.addWidget(self.label1, 0, 0)
        self.loadBtn = QtGui.QPushButton("...")
        self.loadBtn.setFixedWidth(20)
        self.gridLayout.addWidget(self.loadBtn, 0, 1)
        self.loadBtn.clicked.connect(self.load_file)
        self.tree = DataTreeWidget(data=self.data)
        self.gridLayout.addWidget(self.tree, 1, 0, 1, 2)
        self.addBtn = QtGui.QPushButton("")
        add_icon = QtGui.QIcon()
        add_icon.addPixmap(QtGui.QPixmap("resources/add.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.addBtn.setIcon(add_icon)
        self.addBtn.clicked.connect(self.add_plot)
        self.gridLayout.addWidget(self.addBtn, 0, 2)
        self.editBtn = QtGui.QPushButton("")
        edit_icon = QtGui.QIcon()
        edit_icon.addPixmap(QtGui.QPixmap("resources/edit.png"),
                            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.editBtn.setIcon(edit_icon)
        self.editBtn.clicked.connect(self.edit_plot)
        self.gridLayout.addWidget(self.editBtn, 0, 3)
        self.removeBtn = QtGui.QPushButton("")
        remove_icon = QtGui.QIcon()
        remove_icon.addPixmap(QtGui.QPixmap("resources/remove.png"),
                              QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.removeBtn.setIcon(remove_icon)
        self.removeBtn.clicked.connect(self.remove_plot)
        self.gridLayout.addWidget(self.removeBtn, 0, 4)
        self.plotBtn = QtGui.QPushButton("plot")
        # plot_icon = QtGui.QIcon()
        # plot_icon.addPixmap(QtGui.QPixmap("resources/plot.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        # self.plotBtn.setIcon(plot_icon)
        self.plotBtn.clicked.connect(self.plot)
        self.gridLayout.addWidget(self.plotBtn, 0, 5)
        self.plotTree = ParameterTree()
        self.plotData = Parameter.create(name='params',
                                         type='group',
                                         children=self.params)
        self.plotTree.setParameters(self.plotData, showTop=False)
        self.gridLayout.addWidget(self.plotTree, 1, 2, 1, 4)
        # self.tree2.setSizePolicity(self.tree1.width()/2, 499)
        # self.tree1.resize(setWidth(150)
        # self.tree2.setWidth(50)
        self.plotData.sigTreeStateChanged.connect(self.change)

    ##
    # @brief
    #
    # @param param
    # @param changes
    #
    # @return
    def change(self, param, changes):  # todo change plot params
        print("tree changes:(to do)")
        for param, change, data in changes:
            path = self.plotData.childPath(param)
            print(path)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            print('  parameter: %s' % childName)
            print('  change:    %s' % change)
            print('  data:      %s' % str(data))
            print('  ----------')

    ##
    # @brief
    #
    # @param file_name
    # @param start_dir
    #
    # @return
    def load_file(self, file_name=None, start_dir=None):
        """Load a rosbag (*.bag) file.
        """
        start = time.clock()
        if not file_name:
            if not start_dir:
                start_dir = '.'
            self.file_dialog = FileDialog(None, "Load rosbag ..", start_dir,
                                          "rosbag (*.bag)")
            # file_dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
            self.file_dialog.show()
            self.file_dialog.fileSelected.connect(self.load_file)
            return
        file_name = unicode(file_name)
        self.file_name = file_name
        self.label1.setText(str(file_name))
        self.file_info(file_name)
        end = time.clock()
        print("load file cost %s s" % (end - start))

    ##
    # @brief
    #
    # @param file_name
    #
    # @return
    def file_info(self, file_name=None):
        if not file_name:
            self.data = {}
        else:
            self.bag = rosbag.Bag(file_name)
            self.tree.setData(self.bag.get_type_and_topic_info()[1])
            # print(self.bag.get_type_and_topic_info()[1])
            bag_length = self.get_bag_length(
                self.bag.get_type_and_topic_info()[1]) * 10
            if len(file_name) * 8 > bag_length:
                bag_length = len(file_name) * 8
            self.label1.setFixedWidth(bag_length)
            # clear data
            self.msg_types = []
            self.topics = {}
            self.topics_data = {}
            # print(self.get_bag_length(self.bag.get_type_and_topic_info()[1]))
            for m in self.bag.get_type_and_topic_info()[0]:
                self.msg_types.append(m)
            for t in self.bag.get_type_and_topic_info()[1]:
                if self.bag.get_type_and_topic_info(
                )[1][t][0] not in self.msg_types_blacklist:
                    get_topic_params_cmd = "rostopic echo -b " + file_name + " -n 1 -p " + t
                    topic_parms = os.popen(get_topic_params_cmd).read()
                    topic_parms_list = self.topic_str2list(topic_parms)
                    self.topics[t] = topic_parms_list
                    get_topic_data_cmd = "rostopic echo -b " + self.file_name + " -p " + t
                    topic_data = os.popen(get_topic_data_cmd).read()
                    topic_data_list = self.topic_data_str2list(topic_data[:-1])
                    self.topics_data[t] = topic_data_list
                else:
                    print(t + "is not proper for plot")
                # print("topic_data_list", topic_data_list)
                # break

    @staticmethod
    ##
    # @brief
    #
    # @param data
    #
    # @return
    def get_bag_length(data):
        max_topic_len = 0
        max_topic_type_len = 0
        for topic in data:
            if len(topic) > max_topic_len:
                max_topic_len = len(topic)
            if len(data[topic][0]) > max_topic_type_len:
                max_topic_type_len = len(data[topic][0])
        # print(max_topic_len, max_topic_type_len)
        return max_topic_len + max_topic_type_len

    @staticmethod
    ##
    # @brief
    #
    # @param topic_str
    #
    # @return
    def topic_str2list(topic_str):
        # print(len(topic_str))
        # print(topic_str)
        topic_list = []
        if len(topic_str) > 0:
            # print(topic_str[0])
            out1 = re.split('\n', topic_str)
            params = re.split(',', out1[0])
            values = re.split(',', out1[1])
            # print(len(params), len(values))
            for i in range(len(params)):
                if values[i].strip('-').replace(".", '').isdigit():
                    topic_list.append(params[i])
            # print(topic_list)
            return topic_list

    @staticmethod
    ##
    # @brief
    #
    # @param topic_data_str
    #
    # @return
    def topic_data_str2list(topic_data_str):
        topic_data_list = []
        if len(topic_data_str) > 0:
            out1 = re.split('\n', topic_data_str)
            for o in out1:
                data_list = re.split(',', o)
                topic_data_list.append(data_list)
            return topic_data_list

    ##
    # @brief
    #
    # @return
    def add_plot(self):
        if len(self.file_name):
            #print("add plot")
            self.plotwin = PlotWin(self.topics, self.plot_num)
            self.plotwin.setWindowModality(QtCore.Qt.ApplicationModal)
            self.plotwin.setGeometry(500, 500, 600, 150)
            if self.plotwin.exec_():  # accepted
                #print("ok")
                self.plot_num = self.plot_num + 1
                if len(self.plotwin.plot_name.text()) > 0:
                    self.plotwin.param['name'] = unicode(
                        self.plotwin.plot_name.text()) + " " + unicode(
                            self.plotwin.topic_name.currentText())
                    self.plotwin.param['type'] = 'group'
                    x = {
                        'name': 'x',
                        'type': 'str',
                        'value': unicode(self.plotwin.field1.currentText())
                    }
                    y = {
                        'name': 'y',
                        'type': 'str',
                        'value': unicode(self.plotwin.field2.currentText())
                    }
                    color = self.plotwin.colorBtn.color(mode='byte')
                    color_str = ''
                    for i in color[:-1]:
                        c = str(hex(i)).replace("0x", '')
                        if len(c) < 2:
                            c = '0' + c
                        color_str = color_str + c
                    # print(color, color_str)
                    line_color = {
                        'name': 'line_color',
                        'type': 'color',
                        'value': color_str,
                        'tip': "This is a color button"
                    }
                    line_mark = {
                        'name': 'line_mark',
                        'type': 'list',
                        'values': self.line_mark_list,
                        'value': unicode(self.plotwin.line_mark.currentText())
                    }
                    self.plotwin.param['children'] = [
                        x, y, line_color, line_mark
                    ]
                    self.params.append(self.plotwin.param)
                    self.plotData = Parameter.create(
                        name='params',
                        type='group',
                        children=[self.plotwin.param])
                    self.plotTree.addParameters(self.plotData, showTop=False)
                else:
                    print("Please input the plot name first.")

            else:
                print("cancel")
        else:
            print("Please add bag file first!")

    ##
    # @brief
    #
    # @return
    def edit_plot(self):
        # print("edit plot", self.plotTree.selectedItems(), self.plotTree.currentItem())
        if hasattr(self.plotTree.currentItem(), "param"):
            print("edit plot " + re.split(
                '\'', str(getattr(self.plotTree.currentItem(), "param")))[1] +
                  "(to do)")
            # if hasattr(getattr(self.plotTree.currentItem(), "param"), "name"):
            # print(getattr(getattr(self.plotTree.currentItem(), "param"), "name"))
        # print("%x" % id(self.params[0]))

    ##
    # @brief
    #
    # @return
    def remove_plot(self):
        if hasattr(self.plotTree.currentItem(), "param"):
            print("remove plot " + re.split(
                '\'', str(getattr(self.plotTree.currentItem(), "param")))[1] +
                  "(to do)")

    ##
    # @brief
    #
    # @return
    def plot(self):
        print("plot")
        plots = []
        for p in self.params[1:]:
            topic_name = re.split(' ', p['name'])
            # print(topic_name[1])
            x_name = None
            y_name = None
            line_color = None
            line_mark = None
            for c in p['children']:
                if c['name'] == 'x':
                    x_name = c['value']
                elif c['name'] == 'y':
                    y_name = c['value']
                elif c['name'] == 'line_color':
                    line_color = c['value']
                elif c['name'] == 'line_mark':
                    line_mark = c['value']
            plots.append([
                topic_name[0], topic_name[1], x_name, y_name, line_color,
                line_mark
            ])
        # print(plots)

        # plt.figure(figsize=(12, 10))
        for p in plots:
            x, y = self.get_bag_data(p)
            plt.plot(x, y, p[5], color=("#" + p[4]), label=p[0])
        plt.xlabel(self.params[0]['children'][0]['value'])
        plt.ylabel(self.params[0]['children'][1]['value'])
        plt.title(self.params[0]['children'][2]['value'])
        # plt.ylim(-1.2, 1.2)
        plt.legend(loc='upper right')
        plt.grid(True)
        # plt.savefig(gflags.FLAGS.title + '.svg', format= 'svg')
        plt.show()

    ##
    # @brief
    #
    # @param plot_info
    #
    # @return
    def get_bag_data(self, plot_info):
        x = []
        y = []
        plot_data = self.topics_data[plot_info[1]]
        x_index = plot_data[0].index(plot_info[2])
        y_index = plot_data[0].index(plot_info[3])
        # print(plot_data, x_index, y_index)
        for pd in plot_data[1:]:
            # print('len(pd)', len(pd))
            # print('x_index', x_index)
            # print('y_index', y_index)
            x.append(pd[x_index])
            y.append(pd[y_index])
            # break
        return x, y
Exemple #13
0
class MyGUIPlugin(GUIPlugin):
    name = "My Plugin"

    def __init__(self):
        #Define workflows
        self.my_workflow = MyWorkflow()
        #self.my_workflow_editor = WorkflowEditor(self.my_workflow)
        # Define a GUILayout
        # GUILayouts must provide a center widget
        #self.container_widget = QWidget()
        self.split_widget = CatalogAndAnalysisSplitWidget()
        layout = QVBoxLayout()  # what kind of layout
        self.button = QPushButton("push this")
        #layout.addWidget(self.split_widget) # add things to the layout one by one
        #layout.addWidget(self.button)
        #self.container_widget.setLayout(layout) # apply layout to the basic widget
        bottom_widget = QLabel('bottom')
        left_widget = QLabel('left')
        leftbottom_widget = QLabel('left bottom')
        right_widget = QLabel('right')

        self.model = QStandardItemModel()
        self.selectionmodel = QItemSelectionModel(self.model)
        stream = 'primary'
        field = 'img'
        self.test_tab_view = TabView(self.model,
                                     self.selectionmodel,
                                     widgetcls=MyImageView,
                                     stream=stream,
                                     field=field)

        self.parameter_view = ParameterTree()
        for operation in self.my_workflow.operations:
            parameter_dict = operation.as_parameter()
            for list_parameter in parameter_dict:
                parameter = Parameter.create(**list_parameter)
                self.parameter_view.addParameters(parameter)
        stage_layout = GUILayout(
            center=self.split_widget,
            #left=left_widget,
            #right=right_widget,
            #leftbottom = leftbottom_widget,
            bottom=self.button,
        )
        second_stage_layout = GUILayout(center=self.test_tab_view,
                                        righttop=self.parameter_view)
        #workflow_stage = GUILayout(center=self.test_tab_view, righttop=self.my_workflow_editor)
        #self.button.clicked.connect(self.update_label)
        #self.button.clicked.connect(self.show_message)
        self.button.clicked.connect(self.run_workflow)
        self.stages = {
            'catalogviewer and fft': stage_layout,
            'Something Else': second_stage_layout,
            #'testing workflow editor': workflow_stage,
        }

        super(MyGUIPlugin, self).__init__()

    def appendCatalog(self, catalog: BlueskyRun):
        # give catalog to out catalog viewer
        self.split_widget.catalog_view.setCatalog(catalog, 'primary', 'img')

        display_name = f"scan:{catalog.metadata['start']['scan_id']}"
        item = QStandardItem()
        item.setData(display_name, Qt.DisplayRole)
        item.setData(catalog, Qt.UserRole)
        self.model.appendRow(item)
        # tell our model that the data has been updated, the two parameters are rox index and column index
        self.model.dataChanged.emit(item.index(), item.index())

    def update_label(self):
        current_text = self.label.text()
        current_text += "1"
        self.label.setText(current_text)

    def show_message(self):
        notifyMessage("Add another 1.")

    def show_message(self, catalog: BlueskyRun):
        notifyMessage(f'Added catalog {catalog}')

    def run_workflow(self):
        # workflow has an exec() and an exec_all() to run itself
        # extract data from loaded catalog
        if not self.split_widget.catalog_view.catalog:
            notifyMessage("A catalog is not yet loaded, please load one first")
            return
        image_data = self.split_widget.catalog_view.catalog.primary.to_dask(
        )['img'].compute()
        # primary.image.read()
        # execute wkll take in named inputs in your OperationPlugin,
        # and a callback_slot will be called when it finished execution
        self.my_workflow.execute(input_image=image_data,
                                 callback_slot=self.show_fft)

    def show_fft(
            self,
            *results):  # workflow results have a *results passed into them
        # results : a list of dictionarys result objects, eg [ {"output_image":
        #from qtpy.QtCore import pyqtRemoveInputHook
        #pyqtRemoveInputHook()
        #import pdb
        #pdb.set_trace()
        #print(results)
        fft_image = results[-1]['output_image']
        self.split_widget.results_view.setImage(fft_image)
Exemple #14
0
class GlitchExplorerDialog(Parameterized, QtFixes.QDialog):
    _name = "Glitch Explorer"

    def __init__(self, parent):
        super(GlitchExplorerDialog, self).__init__(parent)
        self.setWindowTitle("Glitch Explorer")
        self.setMinimumWidth(500)

        self.mainLayout = QVBoxLayout()
        self.mainSplitter = QSplitter(self)
        self.mainSplitter.setOrientation(Qt.Vertical)

        self.tableList = []
        self.tuneParamList = []

        # Add default table
        self.table = QTableWidget(1, 1)
        # self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.mainSplitter.addWidget(self.table)

        self.getParams().register()
        self.getParams().addChildren(
            [
                {"name": "Clear Output Table", "type": "action", "action": self.clearTable},
                {"name": "Plot Widget", "type": "action", "action": self.openPlotWidget},
                {
                    "name": "Reset",
                    "type": "action",
                    "action": self.reset,
                    "tip": "Resets all Tuning Parameters to its minimum value.",
                },
                {
                    "name": "Tuning Parameters",
                    "key": "numtune",
                    "type": "int",
                    "value": 0,
                    "limits": (0, 4),
                    "action": self.updateParameters,
                    "readonly": False,
                },
                {
                    "name": "Traces Required",
                    "key": "tracesreq",
                    "type": "int",
                    "value": 1,
                    "limits": (1, 1e99),
                    "readonly": True,
                    "children": [
                        {
                            "name": "Use this value",
                            "type": "action",
                            "action": lambda _: Parameter.setParameter(
                                [
                                    "Generic Settings",
                                    "Acquisition Settings",
                                    "Number of Traces",
                                    self.findParam("tracesreq").getValue(),
                                ]
                            ),
                        }
                    ],
                },
                {"name": "Normal Response", "type": "str", "key": "normalresp", "value": 's.startswith("Bad")'},
                {
                    "name": "Successful Response",
                    "type": "str",
                    "key": "successresp",
                    "value": 's.startswith("Welcome")',
                },
                {
                    "name": "Recordings",
                    "type": "group",
                    "expanded": False,
                    "children": [
                        {
                            "name": "Load existing",
                            "type": "action",
                            "key": "open",
                            "action": lambda _: self.loadRecordings(),
                        },
                        {"name": "Autosave Multi-Capture Results", "type": "bool", "key": "saveresults", "value": True},
                        {
                            "name": "Autosaved filename",
                            "type": "str",
                            "key": "savefilename",
                            "value": "",
                            "readonly": True,
                        },
                        {"name": "Notes", "type": "text", "key": "savenotes", "value": ""},
                    ],
                },
            ]
        )

        self.paramTree = ParameterTree()
        self.paramTree.addParameters(self.getParams()._PyQtGraphParameter)
        self.mainSplitter.addWidget(self.paramTree)

        self.statusLabel = QLabel("")

        self.mainSplitter.addWidget(self.statusLabel)

        # self.mainSplitter.setHandleWidth(100)

        self.mainLayout.addWidget(self.mainSplitter)
        self.setLayout(self.mainLayout)
        self.hide()

        # Do an update
        self.table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.table.horizontalHeader().setResizeMode(QHeaderView.Interactive)
        self.clearTable()
        self._campaignRunning = False

    def openPlotWidget(self, _):
        if "Glitch Explorer" not in ResultsBase.registeredObjects:
            ResultsBase.createNew("Scatter Plot", "Glitch Explorer")
        widget = ResultsBase.registeredObjects["Glitch Explorer"]
        widget.raise_()
        widget.yLocked(False)
        self.clearPlotWidget()

    def clearPlotWidget(self):
        widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
        if widget is not None:
            widget.clearPushed()
            widget.setLabels(
                top="Glitch Map",
                xaxis=self.tuneParamList[0].name() if len(self.tuneParamList) > 0 else "",
                yaxis=self.tuneParamList[1].name() if len(self.tuneParamList) > 1 else "",
            )

    def tuneEnabled(self, status):
        self.findParam("numtune").setReadonly(not status)

    def campaignStart(self, prefixname):
        """Called when acqusition campaign (multi-api) starts, generates filename"""
        self._autosavefname = (
            self.parent()
            .api.project()
            .getDataFilepath(prefixname + "_glitchresults.p", subdirectory="glitchresults")["abs"]
        )
        self._autosavef = None
        self._campaignRunning = True
        self.tuneEnabled(False)
        self.clearPlotWidget()

    def campaignDone(self):
        self._campaignRunning = False
        self.tuneEnabled(True)

        if self._autosavef:
            self._autosavef.close()
            self._autosavef = None
        self.table.setSortingEnabled(True)

    def updateStatus(self):
        okcnt = 0
        for t in self.tableList:
            if t["success"]:
                okcnt += 1

        lbl = "Total %d, Glitches Successful %d" % (len(self.tableList), okcnt)
        self.statusLabel.setText(lbl)

    def reset(self, ignored=None):
        for t in self.tuneParamList:
            t.reset()

    def clearTable(self, ignored=None):
        self.tableList = []
        self.table.clear()
        self.table.setRowCount(0)
        self.table.setColumnCount(0)
        self.updateTableHeaders()
        self.table.resizeColumnsToContents()
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(2, 120)
        self.table.setColumnWidth(3, 80)
        self.table.sortByColumn(3, Qt.DescendingOrder)

    def updateParameters(self, ignored=None):
        numparams = self.findParam("numtune").getValue()

        # Did number change? Adjust if needed
        while numparams < len(self.tuneParamList):
            # Shed parameters
            self.tuneParamList[-1].getParams().delete()
            self.tuneParamList.pop()

        while numparams > len(self.tuneParamList):
            # Add parameters
            # p = Parameter.create(name='Tuning Parameter %d' % len(self.tuneParamList), type='group', children=self.glitchTuneParamTemplate)
            p = TuningParameter(len(self.tuneParamList))
            self.tuneParamList.append(p)
            self.getParams().append(p.getParams())

            # Do stuff
            p.nameChanged.connect(self.updateTableHeaders)
            p.rangeComplete.connect(self.rangeDone)
            p.tracesreqChanged.connect(self.tracesreqChanged)

        self.updateTableHeaders()
        self.tracesreqChanged()

    def tracesreqChanged(self, pnum=None, newnum=None):
        treq = 1
        for t in self.tuneParamList:
            treq *= t.tracesrequired
        self.findParam("tracesreq").setValue(treq, ignoreReadonly=True)

    def updateTableHeaders(self, ignored=None, ignoredmore=None, override=None):
        headerlist = ["Status", "Sent", "Received", "Date"]

        if override is not None:
            for c in override:
                headerlist.append(c)
        else:
            for t in self.tuneParamList:
                headerlist.append(t.name())

        self.table.setColumnCount(len(headerlist))
        self.table.setHorizontalHeaderLabels(headerlist)

    def rangeDone(self, pnum):
        if (pnum + 1) < len(self.tuneParamList):
            self.tuneParamList[pnum + 1].findNewValue()

    def traceDone(self):
        """ Single api done """

        # TODO: Improve how looping is done
        if len(self.tuneParamList) > 0:
            # Always increment lowest, triggers upper values
            # try:
            self.tuneParamList[0].findNewValue()
        # except Exception as e:
        #     raise StopIteration(e)

    def appendToTable(self, newdata):
        """ Append a result to the display table """

        try:
            self.table.setSortingEnabled(False)
            self.table.insertRow(0)

            outdata = QTableWidgetItem(repr(newdata["output"]))
            if newdata["success"]:
                color = Qt.green
                status = "Success"
            elif newdata["normal"] == False:
                color = Qt.red
                status = "Failed"
            else:
                color = Qt.white
                status = "Normal"

            outdata.setBackground(color)
            self.table.setItem(0, 0, QTableWidgetItem(status))
            self.table.setItem(0, 1, QTableWidgetItem(""))
            self.table.setItem(0, 2, outdata)
            self.table.setItem(0, 3, QTableWidgetItem(newdata["date"].strftime("%H:%M:%S")))
            for i, v in enumerate(newdata["settings"]):
                self.table.setItem(0, 4 + i, QTableWidgetItem(str(v)))

            self.table.resizeRowsToContents()

            widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
            if widget is not None:
                widget.plot(
                    [newdata["settings"][0] if len(newdata["settings"]) > 0 else 0],
                    [newdata["settings"][1] if len(newdata["settings"]) > 1 else 0],
                    (
                        (0, 255, 0, 75)
                        if status == "Success"
                        else (255, 0, 75)
                        if status == "Failed"
                        else (200, 200, 200, 50)
                    ),
                    str(newdata["settings"]),
                )

        except AttributeError as e:
            raise StopIteration("Error when adding data to the table. Plese clear it and try again. Details:" + str(e))

    def addResponse(self, resp):
        """ Add a response from the system to glitch table + logs """

        normeval = self.findParam("normalresp").getValue()
        succeval = self.findParam("successresp").getValue()

        if len(normeval) > 0:
            # Check if Normal
            normresult = eval(normeval, {"s": resp}, {})
        else:
            normresult = False

        # Check if Successful
        if len(succeval) > 0:
            # Check if Normal
            succresult = eval(succeval, {"s": resp}, {})
        else:
            succresult = False

        # Check ?
        if not isinstance(normresult, bool):
            raise ValueError(
                "Result of 'normal' eval() not a bool, got %s (result: %s)" % (type(normresult), normresult)
            )

        if not isinstance(succresult, bool):
            raise ValueError(
                "Result of 'success' eval() not a bool, got %s (result: %s)" % (type(succresult), succresult)
            )

        if normresult and succresult:
            logging.warning("Both normresult and succresult True!")

        starttime = datetime.now()

        respstr = str(bytearray(resp.encode("utf-8")))
        # respstr = ' '.join(["%02x" % t for t in bytearray(resp)])

        settingsList = []
        for i in range(0, len(self.tuneParamList)):
            try:
                settingsList.append(Parameter.getParameter(self.tuneParamList[i].paramScript))
            except:
                raise StopIteration(
                    'Choose a valid Parameter Path for Tuning Parameter "%s" . Got: %s'
                    % (self.tuneParamList[i].name(), self.tuneParamList[i].paramScript)
                )
        newdata = {
            "input": "",
            "output": respstr,
            "normal": normresult,
            "success": succresult,
            "settings": settingsList,
            "date": starttime,
        }

        self.tableList.append(newdata)
        self.appendToTable(newdata)
        self.updateStatus()

        if self._campaignRunning and self.findParam(["Recordings", "saveresults"]).getValue():
            if self._autosavef is None:
                # File previously not open
                try:
                    self._autosavef = open(self._autosavefname, "w")
                except Exception as e:
                    self.findParam(["Recordings", "saveresults"]).setValue(False)
                    raise Warning(
                        "Could not save recordings to file: %s. Reason: %s. Disabling it in order to continue."
                        % (self._autosavefname, str(e))
                    )
                self.findParam(["Recordings", "savefilename"]).setValue(self._autosavefname, ignoreReadonly=True)

                # Add notes
                pickle.dump({"notes": self.findParam(["Recordings", "savenotes"]).getValue()}, self._autosavef)

                # Add headers
                cmds = [
                    self.tuneParamList[i].findParam("parampath").getValue() for i in range(0, len(self.tuneParamList))
                ]
                pickle.dump({"commands": cmds}, self._autosavef)

            # Add data
            pickle.dump({"data": newdata}, self._autosavef)

    def loadRecordings(self, fname=None):
        if fname == None:
            fname, _ = QFileDialog.getOpenFileName(self, "Open file", QSettings().value("open_glitch_file"), "*.p")

        if fname:
            self.clearTable()
            file = open(fname, "r")
            self.findParam(["Recordings", "savenotes"]).setValue(pickle.load(file)["notes"])
            self.updateTableHeaders(override=pickle.load(file)["commands"])
            while 1:
                try:
                    self.appendToTable(pickle.load(file)["data"])
                except EOFError:
                    break
            file.close()
class GlitchExplorerDialog(Parameterized, QtFixes.QDialog):
    _name = 'Glitch Explorer'

    def __init__(self, parent):
        super(GlitchExplorerDialog, self).__init__(parent)
        self.setWindowTitle("Glitch Explorer")
        self.setMinimumWidth(500)

        self.mainLayout = QVBoxLayout()
        self.mainSplitter = QSplitter(self)
        self.mainSplitter.setOrientation(Qt.Vertical)

        self.tableList = []
        self.tune_parameter_list = OrderedDict()

        #Add default table
        self.table = QTableWidget(1, 1)
        # self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.mainSplitter.addWidget(self.table)

        self.getParams().register()
        self.getParams().addChildren([
            {
                'name': 'Clear Output Table',
                'type': 'action',
                'action': self.clearTable
            },
            {
                'name': 'Plot Widget',
                'type': 'action',
                'action': self.openPlotWidget
            },
            {
                'name': 'Normal Response',
                'type': 'str',
                'key': 'normalresp',
                'value': 's.startswith("Bad")'
            },
            {
                'name': 'Successful Response',
                'type': 'str',
                'key': 'successresp',
                'value': 's.startswith("Welcome")'
            },
            {
                'name':
                'Recordings',
                'type':
                'group',
                'expanded':
                False,
                'children': [
                    {
                        'name': 'Load existing',
                        'type': 'action',
                        'key': 'open',
                        'action': lambda _: self.loadRecordings()
                    },
                    {
                        'name': 'Autosave Multi-Capture Results',
                        'type': 'bool',
                        'key': 'saveresults',
                        'value': True
                    },
                    {
                        'name': 'Autosaved filename',
                        'type': 'str',
                        'key': 'savefilename',
                        'value': '',
                        "readonly": True
                    },
                    {
                        'name': 'Notes',
                        'type': 'text',
                        'key': 'savenotes',
                        'value': ""
                    },
                ]
            },
        ])

        self.paramTree = ParameterTree()
        self.paramTree.addParameters(self.getParams()._PyQtGraphParameter)
        self.mainSplitter.addWidget(self.paramTree)

        self.statusLabel = QLabel("")

        self.mainSplitter.addWidget(self.statusLabel)

        # self.mainSplitter.setHandleWidth(100)

        self.mainLayout.addWidget(self.mainSplitter)

        self.mainLayout.addWidget(
            QLabel(
                "Glitch Explorer Changed in V4.0 - see wiki.newae.com/cw3to4.")
        )

        self.setLayout(self.mainLayout)
        self.hide()

        #Do an update
        self.table.setSizePolicy(QSizePolicy.MinimumExpanding,
                                 QSizePolicy.MinimumExpanding)
        self.table.horizontalHeader().setResizeMode(QHeaderView.Interactive)
        self.clearTable()
        self._campaignRunning = False

    def add_data(self, name, value):
        doupdate = False

        if name not in self.tune_parameter_list.keys():
            doupdate = True

        self.tune_parameter_list[name] = value

        if doupdate:
            self.updateTableHeaders()

    def openPlotWidget(self, _):
        if "Glitch Explorer" not in ResultsBase.registeredObjects:
            ResultsBase.createNew("Scatter Plot", "Glitch Explorer")
        widget = ResultsBase.registeredObjects["Glitch Explorer"]
        widget.raise_()
        widget.yLocked(False)
        self.clearPlotWidget()

    def clearPlotWidget(self):
        widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
        if widget is not None:
            widget.clearPushed()
            widget.setLabels(top="Glitch Map",
                             xaxis=self.tune_parameter_list.keys()[0]
                             if len(self.tune_parameter_list) > 0 else "",
                             yaxis=self.tune_parameter_list.keys()[1]
                             if len(self.tune_parameter_list) > 1 else "")

    def campaignStart(self, prefixname):
        """Called when acqusition campaign (multi-api) starts, generates filename"""
        self._autosavefname = self.parent().api.project().getDataFilepath(
            prefixname + "_glitchresults.p",
            subdirectory="glitchresults")["abs"]
        self._autosavef = None
        self._campaignRunning = True
        self.clearPlotWidget()

    def campaignDone(self):
        self._campaignRunning = False

        if self._autosavef:
            self._autosavef.close()
            self._autosavef = None
        self.table.setSortingEnabled(True)

    def updateStatus(self):
        okcnt = 0
        for t in self.tableList:
            if t["success"]:
                okcnt += 1

        lbl = "Total %d, Glitches Successful %d" % (len(self.tableList), okcnt)
        self.statusLabel.setText(lbl)

    def reset(self, ignored=None):
        self.tune_parameter_list = OrderedDict()

    def clearTable(self, ignored=None):
        self.tableList = []
        self.table.clear()
        self.table.setRowCount(0)
        self.table.setColumnCount(0)
        self.updateTableHeaders()
        self.table.resizeColumnsToContents()
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(2, 120)
        self.table.setColumnWidth(3, 80)
        self.table.sortByColumn(3, Qt.DescendingOrder)

    def updateTableHeaders(self,
                           ignored=None,
                           ignoredmore=None,
                           override=None):
        headerlist = ["Status", "Sent", "Received", "Date"]

        if override is not None:
            for c in override:
                headerlist.append(c)
        else:
            for t in self.tune_parameter_list.keys():
                headerlist.append(t)

        self.table.setColumnCount(len(headerlist))
        self.table.setHorizontalHeaderLabels(headerlist)

    def traceDone(self):
        """ Single api done """

        #Trace is done - write values to table as was done OK

    def appendToTable(self, newdata):
        """ Append a result to the display table """

        try:
            self.table.setSortingEnabled(False)
            self.table.insertRow(0)

            outdata = QTableWidgetItem(repr(newdata["output"]))
            if newdata["success"]:
                color = Qt.green
                status = "Success"
            elif newdata["normal"] == False:
                color = Qt.red
                status = "Failed"
            else:
                color = Qt.white
                status = "Normal"

            outdata.setBackground(color)
            self.table.setItem(0, 0, QTableWidgetItem(status))
            self.table.setItem(0, 1, QTableWidgetItem(""))
            self.table.setItem(0, 2, outdata)
            self.table.setItem(
                0, 3, QTableWidgetItem(newdata["date"].strftime('%H:%M:%S')))
            for i, v in enumerate(newdata["settings"]):
                self.table.setItem(0, 4 + i, QTableWidgetItem(str(v)))

            self.table.resizeRowToContents(0)

            widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
            if widget is not None:
                widget.plot([
                    newdata["settings"][0]
                    if len(newdata["settings"]) > 0 else 0
                ], [
                    newdata["settings"][1]
                    if len(newdata["settings"]) > 1 else 0
                ], ((0, 255, 0, 75) if status == "Success" else
                    (255, 0, 75) if status == "Failed" else
                    (200, 200, 200, 50)), str(newdata["settings"]))

        except AttributeError as e:
            raise StopIteration(
                "Error when adding data to the table. Plese clear it and try again. Details:"
                + str(e))

    def addResponse(self, resp):
        """ Add a response from the system to glitch table + logs """

        normeval = self.findParam('normalresp').getValue()
        succeval = self.findParam('successresp').getValue()

        if len(normeval) > 0:
            #Check if Normal
            normresult = eval(normeval, {'s': resp}, {})
        else:
            normresult = False

        #Check if Successful
        if len(succeval) > 0:
            #Check if Normal
            succresult = eval(succeval, {'s': resp}, {})
        else:
            succresult = False

        #Check ?
        if not isinstance(normresult, bool):
            raise ValueError(
                "Result of 'normal' eval() not a bool, got %s (result: %s)" %
                (type(normresult), normresult))

        if not isinstance(succresult, bool):
            raise ValueError(
                "Result of 'success' eval() not a bool, got %s (result: %s)" %
                (type(succresult), succresult))

        if normresult and succresult:
            logging.warning('Both normresult and succresult True!')

        starttime = datetime.now()

        respstr = str(bytearray(resp))
        # respstr = ' '.join(["%02x" % t for t in bytearray(resp)])

        settingsList = self.tune_parameter_list.values()
        newdata = {
            "input": "",
            "output": respstr,
            "normal": normresult,
            "success": succresult,
            "settings": settingsList,
            "date": starttime
        }

        self.tableList.append(newdata)
        self.appendToTable(newdata)
        self.updateStatus()

        if self._campaignRunning and self.findParam(
            ["Recordings", "saveresults"]).getValue():
            if self._autosavef is None:
                # File previously not open
                try:
                    self._autosavef = open(self._autosavefname, "w")
                except Exception as e:
                    self.findParam(["Recordings",
                                    "saveresults"]).setValue(False)
                    raise Warning(
                        "Could not save recordings to file: %s. Reason: %s. Disabling it in order to continue."
                        % (self._autosavefname, str(e)))
                self.findParam(["Recordings",
                                'savefilename']).setValue(self._autosavefname,
                                                          ignoreReadonly=True)

                # Add notes
                pickle.dump(
                    {
                        "notes":
                        self.findParam(["Recordings", 'savenotes']).getValue()
                    }, self._autosavef)

                # Add headers
                cmds = self.tune_parameter_list.keys()
                pickle.dump({"commands": cmds}, self._autosavef)

            # Add data
            pickle.dump({"data": newdata}, self._autosavef)

    def loadRecordings(self, fname=None):
        if fname == None:
            fname, _ = QFileDialog.getOpenFileName(
                self, 'Open file',
                QSettings().value("open_glitch_file"), '*.p')

        if fname:
            self.clearTable()
            file = open(fname, 'r')
            self.findParam(["Recordings",
                            'savenotes']).setValue(pickle.load(file)['notes'])
            self.updateTableHeaders(override=pickle.load(file)['commands'])
            while 1:
                try:
                    self.appendToTable(pickle.load(file)['data'])
                except EOFError:
                    break
            file.close()
Exemple #16
0
class TraceManagerImport(QtFixes.QDialog):
    def __init__(self, parent=None):
        super(TraceManagerImport, self).__init__(parent)

        layout = QVBoxLayout()

        # Set dialog layout
        self.setLayout(layout)
        self.setWindowTitle("Add Existing Trace")

        self.openCfg = QPushButton("Load .cfg File")
        self.openCfg.clicked.connect(self.loadCfg)

        layout.addWidget(self.openCfg)

        self.modName = QComboBox()
        self.modName.addItem("Select format for manual mode only...")
        self.modName.addItem("ChipWhisperer/Native")
        self.modName.addItem("DPAContestv3")
        if TraceContainerMySQL is not None:
            self.modName.addItem("MySQL", TraceContainerMySQL)
        self.modName.currentIndexChanged.connect(self.traceTypeChanged)

        layout.addWidget(self.modName)

        self.paramTree = ParameterTree()
        layout.addWidget(self.paramTree)

        buts = QHBoxLayout()
        cancel = QPushButton("Close")
        cancel.clicked.connect(self.abort)
        ok = QPushButton("Import")
        ok.clicked.connect(self.accept)
        buts.addWidget(ok)
        buts.addWidget(cancel)

        layout.addLayout(buts)

        self.tmanager = None

    def abort(self):
        self.tmanager = None
        self.reject()

    def traceTypeChanged(self, newindx):
        self.openCfg.setEnabled(False)
        newTT = self.modName.itemData(newindx)
        self.tmanagerParams = newTT.getParamsClass(openMode=True)
        self.tmanager = newTT(self.tmanagerParams)
        self.paramTree.clear()
        self.paramTree.addParameters(
            self.tmanagerParams.getParams()._PyQtGraphParameter)

    def getTrace(self):
        return self.tmanager

    def updateConfigData(self):
        if self.tmanager is not None:
            self.tmanager.updateConfigData()

    def loadCfg(self, fname=None):
        if fname is None:
            fname, _ = QFileDialog.getOpenFileName(
                self, 'Open file',
                QSettings().value("trace_last_file"), '*.cfg')

        if fname:
            QSettings().setValue("trace_last_file", fname)
            self.modName.setEnabled(False)

            #Figure out what format this is in
            tc = TraceContainerConfig(fname)
            fmt = tc.attr("format")

            #Generate a temp class for getting parameters from
            fmtclass = chipwhisperer.common.traces.TraceContainerTypes.TraceContainerFormatList[
                fmt]

            #Use temp class to finally initilize our "good" version
            self.tmanager = fmtclass()
            self.tmanager.config.loadTrace(fname)
            self.tmanager.loadAllConfig()
            self.paramTree.clear()
            self.paramTree.addParameters(
                self.tmanager.getParams()._PyQtGraphParameter)
class SpectrumViewer(QtGui.QMainWindow):
        '''The application main window.'''

        def __init__(self, parent=None):
            # We're not calling the super method so we can span an new instance in
            # the new function.
            # However, when the first created window is closed, all windoes close
            # super(SpectrumViewer, self).__init__()
            QtGui.QMainWindow.__init__(self, parent)
            self.spectra = []
            self.plots = []
            self.initUI()

        def initToolBar(self):
            '''The main toolbar.'''
            # File actions
            self.newAction = QtGui.QAction(QtGui.QIcon('../icons/new.png'), '&New', self)
            self.newAction.setStatusTip('New molecule viewer')
            self.newAction.setShortcut('Ctrl+N')
            self.newAction.triggered.connect(self.new)

            self.openAction = QtGui.QAction(QtGui.QIcon('../icons/open.png'), '&Open', self)
            self.openAction.setStatusTip('Read molecule from file')
            self.openAction.setShortcut('Ctrl+O')
            self.openAction.triggered.connect(self.open)

            self.saveAction = QtGui.QAction(QtGui.QIcon('../icons/save.png'), '&Save', self)
            self.saveAction.setStatusTip('Write molecule to file')
            self.saveAction.setShortcut('Ctrl+S')
            self.saveAction.triggered.connect(self.save)

            self.saveimageAction = QtGui.QAction(QtGui.QIcon('../icons/picture-edit.png'), 'Save &image as PNG', self)
            self.saveimageAction.setStatusTip('Save image as PNG')
            self.saveimageAction.setShortcut('Ctrl+I')
            self.saveimageAction.triggered.connect(self.saveimage)

            self.exitAction = QtGui.QAction(QtGui.QIcon('../icons/exit.png'), '&Exit', self)
            self.exitAction.setShortcut('Ctrl+Q')
            self.exitAction.setStatusTip('Exit application')
            self.exitAction.triggered.connect(QtGui.qApp.quit)

            # View actions
            self.fullScreenAction = QtGui.QAction(QtGui.QIcon('../icons/fullscreen.png'), '&Full Screen', self)
            self.fullScreenAction.setStatusTip('Toggle full screen')
            self.fullScreenAction.setShortcut('F11')
            self.fullScreenAction.triggered.connect(self.fullscreen)

            self.toggleSidebarAction = QtGui.QAction('&Toggle sidebar', self)
            self.toggleSidebarAction.setStatusTip('Toggle sidebar')
            self.toggleSidebarAction.triggered.connect(self.togglesidebar)

            # Spectrum actions
            self.addspectrumAction = QtGui.QAction(QtGui.QIcon('../icons/addspectrum.png'), '&Add spectrum', self)
            self.addspectrumAction.setStatusTip('Add a new spectrum')
            self.addspectrumAction.setShortcut('Ctrl + A')
            self.addspectrumAction.triggered.connect(self.open)

            self.removespectrumAction = QtGui.QAction(QtGui.QIcon('../icons/removespectrum.png'), '&Remove spectrum', self)
            self.removespectrumAction.setStatusTip('Remove a spectrum')
            self.removespectrumAction.setShortcut('Ctrl + R')
            self.removespectrumAction.triggered.connect(self.removespectrum)

            # Toolbars
            self.filetoolbar = self.addToolBar('File')
            self.filetoolbar.addAction(self.newAction)
            self.filetoolbar.addAction(self.openAction)
            self.filetoolbar.addAction(self.saveAction)
            self.filetoolbar.addAction(self.saveimageAction)

            self.viewtoolbar = self.addToolBar('View')
            self.viewtoolbar.addAction(self.fullScreenAction)

            self.spectrumtoolbar = self.addToolBar('Spectrum')
            self.spectrumtoolbar.addAction(self.addspectrumAction)
            self.spectrumtoolbar.addAction(self.removespectrumAction)

        def initMenuBar(self):
            '''The main menubar.'''
            menubar = self.menuBar()
            menubar.setNativeMenuBar(True)

            # Create menus
            file = menubar.addMenu('&File')
            edit = menubar.addMenu('&Edit')
            view = menubar.addMenu('&View')
            spectrum = menubar.addMenu('&Spectrum')
            about = menubar.addMenu('&About')

            # File menu
            file.addAction(self.newAction)
            file.addAction(self.openAction)
            file.addAction(self.saveAction)
            file.addAction(self.saveimageAction)
            file.addSeparator()
            file.addAction(self.exitAction)

            # View menu
            view.addAction(self.fullScreenAction)
            view.addAction(self.toggleSidebarAction)

            # Spectrum menu
            spectrum.addAction(self.addspectrumAction)
            spectrum.addAction(self.removespectrumAction)

        def initParameterTree(self):
            '''The sidebar.'''
            self.parametertree = ParameterTree()
            self.params = []

        def initUI(self):
            '''Initializes the main window widgets.'''
            self.initToolBar()
            self.initMenuBar()
            self.initParameterTree()

            self.plotwidget = pg.PlotWidget()
            self.plot = self.plotwidget.plotItem
            self.plot.setMenuEnabled(False)
            #cross hair
            self.vLine = pg.InfiniteLine(angle=90, movable=False)
            self.hLine = pg.InfiniteLine(angle=0, movable=False)
            self.plotwidget.addItem(self.vLine, ignoreBounds=True)
            self.plotwidget.addItem(self.hLine, ignoreBounds=True)
            self.vb = self.plot.vb
            self.plot.scene().sigMouseMoved.connect(self.mouseMoved)

            widget = QtGui.QWidget()
            hbox = QtGui.QHBoxLayout(widget)
            hbox.addWidget(self.parametertree)
            hbox.addWidget(self.plotwidget, 1)

            self.setCentralWidget(widget)
            self.resize(1200, 600)
            self.setWindowTitle('Molviewer :: Spectrum main window')
            self.show()

        def mouseMoved(self, evt):
            '''Detect mouse movement.'''
            pos = evt
            if self.plot.sceneBoundingRect().contains(pos):
                mousePoint = self.vb.mapSceneToView(pos)
                self.vLine.setPos(mousePoint.x())
                self.hLine.setPos(mousePoint.y())

        def new(self):
            '''Spawn new main window.'''
            spawn = SpectrumViewer(self)
            spawn.setWindowTitle('Molviewer :: Spectrum main window (child)')
            spawn.show()

        def open(self):
            '''Open a new spectrum using the file dialog.'''
            filenames = QtGui.QFileDialog.getOpenFileNames(self, 'Open Files', '', '*.dx;; *.jdx')
            if filenames:
                for f in filenames:
                    spectrum = Spectrum(f)
                    self.addspectrum(spectrum)

        def save(self):
            pass

        def saveimage(self):
            pass

        def draw(self, spectrum):
            '''Draw a new spectrum.

            :param spectrum: The spectrum to draw.
            :type spectrum: spectrum.Spectrum
            :param color: The color in which the spectrum is drawn.

            '''
            p = self.plotwidget.plot(spectrum.x, spectrum.y, pen=spectrum.color)
            if p not in self.plots:
                self.plots.append(p)
            if spectrum.datatype.lower() == 'infrared spectrum':
                # Plot higher wavenumbers to the left hand side
                self.plotwidget.invertX(True)
                self.plotwidget.setLabel('bottom', '1/cm')
            else:
                self.plotwidget.setLabel('bottom', spectrum.xunits)

        def fullscreen(self):
            '''Toggle full screen window.'''
            if self.windowState() & QtCore.Qt.WindowFullScreen:
                self.showNormal()
            else:
                self.showFullScreen()

        def togglesidebar(self):
            if self.parametertree.isVisible():
                self.parametertree.hide()
            else:
                self.parametertree.show()

        def addspectrum(self, spectrum):
            '''Add a new spectrum.

            :param spectrum: The new spectrum.
            :type spectrum: spectrum.Spectrum

            '''
            self.spectra.append(spectrum)
            ind = self.spectra.index(spectrum)
            spectrum.color = spectrumcolors[ind]
            params = [
                {'name': spectrum.title, 'type': 'group', 'children': [
                    {'name': 'Number', 'type': 'int', 'value': self.spectra.index(spectrum)},
                    {'name': 'Color', 'type': 'color', 'value': spectrum.color},
                    {'name': 'Visible', 'type': 'bool', 'value': True},
                    {'name': 'Action Parameter', 'type': 'action'},
                    {'name': 'Spectrum', 'type': 'str', 'value': spectrum, 'visible': False}]
                }]

            p = Parameter.create(name='Files', type='group', children=params)
            p.sigTreeStateChanged.connect(self.change)
            self.parametertree.addParameters(p, showTop=False)
            self.params.append(p)
            self.draw(spectrum)

        def removespectrum(self):
            '''Remove a spectrum from display.'''
            num, ok = QtGui.QInputDialog.getText(self, 'Remove a spectrum', 'Enter spectrum number:')
            if ok and num:
                num = int(num)
                self.plotwidget.removeItem(self.plots[num])
                self.plots.pop(num)
                self.spectra.pop(num)
                self.params.pop(num)
                self.parametertree.clear()
                for p in self.params:
                    self.parametertree.addParameters(p, showTop=False)

        def change(self, param, changes):
            for param, change, data in changes:
                spec = param.parent().child('Spectrum').value()
                index = self.spectra.index(spec)

                if isinstance(param.value(), QtGui.QColor):
                    self.plots[index].setPen(param.value())
                    self.spectra[index].color = param.value()

                if param.name() == 'Visible':
                    if data is False:
                        self.plots[index].clear()
                    elif data is True:
                        self.plots[index].setData(self.spectra[index].x, self.spectra[index].y)
Exemple #18
0
    class maintest(QtCore.QObject):
        paramListUpdated = QtCore.Signal(list)

        def __init__(self):
            super(maintest, self).__init__()
            p = [{
                'name':
                'Basic parameter data types',
                'type':
                'group',
                'helpwnd':
                self.printhelp,
                'children': [{
                    'name':
                    'Module 1',
                    'type':
                    'list',
                    'values': {
                        'module 1': module(),
                        'module 2': module(),
                        'module 3': module()
                    },
                    'set':
                    self.setmodule,
                    'help':
                    '%namehdr%Boatload of text is possible here. Can use markup too with external help window.'
                }, {
                    'name': 'Rocks to Skips',
                    'type': 'int',
                    'help': 'Another help example',
                    'helpwnd': None
                }]
            }]
            self.params = Parameter.create(name='Test',
                                           type='group',
                                           children=p)
            ExtendedParameter.setupExtended(self.params)
            self.module = None

            self.t = ParameterTree()
            self.reloadParams()

        def printhelp(self, msg, obj):
            print msg

        def setmodule(self, module):
            print "Changing Module"
            self.module = module
            self.module.paramListUpdated.connect(self.reloadParams)
            self.paramListUpdated.emit(self.paramList())
            self.reloadParams()

        def reloadParams(self):
            ExtendedParameter.reloadParams(self.paramList(), self.t)

        def reloadParamsBad(self):
            """The following is kept as a reminder you must NOT do this, or else objects get deleted"""

            #Notes about my wasted day to report a bug later when I have more time:
            # *Calling the .clear() causes stuff to be deleted
            # *In file parameterTypes.py at line 180 you have the following:
            #    self.widget.sigChanged.disconnect(self.widgetValueChanged)
            #  If self.widget has been deleted, which will happen once the ParameterTree is cleared, the call
            #  to .disconnect causes a bad crash (sometimes). However - you can insert a call to 'self.widget.value()'
            #  before the .disconnect() call. The self.widget.value() actually checks if the object was deleted, and if so
            #  it raises a nice exception with a handy error message.

            lst = self.paramList()
            self.t.clear()
            for p in lst:
                self.t.addParameters(p)

        def paramList(self):
            p = [self.params]
            if self.module is not None:
                for a in self.module.paramList():
                    p.append(a)
            return p
Exemple #19
0
class TyphonSuite(TyphonBase):
    """
    Complete Typhon Window

    This contains all the neccesities to load tools and devices into a Typhon
    window.

    Parameters
    ----------
    parent : QWidget, optional
    """
    default_tools = {
        'Log': TyphonLogDisplay,
        'StripTool': TyphonTimePlot,
        'Console': TyphonConsole
    }

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        # Setup parameter tree
        self._tree = ParameterTree(parent=self, showHeader=False)
        self._tree.setAlternatingRowColors(False)
        # Setup layout
        self._layout = QHBoxLayout()
        self._layout.setSizeConstraint(QHBoxLayout.SetFixedSize)
        self._layout.addWidget(self._tree)
        self.setLayout(self._layout)
        self.embedded_dock = None

    def add_subdisplay(self, name, display, category):
        """
        Add an arbitrary widget to the tree of available widgets and tools

        Parameters
        ----------
        name : str
            Name to be displayed in the tree

        display : QWidget
            QWidget to show in the dock when expanded.

        category : str
            The top level group to place the controls under in the tree. If the
            category does not exist, a new one will be made
        """
        logger.debug("Adding widget %r with %r to %r ...", name, display,
                     category)
        # Create our parameter
        parameter = SidebarParameter(value=display, name=name)
        self._add_to_sidebar(parameter, category)

    @property
    def top_level_groups(self):
        """All top-level groups as name, ``QGroupParameterItem`` pairs"""
        root = self._tree.invisibleRootItem()
        return dict((root.child(idx).param.name(), root.child(idx).param)
                    for idx in range(root.childCount()))

    def add_tool(self, name, tool):
        """
        Add a widget to the toolbar

        Shortcut for:

        .. code:: python

           suite.add_subdisplay(name, tool, category='Tools')

        Parameters
        ----------
        name :str
            Name of tool to be displayed in sidebar

        tool: QWidget
            Widget to be added to ``.ui.subdisplay``
        """
        self.add_subdisplay(name, tool, 'Tools')

    def get_subdisplay(self, display):
        """
        Get a subdisplay by name or contained device

        Parameters
        ----------
        display :str or Device
            Name of screen or device

        Returns
        -------
        widget : QWidget
            Widget that is a member of the :attr:`.ui.subdisplay`

        Example
        -------
        .. code:: python

            suite.get_subdisplay(my_device.x)
            suite.get_subdisplay('My Tool')
        """
        if isinstance(display, SidebarParameter):
            return display.value()
        for group in self.top_level_groups.values():
            tree = flatten_tree(group)
            for param in tree:
                match = (display in getattr(param.value(), 'devices', [])
                         or param.name() == display)
                if match:
                    return param.value()
        # If we got here we can't find the subdisplay
        raise ValueError(f"Unable to find subdisplay {display}")

    @Slot(str)
    @Slot(object)
    def show_subdisplay(self, widget):
        """
        Open a display in the dock system

        Parameters
        ----------
        widget: QWidget, SidebarParameter or str
            If given a ``SidebarParameter`` from the tree, the widget will be
            shown and the sidebar item update. Otherwise, the information is
            passed to :meth:`.get_subdisplay`
        """
        # Grab true widget
        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        # Setup the dock
        dock = SubDisplay(self)
        # Set sidebar properly
        self._show_sidebar(widget, dock)
        # Add the widget to the dock
        logger.debug("Showing widget %r ...", widget)
        if hasattr(widget, 'display_type'):
            widget.display_type = widget.detailed_screen
        widget.setVisible(True)
        dock.setWidget(widget)
        # Add to layout
        self.layout().addWidget(dock)

    @Slot(str)
    @Slot(object)
    def embed_subdisplay(self, widget):
        """Embed a display in the dock system"""
        # Grab the relevant display
        if not self.embedded_dock:
            self.embedded_dock = SubDisplay()
            self.embedded_dock.setWidget(QWidget())
            self.embedded_dock.widget().setLayout(QVBoxLayout())
            self.embedded_dock.widget().layout().addStretch(1)
            self.layout().addWidget(self.embedded_dock)

        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        # Set sidebar properly
        self._show_sidebar(widget, self.embedded_dock)
        # Set our widget to be embedded
        widget.setVisible(True)
        widget.display_type = widget.embedded_screen
        widget_count = self.embedded_dock.widget().layout().count()
        self.embedded_dock.widget().layout().insertWidget(
            widget_count - 1, widget)

    @Slot()
    @Slot(object)
    def hide_subdisplay(self, widget):
        """
        Hide a visible subdisplay

        Parameters
        ----------
        widget: SidebarParameter or Subdisplay
            If you give a SidebarParameter, we will find the corresponding
            widget and hide it. If the widget provided to us is inside a
            DockWidget we will close that, otherwise the widget is just hidden.
        """
        if not isinstance(widget, QWidget):
            widget = self.get_subdisplay(widget)
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_hidden()
        else:
            logger.warning("Unable to find sidebar item for %r", widget)
        # Make sure the actual widget is hidden
        logger.debug("Hiding widget %r ...", widget)
        if isinstance(widget.parent(), QDockWidget):
            logger.debug("Closing dock ...")
            widget.parent().close()
        # Hide the full dock if this is the last widget
        elif (self.embedded_dock
              and widget.parent() == self.embedded_dock.widget()):
            logger.debug("Removing %r from embedded widget layout ...", widget)
            self.embedded_dock.widget().layout().removeWidget(widget)
            widget.hide()
            if self.embedded_dock.widget().layout().count() == 1:
                logger.debug("Closing embedded layout ...")
                self.embedded_dock.close()
                self.embedded_dock = None
        else:
            widget.hide()

    @Slot()
    def hide_subdisplays(self):
        """
        Hide all open displays
        """
        # Grab children from devices
        for group in self.top_level_groups.values():
            for param in flatten_tree(group)[1:]:
                self.hide_subdisplay(param)

    @property
    def tools(self):
        """Tools loaded into the TyphonDeviceDisplay"""
        if 'Tools' in self.top_level_groups:
            return [
                param.value()
                for param in self.top_level_groups['Tools'].childs
            ]
        return []

    def add_device(self, device, children=True, category='Devices'):
        """
        Add a device to the ``TyphonSuite``

        Parameters
        ----------
        device: ophyd.Device

        children: bool, optional
            Also add any ``subdevices`` of this device to the suite as well.

        category: str, optional
            Category of device. By default, all devices will just be added to
            the "Devices" group
        """
        super().add_device(device)
        # Create DeviceParameter and add to top level category
        dev_param = DeviceParameter(device, subdevices=children)
        self._add_to_sidebar(dev_param, category)
        # Grab children
        for child in flatten_tree(dev_param)[1:]:
            self._add_to_sidebar(child)
        # Add a device to all the tool displays
        for tool in self.tools:
            try:
                tool.add_device(device)
            except Exception:
                logger.exception("Unable to add %s to tool %s", device.name,
                                 type(tool))

    @classmethod
    def from_device(cls, device, parent=None, tools=dict(), **kwargs):
        """
        Create a new TyphonDeviceDisplay from an ophyd.Device

        Parameters
        ----------
        device: ophyd.Device

        children: bool, optional
            Choice to include child Device components

        parent: QWidgets

        tools: dict, optional
            Tools to load for the object. ``dict`` should be name, class pairs.
            By default these will be ``.default_tools``, but ``None`` can be
            passed to avoid tool loading completely.

        kwargs:
            Passed to :meth:`TyphonSuite.add_device`
        """
        display = cls(parent=parent)
        if tools is not None:
            if not tools:
                logger.debug("Using default TyphonSuite tools ...")
                tools = cls.default_tools
                for name, tool in tools.items():
                    try:
                        display.add_tool(name, tool())
                    except Exception:
                        logger.exception("Unable to load %s", type(tool))
        display.add_device(device, **kwargs)
        display.show_subdisplay(device)
        return display

    def _get_sidebar(self, widget):
        items = {}
        for group in self.top_level_groups.values():
            for item in flatten_tree(group):
                items[item.value()] = item
        return items.get(widget)

    def _show_sidebar(self, widget, dock):
        sidebar = self._get_sidebar(widget)
        if sidebar:
            for item in sidebar.items:
                item._mark_shown()
            # Make sure we react if the dock is closed outside of our menu
            dock.closing.connect(partial(self.hide_subdisplay, sidebar))
        else:
            logger.warning("Unable to find sidebar item for %r", widget)

    def _add_to_sidebar(self, parameter, category=None):
        """Add an item to the sidebar, connecting necessary signals"""
        if category:
            # Create or grab our category
            if category in self.top_level_groups:
                group = self.top_level_groups[category]
            else:
                logger.debug("Creating new category %r ...", category)
                group = ptypes.GroupParameter(name=category)
                self._tree.addParameters(group)
                self._tree.sortItems(0, Qt.AscendingOrder)
            logger.debug("Adding %r to category %r ...", parameter.name(),
                         group.name())
            group.addChild(parameter)
        # Setup window to have a parent
        parameter.value().setParent(self)
        parameter.value().setHidden(True)
        logger.debug("Connecting parameter signals ...")
        parameter.sigOpen.connect(partial(self.show_subdisplay, parameter))
        parameter.sigHide.connect(partial(self.hide_subdisplay, parameter))
        if parameter.embeddable:
            parameter.sigEmbed.connect(
                partial(self.embed_subdisplay, parameter))
        return parameter
Exemple #20
0
class MeasuringApp(CamObject, QtGui.QMainWindow):
    def __init__(self, *args, **kwargs):
        CamObject.__init__(self)
        QtGui.QMainWindow.__init__(self)
        self.resize(700, 150)
        self.setWindowTitle('Workpiece Dimensional Control')
        self.area = DockArea()
        self.setCentralWidget(self.area)

        # Window Docks
        self.camMenuDock = Dock('Camera Menu', size=(1, 1))
        self.procMenuDock = Dock('Analysis Menu', size=(1, 1))
        self.paramDock = Dock('Parameter Tree', size=(250, 150))
        self.area.addDock(self.camMenuDock, 'right')
        self.area.addDock(self.procMenuDock, 'right')
        self.area.addDock(self.paramDock, 'left')

        # Parameter Tree
        self._parameter_tree = ParameterTree()
        self._parameter_tree.setWindowTitle('Parameter Tree')
        self.paramDock.addWidget(self._parameter_tree)

        # Camera Menu
        self._cam_menu = pg.LayoutWidget(parent=self.camMenuDock)
        self._cam_buttons = self.cam_buttons()
        [btn.resize(btn.minimumSizeHint()) for btn in self._cam_buttons]
        [self._cam_menu.addWidget(btn, row=i, col=0) for btn, i in zip(
            self._cam_buttons, range(len(self._cam_buttons)))]
        self.camMenuDock.addWidget(self._cam_menu)

        # Analysis menu
        self._proc_menu = pg.LayoutWidget(parent=self.procMenuDock)
        self._proc_buttons = self.process_buttons()
        [btn.resize(btn.minimumSizeHint()) for btn in self._proc_buttons]
        [self._proc_menu.addWidget(btn, row=i, col=1) for btn, i in zip(
            self._proc_buttons, range(len(self._proc_buttons)))]
        self.procMenuDock.addWidget(self._proc_menu)

        # Original frames window
        self._orig_frame = FrameWindow("Original")

        # Flowchart input preparation window
        self._prep_flow = FlowchartPrepWindow('Flowchart Input preparation')

        # Calibrate system window
        self._calib_window = FlowchartCalibrateWindow()
        # Calibration Parameters
        self._calib_params = None

        # Measurement preparation window
        self._measure_prep_window = FlowchartMeasureWindow()

        # Realtime measurement window
        self._realtime_measure_window = MeasureRealtimeWindow()

        # Show Main Window
        self.show()

        # Result Queue init
        self.preproc_queue = queue.Queue()

        # FPS display count
        self.fps_display_count = 0

    def cam_buttons(self):
        """
        Menu buttons as list
        """
        # Camera create button
        cam_create = QtGui.QPushButton('Find Camera', parent=self._cam_menu)
        cam_create.clicked.connect(self.create)
        # Camera open button
        cam_open = QtGui.QPushButton('Open Camera', parent=self._cam_menu)
        cam_open.clicked.connect(self.open)
        # Camera print info
        cam_print_info = QtGui.QPushButton('Print Info', parent=self._cam_menu)
        cam_print_info.clicked.connect(self.print_info)
        # Camera start grabbing
        cam_start_grab = QtGui.QPushButton(
            'Start Grabbing', parent=self._cam_menu)
        cam_start_grab.clicked.connect(self.start_grabbing)
        # Camera stop grabbing
        cam_stop_grab = QtGui.QPushButton(
            'Stop Grabbing', parent=self._cam_menu)
        cam_stop_grab.clicked.connect(self.stop_grabbing)
        # Camera close
        cam_close = QtGui.QPushButton('Close Camera', parent=self._cam_menu)
        cam_close.clicked.connect(self.close)
        return [
            cam_create, cam_open, cam_print_info, cam_start_grab,
            cam_stop_grab, cam_close
        ]

    def process_buttons(self):
        """
        Process buttons as list
        """
        # Grab single frame button
        proc_grab_frame = QtGui.QPushButton(
            'Grab Frame', parent=self._proc_menu)
        proc_grab_frame.clicked.connect(self.grab_single_frame)
        proc_discard_frame = QtGui.QPushButton(
            'Discard Frame', parent=self._proc_menu)
        proc_discard_frame.clicked.connect(self.discard_frame)
        proc_calib_sys = QtGui.QPushButton(
            'Calibrate System', parent=self._proc_menu)
        proc_calib_sys.clicked.connect(self.calibrate_system)
        proc_set_calib_const = QtGui.QPushButton(
            'Set Calibration Constants', parent=self._proc_menu)
        proc_set_calib_const.clicked.connect(self.set_calib_const)
        proc_measure_prep = QtGui.QPushButton(
            'Measurement Preparation', parent=self._proc_menu)
        proc_measure_prep.clicked.connect(self.measurement_preparation)
        proc_realtime_start = QtGui.QPushButton(
            'Start Measurement', parent=self._proc_menu)
        proc_realtime_start.clicked.connect(self.start_realtime_measurement)
        proc_realtime_stop = QtGui.QPushButton(
            'Stop Measurement', parent=self._proc_menu)
        proc_realtime_stop.clicked.connect(self.stop_realtime_measurement)
        return [
            proc_grab_frame, proc_discard_frame, proc_calib_sys,
            proc_set_calib_const, proc_measure_prep, proc_realtime_start,
            proc_realtime_stop
        ]

    def open(self):
        """
        Reimplementation of open function to update GUI numbers and sliders
        """
        super().open()
        self._parameter_tree.clear()
        self._parameter_tree.addParameters(
            CameraParams(name='Camera Parameters', cam_obj=self), showTop=True)

    def close(self):
        """
        Reimplementation of close function to update GUI numbers and sliders
        """
        super().close()
        self._parameter_tree.clear()

    def set_default_params(self):
        """
        Reimplementation of set_default_params function to update GUI
        """
        super().set_default_params()
        self._cam_gain.value = self.cam.Gain()
        self._cam_exposure.value = self.cam.ExposureTime()
        self._cam_width.value = self.cam.Width.GetValue()
        self._cam_height.value = self.cam.Height.GetValue()
        self._cam_offsetx.value = self.cam.OffsetX.GetValue()
        self._cam_offsety.value = self.cam.OffsetY.GetValue()

    def start_grabbing(self, strategy=pylon.GrabStrategy_LatestImageOnly):
        """
        Reimplementation of start_grabbing to show new window
        """
        if not self.cam.IsGrabbing():
            self._orig_frame.show()
            self.frame_queue = queue.Queue()
            fg_hndl = FrameGrabEventHandler(self.frame_queue)
            # Frame grab event registering
            self.cam.RegisterImageEventHandler(
                fg_hndl,
                pylon.RegistrationMode_ReplaceAll,
                pylon.Cleanup_Delete
            )
            super().start_grabbing(strategy)
            self.frame_burst(graphicsObject=self._orig_frame)

    def stop_grabbing(self):
        """
        Reimplementation of stop_grabbing to close new window
        """
        if self.cam.IsGrabbing():
            super().stop_grabbing()
            self._orig_frame.close()

    def frame_burst(self, graphicsObject, updateFrame=True, updateFPS=True,
                    updateMeasurementResult=False, numProc=1, fps_display=5):
        """
        Grab frames from camera using software trigger, scheduling and event
        handler.
        frame_burst reimplementation for FPS, frame and measurement result
        update.

        :param graphicsObject: object which methods are called and graphics updated
        :param updateFrame: bool
        :param updateFPS: bool
        :param updateMeasurementResult: bool
        :param numProc: 1
        :param fps_display: int
        """
        if self.fps_count == 0:
            if updateFPS:
                # Update graphicsObject FPS label
                graphicsObject.update_fps(self.fps)
            self.fps_start = pg.ptime.time()
        if self.cam.IsGrabbing():
            for _ in range(numProc):
                if self.cam.WaitForFrameTriggerReady(
                        300, pylon.TimeoutHandling_ThrowException):
                    self.cam.ExecuteSoftwareTrigger()
            frames = [self.frame_queue.get() for _ in range(numProc)]
            self.fps_display_count += 1
            # print('FPS_display_count: {}'.format(self.fps_display_count))
            if updateFrame and not (self.fps_display_count % fps_display):
                self.fps_display_count = 0
                # Update graphicsObject ImageItem
                [graphicsObject.update_frame(frame) for frame in frames]
                self.fps_count += numProc
            if updateMeasurementResult:
                while not self.preproc_queue.empty():
                    graphicsObject.update_measurement_result(
                        self._measure_prep_window.fc_process(
                            dip.Image(self.preproc_queue.get())
                        ))
            # Average FPS on number of frames
            if self.fps_count >= 10:
                fps_time = pg.ptime.time() - self.fps_start
                self.fps = self.fps_count / fps_time
                print("Camera FPS: {:.2f}".format(
                    self.cam.ResultingFrameRate.GetValue()))
                print("FPS: {:.2f}".format(self.fps))
                self.fps_count = 0
            QtCore.QTimer.singleShot(
                1, lambda : self.frame_burst(graphicsObject,
                                             updateFrame,
                                             updateFPS,
                                             numProc,
                                             ))

    def grab_single_frame(self):
        self._prep_flow.set_frame(self._orig_frame.grab_single_frame())
        self._prep_flow.show()

    def discard_frame(self):
        self._prep_flow.close()

    def calibrate_system(self):
        """
        Show Calibration flowchart and set input frame
        """
        self._calib_window.setInput(self._prep_flow.get_dip_slice())
        self._calib_window.show()

    def set_calib_const(self):
        """
        Set and show calibration parameters in parameterTree
        """
        standard_dict = self._calib_window.output()
        self._calib_params = CalibrationParams(
            name='Calibration Parameters', standard_dict=standard_dict)
        self._parameter_tree.clear()
        self._parameter_tree.addParameters(self._calib_params, showTop=True)

    def measurement_preparation(self):
        """
        Show Measurement preparation flowchart and set input frame
        """
        self._measure_prep_window.setInput(
            self._prep_flow.get_dip_slice(),
            self._calib_params.obj_mm_px.value()
        )
        self._measure_prep_window.show()

    def start_realtime_measurement(
            self, strategy=pylon.GrabStrategy_LatestImageOnly):
        """
        Show window for realtime measurement and start grabbing frames from cam
        """
        if not self.cam.IsGrabbing():
            self._realtime_measure_window.show()
            procParallel = ProcessParallel(
                self._measure_prep_window, numberProc=3
            )
            # Queue for storing frames
            self.frame_queue = queue.Queue()
            # Queue for storing measurement result list
            self.preproc_queue = queue.Queue()
            self.fm_hndl = FrameMeasureEventHandler(
                self.frame_queue, self.preproc_queue, procParallel
            )
            # Frame grab event registering
            self.cam.RegisterImageEventHandler(
                self.fm_hndl,
                pylon.RegistrationMode_ReplaceAll,
                pylon.Cleanup_Delete
            )
            super().start_grabbing(strategy)
            self.frame_burst(
                graphicsObject=self._realtime_measure_window,
                updateFPS=False, updateMeasurementResult=True,
                fps_display=10,
                # numProc=procParallel.getNumProc()
            )

    def stop_realtime_measurement(self):
        """
        Close window for realtime measurement and stop grabbing frames from cam
        """
        if self.cam.IsGrabbing():
            super().stop_grabbing()
            self._realtime_measure_window.close()
            self.cam.DeregisterImageEventHandler(self.fm_hndl)
class TraceManagerImport(QtFixes.QDialog):
    def __init__(self, parent=None):        
        super(TraceManagerImport, self).__init__(parent)

        layout = QVBoxLayout()

        # Set dialog layout
        self.setLayout(layout)
        self.setWindowTitle("Add Existing Trace")

        self.openCfg = QPushButton("Load .cfg File")
        self.openCfg.clicked.connect(self.loadCfg)

        layout.addWidget(self.openCfg)
        
        self.modName = QComboBox()
        self.modName.addItem("Select format for manual mode only...")
        self.modName.addItem("ChipWhisperer/Native")
        self.modName.addItem("DPAContestv3")
        if TraceContainerMySQL is not None:        
            self.modName.addItem("MySQL", TraceContainerMySQL)
        self.modName.currentIndexChanged.connect(self.traceTypeChanged)
        
        layout.addWidget(self.modName)

        self.paramTree = ParameterTree()
        layout.addWidget(self.paramTree)

        buts = QHBoxLayout()
        cancel = QPushButton("Close")
        cancel.clicked.connect(self.abort)
        ok = QPushButton("Import")
        ok.clicked.connect(self.accept)
        buts.addWidget(ok)
        buts.addWidget(cancel)
        
        layout.addLayout(buts)
        
        self.tmanager = None
        
    def abort(self):
        self.tmanager = None
        self.reject()        

    def traceTypeChanged(self, newindx):
        self.openCfg.setEnabled(False)
        newTT = self.modName.itemData(newindx)        
        self.tmanagerParams = newTT.getParamsClass(openMode=True)   
        self.tmanager = newTT(self.tmanagerParams)
        self.paramTree.clear()
        self.paramTree.addParameters(self.tmanagerParams.getParams()._PyQtGraphParameter)
        
    def getTrace(self):
        return self.tmanager
    
    def updateConfigData(self):
        if self.tmanager is not None:
            self.tmanager.updateConfigData()

    def loadCfg(self, fname=None):
        if fname is None:
            fname, _ = QFileDialog.getOpenFileName(self, 'Open file', QSettings().value("trace_last_file"), '*.cfg')

        if fname:
            QSettings().setValue("trace_last_file", fname)
            self.modName.setEnabled(False)
            
            #Figure out what format this is in
            tc = TraceContainerConfig(fname)
            fmt = tc.attr("format")
            
            #Generate a temp class for getting parameters from
            fmtclass = chipwhisperer.common.traces.TraceContainerTypes.TraceContainerFormatList[fmt]
            
            #Use temp class to finally initilize our "good" version
            self.tmanager = fmtclass()
            self.tmanager.config.loadTrace(fname)
            self.tmanager.loadAllConfig()
            self.paramTree.clear()
            self.paramTree.addParameters(self.tmanager.getParams()._PyQtGraphParameter)
Exemple #22
0
class TrackingExperimentWindow(SimpleExperimentWindow):
    """Window for controlling an experiment where the tail of an
    embedded fish is tracked.

    Parameters
    ----------

    Returns
    -------

    """
    def __init__(self, tracking=True, tail=False, eyes=False, *args, **kwargs):
        # TODO refactor movement detection
        self.tracking = tracking
        self.tail = tail
        self.eyes = eyes

        if tail or eyes:
            self.camera_display = CameraEmbeddedTrackingSelection(
                experiment=kwargs["experiment"], tail=tail, eyes=eyes)
        else:
            self.camera_display = CameraViewWidget(
                experiment=kwargs["experiment"])

        self.camera_splitter = QSplitter(Qt.Horizontal)
        self.monitoring_widget = QWidget()
        self.monitoring_layout = QVBoxLayout()
        self.monitoring_widget.setLayout(self.monitoring_layout)

        # Stream plot:
        # if eyes:
        time_past = 30
        # else:
        #     time_past = 5
        self.stream_plot = MultiStreamPlot(time_past=time_past)

        self.monitoring_layout.addWidget(self.stream_plot)

        # Tracking params button:
        self.button_tracking_params = QPushButton(
            "Tracking params" if tracking else "Movement detection params")
        self.button_tracking_params.clicked.connect(
            self.open_tracking_params_tree)
        self.monitoring_layout.addWidget(self.button_tracking_params)

        self.track_params_wnd = None

        super().__init__(*args, **kwargs)

    def construct_ui(self):
        """ """
        self.experiment.gui_timer.timeout.connect(self.stream_plot.update)
        previous_widget = super().construct_ui()
        previous_widget.layout().setContentsMargins(0, 0, 0, 0)
        self.monitoring_layout.addWidget(previous_widget)
        self.monitoring_layout.setStretch(1, 1)
        self.monitoring_layout.setStretch(0, 1)
        self.camera_splitter.addWidget(self.camera_display)
        self.camera_splitter.addWidget(self.monitoring_widget)
        return self.camera_splitter

    def open_tracking_params_tree(self):
        """ """
        self.track_params_wnd = ParameterTree()
        self.track_params_wnd.addParameters(
            self.experiment.tracking_method.params)
        self.track_params_wnd.addParameters(
            self.experiment.preprocessing_method.params)
        self.track_params_wnd.setWindowTitle("Tracking parameters")

        self.track_params_wnd.show()
Exemple #23
0
class signalRecorder(QMainWindow):
    def __init__(self, settings=''):
        super(signalRecorder, self).__init__()
        ''' Create Parameter Tree'''
        self.settings = settings
        self.parameterTree = ParameterTree()
        self.parameters = {}
        self.widget = QWidget()
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.parameterTree)
        self.exitButton = QPushButton('Exit')
        self.exitButton.clicked.connect(sys.exit)
        self.layout.addWidget(self.exitButton)
        self.widget.setLayout(self.layout)
        self.setCentralWidget(self.widget)
        self.nPVs = 0
        self.show()
        self.initialiseRecorder(self.settings)
        self.start()
        self.windows = {}

    def initialiseRecorder(self, settings):
        self.folder, self.day = currentWorkFolder(createdirectory=True)
        self.sp = striptoolRecord.signalRecorderH5(self.folder +
                                                   "Signal_Archive")
        with open(settings, 'r') as stream:
            settings = yaml.load(stream)
        for types in settings:
            for name, pvs in settings[types].items():
                if 'timer' in pvs:
                    timer = pvs['timer']
                else:
                    timer = 1
                if 'suffix' in pvs:
                    for pv in pvs['suffix']:
                        self.nPVs += 1
                        signalPV(self,
                                 name + ':' + pv,
                                 name.replace('-', '_') + '_' + pv,
                                 types,
                                 color=self.nPVs,
                                 timer=1.0 / timer)
                else:
                    self.nPVs += 1
                    signalPV(self,
                             name,
                             name.replace('-', '_'),
                             types,
                             color=self.nPVs,
                             timer=1.0 / timer)

    def start(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.checkFileName)
        self.timer.start(1000)

    def checkFileName(self):
        if datetime.today().timetuple()[2] is not self.day:
            self.sp.close()
            self.sp.deleteLater()
            self.initialiseRecorder(self.settings)

    def contrasting_text_color(self, color):
        r, g, b, a = pg.colorTuple(pg.mkColor(color))
        return pg.mkBrush(
            '000' if 1 -
            (r * 0.299 + g * 0.587 + b * 0.114) / 255 < 0.5 else 'fff')

    def valueFormatter(self, value):
        return "{:.4}".format(value)

    def addParameterSignal(self, name, group):
        gparams = [{'name': group, 'type': 'group'}]
        params = [{
            'name':
            name,
            'type':
            'group',
            'children': [
                {
                    'name': 'Samples',
                    'type': 'int',
                    'readonly': True
                },
                {
                    'name': 'Mean',
                    'type': 'float',
                    'readonly': True
                },
                {
                    'name': 'Standard Deviation',
                    'type': 'float',
                    'readonly': True
                },
                {
                    'name': 'Max',
                    'type': 'float',
                    'readonly': True
                },
                {
                    'name': 'Min',
                    'type': 'float',
                    'readonly': True
                },
                {
                    'name': 'Plot',
                    'type': 'action'
                },
            ]
        }]
        if not group in self.parameters:
            parameter = Parameter.create(name='params',
                                         type='group',
                                         children=gparams)
            self.parameters[group] = parameter
            self.parameterTree.addParameters(parameter, showTop=False)
            header = self.parameterTree.findItems(
                group, Qt.MatchContains | Qt.MatchRecursive)[0]
            header.setExpanded(False)
        else:
            parameter = self.parameters[group]
        param = parameter.child(group)
        if name not in param.names:
            p = param.addChildren(params)
        pChild = param.child(name)
        self.sp.records[name]['worker'].nsamplesSignal.connect(
            lambda x: pChild.child('Samples').setValue(x))
        self.sp.records[name]['worker'].recordMeanSignal.connect(
            lambda x: pChild.child('Mean').setValue(x))
        self.sp.records[name]['worker'].recordStandardDeviationSignal.connect(
            lambda x: pChild.child('Standard Deviation').setValue(x))
        self.sp.records[name]['worker'].recordMinSignal.connect(
            lambda x: pChild.child('Min').setValue(x))
        self.sp.records[name]['worker'].recordMaxSignal.connect(
            lambda x: pChild.child('Max').setValue(x))
        pChild.child('Plot').sigActivated.connect(
            lambda x: self.showPlot(name=str(name)))
        header = self.parameterTree.findItems(
            name, Qt.MatchContains | Qt.MatchRecursive)[0]
        header.setExpanded(False)
        header.setForeground(
            0, self.contrasting_text_color(self.sp.records[name]['pen']))
        header.setBackground(0, pg.mkBrush(self.sp.records[name]['pen']))

    def showPlot(self, name):
        if not name in self.windows:
            self.windows[name] = plotWindow(sp=self.sp, name=name)
        else:
            self.windows[name].show()
Exemple #24
0
class GlitchExplorerDialog(Parameterized, QtFixes.QDialog):
    _name='Glitch Explorer'

    def __init__(self, parent):
        super(GlitchExplorerDialog, self).__init__(parent)
        self.setWindowTitle("Glitch Explorer")
        self.setMinimumWidth(500)

        self.mainLayout = QVBoxLayout()
        self.mainSplitter = QSplitter(self)
        self.mainSplitter.setOrientation(Qt.Vertical)

        self.tableList = []
        self.tuneParamList = []

        #Add default table
        self.table = QTableWidget(1,1)
        # self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.mainSplitter.addWidget(self.table)

        self.getParams().register()
        self.getParams().addChildren([
            {'name':'Clear Output Table', 'type':'action', 'action':self.clearTable},
            {'name':'Plot Widget', 'type':'action', 'action':self.openPlotWidget},
            {'name':'Reset', 'type':'action', 'action':self.reset, 'tip':"Resets all Tuning Parameters to its minimum value."},
            {'name':'Tuning Parameters', 'key':'numtune', 'type':'int', 'value':0, 'limits':(0, 4), 'action':self.updateParameters, 'readonly':False},
            {'name':'Traces Required', 'key':'tracesreq', 'type':'int', 'value':1, 'limits':(1, 1E99), 'readonly':True, 'children':[
                {'name':'Use this value', 'type':'action', 'action':lambda _: Parameter.setParameter(['Generic Settings', 'Acquisition Settings', 'Number of Traces',self.findParam('tracesreq').getValue()])},
             ]},
            {'name':'Normal Response', 'type':'str', 'key':'normalresp', 'value':'s.startswith("Bad")'},
            {'name':'Successful Response', 'type':'str', 'key':'successresp', 'value':'s.startswith("Welcome")'},

            {'name':'Recordings', 'type':'group', 'expanded':False, 'children':[
                {'name':'Load existing', 'type':'action', 'key':'open', 'action':lambda _:self.loadRecordings()},
                {'name':'Autosave Multi-Capture Results', 'type':'bool', 'key':'saveresults', 'value':True},
                {'name':'Autosaved filename', 'type':'str', 'key':'savefilename', 'value':'', "readonly":True},
                {'name':'Notes', 'type':'text', 'key':'savenotes', 'value':""},
            ]},
        ])

        self.paramTree = ParameterTree()
        self.paramTree.addParameters(self.getParams()._PyQtGraphParameter)
        self.mainSplitter.addWidget(self.paramTree)

        self.statusLabel = QLabel("")

        self.mainSplitter.addWidget(self.statusLabel)

        # self.mainSplitter.setHandleWidth(100)

        self.mainLayout.addWidget(self.mainSplitter)
        self.setLayout(self.mainLayout)
        self.hide()

        #Do an update
        self.table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.table.horizontalHeader().setResizeMode(QHeaderView.Interactive)
        self.clearTable()
        self._campaignRunning = False

    def openPlotWidget(self, _):
        if "Glitch Explorer" not in ResultsBase.registeredObjects:
            ResultsBase.createNew("Scatter Plot", "Glitch Explorer")
        widget = ResultsBase.registeredObjects["Glitch Explorer"]
        widget.raise_()
        widget.yLocked(False)
        self.clearPlotWidget()

    def clearPlotWidget(self):
        widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
        if widget is not None:
            widget.clearPushed()
            widget.setLabels(top="Glitch Map", xaxis=self.tuneParamList[0].name() if len(self.tuneParamList)>0 else "",
                             yaxis=self.tuneParamList[1].name() if len(self.tuneParamList)>1 else "")

    def tuneEnabled(self, status):
        self.findParam('numtune').setReadonly(not status)

    def campaignStart(self, prefixname):
        """Called when acqusition campaign (multi-api) starts, generates filename"""
        self._autosavefname = self.parent().api.project().getDataFilepath(prefixname + "_glitchresults.p", subdirectory="glitchresults")["abs"]
        self._autosavef = None
        self._campaignRunning = True
        self.tuneEnabled(False)
        self.clearPlotWidget()

    def campaignDone(self):
        self._campaignRunning = False
        self.tuneEnabled(True)

        if self._autosavef:
            self._autosavef.close()
            self._autosavef = None
        self.table.setSortingEnabled(True)

    def updateStatus(self):
        okcnt = 0
        for t in self.tableList:
            if t["success"]:
                okcnt += 1

        lbl = "Total %d, Glitches Successful %d" % (len(self.tableList), okcnt)
        self.statusLabel.setText(lbl)

    def reset(self, ignored=None):
        for t in self.tuneParamList:
            t.reset()

    def clearTable(self, ignored=None):
        self.tableList = []
        self.table.clear()
        self.table.setRowCount(0)
        self.table.setColumnCount(0)
        self.updateTableHeaders()
        self.table.resizeColumnsToContents()
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(2, 120)
        self.table.setColumnWidth(3, 80)
        self.table.sortByColumn(3, Qt.DescendingOrder)

    def updateParameters(self, ignored=None):
        numparams = self.findParam('numtune').getValue()

        # Did number change? Adjust if needed
        while numparams < len(self.tuneParamList):
            #Shed parameters
            self.tuneParamList[-1].getParams().delete()
            self.tuneParamList.pop()

        while numparams > len(self.tuneParamList):
            #Add parameters
            #p = Parameter.create(name='Tuning Parameter %d' % len(self.tuneParamList), type='group', children=self.glitchTuneParamTemplate)
            p = TuningParameter(len(self.tuneParamList))
            self.tuneParamList.append(p)
            self.getParams().append(p.getParams())

            # Do stuff
            p.nameChanged.connect(self.updateTableHeaders)
            p.rangeComplete.connect(self.rangeDone)
            p.tracesreqChanged.connect(self.tracesreqChanged)

        self.updateTableHeaders()
        self.tracesreqChanged()
        
    def tracesreqChanged(self, pnum=None, newnum=None):
        treq = 1
        for t in self.tuneParamList:
                treq *= t.tracesrequired
        self.findParam('tracesreq').setValue(treq, ignoreReadonly=True)

    def updateTableHeaders(self, ignored=None, ignoredmore=None, override=None):
        headerlist = ["Status", "Sent", "Received", "Date"]

        if override is not None:
            for c in override:
                headerlist.append(c)
        else:
            for t in self.tuneParamList:
                headerlist.append(t.name())

        self.table.setColumnCount(len(headerlist))
        self.table.setHorizontalHeaderLabels(headerlist)

    def rangeDone(self, pnum):
        if (pnum + 1) < len(self.tuneParamList):
            self.tuneParamList[pnum + 1].findNewValue()

    def traceDone(self):
        """ Single api done """

        # TODO: Improve how looping is done
        if len(self.tuneParamList) > 0:
            # Always increment lowest, triggers upper values
            # try:
                self.tuneParamList[0].findNewValue()
            # except Exception as e:
            #     raise StopIteration(e)

    def appendToTable(self, newdata):
        """ Append a result to the display table """

        try:
            self.table.setSortingEnabled(False)
            self.table.insertRow(0)

            outdata = QTableWidgetItem(repr(newdata["output"]))
            if newdata["success"]:
                color = Qt.green
                status = "Success"
            elif newdata["normal"] == False:
                color = Qt.red
                status = "Failed"
            else:
                color = Qt.white
                status = "Normal"

            outdata.setBackground(color)
            self.table.setItem(0, 0, QTableWidgetItem(status))
            self.table.setItem(0, 1, QTableWidgetItem(""))
            self.table.setItem(0, 2, outdata)
            self.table.setItem(0, 3, QTableWidgetItem(newdata["date"].strftime('%H:%M:%S')))
            for i, v in enumerate(newdata["settings"]):
                self.table.setItem(0, 4 + i, QTableWidgetItem(str(v)))

            self.table.resizeRowToContents(0)

            widget = ResultsBase.registeredObjects.get("Glitch Explorer", None)
            if widget is not None:
                widget.plot([newdata["settings"][0] if len(newdata["settings"])>0 else 0],
                    [newdata["settings"][1] if len(newdata["settings"])>1 else 0],
                     ((0, 255, 0, 75) if status=="Success" else
                     (255, 0, 75) if status=="Failed" else
                     (200, 200, 200, 50)), str(newdata["settings"]))

        except AttributeError as e:
            raise StopIteration("Error when adding data to the table. Plese clear it and try again. Details:" + str(e))

    def addResponse(self, resp):
        """ Add a response from the system to glitch table + logs """

        normeval = self.findParam('normalresp').getValue()
        succeval = self.findParam('successresp').getValue()

        if len(normeval) > 0:
            #Check if Normal
            normresult = eval(normeval, {'s':resp}, {})
        else:
            normresult = False

        #Check if Successful
        if len(succeval) > 0:
            #Check if Normal
            succresult = eval(succeval, {'s':resp}, {})
        else:
            succresult = False

        #Check ?
        if not isinstance(normresult, bool):
            raise ValueError("Result of 'normal' eval() not a bool, got %s (result: %s)" % (type(normresult), normresult))

        if not isinstance(succresult, bool):
            raise ValueError("Result of 'success' eval() not a bool, got %s (result: %s)" % (type(succresult), succresult))

        if normresult and succresult:
            logging.warning('Both normresult and succresult True!')

        starttime = datetime.now()

        respstr = str(bytearray(resp.encode('utf-8')))
        # respstr = ' '.join(["%02x" % t for t in bytearray(resp)])

        settingsList = []
        for i in range(0, len(self.tuneParamList)):
            try:
                settingsList.append(Parameter.getParameter(self.tuneParamList[i].paramScript))
            except:
                raise StopIteration("Choose a valid Parameter Path for Tuning Parameter \"%s\" . Got: %s" % (self.tuneParamList[i].name(), self.tuneParamList[i].paramScript))
        newdata = {"input":"", "output":respstr, "normal":normresult, "success":succresult, "settings":settingsList, "date":starttime}

        self.tableList.append(newdata)
        self.appendToTable(newdata)
        self.updateStatus()

        if self._campaignRunning and self.findParam(["Recordings","saveresults"]).getValue():
            if self._autosavef is None:
                # File previously not open
                try:
                    self._autosavef = open(self._autosavefname, "w")
                except Exception as e:
                    self.findParam(["Recordings","saveresults"]).setValue(False)
                    raise Warning("Could not save recordings to file: %s. Reason: %s. Disabling it in order to continue." % (self._autosavefname, str(e)))
                self.findParam(["Recordings",'savefilename']).setValue(self._autosavefname, ignoreReadonly=True)

                # Add notes
                pickle.dump({"notes":self.findParam(["Recordings",'savenotes']).getValue()}, self._autosavef)

                # Add headers
                cmds = [self.tuneParamList[i].findParam('parampath').getValue() for i in range(0, len(self.tuneParamList))]
                pickle.dump({"commands":cmds}, self._autosavef)

            # Add data
            pickle.dump({"data":newdata}, self._autosavef)

    def loadRecordings(self, fname=None):
        if fname == None:
            fname, _ = QFileDialog.getOpenFileName(self, 'Open file', QSettings().value("open_glitch_file"),'*.p')

        if fname:
            self.clearTable()
            file = open(fname, 'r')
            self.findParam(["Recordings",'savenotes']).setValue(pickle.load(file)['notes'])
            self.updateTableHeaders(override=pickle.load(file)['commands'])
            while 1:
                try:
                    self.appendToTable(pickle.load(file)['data'])
                except EOFError:
                    break
            file.close()
Exemple #25
0
                setPiYAmp(newVal)
            elif paramName == 'piZ Amp':
                setPiZAmp(newVal)


topPT.addChildren(expParDef)
topPT.addChildren(graphParDef)
topPT.addChildren(expControlDef)
#topPT.sigTreeStateChanged.connect(paramChanged)
expPT = topPT.child('Experiment')
expPT.sigTreeStateChanged.connect(expParamChanged)
contPT = topPT.child('Other')
contPT.sigTreeStateChanged.connect(controlParamChanged)
graphPT = topPT.child('Graphing')
graphPT.sigTreeStateChanged.connect(graphingParamChanged)
paramTree.addParameters(topPT)


def paramObjToBunch(paramObj=topPT):
    if paramObj.value() is not None:
        return paramObj.value()
    else:
        return Munch(
            **{child.name(): paramObjToBunch(child)
               for child in paramObj})


def updateParamObjFromBunch(bunch, pObj=expPT):
    """ Convert the experiment parameter tree to a Bunch as used by the experiment"""
    #Check if bunch is not actually a bunch
    if not isinstance(bunch, dict):  #it's not a bunch, it's just a value