def on_action_export_polar_plot_triggered(self): selected_file, selected_filter = QFileDialog.getSaveFileName( self.ui, 'Save Polar Image', HexrdConfig().working_dir, 'NPZ files (*.npz)') if selected_file: return self.ui.image_tab_widget.export_polar_plot(selected_file)
def update_config(self): style = self.style style['marker'] = self.ui.marker.currentText() style['s'] = self.ui.marker_size.value() style['facecolors'] = self.ui.face_color.text() style['edgecolors'] = self.ui.edge_color.text() HexrdConfig().wppf_plot_style = copy.deepcopy(style)
def __init__(self, parent=None): super(MaterialsPanel, self).__init__(parent) loader = UiLoader() self.ui = loader.load_file('materials_panel.ui', parent) m = HexrdConfig().active_material self.material_editor_widget = MaterialEditorWidget(m, self.ui) self.materials_table = MaterialsTable(self.ui) self.ui.material_editor_layout.addWidget( self.material_editor_widget.ui) self.material_structure_editor = MaterialStructureEditor(self.ui) self.ui.material_structure_editor_layout.addWidget( self.material_structure_editor.ui) # Turn off autocomplete for the QComboBox self.ui.materials_combo.setCompleter(None) self.add_tool_button_actions() self.setup_connections() self.update_gui_from_config()
def update_position(self, instr, det): pos = HexrdConfig().boundary_position(instr, det) if pos is not None: self.shape.set_xy(pos) self.center = self.get_midpoint() elif instr == 'PXRDIP': self.rotate_shape(angle=90)
def preview_spectrum(self): had_object = self._wppf_object is not None obj = self.wppf_object try: obj.computespectrum() x, y = obj.spectrum_sim.x, obj.spectrum_sim.y fig, ax = plt.subplots() fig.canvas.manager.set_window_title('HEXRD') ax.set_xlabel(r'2$\theta$ (deg)') ax.set_ylabel(r'intensity') ax.set_title('Computed Spectrum') # Match the scaling used... ax.set_yscale(HexrdConfig().azimuthal_integral_axis_scale) ax.plot(x, y) ax.relim() ax.autoscale_view() ax.axis('auto') fig.tight_layout() fig.canvas.draw_idle() fig.show() finally: if not had_object: self.reset_object()
def update_config(self): # Set the new config options on the internal config indexing_config = HexrdConfig().indexing_config maps_config = indexing_config['find_orientations']['orientation_maps'] maps_config['file'] = self.file_name maps_config['threshold'] = self.threshold maps_config['bin_frames'] = self.bin_frames
def create_masks_list(self): self.masks = {} polar_data = HexrdConfig().polar_masks_line_data raw_data = HexrdConfig().raw_masks_line_data for i, (key, val) in enumerate(polar_data.items()): if not any(np.array_equal(m, val) for m in self.masks.values()): self.masks[key] = ('polar', val) for i, (key, val) in enumerate(raw_data.items()): if not any(np.array_equal(m, val) for m in self.masks.values()): self.masks[key] = val if HexrdConfig().threshold_mask_status: self.threshold = True self.masks['threshold'] = ('threshold', HexrdConfig().threshold_mask) HexrdConfig().visible_masks = list(self.masks.keys())
def cart_to_angles(xys, panel, iviewer): ang_crds, _ = panel.cart_to_angles(xys, tvec_c=iviewer.instr.tvec) ang_crds = np.degrees(ang_crds) ang_crds[:, 1] = mapAngle(ang_crds[:, 1], HexrdConfig().polar_res_eta_period, units='degrees') return ang_crds
def update_gui(self): # Updates all of the widgets with their settings from the config self.update_hkl_options() blockers = [QSignalBlocker(x) for x in self.all_widgets] # noqa: F841 def setter(w): if isinstance(w, QComboBox): return lambda x: w.setCurrentIndex(w.findData(x)) # Assume it is a spin box of some kind return w.setValue config = HexrdConfig().indexing_config def set_val(w, path): cur = config for x in path: if x not in cur: # If it's not in the config, skip over it return cur = cur[x] setter(w)(cur) for w, path in self.widget_paths.items(): w = getattr(self.ui, w) set_val(w, path) # Update the method name method = config['find_orientations']['seed_search']['method'] self.method_name = next(iter(method)) self.update_method_tab() # Also set the color map minimum to the threshold value... self.threshold = config['find_orientations']['threshold']
def async_worker_error(self, error): QMessageBox.critical(self, 'HEXRD', str(error[1])) msg = f'{str(self.mode)} view error!' HexrdConfig().emit_update_status_bar(msg) self.clear_figure() self.draw_idle()
def update_azimuthal_integral_plot(self): if self.mode != ViewType.polar: # Nothing to do. Just return. return axis = self.azimuthal_integral_axis line = self.azimuthal_line_artist if any([x is None for x in [axis, line]]): # Nothing to do. Just return. return # Get the "tth" vector tth = np.degrees(self.iviewer.angular_grid[1][0]) # Set the new data data = (tth, self.compute_azimuthal_integral_sum()) line.set_data(*data) HexrdConfig().last_azimuthal_integral_data = data # Update the wppf data if applicable self.update_wppf_plot() # Rescale the axes for the new data axis.relim() axis.autoscale_view(scalex=False)
def update_masks_list(self): if not self.threshold_name and HexrdConfig().threshold_mask_status: name = self.create_unique_name('threshold') self.masks[name] = HexrdConfig().threshold_mask self.visible[name] = HexrdConfig().threshold_mask self.threshold_name = name else: data = HexrdConfig().polar_masks_line_data if not data: return if any(np.array_equal(data[-1], m) for m in self.masks.values()): return name = self.create_unique_name('mask_0') self.masks[name] = data[-1] self.visible[name] = data[-1] self.setup_table()
def load_images(self, detectors, file_names, options=None): HexrdConfig().imageseries_dict.clear() for name, f in zip(detectors, file_names): try: if isinstance(f, list): f = f[0] ims = self.open_file(f, options) HexrdConfig().imageseries_dict[name] = ims except (Exception, IOError) as error: msg = ('ERROR - Could not read file: \n' + str(error)) QMessageBox.warning(None, 'HEXRD', msg) return # Save the path if it should be remembered if self.remember: HexrdConfig().hdf5_path = self.path
def update_all(self, clear_canvases=False): # If there are no images loaded, skip the request if not HexrdConfig().has_images(): return prev_blocked = self.calibration_config_widget.block_all_signals() # Need to clear focus from current widget if enter is pressed or # else all clicks are emit an editingFinished signal and view is # constantly re-rendered if QApplication.focusWidget() is not None: QApplication.focusWidget().clearFocus() if clear_canvases: for canvas in self.ui.image_tab_widget.image_canvases: canvas.clear() if self.image_mode == 'cartesian': self.ui.image_tab_widget.show_cartesian() elif self.image_mode == 'polar': self.ui.image_tab_widget.show_polar() else: self.ui.image_tab_widget.load_images() self.calibration_config_widget.unblock_all_signals(prev_blocked)
def match_images(self, fnames): file_list = [] dets = [] for item in os.scandir(self.parent_dir): file_name = os.path.splitext(item.name)[0] instance = file_name.rsplit('_', 1)[0] if instance == file_name: continue det = file_name.rsplit('_', 1)[1] if os.path.isfile(item) and instance in fnames: file_list.append(item.path) if det and det not in dets: dets.append(det) self.files.append([]) for f in file_list: det = f.rsplit('.', 1)[0].rsplit('_', 1)[1] if det in dets: i = dets.index(det) self.files[i].append(f) # Display error if equivalent files are not found for ea. detector files_per_det = all( len(self.files[0]) == len(elem) for elem in self.files) num_det = len(HexrdConfig().get_detector_names()) if len(self.files) != num_det or not files_per_det: msg = ( 'ERROR - There must be the same number of files for each detector.' ) QMessageBox.warning(None, 'HEXRD', msg) self.files = [] return self.files = sorted(self.files)[:len(self.files)]
def load_config(self): selected_file, selected_filter = QFileDialog.getOpenFileName( self.ui, 'Load Configuration', HexrdConfig().working_dir, 'HEXRD files (*.hexrd *.yml)') self.config_file = selected_file if selected_file else None self.ui.config_file_label.setText(os.path.basename(self.config_file)) self.ui.config_file_label.setToolTip(self.config_file)
def update_config(self): # Set the new config options on the internal config config = HexrdConfig().config detector_config = config['instrument']['detectors'][self.detector] buffer_default = {'status': 0} buffer = detector_config.setdefault('buffer', buffer_default) if self.mode == CONFIG_MODE_BORDER: buffer['value'] = [self.x_border, self.y_border] else: array = np.load(self.file_name) # Must match the detector size detector_shape = (detector_config['pixels']['rows']['value'], detector_config['pixels']['columns']['value']) if array.shape != detector_shape: msg = 'The NumPy array shape must match the detector' QMessageBox.critical(self.ui, 'HEXRD', msg) self.show() return False buffer['value'] = array return True
def ome_maps_viewed(self): # The dialog should have automatically updated our internal config # Let's go ahead and run the indexing! # Create a full indexing config config = create_indexing_config() # Hexrd normally applies filtering immediately after eta omega # maps are loaded. We will perform the user-selected filtering now. filter_maps_if_requested(self.ome_maps, config) # Setup to run indexing in background self.progress_dialog.setWindowTitle('Find Orientations') self.progress_dialog.setRange(0, 0) # no numerical updates find_orientations = HexrdConfig().indexing_config['find_orientations'] if find_orientations['use_quaternion_grid']: # Load qfib from a numpy file self.qfib = np.load(find_orientations['use_quaternion_grid']) self.orientation_fibers_generated() else: worker = AsyncWorker(self.generate_orientation_fibers, config) self.thread_pool.start(worker) worker.signals.result.connect(self.orientation_fibers_generated) worker.signals.error.connect(self.on_async_error) self.progress_dialog.exec_()
def recursive_add_tree_items(self, cur_config, cur_tree_item): if isinstance(cur_config, dict): keys = cur_config.keys() elif isinstance(cur_config, list): keys = range(len(cur_config)) else: # This must be a value. Set it. cur_tree_item.set_data(STATUS_COL, cur_config) return for key in keys: if key == 'value': data = cur_config[key] if (cur_tree_item.data(KEY_COL) == 'tilt' and HexrdConfig().rotation_matrix_euler() is not None): data = [np.degrees(rad).item() for rad in cur_config[key]] self.set_value(key, data, cur_tree_item) continue elif key == 'status': tree_item = cur_tree_item else: tree_item = self.add_tree_item(key, None, REFINABLE, cur_tree_item) if tree_item is not None: self.recursive_add_tree_items(cur_config[key], tree_item)
def run_indexer(self): config = create_indexing_config() # Find orientations self.update_progress_text('Running indexer (paintGrid)') ncpus = config.multiprocessing self.completeness = indexer.paintGrid( self.qfib, self.ome_maps, etaRange=np.radians(config.find_orientations.eta.range), omeTol=np.radians(config.find_orientations.omega.tolerance), etaTol=np.radians(config.find_orientations.eta.tolerance), omePeriod=np.radians(config.find_orientations.omega.period), threshold=config.find_orientations.threshold, doMultiProc=ncpus > 1, nCPUs=ncpus) print('paintGrid complete') orientations_cfg = HexrdConfig().indexing_config['find_orientations'] if orientations_cfg.get('_write_scored_orientations'): # Write out the scored orientations results = {} results['scored_orientations'] = { 'test_quaternions': self.qfib, 'score': self.completeness } print(f'Writing scored orientations in {config.working_dir} ...') write_scored_orientations(results, config)
def setup_table(self, status=True): self.ui.masks_table.setRowCount(0) for i, key in enumerate(self.masks.keys()): # Add label self.ui.masks_table.insertRow(i) self.ui.masks_table.setItem(i, 0, QTableWidgetItem(key)) # Add checkbox to toggle visibility cb = QCheckBox() status = key in HexrdConfig().visible_masks cb.setChecked(status) cb.setStyleSheet('margin-left:50%; margin-right:50%;') cb.toggled.connect(self.toggle_visibility) self.ui.masks_table.setCellWidget(i, 1, cb) # Add push button to remove mask pb = QPushButton('Remove Mask') pb.clicked.connect(self.remove_mask) self.ui.masks_table.setCellWidget(i, 2, pb) # Connect manager to raw image mode tab settings # for threshold mask mtype, data = self.masks[key] if mtype == 'threshold': self.setup_threshold_connections(cb, pb)
def clustering_needs_min_samples(self): # Determine whether we need the min_samples for clustering find_orientations = HexrdConfig().indexing_config['find_orientations'] return all(( find_orientations['use_quaternion_grid'] is None, find_orientations['clustering']['algorithm'] != 'fclusterdata', ))
def match_files(self, fnames): dets = HexrdConfig().detector_names # Look for files that match everything except detector name # ex: /home/user/images/Ruby_line_ff_000017_ge1.npz becomes # /home/user/images/Ruby_line_ff_000017_*.npz search = [] for f in fnames: path, fname = os.path.split(f) files = [det for det in dets if det in fname] if not files: search.append('/'.join([path, fname])) else: for d in dets: next_file = d.join(fname.rsplit(files[0])) search.append('/'.join([path, next_file])) files = self.match_selected_files(fnames, search) if not self.check_success(files): # Look in sibling directories if the matching files were not # found in the current directory. revised_search = [] for f in fnames: directory = os.path.basename(os.path.dirname(f)) for d in dets: revised_search.append(d.join(f.split(directory))) files = self.match_selected_files(fnames, revised_search) return files
def finish_show_cartesian(self, iviewer): self.iviewer = iviewer img = self.iviewer.img # It is important to persist the plot so that we don't reset the scale. rescale_image = True if len(self.axes_images) == 0: self.axis = self.figure.add_subplot(111) self.axes_images.append( self.axis.imshow(img, cmap=self.cmap, norm=self.norm, vmin=None, vmax=None, interpolation="none")) self.axis.set_xlabel(r'x (mm)') self.axis.set_ylabel(r'y (mm)') else: rescale_image = False self.axes_images[0].set_data(img) # We must adjust the extent of the image if rescale_image: self.axes_images[0].set_extent(iviewer.extent) self.axis.relim() self.axis.autoscale_view() self.axis.autoscale(False) self.figure.tight_layout() self.update_overlays() self.draw_detector_borders() msg = 'Cartesian view loaded!' HexrdConfig().emit_update_status_bar(msg)
def results(self): table = self.ui.match_detectors_table detectors = [] image_files = [] for i in range(table.rowCount()): try: detectors.append(table.cellWidget(i, 0).currentText()) except Exception: detectors.append(table.item(i, 0).text()) image_files.append(table.item(i, 2).text()) idx = table.cellWidget(i, 1).currentIndex() imgs_per_det = ( len(self.image_files)/len(HexrdConfig().detector_names)) HexrdConfig().load_panel_state['trans'][int(i/imgs_per_det)] = idx return detectors, image_files
def add_template(self): self.it = InteractiveTemplate(HexrdConfig().image(self.detector, 0), self.parent()) self.it.create_shape( module=hexrd_resources, file_name=f'{self.instrument}_{self.detector}_bnd.txt', det=self.detector) if self.instrument == 'PXRDIP': self.it.rotate_shape(angle=-90) self.display_bounds() self.enable_widgets(self.ui.trans, self.ui.rotate, self.ui.button_box, self.ui.complete, enabled=True) self.enable_widgets(self.ui.detectors, self.ui.add_template, self.ui.load, enabled=False) if self.ui.instruments.currentText() != 'TARDIS': self.enable_widgets(self.ui.height_label, self.ui.bb_height, self.ui.bb_width, self.ui.width_label, self.ui.bb_label, enabled=True) self.ui.trans.setChecked(True)
def on_min_d_spacing_changed(self): min_d = self.ui.min_d_spacing.value() wavelength = HexrdConfig().beam_wavelength w = self.ui.max_tth block_signals = w.blockSignals(True) try: # Bragg's law theta = math.degrees(math.asin(wavelength / 2.0 / min_d)) w.setValue(theta * 2.0) finally: w.blockSignals(block_signals) # Update the config HexrdConfig().active_material_tth_max = math.radians(theta * 2.0) self.update_table()
def finalize(self): self.it.cropped_image img = self.it.masked_image ilm = ImageLoadManager() self.cmap.block_updates(True) ilm.read_data([[img]], parent=self.ui) if self.instrument == 'PXRDIP': ilm.set_state({'trans': [UI_TRANS_INDEX_ROTATE_90]}) ilm.begin_processing(postprocess=True) img = HexrdConfig().image(self.detector, 0) self.cmap.block_updates(False) self.it.update_image(img) self.edited_images[self.detector] = { 'img': img, 'height': img.shape[0], 'width': img.shape[1], 'tilt': self.it.rotation } self.canvas.axes_images[0].set_extent( (0, img.shape[1], img.shape[0], 0)) self.it.redraw() self.clear_boundry()
def update_table(self): block_list = [self.ui.table, self.ui.table.selectionModel()] blockers = [QSignalBlocker(x) for x in block_list] # noqa: F841 prev_selected = self.selected_row overlays = HexrdConfig().overlays self.clear_table() self.ui.table.setRowCount(len(overlays)) for i, overlay in enumerate(overlays): w = self.create_materials_combo(overlay['material']) self.ui.table.setCellWidget(i, COLUMNS['material'], w) w = self.create_type_combo(overlay['type']) self.ui.table.setCellWidget(i, COLUMNS['type'], w) w = self.create_visibility_checkbox(overlay['visible']) self.ui.table.setCellWidget(i, COLUMNS['visible'], w) if prev_selected is not None: select_row = (prev_selected if prev_selected < len(overlays) else len(overlays) - 1) self.select_row(select_row) self.ui.table.resizeColumnsToContents() # Just in case the selection actually changed... self.selection_changed()
def setup_ui_connections(self): self.ui.button_box.accepted.connect(self.apply_masks) self.ui.button_box.rejected.connect(self.cancel) self.ui.rejected.connect(self.cancel) self.ui.shape.currentIndexChanged.connect(self.select_shape) self.ui.undo.clicked.connect(self.undo_selection) HexrdConfig().tab_images_changed.connect(self.tabbed_view_changed)