def manual_move(self, e):
        """
        Allows user to manually move the position of the NS probe. Opens a terminal console if not open already.
        Creates and shows instance of ManualMoveGUI to allow direct input from the user.

        :param e: Event handler.
        :return: Nothing.
        """
        if not self.console_frame:
            self.console_frame = ConsoleGUI(self, "Console")
        self.console_frame.Show(True)
        sys.stdout = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stdout to the console
        sys.stderr = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stderr to the console
        try:
            step = float(self.grid_tctrl.GetValue())
        except ValueError:
            self.errormsg(
                "Invalid scan parameters.\nPlease input numerical values only."
            )
            return
        manual = ManualMoveGUI(self, "Manual Movement", step)
        manual.Show(True)
    def run_correction(self, target_index):
        """
        Runs the 'Correct Previous Value' option from the Post Scan GUI. Starts and runs an instance of
        CorrectionThread to retake a measurement in the specified coordinate.

        :param target_index: the index in the grid that the user chooses to correct.
        :return: Nothing.
        """
        savedir = self.save_tctrl.GetValue()
        # Finding the measurement type
        meas_type = self.type_rbox.GetStringSelection()
        # Finding the measurement field
        meas_field = self.field_rbox.GetStringSelection()
        # Finding the measurement side
        meas_side = self.side_rbox.GetStringSelection()
        # Finding the RBW setting
        meas_rbw = self.rbw_rbox.GetStringSelection()
        self.corr_thread = CorrectionThread(
            self, target_index, self.run_thread.num_steps,
            float(self.dwell_tctrl.GetValue()), self.run_thread.span_start,
            self.run_thread.span_stop, self.values, self.grid, self.curr_row,
            self.curr_col, savedir, self.run_thread.comment, meas_type,
            meas_field, meas_side, meas_rbw, self.max_fname)
        if not self.console_frame:
            self.console_frame = ConsoleGUI(self, "Console")
        self.console_frame.Show(True)
        sys.stdout = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stdout to the console
        sys.stderr = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stderr to the console
        self.corr_thread.start()
    def reset_motors(self, e):
        """
        Resets the motors back to their default position. Starts and runs instance of ResetThread to facilitate motor
        resets. Opens terminal console if not open already.

        :param e: Event handler.
        :return: Nothing.
        """
        self.disablegui()
        if not self.console_frame:
            self.console_frame = ConsoleGUI(self, "Console")
        self.console_frame.Show(True)
        sys.stdout = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stdout to the console
        sys.stderr = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stderr to the console
        ResetThread(self).start()
    def run_post_scan(self):
        """
        Plots the area scan results and prompts the user for a post-scan option ('Exit', 'Zoom Scan', 'Correct previous
        value', 'Save data'). Called by the area scan threads (AreaScanThread, ZoomScanThread, CorrectionThread)
        once threads are closed.

        :return: Nothing.
        """
        # Plot the scan
        plotvals = np.copy(self.values)
        plotvals = np.rot90(plotvals)
        plt.close()
        plt.imshow(plotvals,
                   interpolation='bilinear',
                   extent=[0, plotvals.shape[1] - 1, 0, plotvals.shape[0] - 1])
        plt.title('Area Scan Heat Map')
        cbar = plt.colorbar()
        cbar.set_label('Signal Level')
        plt.show(block=False)

        # Post Scan GUI - User selects which option to proceed with
        with PostScanGUI(self,
                         title="Post Scan Options",
                         style=wx.DEFAULT_DIALOG_STYLE | wx.OK) as post_dlg:
            if post_dlg.ShowModal() == wx.ID_OK:
                choice = post_dlg.option_rbox.GetStringSelection()
                print("Choice: ", choice)
            else:
                print("No option selected - Area Scan Complete.")
                self.enablegui()
                return

        if choice == 'Zoom Scan':
            try:
                zdwell = float(self.zdwell_tctrl.GetValue())
            except ValueError:
                self.errormsg(
                    "Invalid scan parameters.\nPlease input numerical values only."
                )
                return
            savedir = self.save_tctrl.GetValue()
            # Finding the measurement type
            meas_type = self.type_rbox.GetStringSelection()
            # Finding the measurement field
            meas_field = self.field_rbox.GetStringSelection()
            # Finding the measurement side
            meas_side = self.side_rbox.GetStringSelection()
            # Finding the RBW setting
            meas_rbw = self.rbw_rbox.GetStringSelection()
            # Finding the measurement
            meas = self.meas_rbox.GetStringSelection()
            self.zoom_thread = ZoomScanThread(
                self, zdwell, self.run_thread.span_start,
                self.run_thread.span_stop, savedir, self.run_thread.comment,
                meas_type, meas_field, meas_side, meas_rbw, meas,
                self.run_thread.num_steps, self.values, self.grid,
                self.curr_row, self.curr_col)
            if not self.console_frame:
                self.console_frame = ConsoleGUI(self, "Console")
            self.console_frame.Show(True)
            sys.stdout = TextRedirector(
                self.console_frame.console_tctrl
            )  # Redirect text from stdout to the console
            sys.stderr = TextRedirector(
                self.console_frame.console_tctrl
            )  # Redirect text from stderr to the console
            self.zoom_thread.start()

        elif choice == 'Correct Previous Value':
            loc_gui = LocationSelectGUI(self, "Location Selection", self.grid)
            loc_gui.Show(True)
        elif choice == 'Save Data':
            pass
        elif choice == 'Exit':
            print("Area Scan Complete. Exiting module.")
            self.enablegui()
    def run_area_scan(self, e):
        """
        Begins general area scan based on the measurement settings specified on the GUI.
        Starts and runs an instance of AreaScanThread to perform automatic area scan.
        Opens console GUI to help user track progress of the program.

        :param e: Event handler.
        :return: Nothing.
        """
        # Make sure entries are valid
        if self.save_tctrl.GetValue() is None or \
                self.save_tctrl.GetValue() is '' or \
                not os.path.exists(self.save_tctrl.GetValue()):
            self.errormsg(
                "Please select a valid save directory for the output files.")
            return
        try:
            self.save_configuration()
            x = float(self.x_tctrl.GetValue())
            y = float(self.y_tctrl.GetValue())
            step = float(self.grid_tctrl.GetValue())
            dwell = float(self.dwell_tctrl.GetValue())
            span_start = float(self.span_start_tctrl.GetValue())
            span_stop = float(self.span_stop_tctrl.GetValue())
            start_pos = (float(self.x_pos_tctrl.GetValue()),
                         float(self.y_pos_tctrl.GetValue()))
        except ValueError:
            self.errormsg(
                "Invalid scan parameters.\nPlease input numerical values only."
            )
            return
        # Build comment for savefiles
        if self.eut_model_tctrl.GetValue() is '' or self.eut_sn_tctrl.GetValue() is '' or \
                self.initials_tctrl.GetValue() is '' or self.test_num_tctrl.GetValue() is '':
            self.errormsg(
                "Please fill out all entries in the 'Test Information' section."
            )
            return
        comment = "Model of EUT: " + self.eut_model_tctrl.GetValue() + \
                  " - \r\nS/N of EUT: " + self.eut_sn_tctrl.GetValue() + \
                  " - \r\nTest Engineer Initials: " + self.initials_tctrl.GetValue() + \
                  " - \r\nTest Number: " + self.test_num_tctrl.GetValue()
        savedir = self.save_tctrl.GetValue()
        # Finding the measurement type
        meas_type = self.type_rbox.GetStringSelection()
        # Finding the measurement field
        meas_field = self.field_rbox.GetStringSelection()
        # Finding the measurement side
        meas_side = self.side_rbox.GetStringSelection()
        # Finding the RBW setting
        meas_rbw = self.rbw_rbox.GetStringSelection()
        # Finding the measurement
        meas = self.meas_rbox.GetStringSelection()
        self.run_thread = AreaScanThread(self, x, y, step, dwell, span_start,
                                         span_stop, savedir, comment,
                                         meas_type, meas_field, meas_side,
                                         meas_rbw, meas, start_pos)
        # self.disablegui()
        logger.info("")
        logger.info(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        if not self.console_frame:
            self.console_frame = ConsoleGUI(self, "Console")
        self.console_frame.Show(True)
        sys.stdout = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stdout to the console
        sys.stderr = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stderr to the console
        print("Running general scan...")
        self.run_thread.start()
    def run_area_scan(self, e):
        """
        Begins general area scan based on the measurement settings specified on the GUI.
        Starts and runs an instance of AreaScanThread to perform automatic area scan.
        Opens console GUI to help user track progress of the program.

        :param e: Event handler.
        :return: Nothing.
        """
        # Make sure entries are valid
        if self.save_tctrl.GetValue() is None or \
                self.save_tctrl.GetValue() is '' or \
                not os.path.exists(self.save_tctrl.GetValue()):
            self.errormsg(
                "Please select a valid save directory for the output files.")
            return
        try:
            self.save_configuration()
            x = float(self.x_tctrl.GetValue())
            y = float(self.y_tctrl.GetValue())
            step = float(self.grid_tctrl.GetValue())
            dwell = float(self.dwell_tctrl.GetValue())
            span_start = float(self.span_start_tctrl.GetValue())
            span_stop = float(self.span_stop_tctrl.GetValue())
            start_pos = int(self.pos_tctrl.GetValue())
            zoom_scan = self.zoom_checkbox.GetValue()
        except ValueError:
            self.errormsg(
                "Invalid scan parameters.\nPlease input numerical values only."
            )
            return
        # Build comment for savefiles
        if self.eut_model_tctrl.GetValue() is '' or self.eut_sn_tctrl.GetValue() is '' or \
                self.initials_tctrl.GetValue() is '' or self.test_num_tctrl.GetValue() is '':
            self.errormsg(
                "Please fill out all entries in the 'Test Information' section."
            )
            return
        comment = "Model of EUT: " + self.eut_model_tctrl.GetValue() + \
                  " - \r\nS/N of EUT: " + self.eut_sn_tctrl.GetValue() + \
                  " - \r\nTest Engineer Initials: " + self.initials_tctrl.GetValue() + \
                  " - \r\nTest Number: " + self.test_num_tctrl.GetValue()
        savedir = self.save_tctrl.GetValue()
        # Finding the measurement type
        meas_type = self.type_rbox.GetStringSelection()
        # Finding the measurement field
        meas_field = self.field_rbox.GetStringSelection()
        # Finding the measurement side
        meas_side = self.side_rbox.GetStringSelection()
        # Finding the RBW setting
        meas_rbw = self.rbw_rbox.GetStringSelection()
        # Finding the measurement
        meas = self.meas_rbox.GetStringSelection()
        start_pos = int(self.pos_tctrl.GetValue())
        self.logger = Log(self.getLogFileName()).getLogger()

        if zoom_scan:
            # convert grid number to row and col
            try:
                zdwell = float(self.zdwell_tctrl.GetValue())
            except ValueError:
                self.errormsg(
                    "Invalid scan parameters.\nPlease input numerical values only."
                )
                return
            # Preparation
            step_unit = 0.00508  # TODO: Used the default step_unit for now, fix this when unit change
            num_steps = step / step_unit
            x_points = int(np.ceil(np.around(x / step, decimals=3))) + 1
            y_points = int(np.ceil(np.around(y / step, decimals=3))) + 1
            #print("x_points: ", x_points)
            #print("y_points: ", y_points)
            self.run_thread = ZoomScanThread(
                self, zdwell, span_start, span_stop, savedir, comment,
                meas_type, meas_field, meas_side, meas_rbw, meas, num_steps,
                self.values, self.grid, self.curr_row, self.curr_col,
                zoom_scan, start_pos, x_points, y_points)
        else:
            try:
                self.run_thread = AreaScanThread(self, x, y, step, dwell,
                                                 span_start, span_stop,
                                                 savedir, comment, meas_type,
                                                 meas_field, meas_side,
                                                 meas_rbw, meas, start_pos)
            except:
                self.run_thread.join()

        # self.disablegui() # TODO:Check if need disable gui
        self.logger.info(datetime.now().strftime("%Y/%m/%d"))
        if not self.console_frame:
            self.console_frame = ConsoleGUI(self, "Console")
        self.console_frame.Show(True)
        sys.stdout = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stdout to the console
        sys.stderr = TextRedirector(
            self.console_frame.console_tctrl
        )  # Redirect text from stderr to the console
        print("Running general scan...")
        self.logger.info("Running general scan...")
        self.run_thread.start()