Exemple #1
0
class ReplDock(DockWidget):
    """Dock widget with terminal emulator
    """
    def __init__(self, title, icon):
        DockWidget.__init__(self, core.mainWindow(), title, icon, "Alt+I")
        self.setObjectName(title)

        self.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea
                             | Qt.RightDockWidgetArea)

        # Copied from https://github.com/jupyter/qtconsole/blob/master/examples/inprocess_qtconsole.py, then modified based on https://github.com/jupyter/qtconsole/blob/master/qtconsole/qtconsoleapp.py -- the QtInProcessKernelManager is blocking, so infinite loops crash Enki!
        kernel_manager = QtKernelManager()
        kernel_manager.start_kernel()
        kernel_manager.client_factory = QtKernelClient
        kernel_manager.kernel.gui = 'qt'

        kernel_client = kernel_manager.client()
        kernel_client.start_channels()

        self.ipython_widget = RichJupyterWidget()
        self.ipython_widget.kernel_manager = kernel_manager
        self.ipython_widget.kernel_client = kernel_client
        # By default, iPython adds a blank line between inputs. Per Monika's request, this eliminates the extra line. See https://qtconsole.readthedocs.io/en/latest/config_options.html#options; this fix was based on info from https://stackoverflow.com/questions/38652671/ipython-5-0-remove-spaces-between-input-lines.
        self.ipython_widget.input_sep = ''
        self.ipython_widget.show()

        self.setWidget(self.ipython_widget)
        self.setFocusProxy(self.ipython_widget)
Exemple #2
0
class ReplDock(DockWidget):
    """Dock widget with terminal emulator
    """

    def __init__(self, title, icon):
        DockWidget.__init__(self, core.mainWindow(), title, icon, "Alt+I")
        self.setObjectName(title)

        self.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

        # Copied from https://github.com/jupyter/qtconsole/blob/master/examples/inprocess_qtconsole.py, then modified based on https://github.com/jupyter/qtconsole/blob/master/qtconsole/qtconsoleapp.py -- the QtInProcessKernelManager is blocking, so infinite loops crash Enki!
        kernel_manager = QtKernelManager()
        kernel_manager.start_kernel()
        kernel_manager.client_factory = QtKernelClient
        kernel_manager.kernel.gui = 'qt'

        kernel_client = kernel_manager.client()
        kernel_client.start_channels()

        self.ipython_widget = RichJupyterWidget()
        self.ipython_widget.kernel_manager = kernel_manager
        self.ipython_widget.kernel_client = kernel_client
        # By default, iPython adds a blank line between inputs. Per Monika's request, this eliminates the extra line. See https://qtconsole.readthedocs.io/en/latest/config_options.html#options; this fix was based on info from https://stackoverflow.com/questions/38652671/ipython-5-0-remove-spaces-between-input-lines.
        self.ipython_widget.input_sep = ''
        self.ipython_widget.show()

        self.setWidget(self.ipython_widget)
        self.setFocusProxy(self.ipython_widget)
Exemple #3
0
class Ipython(object):
    def __init__(self, scripts_path=''):
        self.kernel_manager = QtInProcessKernelManager()
        self.kernel_manager.start_kernel()
        self.kernel = self.kernel_manager.kernel
        sys.stdout = self.kernel.stdout
        sys.stderr = self.kernel.stderr

        self.scripts_path = scripts_path
        self.kernel.gui = 'qt4'

        self.kernel_client = self.kernel_manager.client()
        self.kernel_client.start_channels()

        self.control = RichJupyterWidget()
        self.control.kernel_manager = self.kernel_manager
        self.control.kernel_client = self.kernel_client
        self.control.exit_requested.connect(self.stop)

        self.control.setWindowTitle("IPython shell")

        self.execute('import numpy as np')
        self.execute('from matplotlib import pyplot as plt')
        self.execute('%matplotlib')
        self.execute('')

    def __del__(self):
        self.stop()
        self.close()

    def show(self):
        self.control.show()

        self.control.setWindowState(self.control.windowState()
                                    & ~QtCore.Qt.WindowMinimized
                                    | QtCore.Qt.WindowActive)
        self.control.activateWindow()

    def stop(self):
        self.kernel_client.stop_channels()
        self.kernel_manager.shutdown_kernel()

    def close(self):
        self.control.close()

    def push(self, vardic):
        self.kernel.shell.push(vardic)

    def execute(self, cmd):
        self.control.execute(cmd)

    def run_script(self, scriptname):
        scriptpath = os.path.join(self.scripts_path, scriptname)
        return self.control.execute('run -i %s' % scriptpath)
def show():
    global ipython_widget  # Prevent from being garbage collected

    # Create an in-process kernel
    kernel_manager = QtInProcessKernelManager()
    kernel_manager.start_kernel(show_banner=False)
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'

    kernel_client = kernel_manager.client()
    kernel_client.start_channels()

    ipython_widget = RichJupyterWidget()
    ipython_widget.kernel_manager = kernel_manager
    ipython_widget.kernel_client = kernel_client
    ipython_widget.show()
