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
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)
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
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)
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)
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)
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)
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
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
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)
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()
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)
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
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
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)
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()
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()
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()
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