diff --git a/pylk/pylk/constants.py b/pylk/pylk/constants.py
index 13e3f0da3893fc2dc2ab5290854a6226e8ea8b78..7bbafeb2b11d227f5fc7510a73cff36f80e788ff 100644
--- a/pylk/pylk/constants.py
+++ b/pylk/pylk/constants.py
@@ -20,8 +20,16 @@ PylkBanner = """
 
 """
 
-winsize_with_jupyter = (1350, 550)
-winsize_without_jupyter = (650, 550)
+#winsize_with_jupyter = (1350, 550)
+#winsize_without_jupyter = (650, 550)
+winsize_with_jupyter = (1400, 700)
+winsize_without_jupyter = (900, 700)
+#winsize_jupyter_console = (700, 500)
+
+plk_figure_dpi = 100
+plk_figsize_inch = (5.0, 4.0)
+plk_figure_frame_lw = 2
+plk_figure_frame_mlw = 3
 
 # Do it like this: dict(list(r.items()) + list(s.items()))
 mpl_rcParams_white = dict({
diff --git a/pylk/pylk/plk.py b/pylk/pylk/plk.py
index a351a9717a21c32fbe57487f68515593be6d3317..45115e2e49ca7d2f4ebdd56414d15a7793b7269a 100644
--- a/pylk/pylk/plk.py
+++ b/pylk/pylk/plk.py
@@ -35,135 +35,6 @@ space           Print info about highlighted points (or all, if none are selecte
   q             Quit
   h             Print help
 
-
-
-
-Help from tempo2 plk:
-
-Fitting and Calculating Options
-===============================
-b          Bin TOAs within certain time bin
-c          Change fitting parameters
-d (or right mouse) delete point
-ctrl-d     delete highlighted points
-e          multiply all TOA errors by given amount
-F          run FITWAVES
-ctrl-f     remove FITWAVES curve from residuals
-i (or left mouse) identify point
-M          toggle removing mean from the residuals
-ctrl-n     Add white noise to site-arrival-times
-p          Change model parameter values
-ctrl-p     Toggle plotting versus pulse phase
-r          Reset (reload .par and .tim file)
-ctrl-r     Select regions in MJDs and write to file
-w          toggle fitting using weights
-x          redo fit using post-fit parameters
-+          add positive phase jump
--          add negative phase jump
-BACKSPACE  remove all phase jumps
-ctrl-=     add period to residuals above cursor
-/          re-read .par file
-
-Plot Selection
-==============
-D (or middle mouse) view profile
-s          start of zoom section
-f          finish of zoom section
-Ctrl-u     Overplot Shapiro delay
-u          unzoom
-v          view profiles for highlighted points
-V          define the user parameter
-Ctrl-v     for pre-fit plotting, decompose the timing model fits
-           (i.e. overplot the fitted curves - only for prefit plots
-ctrl-X     select x-axis specifically
-y          Rescale y-axis only
-Y          set y-scale exactly
-ctrl-Y     select y-axis specifically
-z          Zoom using mouse
-<          in zoom mode include previous observation
->          in zoom mode include next observation
-1          plot pre-fit  residuals vs date
-2          plot post-fit residuals vs date
-3          plot pre-fit  residuals vs orbital phase
-4          plot post-fit residuals vs orbital phase
-5          plot pre-fit  residuals serially
-6          plot post-fit residuals serially
-7          plot pre-fit  residuals vs day of year
-8          plot post-fit residuals vs day of year
-9          plot pre-fit  residuals vs frequency
-a          plot post-fit residuals vs frequency
-!          plot pre-fit  residuals vs TOA error
-@          plot post-fit residuals vs TOA error
-#          plot pre-fit  residuals vs user values
-$          plot post-fit residuals vs user values
-%          plot pre-fit  residuals vs year
-^          plot post-fit residuals vs year
-&          plot pre-fit residuals vs elevation
-*          plot post-fit residuals vs elevation
-(          plot pre-fit residuals vs rounded MJD
-)          plot post-fit residuals vs rounded MJD
-
-Options for selecting x and y axes individually
-Ctrl-X n   set x-axis
-Ctrl-Y n   set y-axis
-where n = 
-
-1         plot pre-fit residuals
-2         plot post-fit residuals
-3         plot centred MJD
-4         plot orbital phase
-5         plot TOA number
-6         plot day of year
-7         plot frequency
-8         plot TOA error
-9         plot user value
-0         plot year
--         plot elevation
-
-Display Options
-===============
-B          place periodic marks on the x-scale
-ctrl-c     Toggle between period epoch and centre for the reference epoch
-E          toggle plotting error bars
-g          change graphics device
-G          change gridding on graphics device
-ctrl-e     highlight points more than 3 sigma from the mean
-H          highlight points with specific flag using symbols
-ctrl-i     highlight points with specific flag using colours
-I          indicate individual observations
-j          draw line between points 
-J          toggle plotting points
-L          add label to plot
-ctrl-l     add line to plot
-ctrl-m     toggle menu bar
-N          highlight point with a given filename
-o          obtain/highlight all points currently in plot
-ctrl-T     set text size
-U          unhighlight selected points
-[          toggle plotting x-axis on log scale
-]          toggle plotting y-axis on log scale
-
-Output Options
-==============
-Ctrl-J     output listing of residuals in Jodrell format
-Ctrl-O     output listing of residuals in simple format
-l          list all data points in zoomed region
-m          measure distance between two points
-P          write new .par file
-Ctrl-w     over-write input .par file
-S          save a new .tim file
-Ctrl-S     overwrite input.tim file
-t          Toggle displaying statistics for zoomed region
-Ctrl-z     Listing of all highlighted points
-
-Various Options
-===============
-C          run unix command with filenames for highlighted observations
-h          this help file
-q          quit
-
-
-
 """
 
 import os, sys
@@ -173,6 +44,7 @@ import copy
 from PyQt5 import QtGui, QtCore
 
 from PyQt5.QtWidgets import (
+    QFrame,
     QCheckBox,
     QListWidget,
     QWidgetItem,
@@ -185,6 +57,7 @@ from PyQt5.QtWidgets import (
     QButtonGroup,
     QLabel,
     QRadioButton,
+    QComboBox,
 )
 
 # All the Qt keys we want to bind
@@ -193,6 +66,7 @@ from PyQt5.QtCore import Qt
 # Importing all the stuff for the matplotlib widget
 import matplotlib as mpl
 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT
 from matplotlib.figure import Figure
 from matplotlib.patches import Rectangle
 
@@ -208,12 +82,6 @@ from pylk import constants
 import pint.logging
 from loguru import logger as log
 
-try:
-    from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
-except ImportError:
-    from matplotlib.backends.backend_tkagg import (
-        NavigationToolbar2TkAgg as NavigationToolbar2Tk,
-    )
 
 # Mapping from Matplotlib key strings to Qt key constants
 key_map = {
@@ -552,6 +420,181 @@ class PlkFitboxesWidget(QWidget):
                     self.boxChecked(parchanged, bool(w.widget().checkState()))
                     print("{0} set to {1}".format(parchanged, bool(w.widget().checkState())))
 
+class PlkRandomModelSelect(QFrame):
+    """
+    Allows one to select whether to fit with random models or not
+    """
+
+    def __init__(self, parent=None, **kwargs):
+        super().__init__(parent)
+        self.setStyleSheet(f'background-color: {background}; color: {foreground}')
+        self.boxChecked = None
+        self.layout = QVBoxLayout()
+        self.setLayout(self.layout)
+        self.checkbox = None
+        self.modeLabel = None
+
+    def addRandomCheckbox(self, parent):
+        self.clear_layout()
+        self.checkbox = QCheckBox(
+            "Random Models",
+            self
+        )
+        self.checkbox.stateChanged.connect(self.changedRMCheckBox)
+        self.layout.addWidget(self.checkbox)
+
+        # You need to create a custom class or function for tooltip
+        # checkbox_ttp = CreateToolTip(checkbox, "Display random timing models consistent with selected TOAs.")
+
+        if "zoom" in parent.plkToolbar.mode:
+            self.modeLabel = QLabel("Mode: Zoom", self)
+        else:
+            self.modeLabel = QLabel("Mode: Select", self)
+        self.layout.addWidget(self.modeLabel)
+
+    def setCallbacks(self, boxChecked):
+        """
+        Set the callback functions
+        """
+        self.boxChecked = boxChecked
+
+    def clear_layout(self):
+        while self.layout.count():
+            child = self.layout.takeAt(0)
+            if child.widget():
+                child.widget().deleteLater()
+
+    def changedRMCheckBox(self, state):
+        if state == Qt.Checked:
+            log.debug("Random Models turned on.")
+        else:
+            log.debug("Random Models turned off.")
+
+    def getRandomModel(self):
+        return self.checkbox.isChecked()
+
+    def changeMode(self, mode):
+        if "zoom" in mode:
+            self.modeLabel.setText("Mode: Zoom")
+        else:
+            self.modeLabel.setText("Mode: Select")
+
+
+class PlkLogLevelSelect(QWidget):
+    """
+    Allows one to select the log output level in the terminal
+    """
+
+    def __init__(self, parent=None, init_loglevel='INFO'):
+        super().__init__(parent)
+        self.layout = QVBoxLayout(self)
+        
+        self.logLabel = QLabel("Minimum Log Level: ", self)
+        self.layout.addWidget(self.logLabel)
+        
+        self.logLevelSelect = QComboBox(self)
+        self.logLevelSelect.addItems(["TRACE", "DEBUG", "INFO", "WARNING", "ERROR"])
+        try:
+            self.logLevelSelect.setCurrentIndex(self.logLevelSelect.findText(init_loglevel))
+        except ValueError:
+            self.logLevelSelect.setCurrentIndex(2)  # Warning is default
+        self.layout.addWidget(self.logLevelSelect)
+
+        self.logLevelSelect.currentIndexChanged.connect(self.changeLogLevel)
+
+    def changeLogLevel(self, index):
+        newLevel = self.logLevelSelect.itemText(index)  # get current value
+        log.remove()
+        log.add(
+            sys.stderr,
+            level=newLevel,
+            colorize=True,
+            format=pint.logging.format,
+            filter=pint.logging.LogFilter(),
+        )
+        log.info(f"Log level changed to {str(newLevel)}")
+
+class PlkFitterSelect(QWidget):
+    """
+    Allows one to select the fitter
+    """
+    
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.layout = QVBoxLayout(self)
+
+        self.fitterLabel = QLabel("Fitter: ", self)
+        self.layout.addWidget(self.fitterLabel)
+
+        self.fitterSelect = QComboBox(self)
+        self.layout.addWidget(self.fitterSelect)
+        self.fitterSelect.addItems([])  # initially empty
+        self.fitterSelect.currentIndexChanged.connect(self.changeFitter)
+    
+    def updateFitterChoices(self, wideband):
+        self.fitterSelect.clear()
+        self.fitterSelect.addItems(wb_fitters if wideband else nb_fitters)
+
+    def changeFitter(self):
+        self.fitter = self.fitterSelect.currentText()
+        log.info(f"Selected {self.fitter}")
+
+
+class PlkColorModeBoxes(QWidget):
+    """
+    Allows one to select the color mode for the plot's TOAs.
+    """
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.layout = QVBoxLayout(self)
+        self.group = QButtonGroup(self)
+        self.label = QLabel("Color Modes", self)
+        self.layout.addWidget(self.label)
+        self.radiobuttons = []
+        self.boxChecked = None
+
+    def addColorModeCheckbox(self, colorModes):
+        for mode in colorModes:
+            radiobutton = QRadioButton(mode.mode_name, self)
+            radiobutton.toggled.connect(lambda checked, m=mode: self.applyChanges(m) if checked else None)
+            self.group.addButton(radiobutton)
+            self.layout.addWidget(radiobutton)
+            self.radiobuttons.append(radiobutton)
+            
+            if mode.mode_name == "default":
+                radiobutton.setChecked(True)
+
+            if mode.mode_name == "jump":
+                if self.parent().psr.fitted:
+                    model = self.parent().psr.postfit_model
+                else:
+                    model = self.parent().psr.prefit_model
+                if "PhaseJump" not in model.components:
+                    radiobutton.setEnabled(False)
+
+    def setCallbacks(self, boxChecked):
+        """
+        Set the callback functions
+        """
+        self.boxChecked = boxChecked
+
+    def applyChanges(self, mode):
+        mode.displayInfo()
+        if self.boxChecked:
+            self.boxChecked(mode.mode_name)
+
+    def clear_grid(self):
+        for rb in self.radiobuttons:
+            self.layout.removeWidget(rb)
+            rb.setParent(None)
+        self.radiobuttons.clear()
+
+    def updateLayout(self):
+        self.clear_grid()
+        self.layout.addWidget(self.label)
+        for rb in self.radiobuttons:
+            self.layout.addWidget(rb)
 
 
 class PlkXYChoiceWidget(QWidget):
@@ -669,6 +712,34 @@ class PlkXYChoiceWidget(QWidget):
         if self.updatePlot is not None:
             self.updatePlot()
 
+class PlkToolbar(NavigationToolbar2QT):
+    """
+    A modification of the stock Matplotlib toolbar to perform the
+    necessary selections/un-selections on points
+    """
+
+    toolitems = [t for t in NavigationToolbar2QT.toolitems if t[0] in ("Home", "Back", "Forward", "Pan", "Zoom", "Save")]
+
+    def __init__(self, *args, **kwargs):
+        super(PlkToolbar, self).__init__(*args, **kwargs)
+
+        self.setIconSize(QtCore.QSize(16, 16))
+        self.set_actions()
+
+    def set_actions(self):
+        for action in self.actions():
+            if action.text() == 'Home':
+                action.triggered.connect(self.updatePlot)
+        
+        self.homeCallback = None
+
+    def setHomeCallback(self, homeCallback):
+        self.homeCallback = homeCallback
+
+    def updatePlot(self):
+        if self.homeCallback:
+            self.homeCallback()
+
 class PlkActionsWidget(QWidget):
     """
     Shows action items like re-fit, write par, write tim, etc.
@@ -722,10 +793,10 @@ class PlkActionsWidget(QWidget):
         button.setToolTip('Reset everything to the beginning of the session.  Be Careful!')
         self.hbox.addWidget(button)
 
-        button = QPushButton('Save fig')
-        button.clicked.connect(self.saveFig)
-        button.setToolTip('Save the current figure to file')
-        self.hbox.addWidget(button)
+        #button = QPushButton('Save fig')
+        #button.clicked.connect(self.saveFig)
+        #button.setToolTip('Save the current figure to file')
+        #self.hbox.addWidget(button)
 
         self.hbox.addStretch(1)
 
@@ -804,6 +875,7 @@ class PlkWidget(QWidget):
         self.state_stack = []
         self.update_callbacks = None
 
+        self.rect = Rectangle((0, 0), 0, 0, fill=False)
         self.press = False
         self.move = False
 
@@ -818,31 +890,39 @@ class PlkWidget(QWidget):
 
 
     def initPlk(self):
-        self.setMinimumSize(*constants.winsize_without_jupyter)
+        # Minimum sizes give problems in general, so be careful
+        #self.setMinimumSize(*constants.winsize_without_jupyter)
 
         self.plkbox = QVBoxLayout()       # plkbox contains the whole PlkWidget
         self.xychoicebox = QHBoxLayout()  # xychoicebox contains the PlkXYChoiceWidget
+        self.actionsbox = QHBoxLayout()   # actionsbox contains the PlkActionsWidget, PlkLogLevelSelect, PlkFitterSelect
 
         self.fitboxesWidget = PlkFitboxesWidget(parent=self)    # Contains all the checkboxes
         self.xyChoiceWidget = PlkXYChoiceWidget(parent=self)
         self.actionsWidget = PlkActionsWidget(parent=self)
 
-        # TODO: implement these
-        #self.randomboxWidget = PlkRandomModelSelect(master=self)
-        #self.logLevelWidget = PlkLogLevelSelect(master=self)
-        #self.fitterWidget = PlkFitterSelect(master=self)
-        #self.colorModeWidget = PlkColorModeBoxes(master=self)
+        self.randomboxWidget = PlkRandomModelSelect(parent=self)
+        self.logLevelWidget = PlkLogLevelSelect(parent=self)
+        self.fitterWidget = PlkFitterSelect(parent=self)
+        self.colorModeWidget = PlkColorModeBoxes(parent=self)
 
         # We are creating the Figure here, so set the color scheme appropriately
         self.setColorScheme(True)
 
         # Create the mpl Figure and FigCanvas objects. 
-        # 5x4 inches, 100 dots-per-inch
-        # TODO: set these in constants.py
-        self.plkDpi = 100
-        self.plkFig = Figure((5.0, 4.0), dpi=self.plkDpi)
+        # To start: 5x4 inches, 100 dots-per-inch
+        # We also 'frame' the Canvas, just for looks
+        self.plkFig = Figure(constants.plk_figsize_inch,
+                             dpi=constants.plk_figure_dpi)
+        self.canvasbox = QVBoxLayout()
+        self.canvasbox_inside = QVBoxLayout()
+        self.plkCanvasFrame = QFrame(self)
+        self.plkCanvasFrame.setFrameStyle(QFrame.Panel | QFrame.Sunken)
+        self.plkCanvasFrame.setLineWidth(constants.plk_figure_frame_lw)
+        self.plkCanvasFrame.setMidLineWidth(constants.plk_figure_frame_mlw)
         self.plkCanvas = FigureCanvas(self.plkFig)
-        self.plkCanvas.setParent(self)
+        self.plkCanvas.setParent(self.plkCanvasFrame)
+        self.plkToolbar = PlkToolbar(self.plkCanvas, self)
         
         # Call-back functions for clicking and key-press.
         # This is a GUI-independent way of dealing with events. Matplotlib
@@ -855,9 +935,6 @@ class PlkWidget(QWidget):
         self.plkCanvas.mpl_connect("motion_notify_event", self.canvasMotionEvent)
         self.plkCanvas.mpl_connect("key_press_event", self.canvasKeyEvent)
 
-        # This makes the "Home" button reset the plot just like the 'k' key
-        #self.plkToolbar.children["!button"].config(command=self.updatePlot)
-
         # Since we have only one plot, we could use add_axes 
         # instead of add_subplot, but then the subplot
         # configuration tool in the navigation toolbar wouldn't
@@ -881,9 +958,12 @@ class PlkWidget(QWidget):
         # At startup, all the widgets are visible
         self.xyChoiceVisible = True
         self.fitboxVisible = True
-        self.actionsVisible = False
-        #self.layoutMode = 1   # (0 = none, 1 = all, 2 = only fitboxes, 3 = fit & action)
-        self.layoutMode = 4    # (0 = none, 1 = all, 2 = only xy select, 3 = only fit, 4 = xy select & fit)
+        self.actionsVisible = True
+        self.layoutMode = 1    # (0 = none, 1 = all, 2 = only xy select, 3 = only fit, 4 = xy select & fit)
+
+        # This makes the "Home" button reset the plot just like the 'k' key
+        #self.plkToolbar.children["!button"].config(command=self.updatePlot)
+        self.plkToolbar.setHomeCallback(self.handleKeyK)
 
     def drawSomething(self):
         """
@@ -896,23 +976,43 @@ class PlkWidget(QWidget):
         self.plkAxes.set_xlabel('MJD')
         self.plkAxes.set_ylabel('Residual ($\mu$s)')
         self.plkFig.tight_layout()
-        #self.plkToolbar.push_current()
+        self.plkToolbar.push_current()
         self.plkCanvas.draw()
         self.setColorScheme(False)
 
     def initPlkLayout(self):
         """
-        Initialise the basic layout of this plk emulator emulator
+        Initialise the basic layout of pylk
+
+        The layout works with 'boxes', either horizontal or vertical.
+        The main box is 'plkbox' (QVBoxLayout)
         """
-        # Initialise the plk box
+        # Initialise the plk box (entire Plk Widget)
         self.plkbox.addWidget(self.fitboxesWidget)
 
+        # Initialize the canvasbox inside the frame
+        # Use a margin of 10 pixels to not overlap with the frame
+        self.canvasbox_inside.setContentsMargins(10,10,10,10)
+        self.canvasbox_inside.addWidget(self.plkCanvas)
+        self.plkCanvasFrame.setLayout(self.canvasbox_inside)
+
+        # Initialize the Figure/Canvas box
+        self.canvasbox.addWidget(self.plkToolbar)
+        self.canvasbox.addWidget(self.plkCanvasFrame)
+
         self.xychoicebox.addWidget(self.xyChoiceWidget)
-        self.xychoicebox.addWidget(self.plkCanvas)
+        self.xychoicebox.addLayout(self.canvasbox)
+        self.xychoicebox.addWidget(self.colorModeWidget)
+        #self.colorModeWidget.grid(row=2, column=0, columnspan=1, sticky="S")
 
         self.plkbox.addLayout(self.xychoicebox)
 
-        self.plkbox.addWidget(self.actionsWidget)
+        # Here: hbox with actionsWidget, fitterWidget, logLevelWidget
+        self.actionsbox.addWidget(self.actionsWidget)
+        self.actionsbox.addWidget(self.fitterWidget)
+        self.actionsbox.addWidget(self.logLevelWidget)
+        self.plkbox.addLayout(self.actionsbox)
+
         self.setLayout(self.plkbox)
 
     def initKeyHandlerDict(self):
@@ -965,7 +1065,10 @@ class PlkWidget(QWidget):
         """
         self.xyChoiceWidget.setVisible(self.xyChoiceVisible)
         self.fitboxesWidget.setVisible(self.fitboxVisible)
+        #self.actionsbox.setVisible(self.actionsVisible)
         self.actionsWidget.setVisible(self.actionsVisible)
+        self.fitterWidget.setVisible(self.actionsVisible)
+        self.logLevelWidget.setVisible(self.actionsVisible)
 
     def setColorScheme(self, start=True):
         """
@@ -1006,12 +1109,12 @@ class PlkWidget(QWidget):
             self.jumped = np.zeros(self.psr.all_toas.ntoas, dtype=bool)
             self.actionsWidget.setFitButtonText("Fit")
             self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
-            #self.randomboxWidget.addRandomCheckbox(self)
-            #self.colorModeWidget.addColorModeCheckbox(self.color_modes)
-            #self.fitterWidget.updateFitterChoices(self.psr.all_toas.wideband)
+            self.randomboxWidget.addRandomCheckbox(self)
+            self.colorModeWidget.addColorModeCheckbox(self.color_modes)
+            self.fitterWidget.updateFitterChoices(self.psr.all_toas.wideband)
             self.xyChoiceWidget.setChoice()
             self.updatePlot(keepAxes=True)
-            #self.plkToolbar.update()
+            self.plkToolbar.update()
             # reset state stack
             self.state_stack = [self.base_state]
             self.current_state = State()
@@ -1034,25 +1137,30 @@ class PlkWidget(QWidget):
             self.state_stack.append(self.base_state)
 
         self.fitboxesWidget.setCallbacks(self.fitboxChecked)
-        #self.colorModeWidget.setCallbacks(self.updateGraphColors)
+        self.colorModeWidget.setCallbacks(self.updateGraphColors)
         self.xyChoiceWidget.setCallbacks(self.updatePlot)
         self.actionsWidget.setCallbacks(self.updatePlot,
             self.fit, self.reset, self.writePar, self.writeTim, self.revert
         )
 
+        # TODO: set the layout
         #self.fitboxesWidget.grid(row=0, column=0, columnspan=2, sticky="W")
-        #self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
-        #self.randomboxWidget.addRandomCheckbox(self)
+        self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
+        self.randomboxWidget.addRandomCheckbox(self)
         #self.colorModeWidget.grid(row=2, column=0, columnspan=1, sticky="S")
-        #self.colorModeWidget.addColorModeCheckbox(self.color_modes)
+        self.colorModeWidget.addColorModeCheckbox(self.color_modes)
         self.xyChoiceWidget.setChoice()
-        #self.fitterWidget.updateFitterChoices(self.psr.all_toas.wideband)
+        self.fitterWidget.updateFitterChoices(self.psr.all_toas.wideband)
+        index = self.fitterWidget.fitterSelect.findText(self.psr.fit_method)
+        if index != -1:  # -1 means the text was not found
+            self.fitterWidget.fitterSelect.setCurrentIndex(index)
+        # This is the TK way:
         #self.fitterWidget.fitterSelect.current(
         #    self.fitterWidget.fitterSelect["values"].index(self.psr.fit_method)
         #)
-        #self.fitterWidget.fitter = self.psr.fit_method
+        self.fitterWidget.fitter = self.psr.fit_method
         self.updatePlot(keepAxes=False)
-        #self.plkToolbar.update()
+        self.plkToolbar.update()
 
         # Draw the residuals
         self.xyChoiceWidget.updateChoice()
@@ -1100,7 +1208,6 @@ class PlkWidget(QWidget):
         """
         fit the selected points using the current pre-fit model
         """
-        raise NotIplementedError()
         if self.psr is not None:
             # check jumps wont cancel fit, if so, exit here
             if self.check_jump_invalid():
@@ -1112,13 +1219,13 @@ class PlkWidget(QWidget):
                 self.state_stack.append(copy.deepcopy(self.current_state))
             self.psr.fit_method = self.fitterWidget.fitter
             self.psr.fit(self.selected)
-            #if self.randomboxWidget.getRandomModel():
-            #    self.psr.random_models(self.selected)
+            if self.randomboxWidget.getRandomModel():
+                self.psr.random_models(self.selected)
             self.current_state.selected = copy.deepcopy(self.selected)
             self.actionsWidget.setFitButtonText("Re-fit")
             self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
-            #self.randomboxWidget.addRandomCheckbox(self)
-            #self.colorModeWidget.addColorModeCheckbox(self.color_modes)
+            self.randomboxWidget.addRandomCheckbox(self)
+            self.colorModeWidget.addColorModeCheckbox(self.color_modes)
             xid, yid = self.xyChoiceWidget.plotIDs()
             self.xyChoiceWidget.setChoice(xid=xid, yid="post-fit")
             self.jumped = np.zeros(self.psr.all_toas.ntoas, dtype=bool)
@@ -1139,11 +1246,11 @@ class PlkWidget(QWidget):
         self.updateAllJumped()
         self.actionsWidget.setFitButtonText("Fit")
         self.fitboxesWidget.addFitCheckBoxes(self.base_state.psr.prefit_model)
-        #self.randomboxWidget.addRandomCheckbox(self)
-        #self.colorModeWidget.addColorModeCheckbox(self.color_modes)
+        self.randomboxWidget.addRandomCheckbox(self)
+        self.colorModeWidget.addColorModeCheckbox(self.color_modes)
         self.xyChoiceWidget.setChoice()
         self.updatePlot(keepAxes=False)
-        #self.plkToolbar.update()
+        self.plkToolbar.update()
         self.current_state = State()
         self.state_stack = [self.base_state]
         self.call_updates(psr_update=True)
@@ -1204,7 +1311,7 @@ class PlkWidget(QWidget):
             self.selected = self.psr.delete_TOAs(self.psr.deleted, self.selected)
             self.updateAllJumped()
             self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
-            #self.randomboxWidget.addRandomCheckbox(self)
+            self.randomboxWidget.addRandomCheckbox(self)
             self.colorModeWidget.addColorModeCheckbox(self.color_modes)
             if len(self.state_stack) == 0:
                 self.state_stack.append(self.base_state)
@@ -1223,8 +1330,8 @@ class PlkWidget(QWidget):
 
         # These three calls are not in pintk
         self.setColorScheme(True)
-        self.plkAxes.clear()
-        self.plkAxes.grid(True)
+        #self.plkAxes.clear()
+        #self.plkAxes.grid(True)
 
         if self.psr is not None:
             # Get a mask for the plotting points
@@ -1274,6 +1381,7 @@ class PlkWidget(QWidget):
         if keepAxes:
             xmin, xmax = self.plkAxes.get_xlim()
             ymin, ymax = self.plkAxes.get_ylim()
+            log.debug(f"plotResiduals(True): ({xmin, xmax}), ({ymin, ymax})")
         else:
             xave = 0.5 * (np.max(self.xvals) + np.min(self.xvals))
             xmin = xave - 1.10 * (xave - np.min(self.xvals))
@@ -1289,6 +1397,7 @@ class PlkWidget(QWidget):
                 ymin = yave - 1.10 * (yave - np.min(self.yvals - self.yerrs))
                 ymax = yave + 1.10 * (np.max(self.yvals + self.yerrs) - yave)
             xmin, xmax = xmin.value, xmax.value
+            log.debug(f"plotResiduals(False): ({xmin, xmax}), ({ymin, ymax})")
 
         # determine if y-axis units need scaling and scale accordingly
         if "fit" in self.yid:
@@ -1315,8 +1424,9 @@ class PlkWidget(QWidget):
         self.plkAx2y.set_visible(False)
         self.plkAx2x.set_visible(False)
         # clears the views stack and puts the scaled view on top, fixes toolbar problems
-        # self.plkToolbar._views.clear()
-        #self.plkToolbar.push_current()
+        # It seems that _views is not exposed
+        #self.plkToolbar._views.clear()
+        self.plkToolbar.push_current()
 
         if self.xid in ["pre-fit", "post-fit"]:
             self.plkAxes.set_xlabel(plotlabels[self.xid][0])
@@ -1602,35 +1712,30 @@ class PlkWidget(QWidget):
             # Unlike in Tk, in PyQt we don't directly draw on the canvas
             # So, we need to create a rectangle artist using Matplotlib and add
             # it to the axes
-            self.rect = Rectangle((0, 0), 0, 0, fill=False)  # create an invisible rectangle
+            self.rect = Rectangle((0, 0), 0, 0, fill=False, edgecolor='gray')  # create an invisible rectangle
             self.plkAxes.add_patch(self.rect)  # add rectangle to the axes
 
     def canvasMotionEvent(self, event):
         """
         Call this function when mouse is moved in the figure/canvas
         """
+        log.trace(f"Canvas motion event triggered (coords = {event.xdata, event.ydata})")
         if event.inaxes == self.plkAxes and self.press:
             self.move = True
             # Draw bounding box
-            x0, x1 = self.pressEvent.x, event.x
-            y0, y1 = self.pressEvent.y, event.y
+            x0, x1 = self.pressEvent.xdata, event.xdata
+            y0, y1 = self.pressEvent.ydata, event.ydata
             self.rect.set_xy((min([x0, x1]), min([y0, y1])))  # set bottom left corner
             self.rect.set_width(abs(x1 - x0))  # set width
             self.rect.set_height(abs(y1 - y0))  # set height
             self.rect.set_visible(True)  # make rectangle visible
             self.plkCanvas.draw()        # Don't need to update the whole plot
 
-            #height = self.plkFig.bbox.height
-            #y0 = height - y0
-            #y1 = height - y1
-            #if hasattr(self, "brect"):
-            #    self.plkCanvas._tkcanvas.delete(self.brect)
-            #self.brect = self.plkCanvas._tkcanvas.create_rectangle(x0, y0, x1, y1)
-
     def canvasReleaseEvent(self, event):
         """
         Call this function when the figure/canvas is released
         """
+        log.debug(f"canvasReleaseEvent triggered (coords = {event.x, event.y})")
         self.rect.set_visible(False)  # hide the rectangle
         self.plkCanvas.draw()
 
@@ -1690,12 +1795,12 @@ class PlkWidget(QWidget):
 
     def clickAndDrag(self, event):
         """
-        Call this function when the mouse is clicked and dragged
+        Call this function when the mouse is clicked and dragged (moved)
         """
-        #log.debug(f"You clicked and dragged in mode '{self.plkToolbar.mode}'")
+        log.debug(f"You clicked and dragged in mode '{self.plkToolbar.mode}'")
         # The following is for a selection if not in zoom mode
-        #if "zoom" not in self.plkToolbar.mode and event.inaxes == self.plkAxes:
-        if event.inaxes == self.plkAxes:
+        if "zoom" not in self.plkToolbar.mode and event.inaxes == self.plkAxes:
+            # Not in zoom mode: selecting TOAs
             xmin, xmax = self.pressEvent.xdata, event.xdata
             ymin, ymax = self.pressEvent.ydata, event.ydata
             if xmin > xmax:
@@ -1708,12 +1813,14 @@ class PlkWidget(QWidget):
             self.updatePlot(keepAxes=True)
             #self.plkCanvas._tkcanvas.delete(self.brect)
             if any(self.selected):
+                log.debug(f"Updating plot with selected points: {np.sum(self.selected)}")
                 self.psr.selected_toas = self.psr.all_toas[self.selected]
                 self.psr.update_resids()
                 self.call_updates()
         else:
-            # This just removes the rectangle from the zoom click and drag
-            pass  # the rectangle is already removed in canvasReleaseEvent
+            # We need to NOT rescale the axes here. That is happening, even though
+            # we should be SELECTING TOAs
+            log.debug(f"In zoom mode/not in axes")
 
     def canvasKeyEvent(self, event):
         """
@@ -1959,8 +2066,8 @@ class PlkWidget(QWidget):
         ):
             self.psr.selected_toas = self.all_toas[self.selected]
         self.fitboxesWidget.addFitCheckBoxes(self.psr.prefit_model)
-        #self.randomboxWidget.addRandomCheckbox(self)
-        #self.colorModeWidget.addColorModeCheckbox(self.color_modes)
+        self.randomboxWidget.addRandomCheckbox(self)
+        self.colorModeWidget.addColorModeCheckbox(self.color_modes)
         self.updatePlot(keepAxes=True)
         self.call_updates()
 
@@ -1975,9 +2082,8 @@ class PlkWidget(QWidget):
 
     def handleKeyZ(self, xpos=None, ypos=None, from_canvas=False):
         """Zoom"""
-        #self.plkToolbar.zoom()
-        #self.randomboxWidget.changeMode(self.plkToolbar.mode)
-        pass
+        self.plkToolbar.zoom()
+        self.randomboxWidget.changeMode(self.plkToolbar.mode)
 
     def handleEscape(self, xpos=None, ypos=None, from_canvas=False):
         log.info("Exiting.")
diff --git a/pylk/scripts/pylk.py b/pylk/scripts/pylk.py
index f391a48c29e0b58abed0164f1d3f62614c16674c..c50aab1dce4b6efcf11eab6df9d95a72a252088f 100644
--- a/pylk/scripts/pylk.py
+++ b/pylk/scripts/pylk.py
@@ -23,6 +23,7 @@ from PyQt5.QtWidgets import (
     QStatusBar,
     QFrame,
     QFileDialog,
+    QSplitter,
 )
 
 import pint.logging
@@ -105,6 +106,7 @@ class PylkWindow(QMainWindow):
         self.mainFrame = QWidget()
         self.setCentralWidget(self.mainFrame)
         self.hbox = QHBoxLayout()     # HBox contains all widgets
+        self.splitter = QSplitter(QtCore.Qt.Horizontal)
 
         # Menu item: open par/tim files
         self.openParTimAction = QAction('&Open par/tim', self)        
@@ -212,7 +214,9 @@ class PylkWindow(QMainWindow):
         """Create the Jupyter widget"""
 
         self.consoleWidget = RichJupyterWidget()
-        #self.consoleWidget.setMinimumSize(600, 550)
+
+        # Minimum size seems to give problems
+        #self.consoleWidget.setMinimumSize(*constants.winsize_jupyter_console)
 
         # Show the banner
         self.consoleWidget.banner = constants.PylkBanner
@@ -266,11 +270,12 @@ class PylkWindow(QMainWindow):
         """Initialise the Pylk layout"""
 
         # If other 'main' widgets exist, they can be added here
-        self.hbox.addWidget(self.openSomethingWidget)
-        self.hbox.addWidget(self.plkWidget)
+        self.splitter.addWidget(self.openSomethingWidget)
+        self.splitter.addWidget(self.plkWidget)
 
-        self.hbox.addStretch(1)
-        self.hbox.addWidget(self.consoleWidget)
+        #self.hbox.addStretch(1)
+        self.splitter.addWidget(self.consoleWidget)
+        self.hbox.addWidget(self.splitter)
         self.mainFrame.setLayout(self.hbox)
 
     def hideAllWidgets(self):
@@ -467,6 +472,8 @@ class PylkWindow(QMainWindow):
         #self.widgets["tim"].setPulsar(self.psr, updates=[self.widgets["plk"].update])
 
         # Update the plk widget
+        #self.plkWidget.setPulsar(self.psr, updates=[self.plkWidget.update])
+        # Calling 'update' here seems to delete our selections
         self.plkWidget.setPulsar(self.psr, updates=[])
 
         # Communicating with the kernel goes as follows