Exemple #5
0
def show():
    global ipython_widget  # Prevent from being garbage collected

    # Create an in-process kernel
    kernel_manager = QtInProcessKernelManager()
    kernel_manager.start_kernel(show_banner=False)
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'

    kernel_client = kernel_manager.client()
    kernel_client.start_channels()

    ipython_widget = RichJupyterWidget()
    ipython_widget.kernel_manager = kernel_manager
    ipython_widget.kernel_client = kernel_client
    ipython_widget.show()
Exemple #6
0
def independent_qtconsole():

    kernel_manager = QtKernelManager()
    kernel_manager.start_kernel(show_banner=False)
    kernel = kernel_manager.kernel
    kernel.gui = 'qt4'

    kernel_client = kernel_manager.client()
    kernel_client.start_channels()

    ipython_widget = RichJupyterWidget()
    ipython_widget.kernel_manager = kernel_manager
    ipython_widget.kernel_client = kernel_client
    ipython_widget.show()

    return ipython_widget
Exemple #7
0
 def __init__(self, namespace, windowtitle=None):
     from .. import qt_error
     if qt_error is not None:
         self._dummy = True
         return
     self.namespace = namespace
     self.kernel_manager = MyQtInProcessKernelManager()
     self.kernel_manager.start_kernel(namespace)
     self.kernel_client = self.kernel_manager.client()
     self.kernel_client.start_channels()
     control = RichJupyterWidget()
     self.control = control
     control.kernel_manager = self.kernel_manager
     control.kernel_client = self.kernel_client
     if windowtitle is not None:
         control.setWindowTitle("Seamless shell: " + windowtitle)
     control.show()
    def show_console(self):
        global ipython_widget  # Prevent from being garbage collected

        # Create an in-process kernel
        kernel_manager = QtInProcessKernelManager()
        kernel_manager.start_kernel(show_banner=False)
        kernel = kernel_manager.kernel
        kernel.gui = 'qt4'

        kernel_client = kernel_manager.client()
        kernel_client.start_channels()

        ipython_widget = RichJupyterWidget()
        ipython_widget.kernel_manager = kernel_manager
        ipython_widget.kernel_client = kernel_client
        ipython_widget.show()

        ipython_widget.append_stream("from ConsoleInterface import *\n")
Exemple #9
0
    def _run_embedded_qtconsole(conn_filename):
        # This is launched as a new process.
        #
        # Wait max. ten seconds for the IPython kernel to be up and running,
        # which is done by checking for presence of the connection file
        # containing the kernels Zero Message Queue sockets and credentials.
        #
        # Then, start a new QApplication running the Jupyter Console client
        # widget connected to the kernel via the connection file.
        #
        for i in range(100):
            try:
                st = os.stat(conn_filename)
            except OSError as e:
                if e.errno != errno.ENOENT:
                    # No such file exception is ignored, all others re-raised
                    raise
            else:
                if st.st_size > 0:
                    # OK, connection file found, kernel seems to be running
                    break
            time.sleep(0.1)

        app = QtGui.QApplication(["Plot Workbench Console"])

        kernel_client = QtKernelClient(connection_file=conn_filename)
        kernel_client.load_connection_file()
        kernel_client.start_channels()

        def exit():
            kernel_client.shutdown()
            kernel_client.stop_channels()
            app.exit()

        ipython_widget = RichJupyterWidget()
        ipython_widget.kernel_client = kernel_client
        ipython_widget.exit_requested.connect(exit)
        ipython_widget.show()

        app.exec_()
Exemple #10
0
    def inprocess_qtconsole(self):

        #w = QtGui.QWidget()
        kernel_manager = QtInProcessKernelManager()
        kernel_manager.start_kernel(show_banner=False)
        kernel = kernel_manager.kernel
        kernel.gui = 'qt4'
        self.kernel_manager = kernel_manager

        kernel_client = kernel_manager.client()
        kernel_client.start_channels()
        self.kernel_client = kernel_client

        ipython_widget = RichJupyterWidget()
        ipython_widget.kernel_manager = kernel_manager
        ipython_widget.kernel_client = kernel_client

        ipython_widget.exit_requested.connect(self.stop_inprocess)

        ipython_widget.show()
        self.ipython_widget = ipython_widget

        return ipython_widget
