def _update_high_q(self, ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file = str(self._content.high_q_combo.lineEdit().text()) if len(file.strip()) == 0: self._high_q_data = None elif os.path.isfile(file) or AnalysisDataService.doesExist(file): self._high_q_data = DataSet(file) try: self._high_q_data.load(True) except: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning( self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file) return self._content.high_scale_edit.setText("1.0") npts = self._high_q_data.get_number_of_points() util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False)
def _update_high_q(self, _ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file_in = str(self._content.high_q_combo.lineEdit().text()) if len(file_in.strip()) == 0: self._high_q_data = None elif os.path.isfile(file_in) or AnalysisDataService.doesExist(file_in): self._high_q_data = DataSet(file_in) try: self._high_q_data.load(True) except (AttributeError, ImportError, NameError, TypeError, ValueError, Warning): self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning( self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file_in) return self._content.high_scale_edit.setText("1.0") util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False)
def _load_workspace(self, workspace): ws_data = DataSet(workspace) try: ws_data.load(True, True) except: ws_data = None QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s." % file) return
def _update_high_q(self, ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file = str(self._content.high_q_combo.lineEdit().text()) if len(file.strip())==0: self._high_q_data = None elif os.path.isfile(file) or AnalysisDataService.doesExist(file): self._high_q_data = DataSet(file) try: self._high_q_data.load(True) except: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file) return self._content.high_scale_edit.setText("1.0") npts = self._high_q_data.get_number_of_points() util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False)
def _update_high_q(self, _ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file_in = str(self._content.high_q_combo.lineEdit().text()) if len(file_in.strip()) == 0: self._high_q_data = None elif os.path.isfile(file_in) or AnalysisDataService.doesExist(file_in): self._high_q_data = DataSet(file_in) try: self._high_q_data.load(True) except (AttributeError, ImportError, NameError, TypeError, ValueError, Warning): self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file_in) return self._content.high_scale_edit.setText("1.0") util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False)
def stitch_data(self, input_file, output_dir, q_min, q_step): from LargeScaleStructures.data_stitching import DataSet, Stitcher, RangeSelector # Identify the data sets to stitch and order them workspace_list = [] _list_name = [] _list_ts = [] ws_list = AnalysisDataService.getObjectNames() for item in ws_list: if item.endswith('ts'): (_name,_ts) = item.split('_#') _list_name.append(item) _list_ts.append(_ts) _name_ts = zip(_list_ts, _list_name) _name_ts.sort() _ts_sorted, workspace_list = zip(*_name_ts) # Stitch the data s = Stitcher() q_max = 0 for item in workspace_list: data = DataSet(item) data.load(True, True) x_min, x_max = data.get_range() if x_max > q_max: q_max = x_max s.append(data) s.set_reference(0) s.compute() # Apply the scaling factors for data in s._data_sets: Scale(InputWorkspace=str(data), OutputWorkspace=data._ws_scaled, Operation="Multiply", Factor=data.get_scale()) SaveAscii(InputWorkspace=str(data), Filename=os.path.join(output_dir, '%s.txt' % str(data))) output_file = input_file.replace('.xml', '_reprocessed.txt') Logger("REFLReprocess").notice("Saving to %s" % output_file) output_ws = _average_y_of_same_x_(q_min, q_step, q_max) SaveAscii(InputWorkspace=output_ws, Filename=output_file)
def set_user_data(self, data): self._data[ReflData.OFF_OFF] = data if self.name.find("Off_Off")>0: ws_name = self.name.replace("Off_Off", "On_Off") if AnalysisDataService.doesExist(ws_name): self._data[ReflData.ON_OFF] = DataSet(ws_name) self._data[ReflData.ON_OFF].load(True, True) ws_name = self.name.replace("Off_Off", "Off_On") if AnalysisDataService.doesExist(ws_name): self._data[ReflData.OFF_ON] = DataSet(ws_name) self._data[ReflData.OFF_ON].load(True, True) ws_name = self.name.replace("Off_Off", "On_On") if AnalysisDataService.doesExist(ws_name): self._data[ReflData.ON_ON] = DataSet(ws_name) self._data[ReflData.ON_ON].load(True, True)
def update_data(self, dataset_control, min_control, max_control, scale_control): """ Update a data set @param dataset_control: combo box with the file path or workspace name @param min_control: text widget containing the minimum Q of the overlap region @param max_control: text widget containing the maximum Q of the overlap region @param scale_control: text widget containing the scale (can be input or output) """ data_object = None file = str(dataset_control.lineEdit().text()) if len(file.strip()) == 0: data_object = None elif os.path.isfile(file) or AnalysisDataService.doesExist(file): data_object = DataSet(file) try: data_object.load(True) except: data_object = None util.set_valid(dataset_control.lineEdit(), False) QtGui.QMessageBox.warning( self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file) return if min_control is not None and max_control is not None \ and (len(min_control.text())==0 or len(max_control.text())==0): minx, maxx = data_object.get_range() min_control.setText("%-6.3g" % minx) max_control.setText("%-6.3g" % maxx) # Set the reference scale, unless we just loaded the data if len(scale_control.text()) == 0: scale_control.setText("1.0") else: scale = util._check_and_get_float_line_edit(scale_control) data_object.set_scale(scale) npts = data_object.get_number_of_points() util.set_valid(dataset_control.lineEdit(), True) else: data_object = None util.set_valid(dataset_control.lineEdit(), False) self._plotted = False return data_object
def update_data(self, dataset_control, min_control, max_control, scale_control): """ Update a data set @param dataset_control: combo box with the file path or workspace name @param min_control: text widget containing the minimum Q of the overlap region @param max_control: text widget containing the maximum Q of the overlap region @param scale_control: text widget containing the scale (can be input or output) """ data_object = None file_in = str(dataset_control.lineEdit().text()) if len(file_in.strip()) == 0: data_object = None elif os.path.isfile(file_in) or AnalysisDataService.doesExist(file_in): data_object = DataSet(file_in) try: data_object.load(True) except (StandardError, Warning): data_object = None util.set_valid(dataset_control.lineEdit(), False) QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file_in) return if min_control is not None and max_control is not None \ and (len(min_control.text()) == 0 or len(max_control.text()) == 0): minx, maxx = data_object.get_range() min_control.setText("%-6.3g" % minx) max_control.setText("%-6.3g" % maxx) # Set the reference scale, unless we just loaded the data if len(scale_control.text()) == 0: scale_control.setText("1.0") else: scale = util._check_and_get_float_line_edit(scale_control) data_object.set_scale(scale) _npts = data_object.get_number_of_points() util.set_valid(dataset_control.lineEdit(), True) else: data_object = None util.set_valid(dataset_control.lineEdit(), False) self._plotted = False return data_object
def stitch_data(self, input_file, output_dir, q_min, q_step): from LargeScaleStructures.data_stitching import DataSet, Stitcher #, RangeSelector # Identify the data sets to stitch and order them workspace_list = [] _list_name = [] _list_ts = [] ws_list = AnalysisDataService.getObjectNames() for item in ws_list: if item.endswith('ts'): (_name, _ts) = item.split('_#') _list_name.append(item) _list_ts.append(_ts) _name_ts = zip(_list_ts, _list_name) _name_ts.sort() _ts_sorted, workspace_list = zip(*_name_ts) # Stitch the data s = Stitcher() q_max = 0 for item in workspace_list: data = DataSet(item) data.load(True, True) dummy_x_min, x_max = data.get_range() if x_max > q_max: q_max = x_max s.append(data) s.set_reference(0) s.compute() # Apply the scaling factors for data in s._data_sets: Scale(InputWorkspace=str(data), OutputWorkspace=data._ws_scaled, Operation="Multiply", Factor=data.get_scale()) SaveAscii(InputWorkspace=str(data), Filename=os.path.join(output_dir, '%s.txt' % str(data))) output_file = input_file.replace('.xml', '_reprocessed.txt') Logger("REFLReprocess").notice("Saving to %s" % output_file) output_ws = _average_y_of_same_x_(q_min, q_step, q_max) SaveAscii(InputWorkspace=output_ws, Filename=output_file)
class StitcherWidget(BaseWidget): """ Widget that present a data catalog to the user """ ## Widget name name = "Data Stitching" def __init__(self, parent=None, state=None, settings=None): super(StitcherWidget, self).__init__(parent, state, settings) class DataFrame(QtGui.QFrame, ui.ui_stitcher.Ui_Frame): def __init__(self, parent=None): QtGui.QFrame.__init__(self, parent) self.setupUi(self) self._content = DataFrame(self) self.initialize_content() self._layout.addWidget(self._content) # General GUI settings if settings is None: settings = GeneralSettings() self._settings = settings # Connect do UI data update self._settings.data_updated.connect(self._data_updated) self._low_q_data = None self._medium_q_data = None self._high_q_data = None # Flag to know when a field has been modified by hand self._low_q_modified = False self._medium_q_modified = False self._high_q_modified = False self._referenceID = 0 self._graph = "StitchedData" self._output_dir = self._settings.data_output_dir self._stitcher = None self._plotted = False def initialize_content(self): """ Initialize the content of the frame """ # Validators self._content.low_scale_edit.setValidator( QtGui.QDoubleValidator(self._content.low_scale_edit)) self._content.medium_scale_edit.setValidator( QtGui.QDoubleValidator(self._content.medium_scale_edit)) self._content.high_scale_edit.setValidator( QtGui.QDoubleValidator(self._content.high_scale_edit)) self._content.low_min_edit.setValidator( QtGui.QDoubleValidator(self._content.low_min_edit)) self._content.low_max_edit.setValidator( QtGui.QDoubleValidator(self._content.low_max_edit)) self._content.medium_min_edit.setValidator( QtGui.QDoubleValidator(self._content.medium_min_edit)) self._content.medium_max_edit.setValidator( QtGui.QDoubleValidator(self._content.medium_max_edit)) # Browse buttons self.connect(self._content.low_q_browse_button, QtCore.SIGNAL("clicked()"), self._low_q_browse) self.connect(self._content.medium_q_browse_button, QtCore.SIGNAL("clicked()"), self._medium_q_browse) self.connect(self._content.high_q_browse_button, QtCore.SIGNAL("clicked()"), self._high_q_browse) self.connect(self._content.low_q_combo, QtCore.SIGNAL("activated(int)"), self._update_low_q) self.connect(self._content.medium_q_combo, QtCore.SIGNAL("activated(int)"), self._update_medium_q) self.connect(self._content.high_q_combo, QtCore.SIGNAL("activated(int)"), self._update_high_q) # Radio buttons self.connect(self._content.low_radio, QtCore.SIGNAL("clicked()"), self._low_q_selected) self.connect(self._content.medium_radio, QtCore.SIGNAL("clicked()"), self._medium_q_selected) self.connect(self._content.high_radio, QtCore.SIGNAL("clicked()"), self._high_q_selected) # Selection buttons self.connect(self._content.low_range_button, QtCore.SIGNAL("clicked()"), self._low_range) self.connect(self._content.medium_range_button, QtCore.SIGNAL("clicked()"), self._medium_range) # Scale factors self.connect(self._content.low_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_low_scale) self.connect(self._content.medium_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_medium_scale) self.connect(self._content.high_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_high_scale) # Apply and save buttons self.connect(self._content.apply_button, QtCore.SIGNAL("clicked()"), self._apply) self.connect(self._content.save_result_button, QtCore.SIGNAL("clicked()"), self._save_result) # Create button group for data set selection g = QtGui.QButtonGroup(self) g.addButton(self._content.low_radio) g.addButton(self._content.medium_radio) g.addButton(self._content.high_radio) g.setExclusive(True) self._content.low_radio.setChecked(True) self._content.low_q_combo.insertItem(0, "") self.populate_combobox(self._content.low_q_combo) self._content.low_q_combo.setEditable(True) self._content.medium_q_combo.insertItem(0, "") self.populate_combobox(self._content.medium_q_combo) self._content.medium_q_combo.setEditable(True) self._content.high_q_combo.insertItem(0, "") self.populate_combobox(self._content.high_q_combo) self._content.high_q_combo.setEditable(True) # pylint: disable = no-self-argument class ShowEventFilter(QtCore.QObject): def eventFilter(obj_self, filteredObj, event): if event.type() == QtCore.QEvent.HoverEnter: self.populate_combobox(filteredObj) filteredObj.update() elif event.type() == QtCore.QEvent.KeyPress: if filteredObj == self._content.low_q_combo: self._low_q_modified = True elif filteredObj == self._content.medium_q_combo: self._medium_q_modified = True elif filteredObj == self._content.high_q_combo: self._high_q_modified = True if event.key() == QtCore.Qt.Key_Return or event.key( ) == QtCore.Qt.Key_Enter: filteredObj.setItemText(0, filteredObj.lineEdit().text()) if filteredObj == self._content.low_q_combo: self._update_low_q() elif filteredObj == self._content.medium_q_combo: self._update_medium_q() elif filteredObj == self._content.high_q_combo: self._update_high_q() return True return QtCore.QObject.eventFilter(obj_self, filteredObj, event) eventFilter = ShowEventFilter(self) self._content.low_q_combo.installEventFilter(eventFilter) self._content.medium_q_combo.installEventFilter(eventFilter) self._content.high_q_combo.installEventFilter(eventFilter) def populate_combobox(self, combo): ws_list = AnalysisDataService.getObjectNames() for _ws in ws_list: ws_object = AnalysisDataService.retrieve(_ws) if not _ws.startswith("__") and combo.findText(_ws) < 0 \ and hasattr(ws_object, "getNumberHistograms") \ and ws_object.getNumberHistograms() == 1: combo.addItem(_ws) def _update_low_scale(self): """ Callback for scale update from user """ self._low_q_data.set_scale(float(self._content.low_scale_edit.text())) self.plot_result() def _update_medium_scale(self): """ Callback for scale update from user """ self._medium_q_data.set_scale( float(self._content.medium_scale_edit.text())) self.plot_result() def _update_high_scale(self): """ Callback for scale update from user """ self._high_q_data.set_scale(float( self._content.high_scale_edit.text())) self.plot_result() def _low_range(self): """ User requested to select range common to data sets 1 and 2 """ if self._low_q_data is not None: def call_back(xmin, xmax): self._content.low_min_edit.setText("%-6.3g" % xmin) self._content.low_max_edit.setText("%-6.3g" % xmax) ws_list = [] if self._low_q_data is not None: ws_list.append(str(self._low_q_data)) if self._medium_q_data is not None: ws_list.append(str(self._medium_q_data)) RangeSelector.connect(ws_list, call_back=call_back) def _medium_range(self): """ User requested to select range common to data sets 2 and 3 """ if self._medium_q_data is not None: def call_back(xmin, xmax): self._content.medium_min_edit.setText("%-6.3g" % xmin) self._content.medium_max_edit.setText("%-6.3g" % xmax) ws_list = [] if self._medium_q_data is not None: ws_list.append(str(self._medium_q_data)) if self._high_q_data is not None: ws_list.append(str(self._high_q_data)) RangeSelector.connect(ws_list, call_back=call_back) def _low_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.low_scale_edit.setText("1.0") self._referenceID = 0 def _medium_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.medium_scale_edit.setText("1.0") self._referenceID = 1 def _high_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.high_scale_edit.setText("1.0") self._referenceID = 2 def update_data(self, dataset_control, min_control, max_control, scale_control): """ Update a data set @param dataset_control: combo box with the file path or workspace name @param min_control: text widget containing the minimum Q of the overlap region @param max_control: text widget containing the maximum Q of the overlap region @param scale_control: text widget containing the scale (can be input or output) """ data_object = None file_in = str(dataset_control.lineEdit().text()) if len(file_in.strip()) == 0: data_object = None elif os.path.isfile(file_in) or AnalysisDataService.doesExist(file_in): data_object = DataSet(file_in) try: data_object.load(True) except (AttributeError, ImportError, NameError, TypeError, ValueError, Warning): data_object = None util.set_valid(dataset_control.lineEdit(), False) QtGui.QMessageBox.warning( self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file_in) return if min_control is not None and max_control is not None \ and (len(min_control.text()) == 0 or len(max_control.text()) == 0): minx, maxx = data_object.get_range() min_control.setText("%-6.3g" % minx) max_control.setText("%-6.3g" % maxx) # Set the reference scale, unless we just loaded the data if len(scale_control.text()) == 0: scale_control.setText("1.0") else: scale = util._check_and_get_float_line_edit(scale_control) data_object.set_scale(scale) util.set_valid(dataset_control.lineEdit(), True) else: data_object = None util.set_valid(dataset_control.lineEdit(), False) self._plotted = False return data_object def _update_low_q(self, _ws=None): """ Update Low-Q data set """ self._low_q_data = self.update_data(self._content.low_q_combo, self._content.low_min_edit, self._content.low_max_edit, self._content.low_scale_edit) self._low_q_modified = False def _update_medium_q(self, _ws=None): """ Update Medium-Q data set """ self._medium_q_data = self.update_data(self._content.medium_q_combo, self._content.medium_min_edit, self._content.medium_max_edit, self._content.medium_scale_edit) self._medium_q_modified = False def _update_high_q(self, _ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file_in = str(self._content.high_q_combo.lineEdit().text()) if len(file_in.strip()) == 0: self._high_q_data = None elif os.path.isfile(file_in) or AnalysisDataService.doesExist(file_in): self._high_q_data = DataSet(file_in) try: self._high_q_data.load(True) except (AttributeError, ImportError, NameError, TypeError, ValueError, Warning): self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning( self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file_in) return self._content.high_scale_edit.setText("1.0") util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) def data_browse_dialog(self): """ Pop up a file dialog box. """ title = "Data file - Choose a reduced I(Q) file" if not os.path.isdir(str(self._output_dir)): self._output_dir = os.path.expanduser("~") fname = QtCore.QFileInfo( QtGui.QFileDialog.getOpenFileName( self, title, self._output_dir, "Reduced XML files (*.xml);; Reduced Nexus files" " (*.nxs);; All files (*)")).filePath() if fname: # Store the location of the loaded file self._output_dir = str(QtCore.QFileInfo(fname).path()) return str(fname) def _low_q_browse(self): """ Browse for Low-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.low_q_combo.setItemText(0, fname) self._content.low_q_combo.setCurrentIndex(0) self._update_low_q() def _medium_q_browse(self): """ Browse for Medium-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.medium_q_combo.setItemText(0, fname) self._content.medium_q_combo.setCurrentIndex(0) self._update_medium_q() def _high_q_browse(self): """ Browse for High-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.high_q_combo.setItemText(0, fname) self._content.high_q_combo.setCurrentIndex(0) self._update_high_q() def is_running(self, is_running): """ Enable/disable controls depending on whether a reduction is running or not @param is_running: True if a reduction is running """ super(StitcherWidget, self).is_running(is_running) self._content.save_result_button.setEnabled(not is_running) self._content.apply_button.setEnabled(not is_running) def _data_updated(self, key, value): """ Respond to application-level key/value pair updates. @param key: key string @param value: value string """ if key == "OUTPUT_DIR": self._output_dir = value def _apply(self): """ Perform auto-scaling """ # Update data sets, in case the user typed in a file name without using the browse button if self._low_q_modified: self._update_low_q() if self._medium_q_modified: self._update_medium_q() if self._high_q_modified: self._update_high_q() s = Stitcher() if self._low_q_data is not None: xmin = util._check_and_get_float_line_edit( self._content.low_min_edit) xmax = util._check_and_get_float_line_edit( self._content.low_max_edit) self._low_q_data.set_range(xmin, xmax) s.append(self._low_q_data) if self._referenceID == 0: scale = util._check_and_get_float_line_edit( self._content.low_scale_edit) self._low_q_data.set_scale(scale) if self._medium_q_data is not None: s.append(self._medium_q_data) if self._referenceID == 1: scale = util._check_and_get_float_line_edit( self._content.medium_scale_edit) self._medium_q_data.set_scale(scale) if self._high_q_data is not None: xmin = util._check_and_get_float_line_edit( self._content.medium_min_edit) xmax = util._check_and_get_float_line_edit( self._content.medium_max_edit) self._high_q_data.set_range(xmin, xmax) s.append(self._high_q_data) if self._referenceID == 2: scale = util._check_and_get_float_line_edit( self._content.high_scale_edit) self._high_q_data.set_scale(scale) if s.size() == 0: return s.set_reference(self._referenceID) s.compute() # Update scaling factor if self._low_q_data is not None: self._content.low_scale_edit.setText( str(self._low_q_data.get_scale())) if self._medium_q_data is not None: self._content.medium_scale_edit.setText( str(self._medium_q_data.get_scale())) if self._high_q_data is not None: self._content.high_scale_edit.setText( str(self._high_q_data.get_scale())) self._stitcher = s self.plot_result() def plot_result(self): """ Plot the scaled data sets """ low_xmin = util._check_and_get_float_line_edit( self._content.low_min_edit) low_xmax = util._check_and_get_float_line_edit( self._content.low_max_edit) med_xmin = util._check_and_get_float_line_edit( self._content.medium_min_edit) med_xmax = util._check_and_get_float_line_edit( self._content.medium_max_edit) ws_list = [] if self._low_q_data is not None: xmin, _ = self._low_q_data.get_skipped_range() self._low_q_data.apply_scale(xmin, low_xmax) ws_list.append(self._low_q_data.get_scaled_ws()) if self._medium_q_data is not None: _, xmax = self._medium_q_data.get_skipped_range() if self._high_q_data is not None: xmax = med_xmax self._medium_q_data.apply_scale(low_xmin, xmax) ws_list.append(self._medium_q_data.get_scaled_ws()) if self._high_q_data is not None: _, xmax = self._high_q_data.get_skipped_range() self._high_q_data.apply_scale(med_xmin, xmax) ws_list.append(self._high_q_data.get_scaled_ws()) if len(ws_list) > 0: g = mantidplot.graph(self._graph) if g is None or not self._plotted: g = mantidplot.plotSpectrum(ws_list, [0], True) g.setName(self._graph) self._plotted = True def _save_result(self): """ Save the scaled output in one combined I(Q) file """ if self._stitcher is not None: if not os.path.isdir(self._output_dir): self._output_dir = os.path.expanduser("~") fname_qstr = QtGui.QFileDialog.getSaveFileName( self, "Save combined I(Q)", self._output_dir, "Data Files (*.xml)") fname = str(QtCore.QFileInfo(fname_qstr).filePath()) if len(fname) > 0: if fname.endswith('.xml'): self._stitcher.save_combined(fname, as_canSAS=True) elif fname.endswith('.txt'): self._stitcher.save_combined(fname, as_canSAS=False) else: fname_tmp = fname + ".xml" self._stitcher.save_combined(fname_tmp, as_canSAS=True) fname_tmp = fname + ".txt" self._stitcher.save_combined(fname_tmp, as_canSAS=False) def set_state(self, state): """ Update the catalog according to the new data path """ # Refresh combo boxes self.populate_combobox(self._content.low_q_combo) self.populate_combobox(self._content.medium_q_combo) self.populate_combobox(self._content.high_q_combo) def get_state(self): """ Return dummy state """ return StitcherState()
def _scale_data_sets(self): """ Perform auto-scaling """ scale_to_unity = self._content.scale_to_one_chk.isChecked() min_q_unity = float(self._content.min_q_unity_edit.text()) max_q_unity = float(self._content.max_q_unity_edit.text()) s = Stitcher() refID = 0 # Get reference cross-section ref_pol = ReflData.OFF_OFF if self._content.off_on_radio.isChecked(): ref_pol = ReflData.OFF_ON elif self._content.on_off_radio.isChecked(): ref_pol = ReflData.ON_OFF elif self._content.on_on_radio.isChecked(): ref_pol = ReflData.ON_ON for i in range(len(self._workspace_list)): item = self._workspace_list[i] data = DataSet(item.name) data.load(True, True) item.set_user_data(data) # Set skipped points for all cross-section xmin, xmax = item.update_skipped() if item.is_selected(): data.set_scale(item.get_scale()) refID = i if scale_to_unity: scale = data.scale_to_unity(max(xmin,min_q_unity), min(xmax,max_q_unity)) data.set_scale(scale) item.set_scale(scale) ref_data = item.get_user_data(ref_pol) if ref_data is None: QtGui.QMessageBox.warning(self, "Invalid choice of reference cross-section", "The selected cross-section is empty, please select another one") return s.append(ref_data) if s.size()==0: Logger("Stitcher").notice("No data to scale") return s.set_reference(refID) s.compute() for item in self._workspace_list: data = item.get_user_data(ref_pol) xmin, xmax = item.get_common_range() data.apply_scale(xmin=xmin, xmax=xmax) scale = data.get_scale() item.set_scale(scale) self._stitcher = s self.plot_result()
class StitcherWidget(BaseWidget): """ Widget that present a data catalog to the user """ ## Widget name name = "Data Stitching" def __init__(self, parent=None, state=None, settings=None): super(StitcherWidget, self).__init__(parent, state, settings) class DataFrame(QtGui.QFrame, ui.ui_stitcher.Ui_Frame): def __init__(self, parent=None): QtGui.QFrame.__init__(self, parent) self.setupUi(self) self._content = DataFrame(self) self.initialize_content() self._layout.addWidget(self._content) # General GUI settings if settings is None: settings = GeneralSettings() self._settings = settings # Connect do UI data update self._settings.data_updated.connect(self._data_updated) self._low_q_data = None self._medium_q_data = None self._high_q_data = None # Flag to know when a field has been modified by hand self._low_q_modified = False self._medium_q_modified = False self._high_q_modified = False self._referenceID = 0 self._graph = "StitchedData" self._output_dir = self._settings.data_output_dir self._stitcher = None self._plotted = False def initialize_content(self): """ Initialize the content of the frame """ # Validators self._content.low_scale_edit.setValidator(QtGui.QDoubleValidator(self._content.low_scale_edit)) self._content.medium_scale_edit.setValidator(QtGui.QDoubleValidator(self._content.medium_scale_edit)) self._content.high_scale_edit.setValidator(QtGui.QDoubleValidator(self._content.high_scale_edit)) self._content.low_min_edit.setValidator(QtGui.QDoubleValidator(self._content.low_min_edit)) self._content.low_max_edit.setValidator(QtGui.QDoubleValidator(self._content.low_max_edit)) self._content.medium_min_edit.setValidator(QtGui.QDoubleValidator(self._content.medium_min_edit)) self._content.medium_max_edit.setValidator(QtGui.QDoubleValidator(self._content.medium_max_edit)) # Browse buttons self.connect(self._content.low_q_browse_button, QtCore.SIGNAL("clicked()"), self._low_q_browse) self.connect(self._content.medium_q_browse_button, QtCore.SIGNAL("clicked()"), self._medium_q_browse) self.connect(self._content.high_q_browse_button, QtCore.SIGNAL("clicked()"), self._high_q_browse) self.connect(self._content.low_q_combo, QtCore.SIGNAL("activated(int)"), self._update_low_q) self.connect(self._content.medium_q_combo, QtCore.SIGNAL("activated(int)"), self._update_medium_q) self.connect(self._content.high_q_combo, QtCore.SIGNAL("activated(int)"), self._update_high_q) # Radio buttons self.connect(self._content.low_radio, QtCore.SIGNAL("clicked()"), self._low_q_selected) self.connect(self._content.medium_radio, QtCore.SIGNAL("clicked()"), self._medium_q_selected) self.connect(self._content.high_radio, QtCore.SIGNAL("clicked()"), self._high_q_selected) # Selection buttons self.connect(self._content.low_range_button, QtCore.SIGNAL("clicked()"), self._low_range) self.connect(self._content.medium_range_button, QtCore.SIGNAL("clicked()"), self._medium_range) # Scale factors self.connect(self._content.low_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_low_scale) self.connect(self._content.medium_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_medium_scale) self.connect(self._content.high_scale_edit, QtCore.SIGNAL("returnPressed()"), self._update_high_scale) # Apply and save buttons self.connect(self._content.apply_button, QtCore.SIGNAL("clicked()"), self._apply) self.connect(self._content.save_result_button, QtCore.SIGNAL("clicked()"), self._save_result) # Create button group for data set selection g = QtGui.QButtonGroup(self) g.addButton(self._content.low_radio) g.addButton(self._content.medium_radio) g.addButton(self._content.high_radio) g.setExclusive(True) self._content.low_radio.setChecked(True) self._content.low_q_combo.insertItem(0,"") self.populate_combobox(self._content.low_q_combo) self._content.low_q_combo.setEditable(True) self._content.medium_q_combo.insertItem(0,"") self.populate_combobox(self._content.medium_q_combo) self._content.medium_q_combo.setEditable(True) self._content.high_q_combo.insertItem(0,"") self.populate_combobox(self._content.high_q_combo) self._content.high_q_combo.setEditable(True) class ShowEventFilter(QtCore.QObject): def eventFilter(obj_self, filteredObj, event): if event.type() == QtCore.QEvent.HoverEnter: self.populate_combobox(filteredObj) filteredObj.update() elif event.type() == QtCore.QEvent.KeyPress: if filteredObj==self._content.low_q_combo: self._low_q_modified = True elif filteredObj==self._content.medium_q_combo: self._medium_q_modified = True elif filteredObj==self._content.high_q_combo: self._high_q_modified = True if event.key() == QtCore.Qt.Key_Return or event.key() == QtCore.Qt.Key_Enter: filteredObj.setItemText(0, filteredObj.lineEdit().text()) if filteredObj==self._content.low_q_combo: self._update_low_q() elif filteredObj==self._content.medium_q_combo: self._update_medium_q() elif filteredObj==self._content.high_q_combo: self._update_high_q() return True return QtCore.QObject.eventFilter(obj_self, filteredObj, event) eventFilter = ShowEventFilter(self) self._content.low_q_combo.installEventFilter(eventFilter) self._content.medium_q_combo.installEventFilter(eventFilter) self._content.high_q_combo.installEventFilter(eventFilter) def populate_combobox(self, combo): ws_list = AnalysisDataService.getObjectNames() for ws in ws_list: ws_object = AnalysisDataService.retrieve(ws) if not ws.startswith("__") and combo.findText(ws)<0\ and hasattr(ws_object, "getNumberHistograms")\ and ws_object.getNumberHistograms()==1: combo.addItem(ws) def _update_low_scale(self): """ Callback for scale update from user """ self._low_q_data.set_scale(float(self._content.low_scale_edit.text())) self.plot_result() def _update_medium_scale(self): """ Callback for scale update from user """ self._medium_q_data.set_scale(float(self._content.medium_scale_edit.text())) self.plot_result() def _update_high_scale(self): """ Callback for scale update from user """ self._high_q_data.set_scale(float(self._content.high_scale_edit.text())) self.plot_result() def _low_range(self): """ User requested to select range common to data sets 1 and 2 """ if self._low_q_data is not None: def call_back(xmin, xmax): self._content.low_min_edit.setText("%-6.3g" % xmin) self._content.low_max_edit.setText("%-6.3g" % xmax) ws_list = [] if self._low_q_data is not None: ws_list.append(str(self._low_q_data)) if self._medium_q_data is not None: ws_list.append(str(self._medium_q_data)) RangeSelector.connect(ws_list, call_back=call_back) def _medium_range(self): """ User requested to select range common to data sets 2 and 3 """ if self._medium_q_data is not None: def call_back(xmin, xmax): self._content.medium_min_edit.setText("%-6.3g" % xmin) self._content.medium_max_edit.setText("%-6.3g" % xmax) ws_list = [] if self._medium_q_data is not None: ws_list.append(str(self._medium_q_data)) if self._high_q_data is not None: ws_list.append(str(self._high_q_data)) RangeSelector.connect(ws_list, call_back=call_back) def _low_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.low_scale_edit.setText("1.0") self._referenceID = 0 def _medium_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.medium_scale_edit.setText("1.0") self._referenceID = 1 def _high_q_selected(self): """ Callback for radio button clicked [selected as reference data set] """ self._content.high_scale_edit.setText("1.0") self._referenceID = 2 def update_data(self, dataset_control, min_control, max_control, scale_control): """ Update a data set @param dataset_control: combo box with the file path or workspace name @param min_control: text widget containing the minimum Q of the overlap region @param max_control: text widget containing the maximum Q of the overlap region @param scale_control: text widget containing the scale (can be input or output) """ data_object = None file = str(dataset_control.lineEdit().text()) if len(file.strip())==0: data_object = None elif os.path.isfile(file) or AnalysisDataService.doesExist(file): data_object = DataSet(file) try: data_object.load(True) except: data_object = None util.set_valid(dataset_control.lineEdit(), False) QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file) return if min_control is not None and max_control is not None \ and (len(min_control.text())==0 or len(max_control.text())==0): minx, maxx = data_object.get_range() min_control.setText("%-6.3g" % minx) max_control.setText("%-6.3g" % maxx) # Set the reference scale, unless we just loaded the data if len(scale_control.text())==0: scale_control.setText("1.0") else: scale = util._check_and_get_float_line_edit(scale_control) data_object.set_scale(scale) npts = data_object.get_number_of_points() util.set_valid(dataset_control.lineEdit(), True) else: data_object = None util.set_valid(dataset_control.lineEdit(), False) self._plotted = False return data_object def _update_low_q(self, ws=None): """ Update Low-Q data set """ self._low_q_data = self.update_data(self._content.low_q_combo, self._content.low_min_edit, self._content.low_max_edit, self._content.low_scale_edit) self._low_q_modified = False def _update_medium_q(self, ws=None): """ Update Medium-Q data set """ self._medium_q_data = self.update_data(self._content.medium_q_combo, self._content.medium_min_edit, self._content.medium_max_edit, self._content.medium_scale_edit) self._medium_q_modified = False def _update_high_q(self, ws=None): """ Update High-Q data set """ self._high_q_data = self.update_data(self._content.high_q_combo, None, None, self._content.high_scale_edit) self._high_q_modified = False file = str(self._content.high_q_combo.lineEdit().text()) if len(file.strip())==0: self._high_q_data = None elif os.path.isfile(file) or AnalysisDataService.doesExist(file): self._high_q_data = DataSet(file) try: self._high_q_data.load(True) except: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) QtGui.QMessageBox.warning(self, "Error loading file", "Could not load %s.\nMake sure you pick the XML output from the reduction." % file) return self._content.high_scale_edit.setText("1.0") npts = self._high_q_data.get_number_of_points() util.set_valid(self._content.high_q_combo.lineEdit(), True) else: self._high_q_data = None util.set_valid(self._content.high_q_combo.lineEdit(), False) def data_browse_dialog(self): """ Pop up a file dialog box. """ title = "Data file - Choose a reduced I(Q) file" if not os.path.isdir(str(self._output_dir)): self._output_dir = os.path.expanduser("~") fname = QtCore.QFileInfo(QtGui.QFileDialog.getOpenFileName(self, title, self._output_dir, "Reduced XML files (*.xml);; Reduced Nexus files (*.nxs);; All files (*.*)")).filePath() if fname: # Store the location of the loaded file self._output_dir = str(QtCore.QFileInfo(fname).path()) return str(fname) def _low_q_browse(self): """ Browse for Low-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.low_q_combo.setItemText(0,fname) self._content.low_q_combo.setCurrentIndex(0) self._update_low_q() def _medium_q_browse(self): """ Browse for Medium-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.medium_q_combo.setItemText(0,fname) self._content.medium_q_combo.setCurrentIndex(0) self._update_medium_q() def _high_q_browse(self): """ Browse for High-Q I(Q) data set """ fname = self.data_browse_dialog() if fname: self._content.high_q_combo.setItemText(0,fname) self._content.high_q_combo.setCurrentIndex(0) self._update_high_q() def is_running(self, is_running): """ Enable/disable controls depending on whether a reduction is running or not @param is_running: True if a reduction is running """ super(StitcherWidget, self).is_running(is_running) self._content.save_result_button.setEnabled(not is_running) self._content.apply_button.setEnabled(not is_running) def _data_updated(self, key, value): """ Respond to application-level key/value pair updates. @param key: key string @param value: value string """ if key=="OUTPUT_DIR": self._output_dir = value def _apply(self): """ Perform auto-scaling """ # Update data sets, in case the user typed in a file name without using the browse button if self._low_q_modified: self._update_low_q() if self._medium_q_modified: self._update_medium_q() if self._high_q_modified: self._update_high_q() s = Stitcher() if self._low_q_data is not None: xmin = util._check_and_get_float_line_edit(self._content.low_min_edit) xmax = util._check_and_get_float_line_edit(self._content.low_max_edit) self._low_q_data.set_range(xmin,xmax) s.append(self._low_q_data) if self._referenceID==0: scale = util._check_and_get_float_line_edit(self._content.low_scale_edit) self._low_q_data.set_scale(scale) if self._medium_q_data is not None: s.append(self._medium_q_data) if self._referenceID==1: scale = util._check_and_get_float_line_edit(self._content.medium_scale_edit) self._medium_q_data.set_scale(scale) if self._high_q_data is not None: xmin = util._check_and_get_float_line_edit(self._content.medium_min_edit) xmax = util._check_and_get_float_line_edit(self._content.medium_max_edit) self._high_q_data.set_range(xmin,xmax) s.append(self._high_q_data) if self._referenceID==2: scale = util._check_and_get_float_line_edit(self._content.high_scale_edit) self._high_q_data.set_scale(scale) if s.size()==0: return s.set_reference(self._referenceID) s.compute() # Update scaling factor if self._low_q_data is not None: self._content.low_scale_edit.setText(str(self._low_q_data.get_scale())) if self._medium_q_data is not None: self._content.medium_scale_edit.setText(str(self._medium_q_data.get_scale())) if self._high_q_data is not None: self._content.high_scale_edit.setText(str(self._high_q_data.get_scale())) self._stitcher = s self.plot_result() def plot_result(self): """ Plot the scaled data sets """ low_xmin = util._check_and_get_float_line_edit(self._content.low_min_edit) low_xmax = util._check_and_get_float_line_edit(self._content.low_max_edit) med_xmin = util._check_and_get_float_line_edit(self._content.medium_min_edit) med_xmax = util._check_and_get_float_line_edit(self._content.medium_max_edit) ws_list = [] if self._low_q_data is not None: xmin,_ = self._low_q_data.get_skipped_range() self._low_q_data.apply_scale(xmin, low_xmax) ws_list.append(self._low_q_data.get_scaled_ws()) if self._medium_q_data is not None: _,xmax = self._medium_q_data.get_skipped_range() if self._high_q_data is not None: xmax = med_xmax self._medium_q_data.apply_scale(low_xmin, xmax) ws_list.append(self._medium_q_data.get_scaled_ws()) if self._high_q_data is not None: _,xmax = self._high_q_data.get_skipped_range() self._high_q_data.apply_scale(med_xmin, xmax) ws_list.append(self._high_q_data.get_scaled_ws()) if len(ws_list)>0: g = mantidplot.graph(self._graph) if g is None or not self._plotted: g = mantidplot.plotSpectrum(ws_list, [0], True) g.setName(self._graph) self._plotted = True def _save_result(self): """ Save the scaled output in one combined I(Q) file """ if self._stitcher is not None: if not os.path.isdir(self._output_dir): self._output_dir = os.path.expanduser("~") fname_qstr = QtGui.QFileDialog.getSaveFileName(self, "Save combined I(Q)", self._output_dir, "Data Files (*.xml)") fname = str(QtCore.QFileInfo(fname_qstr).filePath()) if len(fname)>0: if fname.endswith('.xml'): self._stitcher.save_combined(fname, as_canSAS=True) elif fname.endswith('.txt'): self._stitcher.save_combined(fname, as_canSAS=False) else: fname_tmp = fname + ".xml" self._stitcher.save_combined(fname_tmp, as_canSAS=True) fname_tmp = fname + ".txt" self._stitcher.save_combined(fname_tmp, as_canSAS=False) def set_state(self, state): """ Update the catalog according to the new data path """ # Refresh combo boxes self.populate_combobox(self._content.low_q_combo) self.populate_combobox(self._content.medium_q_combo) self.populate_combobox(self._content.high_q_combo) def get_state(self): """ Return dummy state """ return StitcherState()
def _scale_data_sets(self): """ Perform auto-scaling """ scale_to_unity = self._content.scale_to_one_chk.isChecked() min_q_unity = float(self._content.min_q_unity_edit.text()) max_q_unity = float(self._content.max_q_unity_edit.text()) s = Stitcher() refID = 0 # Get reference cross-section ref_pol = ReflData.OFF_OFF if self._content.off_on_radio.isChecked(): ref_pol = ReflData.OFF_ON elif self._content.on_off_radio.isChecked(): ref_pol = ReflData.ON_OFF elif self._content.on_on_radio.isChecked(): ref_pol = ReflData.ON_ON for i in range(len(self._workspace_list)): item = self._workspace_list[i] data = DataSet(item.name) data.load(True, True) item.set_user_data(data) # Set skipped points for all cross-section xmin, xmax = item.update_skipped() if item.is_selected(): data.set_scale(item.get_scale()) refID = i if scale_to_unity: scale = data.scale_to_unity(max(xmin,min_q_unity), min(xmax,max_q_unity)) data.set_scale(scale) item.set_scale(scale) ref_data = item.get_user_data(ref_pol) if ref_data is None: QtGui.QMessageBox.warning(self,\ "Invalid choice of reference cross-section",\ "The selected cross-section is empty, please select another one") return s.append(ref_data) if s.size()==0: Logger("Stitcher").notice("No data to scale") return s.set_reference(refID) s.compute() for item in self._workspace_list: data = item.get_user_data(ref_pol) xmin, xmax = item.get_common_range() data.apply_scale(xmin=xmin, xmax=xmax) scale = data.get_scale() item.set_scale(scale) self._stitcher = s self.plot_result()