示例#1
0
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
示例#2
0
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)
示例#3
0
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
示例#4
0
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_()
示例#5
0
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()