Exemple #11
0
class CentralWidget(QWidget):
    """The PyNetAnalyzer central widget"""
    def __init__(self, parent):
        QWidget.__init__(self)
        self.parent = parent
        self.appdata: CnaData = parent.appdata
        self.map_counter = 0
        self.searchbar = QLineEdit()
        self.searchbar.setPlaceholderText("Enter search term")

        self.throttler = SignalThrottler(300)
        self.searchbar.textChanged.connect(self.throttler.throttle)
        self.throttler.triggered.connect(self.update_selected)

        self.tabs = QTabWidget()
        self.reaction_list = ReactionList(self.appdata)
        self.metabolite_list = MetaboliteList(self.appdata)
        self.model_info = ModelInfo(self.appdata)
        self.tabs.addTab(self.reaction_list, "Reactions")
        self.tabs.addTab(self.metabolite_list, "Metabolites")
        self.tabs.addTab(self.model_info, "Model")

        self.map_tabs = QTabWidget()
        self.map_tabs.setTabsClosable(True)
        self.map_tabs.setMovable(True)

        # Create an in-process kernel
        kernel_manager = QtInProcessKernelManager()
        kernel_manager.start_kernel(show_banner=False)
        kernel = kernel_manager.kernel
        kernel.gui = 'qt'

        myglobals = globals()
        myglobals["cna"] = self.parent
        self.kernel_shell = kernel_manager.kernel.shell
        self.kernel_shell.push(myglobals)
        self.kernel_client = kernel_manager.client()
        self.kernel_client.start_channels()

        # Check if client is working
        self.kernel_client.execute('import matplotlib.pyplot as plt')
        self.kernel_client.execute('%matplotlib inline')
        self.kernel_client.execute(
            "%config InlineBackend.figure_format = 'svg'")
        self.console = RichJupyterWidget()
        self.console.kernel_manager = kernel_manager
        self.console.kernel_client = self.kernel_client

        self.splitter = QSplitter()
        self.splitter2 = QSplitter()
        self.splitter2.addWidget(self.map_tabs)
        self.mode_navigator = ModeNavigator(self.appdata)
        self.splitter2.addWidget(self.mode_navigator)
        self.splitter2.addWidget(self.console)
        self.splitter2.setOrientation(Qt.Vertical)
        self.splitter.addWidget(self.splitter2)
        self.splitter.addWidget(self.tabs)
        self.console.show()

        layout = QVBoxLayout()
        layout.addWidget(self.searchbar)
        layout.addWidget(self.splitter)
        self.setLayout(layout)

        self.tabs.currentChanged.connect(self.tabs_changed)
        self.reaction_list.jumpToMap.connect(self.jump_to_map)
        self.reaction_list.jumpToMetabolite.connect(self.jump_to_metabolite)
        self.reaction_list.reactionChanged.connect(
            self.handle_changed_reaction)
        self.reaction_list.reactionDeleted.connect(
            self.handle_deleted_reaction)
        self.metabolite_list.metaboliteChanged.connect(
            self.handle_changed_metabolite)
        self.metabolite_list.jumpToReaction.connect(self.jump_to_reaction)
        self.metabolite_list.computeInOutFlux.connect(self.in_out_fluxes)
        self.model_info.optimizationDirectionChanged.connect(
            self.handle_changed_optimization_direction)
        self.map_tabs.tabCloseRequested.connect(self.delete_map)
        self.mode_navigator.changedCurrentMode.connect(self.update_mode)
        self.mode_navigator.modeNavigatorClosed.connect(self.update)

        self.update()

    def fit_mapview(self):
        self.map_tabs.currentWidget().fit()

    def show_bottom_of_console(self):
        (_, r) = self.splitter2.getRange(1)
        self.splitter2.moveSplitter(r * 0.5, 1)

        vSB = self.console.children()[2].verticalScrollBar()
        max_scroll = vSB.maximum()
        vSB.setValue(max_scroll - 100)

    def handle_changed_reaction(self, old_id: str, reaction: cobra.Reaction):
        self.parent.unsaved_changes()
        for mmap in self.appdata.project.maps:
            if old_id in self.appdata.project.maps[mmap]["boxes"].keys():
                self.appdata.project.maps[mmap]["boxes"][
                    reaction.
                    id] = self.appdata.project.maps[mmap]["boxes"].pop(old_id)

        # TODO update only relevant reaction boxes on maps
        self.update_maps()

    def handle_deleted_reaction(self, reaction: cobra.Reaction):
        self.appdata.project.cobra_py_model.remove_reactions(
            [reaction], remove_orphans=True)

        self.parent.unsaved_changes()
        for mmap in self.appdata.project.maps:
            if reaction.id in self.appdata.project.maps[mmap]["boxes"].keys():
                self.appdata.project.maps[mmap]["boxes"].pop(reaction.id)

        # TODO update only relevant reaction boxes on maps
        self.update_maps()

    def handle_changed_metabolite(self, old_id: str,
                                  metabolite: cobra.Metabolite):
        self.parent.unsaved_changes()
        # TODO update only relevant reaction boxes on maps
        self.update_maps()

    def handle_changed_optimization_direction(self, direction: str):
        self.parent.unsaved_changes()

    def shutdown_kernel(self):
        self.console.kernel_client.stop_channels()
        self.console.kernel_manager.shutdown_kernel()

    def switch_to_reaction(self, reaction: str):
        self.tabs.setCurrentIndex(0)
        self.reaction_list.set_current_item(reaction)

    def minimize_reaction(self, reaction: str):
        self.parent.fba_optimize_reaction(reaction, mmin=True)

    def maximize_reaction(self, reaction: str):
        self.parent.fba_optimize_reaction(reaction, mmin=False)

    def update_reaction_value(self, reaction: str, value: str):
        if value == "":
            self.appdata.scen_values_pop(reaction)
            self.appdata.project.comp_values.pop(reaction, None)
        else:
            try:
                x = float(value)
                self.appdata.scen_values_set(reaction, (x, x))
            except ValueError:
                (vl, vh) = make_tuple(value)
                self.appdata.scen_values_set(reaction, (vl, vh))
        self.reaction_list.update()

    def update_reaction_maps(self, _reaction: str):
        self.parent.unsaved_changes()
        self.reaction_list.reaction_mask.update_state()

    def handle_mapChanged(self, _reaction: str):
        self.parent.unsaved_changes()

    def tabs_changed(self, idx):
        if idx == 0:
            self.reaction_list.update()
        elif idx == 1:
            (clean_model, unused_mets) = prune_unused_metabolites(
                self.appdata.project.cobra_py_model)
            self.appdata.project.cobra_py_model = clean_model
            self.metabolite_list.update()
        elif idx == 2:
            self.model_info.update()

    def add_map(self):
        while True:
            name = "Map " + str(self.map_counter)
            self.map_counter += 1
            if name not in self.appdata.project.maps.keys():
                break
        m = CnaMap(name)

        self.appdata.project.maps[name] = m
        mmap = MapView(self.appdata, name)
        mmap.switchToReactionMask.connect(self.switch_to_reaction)
        mmap.minimizeReaction.connect(self.minimize_reaction)
        mmap.maximizeReaction.connect(self.maximize_reaction)

        mmap.reactionValueChanged.connect(self.update_reaction_value)
        mmap.reactionRemoved.connect(self.update_reaction_maps)
        mmap.reactionAdded.connect(self.update_reaction_maps)
        mmap.mapChanged.connect(self.handle_mapChanged)
        self.map_tabs.addTab(mmap, m["name"])
        self.update_maps()
        self.map_tabs.setCurrentIndex(len(self.appdata.project.maps))
        self.parent.unsaved_changes()

    def delete_map(self, idx: int):
        name = self.map_tabs.tabText(idx)
        diag = ConfirmMapDeleteDialog(self, idx, name)
        diag.exec()

    def update_selected(self):
        x = self.searchbar.text()
        idx = self.tabs.currentIndex()
        if idx == 0:
            self.reaction_list.update_selected(x)
        if idx == 1:
            self.metabolite_list.update_selected(x)

        idx = self.map_tabs.currentIndex()
        if idx >= 0:
            m = self.map_tabs.widget(idx)
            m.update_selected(x)

    def update_mode(self):
        if len(self.appdata.project.modes) > self.mode_navigator.current:
            values = self.appdata.project.modes[self.mode_navigator.current]

            # set values
            self.appdata.project.scen_values.clear()
            self.appdata.project.comp_values.clear()
            for i in values:
                self.appdata.project.comp_values[i] = (values[i], values[i])

        self.appdata.modes_coloring = True
        self.update()
        self.appdata.modes_coloring = False

    def update(self):
        if len(self.appdata.project.modes) == 0:
            self.mode_navigator.hide()
            self.mode_navigator.current = 0
        else:
            self.mode_navigator.show()
            self.mode_navigator.update()

        idx = self.tabs.currentIndex()
        if idx == 0:
            self.reaction_list.update()
        elif idx == 1:
            self.metabolite_list.update()
        elif idx == 2:
            self.model_info.update()

        idx = self.map_tabs.currentIndex()
        if idx >= 0:
            m = self.map_tabs.widget(idx)
            m.update()

    def update_map(self, idx):
        m = self.map_tabs.widget(idx)
        if m is not None:
            m.update()

    def update_maps(self):
        for idx in range(0, self.map_tabs.count()):
            m = self.map_tabs.widget(idx)
            m.update()

    def jump_to_map(self, identifier: str, reaction: str):
        for idx in range(0, self.map_tabs.count()):
            name = self.map_tabs.tabText(idx)
            if name == identifier:
                m = self.map_tabs.widget(idx)
                self.map_tabs.setCurrentIndex(idx)

                m.update()
                m.focus_reaction(reaction)
                m.highlight_reaction(reaction)
                break

    def jump_to_metabolite(self, metabolite: str):
        self.tabs.setCurrentIndex(1)
        m = self.tabs.widget(1)
        m.set_current_item(metabolite)

    def jump_to_reaction(self, reaction: str):
        self.tabs.setCurrentIndex(0)
        m = self.tabs.widget(0)
        m.set_current_item(reaction)

    def in_out_fluxes(self, metabolite):
        self.kernel_client.execute("cna.print_in_out_fluxes('" + metabolite +
                                   "')")
        self.show_bottom_of_console()
