def shell(kernel_manager, kernel_client): widget = RichIPythonWidget() widget.kernel_manager = kernel_manager widget.kernel_client = kernel_client widget.exit_requested.connect(stop) widget.setWindowTitle("IPython shell") return widget
class BaseApp(QtCore.QObject): def __init__(self, argv=[]): QtCore.QObject.__init__(self) self.log = get_logger_from_class(self) self.this_dir, self.this_filename = os.path.split(__file__) self.qtapp = QtWidgets.QApplication.instance() if not self.qtapp: self.qtapp = QtWidgets.QApplication(argv) self.settings = LQCollection() # auto creation of console widget self.setup_console_widget() # FIXME Breaks things for microscopes, but necessary for stand alone apps! #if hasattr(self, "setup"): # self.setup() self.setup_logging() if not hasattr(self, 'name'): self.name = "ScopeFoundry" self.qtapp.setApplicationName(self.name) def exec_(self): return self.qtapp.exec_() def setup_console_widget(self, kernel=None): """ Create and return console QWidget. If Jupyter / IPython is installed this widget will be a full-featured IPython console. If Jupyter is unavailable it will fallback to a pyqtgraph.console.ConsoleWidget. If the app is started in an Jupyter notebook, the console will be connected to the notebook's IPython kernel. the returned console_widget will also be accessible as self.console_widget In order to see the console widget, remember to insert it into an existing window or call self.console_widget.show() to create a new window """ if CONSOLE_TYPE == 'pyqtgraph.console': self.console_widget = pyqtgraph.console.ConsoleWidget( namespace={ 'app': self, 'pg': pg, 'np': np }, text="ScopeFoundry Console") elif CONSOLE_TYPE == 'qtconsole': if kernel == None: try: # try to find an existing kernel #https://github.com/jupyter/notebook/blob/master/docs/source/examples/Notebook/Connecting%20with%20the%20Qt%20Console.ipynb import ipykernel as kernel conn_file = kernel.get_connection_file() import qtconsole.qtconsoleapp self.qtconsole_app = qtconsole.qtconsoleapp.JupyterQtConsoleApp( ) self.console_widget = self.qtconsole_app.new_frontend_connection( conn_file) self.console_widget.setWindowTitle( "ScopeFoundry IPython Console") except: # make your own new in-process kernel # https://github.com/ipython/ipython-in-depth/blob/master/examples/Embedding/inprocess_qtconsole.py self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.shell.banner1 += """ ScopeFoundry Console Variables: * np: numpy package * app: the ScopeFoundry App object """ self.kernel.gui = 'qt4' self.kernel.shell.push({'np': np, 'app': self}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() #self.console_widget = RichIPythonWidget() self.console_widget = RichJupyterWidget() self.console_widget.setWindowTitle( "ScopeFoundry IPython Console") self.console_widget.kernel_manager = self.kernel_manager self.console_widget.kernel_client = self.kernel_client else: import qtconsole.qtconsoleapp self.qtconsole_app = qtconsole.qtconsoleapp.JupyterQtConsoleApp( ) self.console_widget = self.qtconsole_app.new_frontend_connection( kernel.get_connection_file()) self.console_widget.setWindowTitle( "ScopeFoundry IPython Console") else: raise ValueError("CONSOLE_TYPE undefined") return self.console_widget def setup(self): pass def settings_save_ini(self, fname, save_ro=True): """""" config = configparser.ConfigParser() config.optionxform = str config.add_section('app') config.set('app', 'name', self.name) for lqname, lq in self.settings.as_dict().items(): if not lq.ro or save_ro: config.set('app', lqname, lq.ini_string_value()) with open(fname, 'w') as configfile: config.write(configfile) self.log.info("ini settings saved to {} {}".format( fname, config.optionxform)) def settings_load_ini(self, fname): self.log.info("ini settings loading from " + fname) config = configparser.ConfigParser() config.optionxform = str config.read(fname) if 'app' in config.sections(): for lqname, new_val in config.items('app'): #print(lqname) lq = self.settings.as_dict().get(lqname) if lq: if lq.dtype == bool: new_val = str2bool(new_val) lq.update_value(new_val) def settings_save_ini_ask(self, dir=None, save_ro=True): """Opens a Save dialogue asking the user to select a save destination and give the save file a filename. Saves settings to an .ini file.""" # TODO add default directory, etc fname, _ = QtWidgets.QFileDialog.getSaveFileName( self.ui, caption=u'Save Settings', dir=u"", filter=u"Settings (*.ini)") #print(repr(fname)) if fname: self.settings_save_ini(fname, save_ro=save_ro) return fname def settings_load_ini_ask(self, dir=None): """Opens a Load dialogue asking the user which .ini file to load into our app settings. Loads settings from an .ini file.""" # TODO add default directory, etc fname, _ = QtWidgets.QFileDialog.getOpenFileName( None, "Settings (*.ini)") #print(repr(fname)) if fname: self.settings_load_ini(fname) return fname def setup_logging(self): logging.basicConfig( level=logging.WARN) #, filename='example.log', stream=sys.stdout) logging.getLogger('traitlets').setLevel(logging.WARN) logging.getLogger('ipykernel.inprocess').setLevel(logging.WARN) logging.getLogger('LoggedQuantity').setLevel(logging.WARN) logging.getLogger('PyQt5').setLevel(logging.WARN) logger = logging.getLogger('FoundryDataBrowser') self.logging_widget = QtWidgets.QWidget() self.logging_widget.setWindowTitle("Log") self.logging_widget.setLayout(QtWidgets.QVBoxLayout()) self.logging_widget.search_lineEdit = QtWidgets.QLineEdit() self.logging_widget.log_textEdit = QtWidgets.QTextEdit("") self.logging_widget.layout().addWidget( self.logging_widget.search_lineEdit) self.logging_widget.layout().addWidget( self.logging_widget.log_textEdit) self.logging_widget.log_textEdit.document().setDefaultStyleSheet( "body{font-family: Courier;}") self.logging_widget_handler = LoggingQTextEditHandler( self.logging_widget.log_textEdit, level=logging.DEBUG) logging.getLogger().addHandler(self.logging_widget_handler)
class BaseApp(QtCore.QObject): def __init__(self, argv): QtCore.QObject.__init__(self) self.log = get_logger_from_class(self) self.this_dir, self.this_filename = os.path.split(__file__) self.qtapp = QtWidgets.QApplication.instance() if not self.qtapp: self.qtapp = QtWidgets.QApplication(argv) self.settings = LQCollection() self.setup_console_widget() # FIXME Breaks things for microscopes, but necessary for stand alone apps! #if hasattr(self, "setup"): # self.setup() if not hasattr(self, 'name'): self.name = "ScopeFoundry" self.qtapp.setApplicationName(self.name) def exec_(self): return self.qtapp.exec_() def setup_console_widget(self): # Console if CONSOLE_TYPE == 'pyqtgraph.console': self.console_widget = pyqtgraph.console.ConsoleWidget( namespace={ 'app': self, 'pg': pg, 'np': np }, text="ScopeFoundry Console") elif CONSOLE_TYPE == 'qtconsole': # https://github.com/ipython/ipython-in-depth/blob/master/examples/Embedding/inprocess_qtconsole.py self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.gui = 'qt4' self.kernel.shell.push({'np': np, 'app': self}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() #self.console_widget = RichIPythonWidget() self.console_widget = RichJupyterWidget() self.console_widget.setWindowTitle("ScopeFoundry IPython Console") self.console_widget.kernel_manager = self.kernel_manager self.console_widget.kernel_client = self.kernel_client else: raise ValueError("CONSOLE_TYPE undefined") return self.console_widget def setup(self): pass def settings_save_ini(self, fname, save_ro=True): """""" config = configparser.ConfigParser() config.optionxform = str config.add_section('app') config.set('app', 'name', self.name) for lqname, lq in self.settings.as_dict().items(): if not lq.ro or save_ro: config.set('app', lqname, lq.ini_string_value()) with open(fname, 'w') as configfile: config.write(configfile) self.log.info("ini settings saved to {} {}".format( fname, config.optionxform)) def settings_load_ini(self, fname): self.log.info("ini settings loading from " + fname) config = configparser.ConfigParser() config.optionxform = str config.read(fname) if 'app' in config.sections(): for lqname, new_val in config.items('app'): #print(lqname) lq = self.settings.as_dict().get(lqname) if lq: if lq.dtype == bool: new_val = str2bool(new_val) lq.update_value(new_val) def settings_save_ini_ask(self, dir=None, save_ro=True): """Opens a Save dialogue asking the user to select a save destination and give the save file a filename. Saves settings to an .ini file.""" # TODO add default directory, etc fname, _ = QtWidgets.QFileDialog.getSaveFileName( self.ui, caption=u'Save Settings', dir=u"", filter=u"Settings (*.ini)") #print(repr(fname)) if fname: self.settings_save_ini(fname, save_ro=save_ro) return fname def settings_load_ini_ask(self, dir=None): """Opens a Load dialogue asking the user which .ini file to load into our app settings. Loads settings from an .ini file.""" # TODO add default directory, etc fname, _ = QtWidgets.QFileDialog.getOpenFileName( None, "Settings (*.ini)") #print(repr(fname)) if fname: self.settings_load_ini(fname) return fname
class DataViewer(QtWidgets.QMainWindow): """ The class is used by instantiating and then entering the main Qt loop with, e.g.: app = DataViewer(sys.argv) app.exec_() """ def __init__(self, argv): """ Initialize class, setting up windows and widgets. """ # Define this as the QApplication object self.qtapp = QtWidgets.QApplication.instance() if not self.qtapp: self.qtapp = QtWidgets.QApplication(argv) QtWidgets.QMainWindow.__init__(self) self.this_dir, self.this_filename = os.path.split(__file__) # Make settings collection self.settings = LQCollection() # Set up sub-windows and arrange into primary py4DSTEM window self.diffraction_space_widget = self.setup_diffraction_space_widget() self.real_space_widget = self.setup_real_space_widget() self.control_widget = self.setup_control_widget() self.console_widget = self.setup_console_widget() self.main_window = self.setup_main_window() # Set up temporary datacube self.datacube = DataCube(data=np.zeros((10, 10, 10, 10))) # Set up initial views in real and diffraction space self.update_diffraction_space_view() self.update_virtual_detector_shape() self.update_virtual_detector_mode() self.update_real_space_view() self.diffraction_space_widget.ui.normDivideRadio.setChecked(True) self.diffraction_space_widget.normRadioChanged() return ############################################### ############ Widget setup methods ############# ############################################### def setup_control_widget(self): """ Set up the control window for diffraction space. """ #self.control_widget = load_qt_ui_file(sibling_path(__file__, "control_widget.ui")) self.control_widget = ControlPanel() self.control_widget.setWindowTitle("Control Panel") ############################ Controls ############################### # For each control: # # -creates items in self.settings # # -connects UI changes to updates in self.settings # # -connects updates in self.settings items to function calls # # -connects button clicks to function calls # ##################################################################### # Load self.settings.New('data_filename', dtype='file') self.settings.data_filename.connect_to_browse_widgets( self.control_widget.lineEdit_LoadFile, self.control_widget.pushButton_BrowseFiles) self.settings.data_filename.updated_value.connect(self.load_file) # Preprocess self.settings.New('R_Nx', dtype=int, initial=1) self.settings.New('R_Ny', dtype=int, initial=1) self.settings.New('bin_r', dtype=int, initial=1) self.settings.New('bin_q', dtype=int, initial=1) self.settings.New('crop_r_showROI', dtype=bool, initial=False) self.settings.New('crop_q_showROI', dtype=bool, initial=False) self.settings.New('isCropped_r', dtype=bool, initial=False) self.settings.New('isCropped_q', dtype=bool, initial=False) self.settings.New('crop_rx_min', dtype=int, initial=0) self.settings.New('crop_rx_max', dtype=int, initial=0) self.settings.New('crop_ry_min', dtype=int, initial=0) self.settings.New('crop_ry_max', dtype=int, initial=0) self.settings.New('crop_qx_min', dtype=int, initial=0) self.settings.New('crop_qx_max', dtype=int, initial=0) self.settings.New('crop_qy_min', dtype=int, initial=0) self.settings.New('crop_qy_max', dtype=int, initial=0) self.settings.R_Nx.connect_bidir_to_widget( self.control_widget.spinBox_Nx) self.settings.R_Ny.connect_bidir_to_widget( self.control_widget.spinBox_Ny) self.settings.bin_r.connect_bidir_to_widget( self.control_widget.spinBox_Bin_Real) self.settings.bin_q.connect_bidir_to_widget( self.control_widget.spinBox_Bin_Diffraction) self.settings.crop_r_showROI.connect_bidir_to_widget( self.control_widget.checkBox_Crop_Real) self.settings.crop_q_showROI.connect_bidir_to_widget( self.control_widget.checkBox_Crop_Diffraction) self.settings.R_Nx.updated_value.connect(self.update_scan_shape_Nx) self.settings.R_Ny.updated_value.connect(self.update_scan_shape_Ny) self.settings.crop_r_showROI.updated_value.connect( self.toggleCropROI_real) self.settings.crop_q_showROI.updated_value.connect( self.toggleCropROI_diffraction) self.control_widget.pushButton_CropData.clicked.connect(self.crop_data) self.control_widget.pushButton_BinData.clicked.connect(self.bin_data) self.control_widget.pushButton_EditFileMetadata.clicked.connect( self.edit_file_metadata) self.control_widget.pushButton_EditDirectoryMetadata.clicked.connect( self.edit_directory_metadata) self.control_widget.pushButton_SaveFile.clicked.connect(self.save_file) self.control_widget.pushButton_SaveDirectory.clicked.connect( self.save_directory) # Virtual detectors self.settings.New('virtual_detector_shape', dtype=int, initial=0) self.settings.New('virtual_detector_mode', dtype=int, initial=0) self.settings.virtual_detector_shape.connect_bidir_to_widget( self.control_widget.buttonGroup_DetectorShape) self.settings.virtual_detector_mode.connect_bidir_to_widget( self.control_widget.buttonGroup_DetectorMode) self.settings.virtual_detector_shape.updated_value.connect( self.update_virtual_detector_shape) self.settings.virtual_detector_mode.updated_value.connect( self.update_virtual_detector_mode) return self.control_widget def setup_diffraction_space_widget(self): """ Set up the diffraction space window. """ # Create pyqtgraph ImageView object self.diffraction_space_widget = pg.ImageView() self.diffraction_space_widget.setImage(np.zeros((512, 512))) # Create virtual detector ROI selector self.virtual_detector_roi = pg.RectROI([256, 256], [50, 50], pen=(3, 9)) self.diffraction_space_widget.getView().addItem( self.virtual_detector_roi) self.virtual_detector_roi.sigRegionChangeFinished.connect( self.update_real_space_view) # Name and return self.diffraction_space_widget.setWindowTitle('Diffraction Space') return self.diffraction_space_widget def setup_real_space_widget(self): """ Set up the real space window. """ # Create pyqtgraph ImageView object self.real_space_widget = pg.ImageView() self.real_space_widget.setImage(np.zeros((512, 512))) # Add point selector connected to displayed diffraction pattern self.real_space_point_selector = pg_point_roi( self.real_space_widget.getView()) self.real_space_point_selector.sigRegionChanged.connect( self.update_diffraction_space_view) # Name and return self.real_space_widget.setWindowTitle('Real Space') return self.real_space_widget def setup_console_widget(self): self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.gui = 'qt4' self.kernel.shell.push({'np': np, 'app': self}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.console_widget = RichJupyterWidget() self.console_widget.setWindowTitle("py4DSTEM IPython Console") self.console_widget.kernel_manager = self.kernel_manager self.console_widget.kernel_client = self.kernel_client return self.console_widget def setup_main_window(self): """ Setup main window, arranging sub-windows inside """ self.main_window = QtWidgets.QWidget() self.main_window.setWindowTitle("py4DSTEM") layout_data = QtWidgets.QHBoxLayout() layout_data.addWidget(self.diffraction_space_widget, 1) layout_data.addWidget(self.real_space_widget, 1) layout_data_and_control = QtWidgets.QHBoxLayout() layout_data_and_control.addWidget(self.control_widget, 0) layout_data_and_control.addLayout(layout_data, 1) layout_data_and_control.setSpacing(0) layout_data_and_control.setContentsMargins(0, 0, 0, 0) self.main_window.setLayout(layout_data_and_control) self.main_window.setGeometry(0, 0, 3600, 1600) self.console_widget.setGeometry(0, 1800, 1600, 250) self.main_window.show() self.main_window.raise_() self.console_widget.show() self.console_widget.raise_() return self.main_window ################################################################## ############## Methods connecting to user inputs ################# ################################################################## ################################################################## # In general, these methods collect any relevant user inputs, # # then pass them to functions defined elsewhere, often in e.g. # # the process directory. # # Additional functionality here should be avoided, to ensure # # consistent output between processing run through the GUI # # or from the command line. # ################################################################## ################ Load ################ def load_file(self): """ Loads a file by creating and storing a DataCube object. """ fname = self.settings.data_filename.val print("Loading file", fname) # Instantiate DataCube object self.datacube = None gc.collect() self.datacube = read(fname) # Update scan shape information self.settings.R_Nx.update_value(self.datacube.R_Nx) self.settings.R_Ny.update_value(self.datacube.R_Ny) # Update data views self.update_diffraction_space_view() self.update_virtual_detector_shape() self.update_virtual_detector_mode() self.update_real_space_view() # Normalize diffraction space view self.diffraction_space_widget.ui.normDivideRadio.setChecked(True) self.diffraction_space_widget.normRadioChanged() # Set scan size maxima self.control_widget.spinBox_Nx.setMaximum(self.datacube.R_N) self.control_widget.spinBox_Ny.setMaximum(self.datacube.R_N) return ############## Preprocess ############## ### Scan Shape ### def update_scan_shape_Nx(self): R_Nx = self.settings.R_Nx.val self.settings.R_Ny.update_value(int(self.datacube.R_N / R_Nx)) R_Ny = self.settings.R_Ny.val self.datacube.set_scan_shape(R_Nx, R_Ny) self.update_real_space_view() def update_scan_shape_Ny(self): R_Ny = self.settings.R_Ny.val self.settings.R_Nx.update_value(int(self.datacube.R_N / R_Ny)) R_Nx = self.settings.R_Nx.val self.datacube.set_scan_shape(R_Nx, R_Ny) self.update_real_space_view() ### Crop ### def toggleCropROI_real(self, show=True): """ If show=True, makes an RIO. If False, removes the ROI. """ if show: self.crop_roi_real = pg.RectROI( [0, 0], [self.datacube.R_Nx, self.datacube.R_Ny], pen=(3, 9), removable=True, translateSnap=True, scaleSnap=True) self.crop_roi_real.setPen(color='r') self.real_space_widget.getView().addItem(self.crop_roi_real) else: if hasattr(self, 'crop_roi_real'): self.real_space_widget.getView().removeItem(self.crop_roi_real) self.crop_roi_real = None else: pass def toggleCropROI_diffraction(self, show=True): """ If show=True, makes an RIO. If False, removes the ROI. """ if show: self.crop_roi_diffraction = pg.RectROI( [0, 0], [self.datacube.Q_Nx, self.datacube.Q_Ny], pen=(3, 9), removable=True, translateSnap=True, scaleSnap=True) self.crop_roi_diffraction.setPen(color='r') self.diffraction_space_widget.getView().addItem( self.crop_roi_diffraction) else: if hasattr(self, 'crop_roi_diffraction'): self.diffraction_space_widget.getView().removeItem( self.crop_roi_diffraction) self.crop_roi_diffraction = None else: pass def crop_data(self): # Diffraction space if self.control_widget.checkBox_Crop_Diffraction.isChecked(): # Get crop limits from ROI slices_q, transforms_q = self.crop_roi_diffraction.getArraySlice( self.datacube.data4D[0, 0, :, :], self.diffraction_space_widget.getImageItem()) slice_qx, slice_qy = slices_q crop_Qx_min, crop_Qx_max = slice_qx.start, slice_qx.stop - 1 crop_Qy_min, crop_Qy_max = slice_qy.start, slice_qy.stop - 1 crop_Qx_min, crop_Qx_max = max(0, crop_Qx_min), min( self.datacube.Q_Nx, crop_Qx_max) crop_Qy_min, crop_Qy_max = max(0, crop_Qy_min), min( self.datacube.Q_Ny, crop_Qy_max) # Move ROI selector x0, y0 = self.virtual_detector_roi.x( ), self.virtual_detector_roi.y() x0_len, y0_len = self.virtual_detector_roi.size() xf = int(x0 * (crop_Qx_max - crop_Qx_min) / self.datacube.Q_Nx) yf = int(y0 * (crop_Qy_max - crop_Qy_min) / self.datacube.Q_Ny) xf_len = int(x0_len * (crop_Qx_max - crop_Qx_min) / self.datacube.Q_Nx) yf_len = int(y0_len * (crop_Qy_max - crop_Qy_min) / self.datacube.Q_Ny) self.virtual_detector_roi.setPos((xf, yf)) self.virtual_detector_roi.setSize((xf_len, yf_len)) # Crop data self.datacube.crop_data_diffraction(crop_Qx_min, crop_Qx_max, crop_Qy_min, crop_Qy_max) # Update settings self.settings.crop_qx_min.update_value(crop_Qx_min) self.settings.crop_qx_max.update_value(crop_Qx_max) self.settings.crop_qy_min.update_value(crop_Qy_min) self.settings.crop_qy_max.update_value(crop_Qy_max) self.settings.isCropped_q.update_value(True) # Uncheck crop checkbox and remove ROI self.control_widget.checkBox_Crop_Diffraction.setChecked(False) # Update display self.update_diffraction_space_view() else: self.settings.isCropped_q.update_value(False) # Real space if self.control_widget.checkBox_Crop_Real.isChecked(): # Get crop limits from ROI slices_r, transforms_r = self.crop_roi_real.getArraySlice( self.datacube.data4D[:, :, 0, 0], self.real_space_widget.getImageItem()) slice_rx, slice_ry = slices_r crop_Rx_min, crop_Rx_max = slice_rx.start, slice_rx.stop - 1 crop_Ry_min, crop_Ry_max = slice_ry.start, slice_ry.stop - 1 crop_Rx_min, crop_Rx_max = max(0, crop_Rx_min), min( self.datacube.R_Nx, crop_Rx_max) crop_Ry_min, crop_Ry_max = max(0, crop_Ry_min), min( self.datacube.R_Ny, crop_Ry_max) # Move point selector x0, y0 = self.real_space_point_selector.x( ), self.real_space_point_selector.y() xf = int(x0 * (crop_Rx_max - crop_Rx_min) / self.datacube.R_Nx) yf = int(y0 * (crop_Ry_max - crop_Ry_min) / self.datacube.R_Ny) self.real_space_point_selector.setPos((xf, yf)) # Crop data self.datacube.crop_data_real(crop_Rx_min, crop_Rx_max, crop_Ry_min, crop_Ry_max) # Update settings self.settings.crop_rx_min.update_value(crop_Rx_min) self.settings.crop_rx_max.update_value(crop_Rx_max) self.settings.crop_ry_min.update_value(crop_Ry_min) self.settings.crop_ry_max.update_value(crop_Ry_max) self.settings.isCropped_r.update_value(True) self.settings.R_Nx.update_value(self.datacube.R_Nx, send_signal=False) self.settings.R_Ny.update_value(self.datacube.R_Ny, send_signal=False) # Uncheck crop checkbox and remove ROI self.control_widget.checkBox_Crop_Real.setChecked(False) # Update display self.update_real_space_view() else: self.settings.isCropped_r.update_value(False) ### Bin ### def bin_data(self): # Get bin factors from GUI bin_factor_Q = self.settings.bin_q.val bin_factor_R = self.settings.bin_r.val if bin_factor_Q > 1: # Move ROI selector x0, y0 = self.virtual_detector_roi.x( ), self.virtual_detector_roi.y() x0_len, y0_len = self.virtual_detector_roi.size() xf = int(x0 / bin_factor_Q) yf = int(y0 / bin_factor_Q) xf_len = int(x0_len / bin_factor_Q) yf_len = int(y0_len / bin_factor_Q) self.virtual_detector_roi.setPos((xf, yf)) self.virtual_detector_roi.setSize((xf_len, yf_len)) # Bin data self.datacube.bin_data_diffraction(bin_factor_Q) # Update display self.update_diffraction_space_view() if bin_factor_R > 1: # Move point selector x0, y0 = self.real_space_point_selector.x( ), self.real_space_point_selector.y() xf = int(x0 / bin_factor_R) yf = int(y0 / bin_factor_R) self.real_space_point_selector.setPos((xf, yf)) # Bin data self.datacube.bin_data_real(bin_factor_R) # Update settings self.settings.R_Nx.update_value(self.datacube.R_Nx, send_signal=False) self.settings.R_Ny.update_value(self.datacube.R_Ny, send_signal=False) # Update display self.update_real_space_view() # Set bin factors back to 1 self.settings.bin_q.update_value(1) self.settings.bin_r.update_value(1) ### Metadata ### def edit_file_metadata(self): """ Creates a popup dialog with tabs for different metadata groups, and fields in each group with current, editable metadata values. """ # Make widget self.EditMetadataWidget = EditMetadataWidget(self.datacube) self.EditMetadataWidget.setWindowTitle("Metadata Editor") self.EditMetadataWidget.show() self.EditMetadataWidget.raise_() # Cancel or save self.EditMetadataWidget.pushButton_Cancel.clicked.connect( self.cancel_editMetadata) self.EditMetadataWidget.pushButton_Save.clicked.connect( self.save_editMetadata) def cancel_editMetadata(self): self.EditMetadataWidget.close() def save_editMetadata(self): print("Updating metadata...") for i in range(self.EditMetadataWidget.tabs.count()): tab = self.EditMetadataWidget.tabs.widget(i) # Get appropriate metadata dict tabname = self.EditMetadataWidget.tabs.tabText(i) metadata_dict_name = [ name for name in self.datacube.metadata.__dict__.keys() if tabname[1:] in name ][0] metadata_dict = getattr(self.datacube.metadata, metadata_dict_name) for row in tab.layout().children(): key = row.itemAt(0).widget().text() try: value = row.itemAt(1).widget().text() except AttributeError: # Catches alternate widget (QPlainTextEdit) in comments tab value = row.itemAt(1).widget().toPlainText() try: value = float(value) except ValueError: pass metadata_dict[key] = value self.EditMetadataWidget.close() print("Done.") def edit_directory_metadata(self): print('edit directory metadata pressed') pass ### Save ### def save_file(self): """ Saving files to the .h5 format. This method: 1) opens a separate dialog 2) puts a name in the "Save as:" field according to the original filename and any preprocessing that's been done 2) Exits with or without saving when 'Save' or 'Cancel' buttons are pressed. """ # Make widget save_path = os.path.splitext( self.settings.data_filename.val)[0] + '.h5' self.save_widget = SaveWidget(save_path) self.save_widget.setWindowTitle("Save as...") self.save_widget.show() self.save_widget.raise_() # Cancel or save self.save_widget.pushButton_Cancel.clicked.connect(self.cancel_saveas) self.save_widget.pushButton_Execute.clicked.connect( self.execute_saveas) def cancel_saveas(self): self.save_widget.close() def execute_saveas(self): f = self.save_widget.lineEdit_SavePath.text() print("Saving file to {}".format(f)) save_dataobject(self.datacube, f) self.save_widget.close() def save_directory(self): print('save directory metadata pressed') pass ################# Virtual Detectors ################# def update_virtual_detector_shape(self): """ Virtual detector shapes are mapped to integers, following the IDs assigned to the radio buttons in VirtualDetectorWidget in dialogs.py. They are as follows: 1: Rectangular 2: Circular 3: Annular """ detector_shape = self.settings.virtual_detector_shape.val x, y = self.diffraction_space_view.shape x0, y0 = x / 2, y / 2 xr, yr = x / 10, y / 10 # Remove existing detector if hasattr(self, 'virtual_detector_roi'): self.diffraction_space_widget.view.scene().removeItem( self.virtual_detector_roi) if hasattr(self, 'virtual_detector_roi_inner'): self.diffraction_space_widget.view.scene().removeItem( self.virtual_detector_roi_inner) if hasattr(self, 'virtual_detector_roi_outer'): self.diffraction_space_widget.view.scene().removeItem( self.virtual_detector_roi_outer) # Rectangular detector if detector_shape == 0: self.virtual_detector_roi = pg.RectROI( [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(3, 9)) self.diffraction_space_widget.getView().addItem( self.virtual_detector_roi) self.virtual_detector_roi.sigRegionChangeFinished.connect( self.update_real_space_view) # Circular detector elif detector_shape == 1: self.virtual_detector_roi = pg.CircleROI( [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(3, 9)) self.diffraction_space_widget.getView().addItem( self.virtual_detector_roi) self.virtual_detector_roi.sigRegionChangeFinished.connect( self.update_real_space_view) # Annular dector elif detector_shape == 2: # Make outer detector self.virtual_detector_roi_outer = pg.CircleROI( [int(x0 - xr), int(y0 - yr)], [int(2 * xr), int(2 * yr)], pen=(3, 9)) self.diffraction_space_widget.getView().addItem( self.virtual_detector_roi_outer) # Make inner detector self.virtual_detector_roi_inner = pg.CircleROI( [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(4, 9), movable=False) self.diffraction_space_widget.getView().addItem( self.virtual_detector_roi_inner) # Connect size/position of inner and outer detectors self.virtual_detector_roi_outer.sigRegionChangeFinished.connect( self.update_annulus_pos) self.virtual_detector_roi_outer.sigRegionChangeFinished.connect( self.update_annulus_radii) self.virtual_detector_roi_inner.sigRegionChangeFinished.connect( self.update_annulus_radii) # Connect to real space view update function self.virtual_detector_roi_outer.sigRegionChangeFinished.connect( self.update_real_space_view) self.virtual_detector_roi_inner.sigRegionChangeFinished.connect( self.update_real_space_view) else: raise ValueError( "Unknown detector shape value {}. Must be 0, 1, or 2.".format( detector_shape)) self.update_virtual_detector_mode() self.update_real_space_view() def update_annulus_pos(self): """ Function to keep inner and outer rings of annulus aligned. """ R_outer = self.virtual_detector_roi_outer.size().x() / 2 R_inner = self.virtual_detector_roi_inner.size().x() / 2 # Only outer annulus is draggable; when it moves, update position of inner annulus x0 = self.virtual_detector_roi_outer.pos().x() + R_outer y0 = self.virtual_detector_roi_outer.pos().y() + R_outer self.virtual_detector_roi_inner.setPos(x0 - R_inner, y0 - R_inner) def update_annulus_radii(self): R_outer = self.virtual_detector_roi_outer.size().x() / 2 R_inner = self.virtual_detector_roi_inner.size().x() / 2 if R_outer < R_inner: x0 = self.virtual_detector_roi_outer.pos().x() + R_outer y0 = self.virtual_detector_roi_outer.pos().y() + R_outer self.virtual_detector_roi_outer.setSize(2 * R_inner + 6) self.virtual_detector_roi_outer.setPos(x0 - R_inner - 3, y0 - R_inner - 3) def update_virtual_detector_mode(self): """ Virtual detector modes are mapped to integers, following the IDs assigned to the radio buttons in VirtualDetectorWidget in dialogs.py. They are as follows: 0: Integrate 1: Difference, X 2: Difference, Y 3: CoM, Y 4: CoM, X """ detector_mode = self.settings.virtual_detector_mode.val detector_shape = self.settings.virtual_detector_shape.val # Integrating detector if detector_mode == 0: if detector_shape == 0: self.get_virtual_image = self.datacube.get_virtual_image_rect_integrate elif detector_shape == 1: self.get_virtual_image = self.datacube.get_virtual_image_circ_integrate elif detector_shape == 2: self.get_virtual_image = self.datacube.get_virtual_image_annular_integrate else: raise ValueError( "Unknown detector shape value {}".format(detector_shape)) # Difference detector elif detector_mode == 1: if detector_shape == 0: self.get_virtual_image = self.datacube.get_virtual_image_rect_diffX elif detector_shape == 1: self.get_virtual_image = self.datacube.get_virtual_image_circ_diffX elif detector_shape == 2: self.get_virtual_image = self.datacube.get_virtual_image_annular_diffX else: raise ValueError( "Unknown detector shape value {}".format(detector_shape)) elif detector_mode == 2: if detector_shape == 0: self.get_virtual_image = self.datacube.get_virtual_image_rect_diffY elif detector_shape == 1: self.get_virtual_image = self.datacube.get_virtual_image_circ_diffY elif detector_shape == 2: self.get_virtual_image = self.datacube.get_virtual_image_annular_diffY else: raise ValueError( "Unknown detector shape value {}".format(detector_shape)) # CoM detector elif detector_mode == 3: if detector_shape == 0: self.get_virtual_image = self.datacube.get_virtual_image_rect_CoMX elif detector_shape == 1: self.get_virtual_image = self.datacube.get_virtual_image_circ_CoMX elif detector_shape == 2: self.get_virtual_image = self.datacube.get_virtual_image_annular_CoMX else: raise ValueError( "Unknown detector shape value {}".format(detector_shape)) elif detector_mode == 4: if detector_shape == 0: self.get_virtual_image = self.datacube.get_virtual_image_rect_CoMY elif detector_shape == 1: self.get_virtual_image = self.datacube.get_virtual_image_circ_CoMY elif detector_shape == 2: self.get_virtual_image = self.datacube.get_virtual_image_annular_CoMY else: raise ValueError( "Unknown detector shape value {}".format(detector_shape)) else: raise ValueError( "Unknown detector mode value {}".format(detector_mode)) self.update_real_space_view() ################## Get virtual images ################## def update_diffraction_space_view(self): roi_state = self.real_space_point_selector.saveState() x0, y0 = roi_state['pos'] xc, yc = int(x0 + 1), int(y0 + 1) # Set the diffraction space image new_diffraction_space_view, success = self.datacube.get_diffraction_space_view( xc, yc) if success: self.diffraction_space_view = new_diffraction_space_view self.diffraction_space_widget.setImage(self.diffraction_space_view, autoLevels=False, autoRange=False) else: pass return def update_real_space_view(self): detector_shape = self.settings.virtual_detector_shape.val # Rectangular detector if detector_shape == 0: # Get slices corresponding to ROI slices, transforms = self.virtual_detector_roi.getArraySlice( self.datacube.data4D[0, 0, :, :], self.diffraction_space_widget.getImageItem()) slice_x, slice_y = slices # Get the virtual image and set the real space view new_real_space_view, success = self.get_virtual_image( slice_x, slice_y) if success: self.real_space_view = new_real_space_view self.real_space_widget.setImage(self.real_space_view, autoLevels=True) else: pass # Circular detector elif detector_shape == 1: # Get slices corresponding to ROI slices, transforms = self.virtual_detector_roi.getArraySlice( self.datacube.data4D[0, 0, :, :], self.diffraction_space_widget.getImageItem()) slice_x, slice_y = slices # Get the virtual image and set the real space view new_real_space_view, success = self.get_virtual_image( slice_x, slice_y) if success: self.real_space_view = new_real_space_view self.real_space_widget.setImage(self.real_space_view, autoLevels=True) else: pass # Annular detector elif detector_shape == 2: # Get slices corresponding to ROI slices, transforms = self.virtual_detector_roi_outer.getArraySlice( self.datacube.data4D[0, 0, :, :], self.diffraction_space_widget.getImageItem()) slice_x, slice_y = slices slices_inner, transforms = self.virtual_detector_roi_inner.getArraySlice( self.datacube.data4D[0, 0, :, :], self.diffraction_space_widget.getImageItem()) slice_inner_x, slice_inner_y = slices_inner R = 0.5 * ((slice_inner_x.stop - slice_inner_x.start) / (slice_x.stop - slice_x.start) + (slice_inner_y.stop - slice_inner_y.start) / (slice_y.stop - slice_y.start)) # Get the virtual image and set the real space view new_real_space_view, success = self.get_virtual_image( slice_x, slice_y, R) if success: self.real_space_view = new_real_space_view self.real_space_widget.setImage(self.real_space_view, autoLevels=True) else: pass else: print( "Error: unknown detector shape value {}. Must be 0, 1, or 2.". format(detector_shape)) return def exec_(self): return self.qtapp.exec_()
from PyQt4.QtGui import QApplication app = QApplication(sys.argv) kernel_manager = QtInProcessKernelManager() kernel_manager.start_kernel() kernel = kernel_manager.kernel kernel.gui = 'qt4' kernel_client = kernel_manager.client() kernel_client.start_channels() def stop(): kernel_client.stop_channels() kernel_manager.shutdown_kernel() # here you should exit your application with a suitable call sys.exit() widget = RichIPythonWidget() widget.kernel_manager = kernel_manager widget.kernel_client = kernel_client widget.exit_requested.connect(stop) widget.setWindowTitle("IPython shell") ipython_widget = widget ipython_widget.show() app.exec_() sys.exit()