class CaseList(QWidget): def __init__(self): QWidget.__init__(self) addHelpToWidget(self, "init/case_list") layout = QVBoxLayout() self._list = QListWidget(self) self._list.setMinimumHeight(100) self._list.setMaximumHeight(250) self._default_selection_mode = self._list.selectionMode() self.setSelectable(False) layout.addWidget(QLabel("Available Cases:")) layout.addWidget(self._list) self._addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem, horizontal=True) self._addRemoveWidget.enableRemoveButton(False) layout.addWidget(self._addRemoveWidget) self._title = "New keyword" self._description = "Enter name of keyword:" self.setLayout(layout) ERT.ertChanged.connect(self.updateList) self.updateList() def setSelectable(self, selectable): if selectable: self._list.setSelectionMode(self._default_selection_mode) else: self._list.setSelectionMode(QAbstractItemView.NoSelection) def addItem(self): dialog = ValidatedDialog("New case", "Enter name of new case:", getAllCases()) new_case_name = dialog.showAndTell() if not new_case_name == "": selectOrCreateNewCase(new_case_name) def removeItem(self): message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def updateList(self): """Retrieves data from the model and inserts it into the list""" case_list = getAllCases() self._list.clear() for case in case_list: self._list.addItem(case)
class OWMoleculeVisualizer(OWWidget): settingsList = ["colorFragmets", "showFragments"] contextHandlers = { "": DomainContextHandler("", [ ContextField("selected_title_indices"), ContextField("moleculeTitleAttributeList", (DomainContextHandler.List + DomainContextHandler.SelectedRequired + DomainContextHandler.IncludeMetaAttributes), selected="selectedMoleculeTitleAttrs"), ContextField( "smiles_var", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes) ], maxAttributesToPickle=1000) } def __init__(self, parent=None, signalManager=None, title="Molecule visualizer"): super(OWMoleculeVisualizer, self).__init__(parent, signalManager, title) self.colorFragments = 1 self.showFragments = 0 self.selectedFragment = "" self.moleculeSmiles = [] self.fragmentSmiles = [] self.defFragmentSmiles = [] self.smiles_var = 0 self.moleculeTitleAttr = 0 self.moleculeTitleAttributeList = [] self.selectedMoleculeTitleAttrs = [] self.fragmentSmilesAttr = 0 self.imageSize = 200 self.numColumns = 4 self.commitOnChange = 0 ## GUI box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True) self.infoLabel = OWGUI.label(box, self, "Chemicals:") box = OWGUI.radioButtonsInBox(self.controlArea, self, "showFragments", ["Show molecules", "Show fragments"], "Show", callback=self.updateitems) self.showFragmentsRadioButton = box.buttons[-1] self.markFragmentsCheckBox = OWGUI.checkBox(box, self, "colorFragments", "Mark fragments", callback=self._update) box.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) OWGUI.separator(self.controlArea) self.moleculeSmilesCombo = OWGUI.comboBox(self.controlArea, self, "smiles_var", "Molecule SMILES Attribute", callback=self.updateitems) self.moleculeSmilesCombo.box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) self.smiles_var_model = VariableListModel(parent=self) self.moleculeSmilesCombo.setModel(self.smiles_var_model) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Molecule Title Attributes", addSpace=True) self.title_var_view = QListView( selectionMode=QListView.ExtendedSelection) self.title_var_model = VariableListModel(parent=self) self.title_var_view.setModel(self.title_var_model) self.title_var_view.selectionModel().selectionChanged.connect( self._title_selection_changed) box.layout().addWidget(self.title_var_view) OWGUI.separator(self.controlArea) self.fragmentSmilesCombo = OWGUI.comboBox( self.controlArea, self, "fragmentSmilesAttr", "Fragment SMILES Attribute", callback=self.updateFragmentsListBox) self.fragmentSmilesCombo.setModel(VariableListModel(parent=self)) self.fragmentSmilesCombo.box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) OWGUI.separator(self.controlArea) box = OWGUI.spin(self.controlArea, self, "imageSize", 50, 500, 10, box="Image Size", callback=self._image_size_changed) box.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Selection", addSpace=True) OWGUI.checkBox(box, self, "commitOnChange", "Commit on change") self.selectMarkedMoleculesButton = OWGUI.button( box, self, "Select &matched molecules", self.select_marked) OWGUI.button(box, self, "&Commit", callback=self.commit, default=True) OWGUI.separator(self.controlArea) OWGUI.rubber(self.controlArea) spliter = QSplitter(Qt.Vertical) self.scrollArea = ScrollArea(spliter) self.grid = GridWidget() self.grid.selectionChanged.connect(self._on_selection_changed) self.scrollArea.setWidget(self.grid) self.scrollArea.setWidgetResizable(True) self.mainArea.layout().addWidget(spliter) if pybel: self.listBox = QListWidget(spliter) else: self.listBox = QListWidget(None) self.listBox.setHidden(True) self.listBox.itemClicked.connect(self.fragmentSelection) self.fragmentSmilesCombo.box.setDisabled(not pybel) self.data = None self.data_subset = [] self.fragment_data = None self.resize(800, 600) self.listBox.setMaximumHeight(150) self.fragmentSmilesCombo.setDisabled(True) self.selectMarkedMoleculesButton.setDisabled(True) self.markFragmentsCheckBox.setDisabled(True) self.showFragmentsRadioButton.setDisabled(True) self.loadSettings() if not pybel: self.showFragments = 0 self.warning( 10, "Pybel module not installed. To view molecule fragments\n" "please install openbabel python extension.") self.__loop = None def setMoleculeTable(self, data): self.closeContext() self.clear() self.data = data if data is not None: all_vars = data.domain.variables + data.domain.get_metas().values() text_vars = filter( lambda v: isinstance(v, (Orange.feature.Discrete, Orange. feature.String)), all_vars) var_scored = score_smiles_variables(data, text_vars) self.smiles_var_model[:] = [var for var, _ in var_scored] self.smiles_var = max(range(len(var_scored)), key=lambda i: var_scored[i][1]) self.title_var_model[:] = all_vars self.setFragmentSmilesCombo() self.updateFragmentsListBox() if self.data_subset: try: self.data_subset = self.data_subset.select( self.data.domain) except Exception: self.data_subset = [] self.openContext("", data) else: self.defFragmentSmiles = [] if not self.fragmentSmilesAttr: self.listBox.clear() self.openContext("", data) self.send("Selected Molecules", None) def setMoleculeSubset(self, data): self.data_subset = data try: self.data_subset = self.data_subset.select(self.data.domain) except Exception: self.data_subset = [] def setFragmentTable(self, data): self.fragment_data = data if data is not None: self.setFragmentSmilesCombo() self.updateFragmentsListBox() self.selectedFragment = "" else: self.setFragmentSmilesCombo() self.updateFragmentsListBox() self.fragmentSmilesCombo.setEnabled(data is not None) def handleNewSignals(self): self.updateitems() def clear(self): self.smiles_var_model[:] = [] self.title_var_model[:] = [] self.fragmentSmilesCombo.clear() self.grid.clear() self._widgets = [] self._items = [] if self.__loop is not None: self.__loop.close() self.__loop = None def cleargrid(self): self.grid.clear() self._widgets = [] def _update_titles(self): if self.data is None: return title_vars = [ self.title_var_model[ind.row()] for ind in self.title_var_view.selectedIndexes() ] for item, widget in zip(self._items, self._widgets): inst = self.data[item.index] text = " / ".join(map(str, (inst[var] for var in title_vars))) widget.label.setText(text) def setFragmentSmilesCombo(self): if self.fragment_data: candidates = score_smiles_variables(self.fragment_data) else: candidates = [] self.fragmentSmilesCombo.model()[:] = [v for v, _ in candidates] if self.fragmentSmilesAttr > len(candidates): self.fragmentSmilesAttr = 0 def updateFragmentsListBox(self): if pybel is None: return fragvars = self.fragmentSmilesCombo.model() if 0 <= self.fragmentSmilesAttr < len(fragvars): fvar = fragvars[self.fragmentSmilesAttr] else: fvar = None if fvar: frags = [ str(e[fvar]) for e in self.fragment_data if not e[fvar].is_special() ] self.fragmentSmiles = [""] + frags else: self.fragmentSmiles = [""] + self.defFragmentSmiles self.listBox.clear() self.listBox.addItems(self.fragmentSmiles) self.showFragmentsRadioButton.setDisabled( len(self.fragmentSmiles) == 1) self.markFragmentsCheckBox.setDisabled(len(self.fragmentSmiles) == 1) self.selectMarkedMoleculesButton.setDisabled(True) def fragmentSelection(self, item): if pybel is None: return index = self.listBox.indexFromItem(item).row() if index == -1: index = 0 self.selectedFragment = self.fragmentSmiles[index] self.selectMarkedMoleculesButton.setEnabled(bool( self.selectedFragment)) self.markFragmentsCheckBox.setEnabled(bool(self.selectedFragment)) if not self.showFragments and self.colorFragments: self._update() def _title_text(self, index): title_vars = [ self.title_var_model[ind.row()] for ind in self.title_var_view.selectedIndexes() ] inst = self.data[index] return " / ".join(map(str, (inst[var] for var in title_vars))) def _items_from_var(self, var): if self.data is None: return None values = [(i, str(inst[var])) for i, inst in enumerate(self.data) if not inst[var].is_special()] return [ Item(i, smiles, *self._parse_smiles(smiles)) for i, smiles in values ] def _parse_smiles(self, smiles): try: return (OK, molecule_from_smiles(smiles)) except Exception: return (ParseError, None) def updateitems(self): if self.showFragments and self.fragmentSmiles: values = [(None, frag) for frag in self.fragmentSmiles[1:]] items = [ Item(i, smiles, *self._parse_smiles(smiles)) for i, smiles in values ] else: smilesvar = self.smiles_var_model[self.smiles_var] items = self._items_from_var(smilesvar) self._items = items self.setupgrid() def setupgrid(self): self.cleargrid() layout = self.grid widgets = [] for item in self._items: thumb = ThumbnailWidget(self.grid) thumb.setImageSize(self.imageSize, self.imageSize) if item.index is not None: text = self._title_text(item.index) else: text = "" thumb.label.setText(text) widgets.append(thumb) layout.appendWidget(thumb) self._widgets = widgets self.infoLabel.setText("Chemicals %i" % len(self._items)) self._update() def __update_items(self, items, widgets, pattern=None): for i, item, widget in zip(range(len(items)), items, widgets): if item.status != ParseError: if pattern is not None: emb = substructure_embedding(item.molecule, pattern) emb = reduce(list.__iadd__, emb, []) svg = molecule_to_svg_with_substructure(item.molecule, emb) else: svg = molecule_to_svg(item.molecule) else: svg = "" widget.setData(svg) widget.setEnabled(True) yield i * 100.0 / len(items) def _update(self): if self.showFragments and self.fragmentSmiles: loop = self.__update_items(self._items, self._widgets) elif self.colorFragments and self.selectedFragment: pattern = pybel.Smarts(self.selectedFragment) loop = self.__update_items(self._items, self._widgets, pattern) else: loop = self.__update_items(self._items, self._widgets) self.__schedule(loop) def __schedule(self, coroutine): if self.__loop is not None: self.progressBarFinished() self.__loop.close() self.__loop = None self.__loop = coroutine self.progressBarInit() QTimer.singleShot(0, self.__loop_update) @Slot() def __loop_update(self): if self.__loop is None: return try: progress = next(self.__loop) except StopIteration: self.__loop = None self.progressBarFinished() else: self.progressBarSet(progress) QTimer.singleShot(0, self.__loop_update) def _title_selection_changed(self): self._update_titles() def _image_size_changed(self): for widget in self._widgets: widget.setImageSize(self.imageSize, self.imageSize) self.grid.layout().invalidate() def select_marked(self): if not pybel: return if not self.showFragments: pattern = pybel.Smarts(self.selectedFragment) for item, widget in zip(self._items, self._widgets): if item.status != ParseError: emb = substructure_embedding(item.molecule, pattern) widget.setSelected(bool(emb)) else: widget.setSelected(False) if self.commitOnChange: self.commit() def _on_selection_changed(self): if self.commitOnChange: self.commit() def commit(self): if self.showFragments: svar = self.smiles_var_model[self.smiles_var] items = self._items_from_var(svar) frags = [ item for item, w in zip(self._items, self._widgets) if w.selected ] patterns = [pybel.Smarts(item.smiles) for item in frags] def test(molecule, patterns): return any( bool(substructure_embedding(molecule, patt)) for patt in patterns) matched = filter( lambda item: item.status != ParseError and test( item.molecule, patterns), items) instances = [self.data[item.index] for item in matched] if instances: table = Orange.data.Table(instances) self.send("Selected Molecules", table) else: self.send("Selected Molecules", None) else: items = [ item for item, w in zip(self._items, self._widgets) if w.selected ] instances = [self.data[item.index] for item in items] if instances: table = Orange.data.Table(instances) self.send("Selected Molecules", table) else: self.send("Selected Molecules", None) def onDeleteWidget(self): OWWidget.onDeleteWidget(self) if self.__loop is not None: self.__loop.close() self.__loop = None
class MainWindow(QMainWindow): """The main window widget for the program. """ def __init__(self, parent=None): super(MainWindow, self).__init__(parent) #### 1 CREATE AND INITIALIZE DATA STRUCTURES #### self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} # Y selector on Left self.ySelector = QListWidget() ySelectorLabel = QLabel("y axis channel") self.ySelector.setMaximumWidth(ySelectorLabel.sizeHint().width()) # File name and plot in the middle self.sourceFileName = QLabel("None") self.sourceFileName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sourceFileLabel = QLabel("current file") sourceFileLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) # Matplotlib canvas fig = Figure(dpi=100) self.canvas = FigureCanvas(fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) mpl_toolbar = NavigationToolbar(self.canvas, self.canvas) self.axes = fig.add_subplot(111) # X selector on bottom self.xSelector = QListWidget() self.xSelector.addItem("Time") self.xSelector.setFlow(0) xSelectorLabel = QLabel("x axis channel") self.xSelector.setMaximumHeight(self.xSelector.sizeHintForColumn(0)) # Offset and parameter widgets on the right top self.offsetThing = OffsetWidget() self.attributesThing = AttributesWidget() # Save channel on right bottom self.save_chan_chkbx = QCheckBox() save_chan_label = QLabel("Save Channel") # Status bar at the bottom self.fileSizeLabel = QLabel("File Size: {f_size:0>7.3f} MB".format(f_size=0.0)) self.fileSizeLabel.setFixedWidth(self.fileSizeLabel.sizeHint().width()+10) self.fileSizeLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.yChanLength = QLabel("Y Channel Length: {y_len:0>7.0f}".format(y_len=0.0)) self.yChanLength.setFixedWidth(self.yChanLength.sizeHint().width()+10) self.yChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.xChanLength = QLabel("X Channel Length: {x_len:0>7.0f}".format(x_len=0.0)) self.xChanLength.setFixedWidth(self.xChanLength.sizeHint().width()+10) self.xChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.fileSizeLabel) status.addPermanentWidget(self.yChanLength) status.addPermanentWidget(self.xChanLength) status.showMessage("Ready", 5000) #2 Create the central widget self.centralWidget = QWidget() # Left Side selectorLayout = QVBoxLayout() #selectorLayout.addWidget(xSelectorLabel) #selectorLayout.addWidget(self.xSelector) selectorLayout.addWidget(ySelectorLabel) selectorLayout.addWidget(self.ySelector) selectorLayout.addStretch() # Center centralLayout = QVBoxLayout() fileNameLayout = QHBoxLayout() xSelectorLayout = QHBoxLayout() fileNameLayout.addWidget(sourceFileLabel) fileNameLayout.addWidget(self.sourceFileName) xSelectorLayout.addWidget(xSelectorLabel) xSelectorLayout.addWidget(self.xSelector) centralLayout.addLayout(fileNameLayout) centralLayout.addWidget(self.canvas) centralLayout.addWidget(mpl_toolbar) centralLayout.addLayout(xSelectorLayout) # Right bottom save_chan_layout = QHBoxLayout() save_chan_layout.addWidget(self.save_chan_chkbx) save_chan_layout.addWidget(save_chan_label) # Right Side rightLayout = QVBoxLayout() rightLayout.addWidget(self.offsetThing) rightLayout.addWidget(self.attributesThing) rightLayout.addStretch() rightLayout.addLayout(save_chan_layout) layout = QHBoxLayout() layout.addLayout(selectorLayout) layout.addLayout(centralLayout) layout.addLayout(rightLayout) self.centralWidget.setLayout(layout) self.setCentralWidget(self.centralWidget) self.resize(self.sizeHint()) #3 Create and set up any dock windows #4 Create actions and insert them into menus and toolbars fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "exit", "Close the application") fileOpenAction = self.createAction("&Open TDMS File", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing TDMS file") fileExportAction = self.createAction("&Export", self.exprtToHDF5, "Ctrl+E", tip="Export the TDMS data to HDF5") self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileOpenAction, fileExportAction, fileQuitAction) #self.addActions(self.fileMenu, self.fileMenuActions) self.xSelector.itemSelectionChanged.connect(self.make_x_selection) self.ySelector.itemSelectionChanged.connect(self.make_y_selection) self.offsetThing.new_offset.connect(self.subtract_offset) self.fileMenu.triggered.connect(self.update_file_menu) self.save_chan_chkbx.stateChanged.connect(self.toggle_save) #5 Read in application's settings settings = QSettings() # Restore the geometry and state of the main window from last use #self.restoreGeometry(settings.value("MainWindow/Geometry")) #self.restoreState(settings.value("MainWindow/State")) self.setWindowTitle("TDMS to HDF5 Converter") self.recentFiles = settings.value("RecentFiles") if not self.recentFiles: self.recentFiles = [] self.update_file_menu() def update_ui(self): pass def initVariables(self): self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): # Create the action action = QAction(text, self) # Give it its icon if icon is not None: action.setIcon(QIcon(":/{icon}.png".format(icon=icon))) # Give it its shortcut if shortcut is not None: action.setShortcut(shortcut) # Set up its help/tip text if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) # Connect it to a signal if slot is not None: self.connect(action, SIGNAL(signal), slot) # Make it checkable if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def update_file_menu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = self.filename if self.filename is not None else None recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction("&{num} {name}".format(num=i+1, name=QFileInfo(fname).fileName()), self) action.setData(fname) action.triggered.connect(lambda: self.loadFile(fname)) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileOpen(self): # Process 1 self.initVariables() basedir = os.path.dirname(self.filename) if self.filename is not None \ else "~/Documents/PhD/root/raw-data/sio2al149/CryoMeasurement" formats = "TDMS files (*.tdms)" fname = QFileDialog.getOpenFileName(self, "Open a TDMS File", basedir, formats) # Process 1.1 Collect file name if fname and QFile.exists(fname): self.loadFile(fname) def loadFile(self, fname): # Process 1.2 Generate TDMS file object self.add_recent_file(fname) self.tdms_file_object = TdmsFile(fname) self.filename = fname # Process 1.3 Read data into local structure if self.tdms_file_object: # Process 1.3.0 Generate group list group_list = self.tdms_file_object.groups() # Processes 1.3.1 through 1.3.3 Sort TDMS data for group in group_list: self.sortTDMSGroupData(group) message = "Loaded {f_name}".format(f_name=os.path.basename(fname)) self.sourceFileName.setText(os.path.basename(fname)) # Process 2.1 Populate channel selection lists self.update_selectors() else: message = "Failed to load {f_name}".format(f_name=os.path. basename(fname)) self.statusBar().showMessage(message, 5000) fsize = os.path.getsize(self.filename) self.fileSizeLabel.setText("File Size: {file_size:>7.3f} MB".format(file_size=fsize/1E6)) #TODO self.updateStatus(message) # see Rapid GUI ch06.pyw def add_recent_file(self, fname): if fname is None: return if not fname in self.recentFiles: self.recentFiles.insert(0, fname) while len(self.recentFiles) > 9: self.recentFiles.pop() def sortTDMSGroupData(self, group): # Process 1.3 Sort Group data # Process 1.3.1 Get <Group> Channels group_props = self.tdms_file_object.object(group).properties # Process 1.3.2 Get <Group> Properties group_chans = self.tdms_file_object.group_channels(group) # Process 1.3.3 Create a new channel in the registry for each channel # in the group for chan in group_chans: chan_name = chan.path.split('/')[-1].strip("'") # Process 1.3.3.1 Generate new channel object and fill with data # Some of the TDMS channels were created, but never populated with # data. The following weeds those out. try: new_chan = Channel(chan_name, device=group, meas_array=chan.data) except TypeError: self.statusBar().showMessage("Channel {chan} in {dev} has no data" .format(chan=chan_name, dev=group), 5000) try: new_chan.set_start_time(chan.property("wf_start_time")) new_chan.set_delta_time(chan.property("wf_increment")) new_chan.set_location('raw/{c2_name}'.format(c2_name=chan_name)) if chan_name not in ['TCap', 'xMagnet']: new_chan.set_write() # Some of the channel-specific properties were actually # saved in the group object's properties list. # We retrieve those here. # Process 1.3.3.2 Resort the group properties of TDMS ADWin if group == "ADWin": for atr_name in ADWIN_DICT[chan_name]: try: new_chan.attributes[atr_name] = \ group_props[atr_name] except KeyError: #print('The key {a_name} was not found.' # .format(a_name=atr_name)) #print('The keys available are\n') #print(group_props) pass # Process 1.3.3.3 Add new channel to the registry self.channel_registry[chan_name] = new_chan #print('\tChannel name:\t{ch_name}'.format(ch_name=chan_name)) except (KeyError, UnboundLocalError): pass #print('Error: Was unable to load {c3_name}' # .format(c3_name=chan_name)) def update_selectors(self): # Clear the selectors self.xSelector.clear() self.ySelector.clear() # Add the names of the channels in the registry to both selectors for key in self.channel_registry.keys(): self.xSelector.addItem(key) self.ySelector.addItem(key) # Add the time "channel" to the x selector self.xSelector.addItem('Time') # Sort the lists (alphabetically) otherwise the order constantly changes self.xSelector.sortItems() self.ySelector.sortItems() # Set the current x selector default default_x_item = self.xSelector.findItems(DEFAULTX, Qt.MatchExactly) self.xSelector.setCurrentItem(default_x_item[0]) # Set the current y selector default try: default_y_item = self.ySelector.findItems(DEFAULTY, Qt.MatchExactly) self.ySelector.setCurrentItem(default_y_item[0]) except IndexError: self.ySelector.setCurrentRow(0) self.xSelector.setMinimumHeight(self.xSelector.sizeHintForRow(0)*3) self.ySelector.setMinimumWidth(self.ySelector.sizeHintForColumn(0)+10) def exprtToHDF5(self): # Process 5 Save to HDF5 fname = self.filename.split('.')[0] + '.hdf5' basedir = "/home/chris/Documents/PhD/root/data/sio2al149/cryo_measurement" if not os.path.exists(basedir): os.makedirs(basedir) formats = "TDMS files (*.hdf5 *.h5 *.he5 *.hdf)" dialog = QFileDialog() dialog.setFilter(formats) dialog.setDefaultSuffix("*.hdf5") dialog.selectFile(os.path.join(basedir, fname)) dialog.setDirectory(basedir) if dialog.exec_(): fname = dialog.selectedFiles() else: return # Process 5.1 Create HDF5 file object hdf5_file_object = h5py.File(fname[0]) # Process 5.2 Create channels at their locations for chan in self.channel_registry: chan_obj = self.channel_registry[chan] chan_name = chan #print(chan, self.channel_registry[chan].location, # self.channel_registry[chan].write_to_file) # Process 5.2.1 Write channel data if self.channel_registry[chan].write_to_file: dset = hdf5_file_object.create_dataset(chan_obj.location, data=chan_obj.data) # Process 5.2.2 Write channel attributes for attr_name in self.channel_registry[chan].attributes: attr_value = self.channel_registry[chan].attributes[attr_name] # Convert the datetime format to a string if type(attr_value) is datetime: attr_value = attr_value.isoformat() # There's currently a wierd bug when dealing with python3 # strings. # This gets around that if type(attr_value) is str: #attr_value = attr_value.encode('utf-8') #attr_value = np.string_(attr_value, dtype="S10") attr_value = np.string_(attr_value) dset.attrs.create(attr_name, attr_value) # Process 5.3 Write data to file hdf5_file_object.flush() hdf5_file_object.close() def make_x_selection(self): self.x_change = True # Get the name of the newly selected channel self.xSelection = self.xSelector.currentItem().text() # Get the axis label self.xLabel = self.gen_axis_label(self.xSelection) # If the xSelection is time, use the time data instead of measurement # data if self.xSelection == 'Time': try: self.xArray = self.channel_registry[self.ySelection].time except KeyError: self.xArray = np.array([]) else: self.xArray = self.channel_registry[self.xSelection].data if self.yLabel: self.plotData() self.xSelection_old = self.xSelector.currentItem() self.x_change = False self.xChanLength.setText("X Channel Length: {x_len:>7.0f}".format(x_len=len(self.xArray))) def make_y_selection(self, offset=0.0): self.y_change = True # Get the names of the selected channels from the selectors try: self.ySelection = self.ySelector.currentItem().text() except AttributeError: self.ySelection = DEFAULTY # Set save channel checkbox state self.save_chan_chkbx.setChecked(self.channel_registry[self.ySelection] .write_to_file) # Get the axis label self.yLabel = self.gen_axis_label(self.ySelection) # Generate the y-channel array to be plotted self.yArray = self.channel_registry[self.ySelection].data - offset # Update the attributes view self.attributesThing.clear_attributes() self.attributesThing.select_chan(self.channel_registry[self.ySelection]) if self.xSelection == 'Time': self.make_x_selection() else: self.plotData() self.ySelection_old = self.ySelector.currentItem() self.y_change = False self.yChanLength.setText("Y Channel Length: {y_len:>7.0f}".format(y_len=len(self.yArray))) def gen_axis_label(self, chan_name): # Generate the axis labels based on the selected channels # Cycle through the labes in the AXESLABELS dictionary for axlbl in AXESLABELS.keys(): # Cycle through the channel names in each label's dictionary entry for cn in AXESLABELS[axlbl]: # If a channel equals one of the selections, save the label if chan_name == cn: label = axlbl return label def plotData(self): # Clear the plot self.axes.cla() # Turn on the grid self.axes.grid(True) # Set the labels try: self.axes.set_xlabel(self.xLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.xSelection), 5000) try: self.axes.set_ylabel(self.yLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.ySelection), 5000) # Try plotting the data. There are still no checks in place to make sure # the arrays are of the same length. try: # Plot the data and label it self.axes.plot(self.xArray, self.yArray, label=self.ySelection) # Show the legend self.axes.legend(loc=0) # Draw everything self.canvas.draw() except ValueError: QMessageBox.warning(self, "Unequal Arrays", "{y_chan} and {x_chan} " .format(y_chan=self.ySelection, x_chan=self.xSelection) + \ "are not the same length!") if self.x_change: self.xSelector.setCurrentItem(self.xSelection_old) elif self.y_change: self.ySelector.setCurrentItem(self.ySelection_old) def subtract_offset(self): "Subtract the offset entered from the currently selected y channel." offset = self.offsetThing.offset_entry.value() self.make_y_selection(offset=offset) def toggle_save(self): self.channel_registry[self.ySelection].write_to_file = \ self.save_chan_chkbx.isChecked() def create_new_channel(self, ch_name): "Create a new channel in the registry." #print(ch_name) pass def closeEvent(self, event): """Reimplementation of the close even handler. We have to reimplement this because not all close actions, e.g. clicking the X button, call the close() method. We want to catch this so we can give the user the opportunity to save unsaved changes before the program exits. """ settings = QSettings() #settings.setValue("MainWindow/Geometry", QVariant( # self.saveGeometry())) #settings.setValue("MainWindow/State", QVariant( # self.saveState())) if self.recentFiles: recentFiles = self.recentFiles else: recentFiles = [] settings.setValue("RecentFiles", recentFiles)
class KeywordList(HelpedWidget): """Shows a list of keywords. The data structure expected and sent to the getter and setter is an array of values.""" def __init__(self, model, list_label="", help_link=""): HelpedWidget.__init__(self, list_label, help_link) assert isinstance(model, ListModelMixin) self.model = model self.keyword_list = [] self.list = QListWidget(self) self.list.setMinimumHeight(100) self.list.setMaximumHeight(150) self.default_selection_mode = self.list.selectionMode() self.addWidget(self.list) self.addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem) self.addWidget(self.addRemoveWidget) self.title = "New keyword" self.description = "Enter name of keyword:" self.model.observable().attach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged) self.modelChanged() def setSelectable(self, selectable): if selectable: self.list.setSelectionMode(self.default_selection_mode) else: self.list.setSelectionMode(QAbstractItemView.NoSelection) def setPopupLabels(self, title, description): """Change the labels of the default popup.""" self.title = title self.description = description def newKeywordPopup(self, keyword_list): """ Pops up a message box asking for a new keyword. Override this and return a string to customize the input dialog - Empty string equals canceled. The provided list are the already defined keywords """ new_keyword, ok = QInputDialog.getText(self, self.tr(self.title), self.tr(self.description), QLineEdit.Normal) if ok: return str(new_keyword).strip() else: return "" def addItem(self): """Called by the add button to insert a new keyword""" new_keyword = self.newKeywordPopup(self.keyword_list) if not new_keyword == "": self.model.addItem(new_keyword) def removeItem(self): """Called by the remove button to remove a selected keyword""" if not self.list.currentItem() is None: row = self.list.currentRow() try: self.model.removeItem(self.keyword_list[row]) except NotImplementedError: message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def modelChanged(self): """Retrieves data from the model and inserts it into the list""" keywords = self.model.getList() self.list.clear() self.keyword_list = keywords for keyword in keywords: self.list.addItem(keyword)
class KeywordList(HelpedWidget): """Shows a list of keywords. The data structure expected and sent to the getter and setter is an array of values.""" def __init__(self, model, list_label="", help_link=""): HelpedWidget.__init__(self, list_label, help_link) assert isinstance(model, ListModelMixin) self.model = model self.keyword_list = [] self.list = QListWidget(self) self.list.setMinimumHeight(100) self.list.setMaximumHeight(150) self.default_selection_mode = self.list.selectionMode() self.addWidget(self.list) self.addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem) self.addWidget(self.addRemoveWidget) self.title = "New keyword" self.description = "Enter name of keyword:" self.model.observable().attach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged) self.modelChanged() def setSelectable(self, selectable): if selectable: self.list.setSelectionMode(self.default_selection_mode) else: self.list.setSelectionMode(QAbstractItemView.NoSelection) def setPopupLabels(self, title, description): """Change the labels of the default popup.""" self.title = title self.description = description def newKeywordPopup(self, keyword_list): """ Pops up a message box asking for a new keyword. Override this and return a string to customize the input dialog - Empty string equals canceled. The provided list are the already defined keywords """ new_keyword, ok = QInputDialog.getText(self, self.tr(self.title), self.tr(self.description), QLineEdit.Normal) if ok: return str(new_keyword).strip() else: return "" def addItem(self): """Called by the add button to insert a new keyword""" new_keyword = self.newKeywordPopup(self.keyword_list) if not new_keyword == "": self.model.addItem(new_keyword) def removeItem(self): """Called by the remove button to remove a selected keyword""" if not self.list.currentItem() is None: row = self.list.currentRow() try: self.model.removeItem(self.keyword_list[row]) except NotImplementedError: message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def modelChanged(self): """Retrieves data from the model and inserts it into the list""" keywords = self.model.getList() self.list.clear() self.keyword_list = keywords for keyword in keywords: self.list.addItem(keyword) def cleanup(self): self.model.observable().detach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged)
class OWMoleculeVisualizer(OWWidget): settingsList = ["colorFragmets", "showFragments"] contextHandlers = { "": DomainContextHandler( "", [ContextField("selected_title_indices"), ContextField("moleculeTitleAttributeList", (DomainContextHandler.List + DomainContextHandler.SelectedRequired + DomainContextHandler.IncludeMetaAttributes), selected="selectedMoleculeTitleAttrs"), ContextField("smiles_var", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes)], maxAttributesToPickle=1000) } def __init__(self, parent=None, signalManager=None, title="Molecule visualizer"): super(OWMoleculeVisualizer, self).__init__(parent, signalManager, title) self.colorFragments = 1 self.showFragments = 0 self.selectedFragment = "" self.moleculeSmiles = [] self.fragmentSmiles = [] self.defFragmentSmiles = [] self.smiles_var = 0 self.moleculeTitleAttr = 0 self.moleculeTitleAttributeList = [] self.selectedMoleculeTitleAttrs = [] self.fragmentSmilesAttr = 0 self.imageSize = 200 self.numColumns = 4 self.commitOnChange = 0 ## GUI box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True) self.infoLabel = OWGUI.label(box, self, "Chemicals:") box = OWGUI.radioButtonsInBox( self.controlArea, self, "showFragments", ["Show molecules", "Show fragments"], "Show", callback=self.updateitems ) self.showFragmentsRadioButton = box.buttons[-1] self.markFragmentsCheckBox = OWGUI.checkBox( box, self, "colorFragments", "Mark fragments", callback=self._update ) box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) OWGUI.separator(self.controlArea) self.moleculeSmilesCombo = OWGUI.comboBox( self.controlArea, self, "smiles_var", "Molecule SMILES Attribute", callback=self.updateitems ) self.moleculeSmilesCombo.box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) ) self.smiles_var_model = VariableListModel(parent=self) self.moleculeSmilesCombo.setModel(self.smiles_var_model) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Molecule Title Attributes", addSpace=True) self.title_var_view = QListView( selectionMode=QListView.ExtendedSelection ) self.title_var_model = VariableListModel(parent=self) self.title_var_view.setModel(self.title_var_model) self.title_var_view.selectionModel().selectionChanged.connect( self._title_selection_changed ) box.layout().addWidget(self.title_var_view) OWGUI.separator(self.controlArea) self.fragmentSmilesCombo = OWGUI.comboBox( self.controlArea, self, "fragmentSmilesAttr", "Fragment SMILES Attribute", callback=self.updateFragmentsListBox ) self.fragmentSmilesCombo.setModel(VariableListModel(parent=self)) self.fragmentSmilesCombo.box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum) ) OWGUI.separator(self.controlArea) box = OWGUI.spin(self.controlArea, self, "imageSize", 50, 500, 10, box="Image Size", callback=self._image_size_changed) box.setSizePolicy( QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Selection", addSpace=True) OWGUI.checkBox(box, self, "commitOnChange", "Commit on change") self.selectMarkedMoleculesButton = OWGUI.button( box, self, "Select &matched molecules", self.select_marked ) OWGUI.button(box, self, "&Commit", callback=self.commit, default=True) OWGUI.separator(self.controlArea) OWGUI.rubber(self.controlArea) spliter = QSplitter(Qt.Vertical) self.scrollArea = ScrollArea(spliter) self.grid = GridWidget() self.grid.selectionChanged.connect(self._on_selection_changed) self.scrollArea.setWidget(self.grid) self.scrollArea.setWidgetResizable(True) self.mainArea.layout().addWidget(spliter) if pybel: self.listBox = QListWidget(spliter) else: self.listBox = QListWidget(None) self.listBox.setHidden(True) self.listBox.itemClicked.connect(self.fragmentSelection) self.fragmentSmilesCombo.box.setDisabled(not pybel) self.data = None self.data_subset = [] self.fragment_data = None self.resize(800, 600) self.listBox.setMaximumHeight(150) self.fragmentSmilesCombo.setDisabled(True) self.selectMarkedMoleculesButton.setDisabled(True) self.markFragmentsCheckBox.setDisabled(True) self.showFragmentsRadioButton.setDisabled(True) self.loadSettings() if not pybel: self.showFragments = 0 self.warning(10, "Pybel module not installed. To view molecule fragments\n" "please install openbabel python extension.") self.__loop = None def setMoleculeTable(self, data): self.closeContext() self.clear() self.data = data if data is not None: all_vars = data.domain.variables + data.domain.get_metas().values() text_vars = filter( lambda v: isinstance(v, (Orange.feature.Discrete, Orange.feature.String)), all_vars) var_scored = score_smiles_variables(data, text_vars) self.smiles_var_model[:] = [var for var, _ in var_scored] self.smiles_var = max(range(len(var_scored)), key=lambda i: var_scored[i][1]) self.title_var_model[:] = all_vars self.setFragmentSmilesCombo() self.updateFragmentsListBox() if self.data_subset: try: self.data_subset = self.data_subset.select(self.data.domain) except Exception: self.data_subset = [] self.openContext("", data) else: self.defFragmentSmiles = [] if not self.fragmentSmilesAttr: self.listBox.clear() self.openContext("", data) self.send("Selected Molecules", None) def setMoleculeSubset(self, data): self.data_subset = data try: self.data_subset = self.data_subset.select(self.data.domain) except Exception: self.data_subset = [] def setFragmentTable(self, data): self.fragment_data = data if data is not None: self.setFragmentSmilesCombo() self.updateFragmentsListBox() self.selectedFragment = "" else: self.setFragmentSmilesCombo() self.updateFragmentsListBox() self.fragmentSmilesCombo.setEnabled(data is not None) def handleNewSignals(self): self.updateitems() def clear(self): self.smiles_var_model[:] = [] self.title_var_model[:] = [] self.fragmentSmilesCombo.clear() self.grid.clear() self._widgets = [] self._items = [] if self.__loop is not None: self.__loop.close() self.__loop = None def cleargrid(self): self.grid.clear() self._widgets = [] def _update_titles(self): if self.data is None: return title_vars = [self.title_var_model[ind.row()] for ind in self.title_var_view.selectedIndexes()] for item, widget in zip(self._items, self._widgets): inst = self.data[item.index] text = " / ".join(map(str, (inst[var] for var in title_vars))) widget.label.setText(text) def setFragmentSmilesCombo(self): if self.fragment_data: candidates = score_smiles_variables(self.fragment_data) else: candidates = [] self.fragmentSmilesCombo.model()[:] = [v for v, _ in candidates] if self.fragmentSmilesAttr > len(candidates): self.fragmentSmilesAttr = 0 def updateFragmentsListBox(self): if pybel is None: return fragvars = self.fragmentSmilesCombo.model() if 0 <= self.fragmentSmilesAttr < len(fragvars): fvar = fragvars[self.fragmentSmilesAttr] else: fvar = None if fvar: frags = [str(e[fvar]) for e in self.fragment_data if not e[fvar].is_special()] self.fragmentSmiles = [""] + frags else: self.fragmentSmiles = [""] + self.defFragmentSmiles self.listBox.clear() self.listBox.addItems(self.fragmentSmiles) self.showFragmentsRadioButton.setDisabled(len(self.fragmentSmiles) == 1) self.markFragmentsCheckBox.setDisabled(len(self.fragmentSmiles) == 1) self.selectMarkedMoleculesButton.setDisabled(True) def fragmentSelection(self, item): if pybel is None: return index = self.listBox.indexFromItem(item).row() if index == -1: index = 0 self.selectedFragment = self.fragmentSmiles[index] self.selectMarkedMoleculesButton.setEnabled(bool(self.selectedFragment)) self.markFragmentsCheckBox.setEnabled(bool(self.selectedFragment)) if not self.showFragments and self.colorFragments: self._update() def _title_text(self, index): title_vars = [self.title_var_model[ind.row()] for ind in self.title_var_view.selectedIndexes()] inst = self.data[index] return " / ".join(map(str, (inst[var] for var in title_vars))) def _items_from_var(self, var): if self.data is None: return None values = [(i, str(inst[var])) for i, inst in enumerate(self.data) if not inst[var].is_special()] return [Item(i, smiles, *self._parse_smiles(smiles)) for i, smiles in values] def _parse_smiles(self, smiles): try: return (OK, molecule_from_smiles(smiles)) except Exception: return (ParseError, None) def updateitems(self): if self.showFragments and self.fragmentSmiles: values = [(None, frag) for frag in self.fragmentSmiles[1:]] items = [Item(i, smiles, *self._parse_smiles(smiles)) for i, smiles in values] else: smilesvar = self.smiles_var_model[self.smiles_var] items = self._items_from_var(smilesvar) self._items = items self.setupgrid() def setupgrid(self): self.cleargrid() layout = self.grid widgets = [] for item in self._items: thumb = ThumbnailWidget(self.grid) thumb.setImageSize(self.imageSize, self.imageSize) if item.index is not None: text = self._title_text(item.index) else: text = "" thumb.label.setText(text) widgets.append(thumb) layout.appendWidget(thumb) self._widgets = widgets self.infoLabel.setText("Chemicals %i" % len(self._items)) self._update() def __update_items(self, items, widgets, pattern=None): for i, item, widget in zip(range(len(items)), items, widgets): if item.status != ParseError: if pattern is not None: emb = substructure_embedding(item.molecule, pattern) emb = reduce(list.__iadd__, emb, []) svg = molecule_to_svg_with_substructure(item.molecule, emb) else: svg = molecule_to_svg(item.molecule) else: svg = "" widget.setData(svg) widget.setEnabled(True) yield i * 100.0 / len(items) def _update(self): if self.showFragments and self.fragmentSmiles: loop = self.__update_items(self._items, self._widgets) elif self.colorFragments and self.selectedFragment: pattern = pybel.Smarts(self.selectedFragment) loop = self.__update_items(self._items, self._widgets, pattern) else: loop = self.__update_items(self._items, self._widgets) self.__schedule(loop) def __schedule(self, coroutine): if self.__loop is not None: self.progressBarFinished() self.__loop.close() self.__loop = None self.__loop = coroutine self.progressBarInit() QTimer.singleShot(0, self.__loop_update) @Slot() def __loop_update(self): if self.__loop is None: return try: progress = next(self.__loop) except StopIteration: self.__loop = None self.progressBarFinished() else: self.progressBarSet(progress) QTimer.singleShot(0, self.__loop_update) def _title_selection_changed(self): self._update_titles() def _image_size_changed(self): for widget in self._widgets: widget.setImageSize(self.imageSize, self.imageSize) self.grid.layout().invalidate() def select_marked(self): if not pybel: return if not self.showFragments: pattern = pybel.Smarts(self.selectedFragment) for item, widget in zip(self._items, self._widgets): if item.status != ParseError: emb = substructure_embedding(item.molecule, pattern) widget.setSelected(bool(emb)) else: widget.setSelected(False) if self.commitOnChange: self.commit() def _on_selection_changed(self): if self.commitOnChange: self.commit() def commit(self): if self.showFragments: svar = self.smiles_var_model[self.smiles_var] items = self._items_from_var(svar) frags = [item for item, w in zip(self._items, self._widgets) if w.selected] patterns = [pybel.Smarts(item.smiles) for item in frags] def test(molecule, patterns): return any(bool(substructure_embedding(molecule, patt)) for patt in patterns) matched = filter( lambda item: item.status != ParseError and test(item.molecule, patterns), items ) instances = [self.data[item.index] for item in matched] if instances: table = Orange.data.Table(instances) self.send("Selected Molecules", table) else: self.send("Selected Molecules", None) else: items = [item for item, w in zip(self._items, self._widgets) if w.selected] instances = [self.data[item.index] for item in items] if instances: table = Orange.data.Table(instances) self.send("Selected Molecules", table) else: self.send("Selected Molecules", None) def onDeleteWidget(self): OWWidget.onDeleteWidget(self) if self.__loop is not None: self.__loop.close() self.__loop = None