Exemple #12
0
class QtipWindow(QtGui.QMainWindow):
    """Main Qtip window class"""
    
    def __init__(self, parent=None, engine='pint', \
            parfile=None, timfile=None, **kwargs):
        """
        Initialize the main window

        :param parent:
            The parent window that embeds the Qtip window

        :param engine:
            The preferred timing package to use ('pint'/'libstempo') ['pint']

        :param parfile:
            Par-file top open on startup

        :param timfile:
            Tim-file top open on startup

        """

        super(QtipWindow, self).__init__(parent)
        self.setWindowTitle('Jupyter interface for pulsar timing')

        # Initialise basic gui elements
        self.initUI()

        # Start the embedded Jupyter kernel
        self.createJupyterKernel()

        # Create the display widgets
        self.createPlkWidget()
        self.createJupyterWidget()
        self.createOpenSomethingWidget()

        # Position the widgets
        self.initQtipLayout()

        # Initialize the main widget (the plk emulator)
        self.setQtipLayout(whichWidget='plk',
                showJupyter=False, firsttime=True)

        # The preferred engine to use (PINT)
        self.pref_engine = engine

        # We are still in MAJOR testing mode, so open a test-pulsar right away
        # if no par/tim file is given
        if parfile is None or timfile is None:
            testpulsar = True
        else:
            testpulsar = False

        # Open plk as the main widget
        self.requestOpenPlk(testpulsar=testpulsar, parfilename=parfile, \
                timfilename=timfile, engine=self.pref_engine)

        self.show()

    def __del__(self):
        pass

    def onAbout(self):
        """Show an about box"""

        msg = constants.QtipBanner
        QtGui.QMessageBox.about(self, "About Qtip", msg.strip())

    def initUI(self):
        """Initialise the user-interface elements"""

        # Create the main-frame widget, and the layout
        self.mainFrame = QtGui.QWidget()
        self.setCentralWidget(self.mainFrame)
        self.hbox = QtGui.QHBoxLayout()     # HBox contains all widgets

        # Menu item: open par/tim files
        self.openParTimAction = QtGui.QAction('&Open par/tim', self)        
        self.openParTimAction.setShortcut('Ctrl+O')
        self.openParTimAction.setStatusTip('Open par/tim')
        self.openParTimAction.triggered.connect(self.openParTim)

        # Menu item: exit Qtip
        self.exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)        
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.setStatusTip('Exit application')
        self.exitAction.triggered.connect(self.close)

        # Previously, it was possible to switch out the 'plk' widget for another
        # main widget (the binary pulsar one). That one has been stripped out
        # now, so for now it makes no sense to 'toggle' on or off the plk
        # widget. However, the option is still there for now...
        self.togglePlkAction = QtGui.QAction('&Plk', self)        
        self.togglePlkAction.setShortcut('Ctrl+P')
        self.togglePlkAction.setStatusTip('Toggle plk widget')
        self.togglePlkAction.triggered.connect(self.togglePlk)

        # Menu item: toggle the Jupyter window
        self.toggleJupyterAction = QtGui.QAction('&Jupyter', self)        
        self.toggleJupyterAction.setShortcut('Ctrl+J')
        self.toggleJupyterAction.setStatusTip('Toggle Jupyter')
        self.toggleJupyterAction.triggered.connect(self.toggleJupyter)

        # Menu item: about Qtip
        self.aboutAction = QtGui.QAction('&About', self)        
        self.aboutAction.setShortcut('Ctrl+A')
        self.aboutAction.setStatusTip('About Qtip')
        self.aboutAction.triggered.connect(self.onAbout)

        # The status bar
        self.theStatusBar = QtGui.QStatusBar()
        #self.statusBar()
        self.setStatusBar(self.theStatusBar)

        # A label that shows what engine is being used (hardcoded: PINT)
        self.engine_label = QtGui.QLabel("PINT")
        self.engine_label.setFrameStyle( QtGui.QFrame.Sunken|QtGui.QFrame.Panel)
        self.engine_label.setLineWidth(4)
        self.engine_label.setMidLineWidth(4)
        self.engine_label.setStyleSheet("QLabel{color:black;background-color:red}")
        self.theStatusBar.addPermanentWidget(self.engine_label)

        # On OSX, make sure the menu can be displayed (in the window itself)
        if sys.platform == 'darwin':
            # On OSX, the menubar is usually on the top of the screen, not in
            # the window. To make it in the window:
            QtGui.qt_mac_set_native_menubar(False) 

            # Otherwise, if we'd like to get the system menubar at the top, then
            # we need another menubar object, not self.menuBar as below. In that
            # case, use:
            # self.menubar = QtGui.QMenuBar()
            # TODO: Somehow this does not work. Per-window one does though

        # Create the menu bar, and link the action items
        self.menubar = self.menuBar()
        self.fileMenu = self.menubar.addMenu('&File')
        self.fileMenu.addAction(self.openParTimAction)
        self.fileMenu.addAction(self.exitAction)
        self.viewMenu = self.menubar.addMenu('&View')
        self.viewMenu.addAction(self.togglePlkAction)
        self.viewMenu.addAction(self.toggleJupyterAction)
        self.helpMenu = self.menubar.addMenu('&Help')
        self.helpMenu.addAction(self.aboutAction)

        # What is the status quo of the user interface?
        self.showJupyter = False
        self.whichWidget = 'None'
        self.prevShowJupyter = None
        self.prevWhichWidget = 'None'

    def createJupyterKernel(self):
        """Create and start the embedded Jupyter Kernel"""

        # Create an in-process kernel
        self.kernelManager = QtInProcessKernelManager()
        self.kernelManager.start_kernel()
        self.kernel = self.kernelManager.kernel

        # Launch the kernel
        self.kernelClient = self.kernelManager.client()
        self.kernelClient.start_channels()

        # Allow inline matplotlib figures
        self.kernel.shell.enable_matplotlib(gui='inline')

        # Load the necessary packages in the embedded kernel
        # TODO: show this line in a cell of it's own
        cell = "import numpy as np, matplotlib.pyplot as plt, qtpulsar as qp"
        self.kernel.shell.run_cell(cell, store_history=False)

        # Set the in-kernel matplotlib color scheme to black.
        self.setMplColorScheme('black')     # Outside as well (do we need this?)
        self.kernel.shell.run_cell(constants.matplotlib_rc_cell_black,
                store_history=False)

    def createJupyterWidget(self):
        """Create the Jupyter widget"""

        self.consoleWidget = RichJupyterWidget()
        #self.consoleWidget.setMinimumSize(600, 550)

        # Show the banner
        self.consoleWidget.banner = constants.QtipBanner
        self.consoleWidget.kernel_manager = self.kernelManager

        # Couple the client
        self.consoleWidget.kernel_client = self.kernelClient
        self.consoleWidget.exit_requested.connect(self.toggleJupyter)
        self.consoleWidget.set_default_style(colors='linux')
        self.consoleWidget.hide()

        # Register a call-back function for the Jupyter shell. This one is
        # executed insite the child-kernel.
        #self.kernel.shell.register_post_execute(self.postExecute)
        #
        # In Jupyter >= 2, we can use the event register
        # Events: post_run_cell, pre_run_cell, etc...`
        self.kernel.shell.events.register('pre_execute', self.preExecute)
        self.kernel.shell.events.register('post_execute', self.postExecute)
        self.kernel.shell.events.register('post_run_cell', self.postRunCell)


    def createOpenSomethingWidget(self):
        """Create the OpenSomething widget. Do not add it to the layout yet

        TODO:   This widget should become the first main widget to see? At the
                moment, we're avoiding it for the sake of testing purposes
        """

        self.openSomethingWidget = OpenSomethingWidget(parent=self.mainFrame, \
                openFile=self.requestOpenPlk)
        self.openSomethingWidget.hide()

    def createPlkWidget(self):
        """Create the Plk widget"""

        self.plkWidget = PlkWidget(parent=self.mainFrame)
        self.plkWidget.hide()

    def toggleJupyter(self):
        """Toggle the Jupyter widget on or off"""

        self.setQtipLayout(showJupyter = not self.showJupyter)

    def togglePlk(self):
        """Toggle the plk widget on or off"""

        self.setQtipLayout(whichWidget='plk')

    def initQtipLayout(self):
        """Initialise the Qtip layout"""

        # If other 'main' widgets exist, they can be added here
        self.hbox.addWidget(self.openSomethingWidget)
        self.hbox.addWidget(self.plkWidget)

        self.hbox.addStretch(1)
        self.hbox.addWidget(self.consoleWidget)
        self.mainFrame.setLayout(self.hbox)

    def hideAllWidgets(self):
        """Hide all widgets of the mainFrame"""

        # Remove all widgets from the main window
        # No, hiding seems to work better
        """
        while self.hbox.count():
            item = self.hbox.takeAt(0)
            if isinstance(item, QtGui.QWidgetItem):
                #item.widget().deleteLater()
                item.widget().hide()
            elif isinstance(item, QtGui.QSpacerItem):
                #self.hbox.removeItem(item)
                pass
            else:
                #fcbox.clearLayout(item.layout())
                #self.hbox.removeItem(item)
                pass
        """
        self.openSomethingWidget.hide()
        self.plkWidget.hide()
        self.consoleWidget.hide()

    def showVisibleWidgets(self):
        """Show the correct widgets in the mainFrame"""

        # Add the widgets we need
        if self.whichWidget.lower() == 'opensomething':
            self.openSomethingWidget.show()
        elif self.whichWidget.lower() == 'plk':
            self.plkWidget.show()
        # Other widgets can be added here

        if self.showJupyter:
            self.consoleWidget.show()
        else:
            pass

        # Request focus back to the main widget
        if self.whichWidget.lower() == 'plk' and not self.showJupyter:
            self.plkWidget.setFocusToCanvas()
        # Do it for other main widgets, if they exist
        #elif self.whichWidget.lower() == 'binary' and not self.showJupyter:
        #    self.binaryWidget.setFocusToCanvas()

        # Do we immediately get focus to the Jupyter console?
        #elif self.showJupyter:
        #    self.consoleWidget.setFocus()

    def setQtipLayout(self, whichWidget=None, showJupyter=None, firsttime=False):
        """Given the current main widget, hide all the other widgets
        
        :param whichWidget:
            Which main widget we are showing right now

        :param showJupyter:
            Whether to show the Jupyter console

        :param firsttime:
            Whether or not this is the first time setting the layout. If so,
            resize to proper dimensions.
            TODO: How to do this more elegantly?
        """

        if not whichWidget is None:
            self.whichWidget = whichWidget
        if not showJupyter is None:
            self.showJupyter = showJupyter

        # After hiding the widgets, wait 0 milliseonds before showing them again
        # (what a dirty hack, ugh!)
        self.hideAllWidgets()
        QtCore.QTimer.singleShot(0, self.showVisibleWidgets)

        self.prevWhichWidget = self.whichWidget

        if self.showJupyter != self.prevShowJupyter:
            # Jupyter has been toggled
            self.prevShowJupyter = self.showJupyter
            if self.showJupyter:
                self.resize(1350, 550)
                self.mainFrame.resize(1350, 550)
            else:
                self.resize(650, 550)
                self.mainFrame.resize(650, 550)

        # TODO: How to do this more elegantly?
        if firsttime:
            # Set position slightly more to the left of the screen, so we can
            # still open Jupyter
            self.move(50, 100)

        self.mainFrame.setLayout(self.hbox)
        self.mainFrame.show()

    def requestOpenPlk(self, parfilename=None, timfilename=None, \
            testpulsar=False, engine='pint'):
        """Request to open a file in the plk widget

        :param parfilename:
            The parfile to open. If none, ask the user
        :param timfilename:
            The timfile to open. If none, ask the user
        """

        self.setQtipLayout(whichWidget='plk', showJupyter=self.showJupyter)

        if parfilename is None and not testpulsar:
            parfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open par-file', '~/')

        if timfilename is None and not testpulsar:
            timfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open tim-file', '~/')

        # Load the pulsar
        self.openPlkPulsar(parfilename, timfilename, engine=engine, \
                testpulsar=testpulsar)

    def setMplColorScheme(self, scheme):
        """
        Set the matplotlib color scheme

        :param scheme: 'black'/'white', the color scheme
        """

        # Obtain the Widget background color
        color = self.palette().color(QtGui.QPalette.Window)
        r, g, b = color.red(), color.green(), color.blue()
        rgbcolor = (r/255.0, g/255.0, b/255.0)

        if scheme == 'white':
            rcP = constants.mpl_rcParams_white

            rcP['axes.facecolor'] = rgbcolor
            rcP['figure.facecolor'] = rgbcolor
            rcP['figure.edgecolor'] = rgbcolor
            rcP['savefig.facecolor'] = rgbcolor
            rcP['savefig.edgecolor'] = rgbcolor
        elif scheme == 'black':
            rcP = constants.mpl_rcParams_black

        for key, value in rcP.iteritems():
            matplotlib.rcParams[key] = value


    def openParTim(self):
        """Open a par-file and a tim-file"""

        # Ask the user for a par and tim file, and open these with libstempo/pint
        parfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open par-file', '~/')
        timfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open tim-file', '~/')

        # Load the pulsar
        self.openPlkPulsar(parfilename, timfilename, engine=self.pref_engine)

    def openPlkPulsar(self, parfilename, timfilename, engine='pint', \
            testpulsar=False):
        """Open a pulsar, given a parfile and a timfile

        :param parfilename: The name of the parfile to open
        :param timfilename: The name fo the timfile to open
        :param engine:      Which pulsar timing engine to use [pint]
        :param testpulsar:  If True, open the test pulsar (J1744, NANOGrav)
        """

        if engine=='pint':
            trypint = True
        else:
            trypint = False

        engine, pclass = qp.get_engine(trypint=trypint)

        # This all is a bit ugly...
        if engine == 'libstempo':
            if not testpulsar:
                # Obtain the directory name of the timfile, and change to it
                timfiletup = os.path.split(timfilename)
                dirname = timfiletup[0]
                reltimfile = timfiletup[-1]
                relparfile = os.path.relpath(parfilename, dirname)
                savedir = os.getcwd()

                # Change directory to the base directory of the tim-file to deal with
                # INCLUDE statements in the tim-file
                if dirname != '':
                    os.chdir(dirname)

                # Load the pulsar
                cell = "psr = qp."+pclass+"('"+relparfile+"', '"+reltimfile+"')"
                self.kernel.shell.run_cell(cell)
                psr = self.kernel.shell.ns_table['user_local']['psr']

                # Change directory back to where we were
                if dirname != '':
                    os.chdir(savedir)
            else:
                cell = "psr = qp."+pclass+"(testpulsar=True)"
                self.kernel.shell.run_cell(cell)
                psr = self.kernel.shell.ns_table['user_local']['psr']
        elif engine == 'pint':
            if not testpulsar:
                psr = qp.PPulsar(parfilename, timfilename)
                cell = "psr = qp."+pclass+"('"+parfilename+"', '"+timfilename+"')"
            else:
                psr = qp.PPulsar(testpulsar=True)
                cell = "psr = qp."+pclass+"(testpulsar=True)"
            self.kernel.shell.run_cell(cell)
            psr = self.kernel.shell.ns_table['user_local']['psr']
        else:
            print("Engine = ", engine)
            raise NotImplemented("Only works with PINT/libstempo")

        # Update the plk widget
        self.plkWidget.setPulsar(psr)

        # Communicating with the kernel goes as follows
        # self.kernel.shell.push({'foo': 43, 'print_process_id': print_process_id}, interactive=True)
        # print("Embedded, we have:", self.kernel.shell.ns_table['user_local']['foo'])


    def keyPressEvent(self, event, **kwargs):
        """Handle a key-press event

        :param event:   event that is handled here
        """

        key = event.key()

        if key == QtCore.Qt.Key_Escape:
            self.close()
        elif key == QtCore.Qt.Key_Left:
            #print("Left pressed")
            pass
        else:
            #print("Other key")
            pass

        #print("QtipWindow: key press")
        super(QtipWindow, self).keyPressEvent(event, **kwargs)

    def mousePressEvent(self, event, **kwargs):
        """Handle a mouse-click event

        :param event:   event that is handled here
        """

        super(QtipWindow, self).mousePressEvent(event, **kwargs)

    def preExecute(self):
        """Callback function that is run prior to execution of a cell"""
        pass

    def postExecute(self):
        """Callback function that is run after execution of a code"""
        pass

    def postRunCell(self):
        """Callback function that is run after execution of a cell (after
        post-execute)
        """

        # TODO: Do more than just update the plot, but also update _all_ the
        # widgets. Make a callback in plkWidget for that. QtipWindow might also
        # want to loop over some stuff.
        if self.whichWidget == 'plk':
            #self.plkWidget.updatePlot()
            pass
