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 createOpenSomethingWidget(self): """ Create the OpenSomething widget. Do not add it to the layout yet TODO: This widget will become the first main widget to see. At the moment, however, we're avoiding it for the sake of testing purposes """ # TODO: This widget is not really used at the moment self.openSomethingWidget = OpenSomethingWidget(parent=self.mainFrame, \ openFile=self.requestOpenPlk) self.openSomethingWidget.hide()
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
class QtipWindow(QtGui.QMainWindow): """ Main Qtip window Note, is the main window now, but the content will later be moved to a libstempo tab, as part of the Piccard suite """ def __init__(self, parent=None, engine='pint', \ parfile=None, timfile=None, perfile=None, **kwargs): super(QtipWindow, self).__init__(parent) self.setWindowTitle('QtIpython interface to PINT/libstempo') # Initialise basic gui elements self.initUI() # Start the embedded IPython kernel self.createIPythonKernel() # Create the display widgets self.createBinaryWidget() self.createPlkWidget() self.createIPythonWidget() self.createOpenSomethingWidget() # Position the widgets self.initQtipLayout() self.setQtipLayout(whichWidget='binary', showIPython=False, firsttime=True) self.pref_engine = engine if True: # We are still in MAJOR testing mode, so open a test-pulsar right away # (delete this line when going into production) if parfile is None or timfile is None: testpulsar = True else: testpulsar = False # Also open the Binary Widget self.requestOpenBinary(testpulsar=True) # Are we going to open plk straight away? self.requestOpenPlk(testpulsar=testpulsar, parfilename=parfile, \ timfilename=timfile, engine=self.pref_engine) else: if perfile is None: testpulsar = True else: testpulsar = False if parfile is None: parfile = "" self.requestOpenBinary(testpulsar=testpulsar, parfilename=parfile, \ perfilename=perfile) self.show() def __del__(self): pass def onAbout(self): msg = """ A plk emulator, written in Python. Powered by PyQt, matplotlib, libstempo, and IPython: """ QtGui.QMessageBox.about(self, "About the demo", 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 # Create the menu action items 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) self.openParPerAction = QtGui.QAction('Open &par/bestprof', self) self.openParPerAction.setShortcut('Ctrl+G') self.openParPerAction.setStatusTip('Open par/bestprof files') self.openParPerAction.triggered.connect(self.openParPer) self.openPerAction = QtGui.QAction('Open &bestprof', self) self.openPerAction.setShortcut('Ctrl+H') self.openPerAction.setStatusTip('Open bestprof files') self.openPerAction.triggered.connect(self.openPer) 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) self.toggleBinaryAction = QtGui.QAction('&Binary', self) self.toggleBinaryAction.setShortcut('Ctrl+B') self.toggleBinaryAction.setStatusTip('Toggle binary widget') self.toggleBinaryAction.triggered.connect(self.toggleBinary) self.togglePlkAction = QtGui.QAction('&Plk', self) self.togglePlkAction.setShortcut('Ctrl+P') self.togglePlkAction.setStatusTip('Toggle plk widget') self.togglePlkAction.triggered.connect(self.togglePlk) self.toggleIPythonAction = QtGui.QAction('&IPython', self) self.toggleIPythonAction.setShortcut('Ctrl+I') self.toggleIPythonAction.setStatusTip('Toggle IPython') self.toggleIPythonAction.triggered.connect(self.toggleIPython) self.aboutAction = QtGui.QAction('&About', self) self.aboutAction.setShortcut('Ctrl+A') self.aboutAction.setStatusTip('About Qtip') self.aboutAction.triggered.connect(self.onAbout) self.theStatusBar = QtGui.QStatusBar() #self.statusBar() self.setStatusBar(self.theStatusBar) self.engine_label = QtGui.QLabel("Tempo2") 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 self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu('&File') self.fileMenu.addAction(self.openParTimAction) self.fileMenu.addAction(self.openParPerAction) self.fileMenu.addAction(self.openPerAction) self.fileMenu.addAction(self.exitAction) self.viewMenu = self.menubar.addMenu('&View') self.viewMenu.addAction(self.toggleBinaryAction) self.viewMenu.addAction(self.togglePlkAction) self.viewMenu.addAction(self.toggleIPythonAction) self.helpMenu = self.menubar.addMenu('&Help') self.helpMenu.addAction(self.aboutAction) # What is the status quo of the user interface? self.showIPython = False self.whichWidget = 'None' self.prevShowIPython = None self.prevWhichWidget = 'None' def createIPythonKernel(self): """ Create the IPython Kernel """ # Create an in-process kernel self.kernelManager = QtInProcessKernelManager() self.kernelManager.start_kernel() self.kernel = self.kernelManager.kernel self.kernelClient = self.kernelManager.client() self.kernelClient.start_channels() self.kernel.shell.enable_matplotlib(gui='inline') # Load the necessary packages in the embedded kernel cell = "import numpy as np, matplotlib.pyplot as plt, qtpulsar as qp, libfitorbit as lo" 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 createIPythonWidget(self): """ Create the IPython widget """ #self.consoleWidget = RichIPythonWidget() self.consoleWidget = JupyterWidget() #self.consoleWidget.setMinimumSize(600, 550) # Why is there another banner showing as well? self.consoleWidget.banner = QtipBanner self.consoleWidget.kernel_manager = self.kernelManager # The client ... self.consoleWidget.kernel_client = self.kernelClient self.consoleWidget.exit_requested.connect(self.toggleIPython) self.consoleWidget.set_default_style(colors='linux') self.consoleWidget.hide() # Register a call-back function for the IPython shell. This one is # executed insite the child-kernel. #self.kernel.shell.register_post_execute(self.postExecute) # # In IPython >= 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 will become the first main widget to see. At the moment, however, we're avoiding it for the sake of testing purposes """ # TODO: This widget is not really used at the moment 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 createBinaryWidget(self): """ Create the binary model widget """ self.binaryWidget = BinaryWidget(parent=self.mainFrame) self.binaryWidget.hide() def toggleIPython(self): """ Toggle the IPython widget on or off """ self.setQtipLayout(showIPython = not self.showIPython) def toggleBinary(self): """ Toggle the binary model widget on or off """ self.setQtipLayout(whichWidget='binary') def togglePlk(self): """ Toggle the plk widget on or off """ self.setQtipLayout(whichWidget='plk') def initQtipLayout(self): """ Initialise the Qtip layout """ self.hbox.addWidget(self.openSomethingWidget) self.hbox.addWidget(self.plkWidget) self.hbox.addWidget(self.binaryWidget) 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 # ??? """ 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.binaryWidget.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() elif self.whichWidget.lower() == 'binary': self.binaryWidget.show() if self.showIPython: self.consoleWidget.show() else: pass if self.whichWidget.lower() == 'plk' and not self.showIPython: self.plkWidget.setFocusToCanvas() elif self.whichWidget.lower() == 'binary' and not self.showIPython: self.binaryWidget.setFocusToCanvas() #elif self.showIPython: # self.consoleWidget.setFocus() def setQtipLayout(self, whichWidget=None, showIPython=None, firsttime=False): """ Given which widgets to show, display the right widgets and hide the rest @param whichWidget: Which widget to show @param showIPython: Whether to show the IPython console """ if not whichWidget is None: self.whichWidget = whichWidget if not showIPython is None: self.showIPython = showIPython # After hiding the widgets, wait 25 (or 0?) miliseconds before showing them again self.hideAllWidgets() QtCore.QTimer.singleShot(0, self.showVisibleWidgets) self.prevWhichWidget = self.whichWidget if self.showIPython != self.prevShowIPython: # IPython has been toggled self.prevShowIPython = self.showIPython if self.showIPython: self.resize(1350, 550) self.mainFrame.resize(1350, 550) else: self.resize(650, 550) self.mainFrame.resize(650, 550) if firsttime: # Set position slightly more to the left of the screen, so we can # still open IPython self.move(50, 100) self.mainFrame.setLayout(self.hbox) self.mainFrame.show() def requestOpenBinary(self, parfilename=None, perfilename=None, \ testpulsar=False): """ Request to open a file in the binary widget @param parfilename: The parfile to open. If None, ask the user @param perfilename: The per/bestprof file to open. If None, ask user """ self.setQtipLayout(whichWidget='binary', showIPython=self.showIPython) if parfilename is None and not testpulsar: parfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open par-file', '~/') elif parfilename == "": # We do not need to load a par file parfilename = None if perfilename is None and not testpulsar: perfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open per/bestprof file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename, perfilename, testpulsar=testpulsar) 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', showIPython=self.showIPython) 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 """ # TODO: obtain the engine from elsewhere #engine='libstempo' # 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 openParPer(self): """ Open a par-file and a per/bestprof file """ # Ask the user for a par and tim file, and open these with libstempo/pint parfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open par-file', '~/') perfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open per/bestprof-file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename=parfilename, \ perfilename=perfilename) def openPer(self): """ Open a per/bestprof file """ # Ask the user for a par and tim file, and open these with libstempo/pint perfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open per/bestprof-file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename=None, perfilename=perfilename) 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) 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 openBinaryPulsar(self, parfilename=None, perfilename=None, \ testpulsar=False): """ Open a pulsar, given a .bestprof file, and perhaps a par file @param parfilename: The name of the par/ephemeris file to open @param perfilename: The name of the .bestprof file to open @param testpulsar: If True, open the test pulsar (J1756) """ if testpulsar or perfilename is None: # Need to load the test pulsar tperfilename = tempfile.mktemp() tperfile = open(tperfilename, 'w') tperfile.write(constants.J1903PER) #tperfile.write(constants.J1756PER) tperfile.close() else: tperfilename = perfilename # Load the per-file cell = "bpsr = lo.orbitpulsar()" self.kernel.shell.run_cell(cell) cell = "bpsr.readPerFile('" + tperfilename +"')" self.kernel.shell.run_cell(cell) if testpulsar or perfilename is None: os.remove(tperfilename) if testpulsar: tparfilename = tempfile.mktemp() tparfile = open(tparfilename, 'w') tparfile.write(constants.J1903EPH) #tperfile.write(constants.J1756PER) tparfile.close() cell = "bpsr.readParFile('" + tparfilename +"')" self.kernel.shell.run_cell(cell) os.remove(tparfilename) elif parfilename is not None: cell = "bpsr.readParFile('" + parfilename +"')" self.kernel.shell.run_cell(cell) bpsr = self.kernel.shell.ns_table['user_local']['bpsr'] self.binaryWidget.setPulsar(bpsr) 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 """ #print("QtipWindow: mouse click") 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() elif self.whichWidget == 'binary': self.binaryWidget.updatePlot()
class QtipWindow(QtGui.QMainWindow): """ Main Qtip window Note, is the main window now, but the content will later be moved to a libstempo tab, as part of the Piccard suite """ def __init__(self, parent=None, engine='pint', \ parfile=None, timfile=None, perfile=None, **kwargs): super(QtipWindow, self).__init__(parent) self.setWindowTitle('QtIpython interface to PINT/libstempo') # Initialise basic gui elements self.initUI() # Start the embedded IPython kernel self.createIPythonKernel() # Create the display widgets self.createBinaryWidget() self.createPlkWidget() self.createIPythonWidget() self.createOpenSomethingWidget() # Position the widgets self.initQtipLayout() self.setQtipLayout(whichWidget='binary', showIPython=False, firsttime=True) self.pref_engine = engine if True: # We are still in MAJOR testing mode, so open a test-pulsar right away # (delete this line when going into production) if parfile is None or timfile is None: testpulsar = True else: testpulsar = False # Also open the Binary Widget self.requestOpenBinary(testpulsar=True) # Are we going to open plk straight away? self.requestOpenPlk(testpulsar=testpulsar, parfilename=parfile, \ timfilename=timfile, engine=self.pref_engine) else: if perfile is None: testpulsar = True else: testpulsar = False if parfile is None: parfile = "" self.requestOpenBinary(testpulsar=testpulsar, parfilename=parfile, \ perfilename=perfile) self.show() def __del__(self): pass def onAbout(self): msg = """ A plk emulator, written in Python. Powered by PyQt, matplotlib, libstempo, and IPython: """ QtGui.QMessageBox.about(self, "About the demo", 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 # Create the menu action items 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) self.openParPerAction = QtGui.QAction('Open &par/bestprof', self) self.openParPerAction.setShortcut('Ctrl+G') self.openParPerAction.setStatusTip('Open par/bestprof files') self.openParPerAction.triggered.connect(self.openParPer) self.openPerAction = QtGui.QAction('Open &bestprof', self) self.openPerAction.setShortcut('Ctrl+H') self.openPerAction.setStatusTip('Open bestprof files') self.openPerAction.triggered.connect(self.openPer) 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) self.toggleBinaryAction = QtGui.QAction('&Binary', self) self.toggleBinaryAction.setShortcut('Ctrl+B') self.toggleBinaryAction.setStatusTip('Toggle binary widget') self.toggleBinaryAction.triggered.connect(self.toggleBinary) self.togglePlkAction = QtGui.QAction('&Plk', self) self.togglePlkAction.setShortcut('Ctrl+P') self.togglePlkAction.setStatusTip('Toggle plk widget') self.togglePlkAction.triggered.connect(self.togglePlk) self.toggleIPythonAction = QtGui.QAction('&IPython', self) self.toggleIPythonAction.setShortcut('Ctrl+I') self.toggleIPythonAction.setStatusTip('Toggle IPython') self.toggleIPythonAction.triggered.connect(self.toggleIPython) self.aboutAction = QtGui.QAction('&About', self) self.aboutAction.setShortcut('Ctrl+A') self.aboutAction.setStatusTip('About Qtip') self.aboutAction.triggered.connect(self.onAbout) self.theStatusBar = QtGui.QStatusBar() #self.statusBar() self.setStatusBar(self.theStatusBar) self.engine_label = QtGui.QLabel("Tempo2") 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 self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu('&File') self.fileMenu.addAction(self.openParTimAction) self.fileMenu.addAction(self.openParPerAction) self.fileMenu.addAction(self.openPerAction) self.fileMenu.addAction(self.exitAction) self.viewMenu = self.menubar.addMenu('&View') self.viewMenu.addAction(self.toggleBinaryAction) self.viewMenu.addAction(self.togglePlkAction) self.viewMenu.addAction(self.toggleIPythonAction) self.helpMenu = self.menubar.addMenu('&Help') self.helpMenu.addAction(self.aboutAction) # What is the status quo of the user interface? self.showIPython = False self.whichWidget = 'None' self.prevShowIPython = None self.prevWhichWidget = 'None' def createIPythonKernel(self): """ Create the IPython Kernel """ # Create an in-process kernel self.kernelManager = QtInProcessKernelManager() self.kernelManager.start_kernel() self.kernel = self.kernelManager.kernel self.kernelClient = self.kernelManager.client() self.kernelClient.start_channels() self.kernel.shell.enable_matplotlib(gui='inline') # Load the necessary packages in the embedded kernel cell = "import numpy as np, matplotlib.pyplot as plt, qtpulsar as qp, libfitorbit as lo" 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 createIPythonWidget(self): """ Create the IPython widget """ #self.consoleWidget = RichIPythonWidget() self.consoleWidget = JupyterWidget() #self.consoleWidget.setMinimumSize(600, 550) # Why is there another banner showing as well? self.consoleWidget.banner = QtipBanner self.consoleWidget.kernel_manager = self.kernelManager # The client ... self.consoleWidget.kernel_client = self.kernelClient self.consoleWidget.exit_requested.connect(self.toggleIPython) self.consoleWidget.set_default_style(colors='linux') self.consoleWidget.hide() # Register a call-back function for the IPython shell. This one is # executed insite the child-kernel. #self.kernel.shell.register_post_execute(self.postExecute) # # In IPython >= 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 will become the first main widget to see. At the moment, however, we're avoiding it for the sake of testing purposes """ # TODO: This widget is not really used at the moment 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 createBinaryWidget(self): """ Create the binary model widget """ self.binaryWidget = BinaryWidget(parent=self.mainFrame) self.binaryWidget.hide() def toggleIPython(self): """ Toggle the IPython widget on or off """ self.setQtipLayout(showIPython=not self.showIPython) def toggleBinary(self): """ Toggle the binary model widget on or off """ self.setQtipLayout(whichWidget='binary') def togglePlk(self): """ Toggle the plk widget on or off """ self.setQtipLayout(whichWidget='plk') def initQtipLayout(self): """ Initialise the Qtip layout """ self.hbox.addWidget(self.openSomethingWidget) self.hbox.addWidget(self.plkWidget) self.hbox.addWidget(self.binaryWidget) 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 # ??? """ 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.binaryWidget.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() elif self.whichWidget.lower() == 'binary': self.binaryWidget.show() if self.showIPython: self.consoleWidget.show() else: pass if self.whichWidget.lower() == 'plk' and not self.showIPython: self.plkWidget.setFocusToCanvas() elif self.whichWidget.lower() == 'binary' and not self.showIPython: self.binaryWidget.setFocusToCanvas() #elif self.showIPython: # self.consoleWidget.setFocus() def setQtipLayout(self, whichWidget=None, showIPython=None, firsttime=False): """ Given which widgets to show, display the right widgets and hide the rest @param whichWidget: Which widget to show @param showIPython: Whether to show the IPython console """ if not whichWidget is None: self.whichWidget = whichWidget if not showIPython is None: self.showIPython = showIPython # After hiding the widgets, wait 25 (or 0?) miliseconds before showing them again self.hideAllWidgets() QtCore.QTimer.singleShot(0, self.showVisibleWidgets) self.prevWhichWidget = self.whichWidget if self.showIPython != self.prevShowIPython: # IPython has been toggled self.prevShowIPython = self.showIPython if self.showIPython: self.resize(1350, 550) self.mainFrame.resize(1350, 550) else: self.resize(650, 550) self.mainFrame.resize(650, 550) if firsttime: # Set position slightly more to the left of the screen, so we can # still open IPython self.move(50, 100) self.mainFrame.setLayout(self.hbox) self.mainFrame.show() def requestOpenBinary(self, parfilename=None, perfilename=None, \ testpulsar=False): """ Request to open a file in the binary widget @param parfilename: The parfile to open. If None, ask the user @param perfilename: The per/bestprof file to open. If None, ask user """ self.setQtipLayout(whichWidget='binary', showIPython=self.showIPython) if parfilename is None and not testpulsar: parfilename = QtGui.QFileDialog.getOpenFileName( self, 'Open par-file', '~/') elif parfilename == "": # We do not need to load a par file parfilename = None if perfilename is None and not testpulsar: perfilename = QtGui.QFileDialog.getOpenFileName( self, 'Open per/bestprof file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename, perfilename, testpulsar=testpulsar) 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', showIPython=self.showIPython) 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 """ # TODO: obtain the engine from elsewhere #engine='libstempo' # 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 openParPer(self): """ Open a par-file and a per/bestprof file """ # Ask the user for a par and tim file, and open these with libstempo/pint parfilename = QtGui.QFileDialog.getOpenFileName( self, 'Open par-file', '~/') perfilename = QtGui.QFileDialog.getOpenFileName( self, 'Open per/bestprof-file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename=parfilename, \ perfilename=perfilename) def openPer(self): """ Open a per/bestprof file """ # Ask the user for a par and tim file, and open these with libstempo/pint perfilename = QtGui.QFileDialog.getOpenFileName( self, 'Open per/bestprof-file', '~/') # Load the pulsar self.openBinaryPulsar(parfilename=None, perfilename=perfilename) 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) 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 openBinaryPulsar(self, parfilename=None, perfilename=None, \ testpulsar=False): """ Open a pulsar, given a .bestprof file, and perhaps a par file @param parfilename: The name of the par/ephemeris file to open @param perfilename: The name of the .bestprof file to open @param testpulsar: If True, open the test pulsar (J1756) """ if testpulsar or perfilename is None: # Need to load the test pulsar tperfilename = tempfile.mktemp() tperfile = open(tperfilename, 'w') tperfile.write(constants.J1903PER) #tperfile.write(constants.J1756PER) tperfile.close() else: tperfilename = perfilename # Load the per-file cell = "bpsr = lo.orbitpulsar()" self.kernel.shell.run_cell(cell) cell = "bpsr.readPerFile('" + tperfilename + "')" self.kernel.shell.run_cell(cell) if testpulsar or perfilename is None: os.remove(tperfilename) if testpulsar: tparfilename = tempfile.mktemp() tparfile = open(tparfilename, 'w') tparfile.write(constants.J1903EPH) #tperfile.write(constants.J1756PER) tparfile.close() cell = "bpsr.readParFile('" + tparfilename + "')" self.kernel.shell.run_cell(cell) os.remove(tparfilename) elif parfilename is not None: cell = "bpsr.readParFile('" + parfilename + "')" self.kernel.shell.run_cell(cell) bpsr = self.kernel.shell.ns_table['user_local']['bpsr'] self.binaryWidget.setPulsar(bpsr) 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 """ #print("QtipWindow: mouse click") 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() elif self.whichWidget == 'binary': self.binaryWidget.updatePlot()