Exemple #13
0
class IPythonDock(Dock):
    def __init__(self, *args, **kwargs):
        super(IPythonDock, self).__init__(*args, **kwargs)
        self.setMinimumHeight(25)
        self.setMinimumWidth(500)
        self.setWindowTitle("IPython Shell")
        self.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas)
        self.console = RichJupyterWidget(name="console")
        self.console.font_size = 7
        self.setWidget(self.console)

    def setup_ipython(self, main_window):
        """
        Sets up the ipython shell for the relevant docks. 
        :return: 
        """
        self.console.kernel_manager = kernel_manager = \
            QtInProcessKernelManager()
        kernel_manager.start_kernel(show_banner=True)
        kernel_manager.kernel.gui = 'qt'
        self.console.kernel_client = kernel_client = kernel_manager.client()
        kernel_client.start_channels()

        def stop():
            kernel_client.stop_channels()
            kernel_manager.shutdown_kernel()

        self.console.exit_requested.connect(stop)
        self.push_vars({"KatilInstance": main_window})
        self.console.show()
        self.inject_globals()
        self.inject_debugs()

    def push_vars(self, variableDict):
        """
        Given a dictionary containing name / value pairs, push those variables
        to the Jupyter console widget
        """
        self.console.kernel_manager.kernel.shell.push(variableDict)

    def pull_var(self, varName, delete=False):
        v = self.console.kernel_manager.kernel.shell.user_ns[varName]
        if delete:
            del self.console.kernel_manager.kernel.shell.user_ns[varName]
        return v

    def delete_var(self, varName):
        del self.console.kernel_manager.kernel.shell.user_ns[varName]

    def clear(self):
        """
        Clears the terminal
        """
        self.console._control.clear()

        # self.kernel_manager

    def print_text(self, text):
        """
        Prints some plain text to the console
        """
        self.console._append_plain_text(text)

    def execute_command(self, command):
        """
        Execute a command in the frame of the console widget
        """
        self.console._execute(command, False)

    def inject_globals(self, glbls=None):
        """
        Inject the globals() dict into the IPython kernel
        under the key '_injected'
        :return:
        """
        if glbls is None:
            glbls = globals()
        self.push_vars({"_injected": glbls})
        self.execute_command("from PyQt5.QtWidgets import *")
        self.execute_command("from praatkatili import *")

    def inject_debugs(self):
        self.push_vars({'canvas': self.findChildren(PlotCanvas)})