class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__()

        self.setWindowTitle('Data Analysis for NSOR project')
        self.setWindowIcon(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\window_icon.png'))
        '''
        q actions that are intend to be in menu or toolbar
        '''

        openFile = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\open_file.png'),
            '&Open File...', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('Open the data file')
        openFile.triggered.connect(self.open_file)

        exitProgram = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\exit_program.png'),
            '&Exit', self)
        exitProgram.setShortcut("Ctrl+W")
        exitProgram.setStatusTip('Close the Program')
        exitProgram.triggered.connect(self.exit_program)

        renewData = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\renew.png'), '&Renew',
            self)
        renewData.setShortcut("Ctrl+R")
        renewData.setStatusTip('Reload the original data')
        renewData.triggered.connect(self.renew_data)

        self.verticalZoom = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\vertical_zoom.png'),
            '&Vertical Zoom', self)
        self.verticalZoom.setShortcut("Ctrl+Shift+V")
        self.verticalZoom.setStatusTip('Zoom in the vertical direction')
        self.verticalZoom.setCheckable(True)
        self.verticalZoom.toggled.connect(self.vzoom)

        self.horizontalZoom = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\horizontal_zoom.png'),
            '&Horizontal Zoom', self)
        self.horizontalZoom.setShortcut("Ctrl+Shift+H")
        self.horizontalZoom.setStatusTip('Zoom in the horizaontal direction')
        self.horizontalZoom.setCheckable(True)
        self.horizontalZoom.toggled.connect(self.hzoom)

        self.moveCursor = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\move_cursor.png'),
            '&Move Cursor', self)
        self.moveCursor.setShortcut("Ctrl+M")
        self.moveCursor.setStatusTip('Move cursors')
        self.moveCursor.setCheckable(True)
        self.moveCursor.toggled.connect(self.move_cursor)

        self.autoAxis = {}
        self.autoAxis['time_x'] = MyQAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_time_x.png'),
            '&Auto X axis (time)', 'time_x', self)
        self.autoAxis['time_y'] = MyQAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_time_y.png'),
            '&Auto Y axis (time)', 'time_y', self)
        self.autoAxis['freq_x'] = MyQAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_freq_x.png'),
            '&Auto X axis (freq)', 'freq_x', self)
        self.autoAxis['freq_y'] = MyQAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_freq_y.png'),
            '&Auto Y axis (freq)', 'freq_y', self)

        editParameters = QAction('&Edit Parameter', self)
        editParameters.setShortcut('Ctrl+E')
        editParameters.setStatusTip('open and edit the parameter file')
        editParameters.triggered.connect(self.edit_parameters)

        saveParameters = QAction('&Save Parameter', self)
        saveParameters.setShortcut('Ctrl+S')
        saveParameters.setStatusTip('save the parameters on screen to file')
        saveParameters.triggered.connect(self.save_parameters)

        self.data_type = QComboBox()
        self.data_type.setStatusTip(
            'bin for legacy data recorded from labview program, big endian coded binary data, npy for numpy type data'
        )
        self.data_type.addItems(['bin', '.npy'])
        '''
        setting menubar
        '''
        mainMenu = self.menuBar()  #create a menuBar
        fileMenu = mainMenu.addMenu('&File')  #add a submenu to the menu bar
        fileMenu.addAction(
            openFile)  # add what happens when this menu is interacted
        fileMenu.addSeparator()
        fileMenu.addAction(exitProgram)  # add an exit menu
        parameterMenu = mainMenu.addMenu('&Parameter')
        parameterMenu.addAction(editParameters)
        parameterMenu.addAction(saveParameters)
        '''
        setting toolbar
        '''
        self.toolbar = self.addToolBar(
            'nsor_toolbar')  #add a tool bar to the window
        if app.desktop().screenGeometry().height() == 2160:
            self.toolbar.setIconSize(QSize(100, 100))
        else:
            self.toolbar.setIconSize(QSize(60, 60))
        self.toolbar.addAction(
            openFile)  # add what happens when this tool is interacted

        self.toolbar.addWidget(self.data_type)
        self.toolbar.addAction(renewData)
        self.toolbar.addSeparator()

        self.toolbar.addAction(self.verticalZoom)
        self.toolbar.addAction(self.horizontalZoom)
        self.toolbar.addAction(self.moveCursor)
        self.toolbar.addSeparator()
        for key, item in self.autoAxis.items():
            self.autoAxis[key].setStatusTip(
                f'set {key} axis to size automatically')
            self.autoAxis[key].btnToggled.connect(self.auto_axis)
            self.toolbar.addAction(self.autoAxis[key])

        self.statusBar()  #create a status bar
        '''
        setting matplotlib
        '''

        if app.desktop().screenGeometry().height() == 2160:
            matplotlib.rcParams.update({'font.size': 28})
        else:
            matplotlib.rcParams.update({'font.size': 14})
        self.canvas = FigureCanvas(Figure(figsize=(40, 9)))
        self.fig = self.canvas.figure
        '''
        setting axis as dictionary,

        containing two axes of time and freq
        ax['time']
        ax['freq']
        also initiate the vertical lines
        vline['time_l']
        vline['time_r']
        vline['freq_l']
        vline['freq_r']
        '''
        self.ax = {}
        self.vline = {}
        self.ax['time'] = self.fig.add_subplot(121)
        self.ax['freq'] = self.fig.add_subplot(122)

        for axis in self.ax.values():
            if app.desktop().screenGeometry().height() == 2160:
                axis.tick_params(pad=20)
            elif app.desktop().screenGeometry().height() == 1080:
                axis.tick_params(pad=10)
            # axis.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

        self.fourier_lb = QLabel("Ready", self)

        self.parameters = read_parameter(PARAMETER_FILE)
        '''
        setting edits and labels as dictionary,

        representing all time and freq edits
        "file_name" is excluded
        "time_x_limit"
        "time_y_limit"
        "freq_x_limit"
        "freq_y_imit"
        "time_cursor"
        "freq_cursor"
        '''
        self.edits = {}
        labels = {}
        for key, value in self.parameters.items():
            if type(value) == list:
                val = str(value[0]) + ' ' + str(value[1])
            if key == 'file_name':
                continue
            labels[key] = QLabel(key.replace('_', ' ').title(), self)
            self.edits[key] = MyLineEdit(key, val, self)
            self.edits[key].setStatusTip(f'{key}')
            self.edits[key].textModified.connect(self.limit_and_cursor)
            if key[0:4] == 'freq':
                self.edits[key].setFixedWidth(250)
            if 'cursor' in key:
                self.vline[key[0:4] + '_l'] = self.ax[key[0:4]].axvline(
                    float(value[0]), c='red')
                self.vline[key[0:4] + '_r'] = self.ax[key[0:4]].axvline(
                    float(value[1]), c='red')
                self.vline[key[0:4] + '_l'].set_animated(True)
                self.vline[key[0:4] + '_r'].set_animated(True)

        self.integral_label = QLabel('Peak Intensity: \n0', self)

        self.zeroPadPower = QComboBox(self)
        self.zeroPadPower.addItems(['x1', 'x2', 'x4', 'x8'])
        self.zeroPadPower.setStatusTip('This sets the zerofilling of the data')
        self.zeroPadPower.activated[str].connect(self.zero_padding)
        '''
        phase stuff
        '''
        self.toolbar.addSeparator()
        first_order_phase_check = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_phase_check.png'),
            '&First order on', self)
        first_order_phase_check.setStatusTip('Check to enbale 1st order phase')
        first_order_phase_check.setShortcut('Ctrl+F')
        first_order_phase_check.toggled.connect(self.first_order_phase_check)
        first_order_phase_check.setCheckable(True)
        self.toolbar.addAction(first_order_phase_check)

        auto_phase_btn = QAction(
            QIcon(BASE_FOLDER + r'\pyqt_analysis\icons\auto_phase_btn.png'),
            '&Auto Phase', self)
        auto_phase_btn.setStatusTip('Auto phase the peak (0th order only)')
        auto_phase_btn.setShortcut('Ctrl+A')
        auto_phase_btn.triggered.connect(self.auto_phase)
        self.toolbar.addAction(auto_phase_btn)

        self.zeroth_slider = QSlider(self)
        self.zeroth_slider.setMinimum(0)
        self.zeroth_slider.setMaximum(360)
        self.zeroth_slider.setValue(0)
        self.zeroth_slider.setTickInterval(1)
        self.zeroth_slider.valueChanged.connect(self.zeroth_order_phase)
        self.zeroth_slider.sliderReleased.connect(self.slider_released)

        self.first_slider = QSlider(self)
        self.first_slider.setMinimum(0)
        self.first_slider.setMaximum(360)
        self.first_slider.setValue(0)
        self.first_slider.hide()
        self.first_slider.valueChanged.connect(self.first_order_phase)

        self.phase_info = QLabel('Current Phase: \n0th: 0\n1st: 0 \nInt: 0',
                                 self)
        '''
        setting layout
        '''
        self._main = QWidget()
        self.setCentralWidget(self._main)
        layout1 = QHBoxLayout(self._main)
        layout2 = QVBoxLayout()
        layout3 = QVBoxLayout()
        layout4 = QVBoxLayout()
        layout5 = QHBoxLayout()

        for key in labels.keys():
            if key[0:4] == 'time':
                layout2.addWidget(labels[key])
                layout2.addWidget(self.edits[key])
            elif key[0:4] == 'freq':
                layout4.addWidget(labels[key])
                layout4.addWidget(self.edits[key])
        layout4.addWidget(self.integral_label)
        layout4.addWidget(self.phase_info)

        layout4.addLayout(layout5)
        layout5.addWidget(self.zeroth_slider)
        layout5.addWidget(self.first_slider)

        layout2.addWidget(self.zeroPadPower)
        layout1.addLayout(layout2)
        layout2.addStretch(1)
        layout1.addLayout(layout3)
        layout3.addWidget(self.canvas)
        layout3.addWidget(self.fourier_lb)
        layout1.addLayout(layout4)
        # layout4.addStretch(1)

        self.threadpool = QThreadPool()  #Multithreading

    '''
    ################################################################################
    phase
    '''

    def slider_released(self):
        self.canvas.draw()
        key = 'freq'
        self.ax[key[0:4]].ticklabel_format(
            style='sci', axis='both',
            scilimits=(0, 0))  # format the tick label of the axes
        for k in self.ax.keys():
            self.ax[k].draw_artist(self.vline[k + '_l'])
            self.ax[k].draw_artist(self.vline[k + '_r'])

    def first_order_phase_check(self, toggle_state):
        if toggle_state:
            self.first_slider.show()
        else:
            self.first_slider.setValue(0)
            self.first_slider.hide()

    def auto_phase(self):
        try:
            reft = self.data['freq_y'].real[self.csL:self.csR]
            imft = self.data['freq_y'].imag[self.csL:self.csR]
            intensity_int = np.array([])
            for angle in range(360):
                phi = angle / 360 * 2 * pi
                intensity_int = np.append(
                    intensity_int,
                    np.sum(np.cos(phi) * reft + np.sin(phi) * imft))
            best_angle = intensity_int.argmax()
            best_phi = best_angle / 360 * 2 * pi
            self.zeroth_slider.setValue(best_angle)
            self.data['freq_real'] = self.data['freq_y'].real*np.cos(best_phi) + \
                                     self.data['freq_y'].imag*np.sin(best_phi)
            self.draw_phased_data()
        except AttributeError:
            dlg = QMessageBox.warning(self, 'WARNING',
                                      'No original data available!',
                                      QMessageBox.Ok)

    def zeroth_order_phase(self, value):
        phi = value / 360 * 2 * pi
        try:
            reft = self.data['freq_y'].real[self.csL:self.csR]
            imft = self.data['freq_y'].imag[self.csL:self.csR]
            self.data['freq_real'] = self.data['freq_y'].real*np.cos(phi) + \
                                     self.data['freq_y'].imag*np.sin(phi)
            intensity = np.sum(np.cos(phi) * reft + np.sin(phi) * imft)
            str = self.phase_info.text()
            str_lst = str.split('\n')
            intensity_str = "{:.5f}".format(intensity * 2)
            self.phase_info.setText(f'Current Phase: \n0th: {value}\n' +
                                    str_lst[2] + f'\nInt: {intensity_str}')
            self.draw_phased_data()
            self.canvas.blit(self.ax['freq'].bbox)
        except AttributeError:
            dlg = QMessageBox.warning(self, 'WARNING',
                                      'No original data available!',
                                      QMessageBox.Ok)

    def first_order_phase(self, value):
        intensity = 0
        str = self.phase_info.text()
        str_lst = str.split('\n')
        intensity_str = "{:.5f}".format(intensity * 2)
        self.phase_info.setText('Current Phase: \n' + str_lst[1] +
                                f'\n1st: {value}' + f'\nInt: {intensity_str}')

    def draw_phased_data(self):
        key = 'freq'
        self.ax[key].clear()
        self.ax[key].plot(self.data[key + '_x'], self.data[key + '_real'])

        cs_value = [
            float(x) for x in self.edits[key + '_cursor'].text().split(' ')
        ]
        self.vline[key + '_l'].set_xdata([cs_value[0], cs_value[0]])
        self.vline[key + '_r'].set_xdata([cs_value[1], cs_value[1]])

        lm_value = [
            float(x) for x in self.edits[key + '_x_limit'].text().split(' ')
        ]

        self.ax[key].set_xlim(lm_value[0], lm_value[1])

        self.canvas.draw()
        self.ax[key].ticklabel_format(
            style='sci', axis='both',
            scilimits=(0, 0))  # format the tick label of the axes
        for k in self.ax.keys():
            self.ax[k].draw_artist(self.vline[k + '_l'])
            self.ax[k].draw_artist(self.vline[k + '_r'])

    '''
    ################################################################################
    some less complicated slot
    '''

    def edit_parameters(self):
        os.startfile(PARAMETER_FILE)

    def save_parameters(self):
        for key in self.parameters.keys():
            if key == 'file_name':
                continue
            str = self.edits[key].text()
            self.parameters[key] = str.split(' ')

        save_parameter(PARAMETER_FILE, **self.parameters)

    def auto_axis(self, key):
        '''
        auto scale the axis
        '''
        if key != 'time_y':
            self.ax[key[0:4]].autoscale(axis=key[5])
        else:
            try:
                average = np.mean(np.abs(self.data['time_y']))
                self.ax['time'].set_ylim(-2 * average, 2 * average)
            except AttributeError:
                self.ax[key[0:4]].autoscale(axis=key[5])

        self.canvas.draw()
        self.ax[key[0:4]].ticklabel_format(
            style='sci', axis='both',
            scilimits=(0, 0))  # format the tick label of the axes
        for k in self.ax.keys():
            self.ax[k].draw_artist(self.vline[k + '_l'])
            self.ax[k].draw_artist(self.vline[k + '_r'])

    '''
    ################################################################################
    browse the figure
    calculate based on cursors
    '''

    def limit_and_cursor(self, key, text):
        '''
        respond to the change of text in the edits
        '''
        try:
            value = [float(x) for x in text.split(' ')]
            if 'limit' in key:
                if 'x' in key:
                    self.ax[key[0:4]].set_xlim(value[0], value[1])
                elif 'y' in key:
                    self.ax[key[0:4]].set_ylim(value[0], value[1])

            elif 'cursor' in key:
                self.vline[key[0:4] + '_l'].set_xdata([value[0], value[0]])
                self.vline[key[0:4] + '_r'].set_xdata([value[1], value[1]])
                try:
                    cs1 = np.argmin(
                        np.abs(self.data[key[0:4] + '_x'] - value[0])
                    )  # finding the index corresponding to the time stamp
                    cs2 = np.argmin(
                        np.abs(self.data[key[0:4] + '_x'] - value[1]))
                    if cs1 > cs2:
                        self.cursor_operation(key, cs2, cs1)
                    else:
                        self.cursor_operation(key, cs1, cs2)
                except AttributeError:
                    dlg = QMessageBox.warning(self, 'WARNING',
                                              'No original data available!',
                                              QMessageBox.Ok)

            self.canvas.draw()
            self.ax[key[0:4]].ticklabel_format(
                style='sci', axis='both',
                scilimits=(0, 0))  # format the tick label of the axes
            for k in self.ax.keys():
                self.ax[k].draw_artist(self.vline[k + '_l'])
                self.ax[k].draw_artist(self.vline[k + '_r'])

        except ValueError:
            dlg = QMessageBox.warning(self, 'WARNING', 'Input only number',
                                      QMessageBox.Ok)

    def cursor_operation(self, key, csL, csR):
        self.csL = csL
        self.csR = csR
        if 'time' in key:
            self.zero_padding(self.zeroPadPower.currentText(), [csL, csR])
        elif 'freq' in key:
            intensity = (np.sum(self.data['freq_y'].real)**2 +
                         np.sum(self.data['freq_y'].imag)**2)**(1 / 2)
            intensity_str = "{:.5f}".format(intensity)
            self.integral_label.setText(
                f'Peak Intensity: \n{intensity_str}')  #

    def cursor_lines_in_axis(self, ax):
        if ax == self.ax['time']:
            line1 = self.vline['time_l']
            line2 = self.vline['time_r']
        else:
            line1 = self.vline['freq_l']
            line2 = self.vline['freq_r']
        return line1, line2

    def move_cursor(self, state):
        def on_press(event):
            if self.in_ax:
                if self.current_line != None:
                    if event.button == 1:
                        ax = event.inaxes
                        self.last_ax = ax
                        self.c_lock = True
                        self.x0 = event.xdata
                        self.current_line.set_xdata([event.xdata, event.xdata])
                        line1, line2 = self.cursor_lines_in_axis(ax)

                        self.canvas.draw()
                        self.background = self.canvas.copy_from_bbox(ax.bbox)
                        ax.draw_artist(line1)
                        ax.draw_artist(line2)
                        self.canvas.blit(ax.bbox)

        def on_motion(event):
            ax = event.inaxes
            if ax != None:
                line1, line2 = self.cursor_lines_in_axis(ax)

                if self.c_lock:
                    self.current_line.set_xdata([event.xdata, event.xdata])
                    self.canvas.restore_region(self.background)
                    ax.draw_artist(line1)
                    ax.draw_artist(line2)
                    self.canvas.blit(ax.bbox)
                    if self.x0 > event.xdata:
                        self.c_side = 'left'
                    else:
                        self.c_side = 'right'

                else:
                    if abs(event.xdata -
                           line1.get_xdata()[0]) / self.xrange <= 0.02:
                        if self.cursor == 'arrow':
                            QApplication.setOverrideCursor(Qt.CrossCursor)
                            self.current_line = line1
                            self.cursor = 'cross'
                    elif abs(event.xdata -
                             line2.get_xdata()[0]) / self.xrange <= 0.02:
                        if self.cursor == 'arrow':
                            QApplication.setOverrideCursor(Qt.CrossCursor)
                            self.cursor = 'cross'
                            self.current_line = line2
                    else:
                        if self.cursor == 'cross':
                            QApplication.restoreOverrideCursor()
                            self.cursor = 'arrow'
                            self.current_line = None

        def on_release(event):
            if self.c_lock:
                self.background = None
                self.c_lock = False

                ax = event.inaxes
                if ax != self.last_ax:
                    ax = self.last_ax

                    limit = ax.get_xlim()
                    if self.c_side == 'left':
                        event.xdata = limit[0]
                    else:
                        event.xdata = limit[1]

                line1, line2 = self.cursor_lines_in_axis(ax)

                str1 = "{:.5E}".format(line1.get_xdata()[0])
                str2 = "{:.5E}".format(line2.get_xdata()[0])

                if line2.get_xdata()[0] < line1.get_xdata()[0]:
                    str1, str2 = str2, str1

                if ax == self.ax['freq']:
                    self.edits['freq_cursor'].setText(str1 + ' ' + str2)
                else:
                    self.edits['time_cursor'].setText(str1 + ' ' + str2)

        def move_in_ax(event):
            self.in_ax = True
            ax = event.inaxes
            xmin, xmax = ax.get_xlim()
            self.xrange = xmax - xmin

        def move_out_ax(event):
            self.out_ax = False

        if state:
            self.cursor = 'arrow'
            self.verticalZoom.setChecked(False)
            self.horizontalZoom.setChecked(False)
            self.c_lock = False
            self.c_onpick = False
            self.c_cid_press = self.canvas.mpl_connect('button_press_event',
                                                       on_press)
            self.c_cid_release = self.canvas.mpl_connect(
                'button_release_event', on_release)
            self.c_cid_motion = self.canvas.mpl_connect(
                'motion_notify_event', on_motion)
            self.c_in_ax = self.canvas.mpl_connect('axes_enter_event',
                                                   move_in_ax)
            self.c_out_ax = self.canvas.mpl_connect('axes_leave_event',
                                                    move_out_ax)

        else:
            self.canvas.mpl_disconnect(self.c_cid_press)
            self.canvas.mpl_disconnect(self.c_cid_release)
            self.canvas.mpl_disconnect(self.c_cid_motion)
            self.canvas.mpl_disconnect(self.c_in_ax)
            self.canvas.mpl_disconnect(self.c_out_ax)

    def vzoom(self, state):
        def on_press(event):
            if self.in_ax:
                ax = event.inaxes
                line1, line2 = self.cursor_lines_in_axis(ax)
                try:
                    if event.button == 1:
                        self.vlock = True
                        self.last_ax = ax
                        ymin, ymax = ax.get_ylim()
                        self.yrange = ymax - ymin
                        xmin, xmax = ax.get_xlim()
                        self.xrange = xmax - xmin
                        self.y0 = event.ydata
                        self.top_ln, = ax.plot([
                            event.xdata - self.xrange * 0.02,
                            event.xdata + self.xrange * 0.02
                        ], [event.ydata, event.ydata])
                        self.btm_ln, = ax.plot([
                            event.xdata - self.xrange * 0.02,
                            event.xdata + self.xrange * 0.02
                        ], [event.ydata, event.ydata])
                        self.vzoom_ln, = ax.plot([event.xdata, event.xdata],
                                                 [event.ydata, event.ydata])
                        self.top_ln.set_color('m')
                        self.btm_ln.set_color('m')
                        self.vzoom_ln.set_color('m')
                        # print(self.right_ln.get_xdata(), self.right_ln.get_ydata())
                        self.btm_ln.set_animated(True)
                        self.vzoom_ln.set_animated(True)
                        self.canvas.draw()
                        self.background = self.canvas.copy_from_bbox(ax.bbox)
                        ax.draw_artist(self.vzoom_ln)
                        ax.draw_artist(self.btm_ln)
                        line1, line2 = self.cursor_lines_in_axis(ax)
                        ax.draw_artist(line1)
                        ax.draw_artist(line2)
                        self.canvas.blit(ax.bbox)
                    else:

                        self.top_ln.remove()
                        self.vzoom_ln.remove()
                        self.btm_ln.remove()
                        self.canvas.draw()
                        self.background = None
                        self.vlock = False
                        ax.draw_artist(line1)
                        ax.draw_artist(line2)
                        self.canvas.blit(ax.bbox)
                except:
                    print('no')

        def on_release(event):
            if self.vlock:
                try:
                    self.top_ln.remove()
                    self.vzoom_ln.remove()
                    self.btm_ln.remove()
                    self.canvas.draw()
                    self.background = None
                    self.vlock = False
                    ax = event.inaxes
                    if ax != self.last_ax:
                        ax = self.last_ax
                        limit = ax.get_ylim()
                        if self.vside == 'btm':
                            event.ydata = limit[0]
                        else:
                            event.ydata = limit[1]

                    if self.y0 > event.ydata:
                        self.y0, event.ydata = event.ydata, self.y0
                    str1 = "{:.5E}".format(self.y0)
                    str2 = "{:.5E}".format(event.ydata)
                    if ax == self.ax['freq']:
                        self.edits['freq_y_limit'].setText(str1 + ' ' + str2)
                    else:
                        self.edits['time_y_limit'].setText(str1 + ' ' + str2)
                except:
                    print('no')

        def on_motion(event):
            if self.vlock:
                ax = event.inaxes
                if ax != None:
                    self.btm_ln.set_ydata([event.ydata, event.ydata])
                    self.vzoom_ln.set_ydata([self.y0, event.ydata])
                    self.canvas.restore_region(self.background)
                    ax.draw_artist(self.vzoom_ln)
                    ax.draw_artist(self.btm_ln)
                    line1, line2 = self.cursor_lines_in_axis(ax)
                    ax.draw_artist(line1)
                    ax.draw_artist(line2)
                    self.canvas.blit(ax.bbox)
                    if self.y0 > event.ydata:
                        self.vside = 'btm'
                    else:
                        self.vside = 'top'

        def move_in_ax(event):
            self.in_ax = True

        def move_out_ax(event):
            self.out_ax = False

        if state:
            self.horizontalZoom.setChecked(False)
            self.moveCursor.setChecked(False)
            self.vlock = False
            self.vcid_press = self.canvas.mpl_connect('button_press_event',
                                                      on_press)
            self.vcid_release = self.canvas.mpl_connect(
                'button_release_event', on_release)
            self.vcid_motion = self.canvas.mpl_connect('motion_notify_event',
                                                       on_motion)
            self.vin_ax = self.canvas.mpl_connect('axes_enter_event',
                                                  move_in_ax)
            self.vout_ax = self.canvas.mpl_connect('axes_leave_event',
                                                   move_out_ax)
        else:
            self.canvas.mpl_disconnect(self.vcid_press)
            self.canvas.mpl_disconnect(self.vcid_release)
            self.canvas.mpl_disconnect(self.vcid_motion)
            self.canvas.mpl_disconnect(self.vin_ax)
            self.canvas.mpl_disconnect(self.vout_ax)

    def hzoom(self, state):
        def on_press(event):
            if self.in_ax:
                ax = event.inaxes
                line1, line2 = self.cursor_lines_in_axis(ax)
                try:
                    if event.button == 1:
                        self.hlock = True
                        self.last_ax = ax
                        ymin, ymax = ax.get_ylim()
                        self.yrange = ymax - ymin
                        xmin, xmax = ax.get_xlim()
                        self.xrange = xmax - xmin
                        self.x0 = event.xdata
                        self.left_ln, = ax.plot([event.xdata, event.xdata], [
                            event.ydata - self.yrange * 0.02,
                            event.ydata + self.yrange * 0.02
                        ])
                        self.right_ln, = ax.plot([event.xdata, event.xdata], [
                            event.ydata - self.yrange * 0.02,
                            event.ydata + self.yrange * 0.02
                        ])
                        self.hzoom_ln, = ax.plot([event.xdata, event.xdata],
                                                 [event.ydata, event.ydata])
                        self.left_ln.set_color('m')
                        self.right_ln.set_color('m')
                        self.hzoom_ln.set_color('m')
                        # print(self.right_ln.get_xdata(), self.right_ln.get_ydata())
                        self.right_ln.set_animated(True)
                        self.hzoom_ln.set_animated(True)
                        self.canvas.draw()
                        self.background = self.canvas.copy_from_bbox(ax.bbox)
                        ax.draw_artist(self.hzoom_ln)
                        ax.draw_artist(self.right_ln)
                        ax.draw_artist(line1)
                        ax.draw_artist(line2)
                        self.canvas.blit(ax.bbox)

                    else:
                        self.left_ln.remove()
                        self.hzoom_ln.remove()
                        self.right_ln.remove()
                        self.canvas.draw()
                        self.background = None
                        self.hlock = False
                        ax.draw_artist(line1)
                        ax.draw_artist(line2)
                        self.canvas.blit(ax.bbox)

                except:
                    print('no')

        def on_motion(event):
            if self.hlock:
                ax = event.inaxes
                if ax != None:
                    self.right_ln.set_xdata([event.xdata, event.xdata])
                    self.hzoom_ln.set_xdata([self.x0, event.xdata])
                    self.canvas.restore_region(self.background)
                    ax.draw_artist(self.hzoom_ln)
                    ax.draw_artist(self.right_ln)
                    line1, line2 = self.cursor_lines_in_axis(ax)
                    ax.draw_artist(line1)
                    ax.draw_artist(line2)
                    self.canvas.blit(ax.bbox)
                    if self.x0 > event.xdata:
                        self.hside = 'left'
                    else:
                        self.hside = 'right'

        def on_release(event):
            if self.hlock:
                try:
                    self.left_ln.remove()
                    self.hzoom_ln.remove()
                    self.right_ln.remove()
                    self.canvas.draw()
                    self.background = None
                    self.hlock = False
                    ax = event.inaxes
                    if ax != self.last_ax:
                        ax = self.last_ax
                        limit = ax.get_xlim()
                        if self.hside == 'left':
                            event.xdata = limit[0]
                        else:
                            event.xdata = limit[1]

                    if self.x0 > event.xdata:
                        self.x0, event.xdata = event.xdata, self.x0

                    # ax.set_xlim(self.x0, event.xdata)
                    str1 = "{:.5E}".format(self.x0)
                    str2 = "{:.5E}".format(event.xdata)
                    if ax == self.ax['freq']:
                        self.edits['freq_x_limit'].setText(str1 + ' ' + str2)
                    else:
                        self.edits['time_x_limit'].setText(str1 + ' ' + str2)

                except:
                    print('no')

        def move_in_ax(event):
            self.in_ax = True

        def move_out_ax(event):
            self.out_ax = False

        if state:
            self.moveCursor.setChecked(False)
            self.verticalZoom.setChecked(False)
            self.hlock = False
            self.hcid_press = self.canvas.mpl_connect('button_press_event',
                                                      on_press)
            self.hcid_release = self.canvas.mpl_connect(
                'button_release_event', on_release)
            self.hcid_motion = self.canvas.mpl_connect('motion_notify_event',
                                                       on_motion)
            self.hin_ax = self.canvas.mpl_connect('axes_enter_event',
                                                  move_in_ax)
            self.hout_ax = self.canvas.mpl_connect('axes_leave_event',
                                                   move_out_ax)
        else:
            self.canvas.mpl_disconnect(self.hcid_press)
            self.canvas.mpl_disconnect(self.hcid_release)
            self.canvas.mpl_disconnect(self.hcid_motion)
            self.canvas.mpl_disconnect(self.hin_ax)
            self.canvas.mpl_disconnect(self.hout_ax)

    '''
    ################################################################################
    Multithreading fft calculation
    '''

    def fourier_multithreading(self, time_sig):
        self.fourier_lb.setText('Waiting...')
        fourier_worker = FourierWorker(time_sig, self.f_max)
        fourier_worker.signals.data.connect(self.set_fourier)
        fourier_worker.signals.finished.connect(self.fourier_finished)
        self.threadpool.start(fourier_worker)

    def set_fourier(self, data):
        self.data['freq_x'] = data[0]
        self.data['freq_y'] = data[1]
        self.draw('freq')
        self.edits['freq_x_limit'].returnPressed.emit()
        self.edits['freq_cursor'].returnPressed.emit()

    def fourier_finished(self):
        self.fourier_lb.setText('Ready')

    '''
    ################################################################################
    make zerofilling work
    '''

    def zero_padding(self, pad_power, value=[]):
        if value == []:
            value = [float(val) for val in self.parameters['time_cursor']]
            cs1 = np.argmin(np.abs(
                self.data['time_x'] -
                value[0]))  # finding the index corresponding to the time stamp
            cs2 = np.argmin(np.abs(self.data['time_x'] - value[1]))
        else:
            cs1 = value[0]
            cs2 = value[1]
        try:
            time_data = self.data['time_y'][cs1:cs2]
            pad_power = int(pad_power[1:])
            x = np.ceil(np.log2(len(self.data['time_y'])))
            n = 2**(pad_power - 1)
            l = int(2**x * n)
            time_sig = np.pad(time_data, (0, l - len(time_data)), 'constant')
            self.fourier_multithreading(time_sig)
        except AttributeError:
            dlg = QMessageBox.warning(self, 'WARNING',
                                      'No original data available!',
                                      QMessageBox.Ok)
            self.zeroPadPower.setCurrentIndex(0)

    '''
    ################################################################################
    other miscellaneous function
    '''

    def renew_data(self):
        try:
            self.data['time_x'] = self.data['raw_x']
            self.data['time_y'] = self.data['raw_y']
            self.draw('time')
            self.zeroPadPower.setCurrentIndex(0)
        except AttributeError:
            dlg = QMessageBox.warning(self, 'WARNING',
                                      'No original data available!',
                                      QMessageBox.Ok)

    def exit_program(self):
        choice = QMessageBox.question(
            self, 'Exiting', 'Are you sure about exit?',
            QMessageBox.Yes | QMessageBox.No)  #Set a QMessageBox when called
        if choice == QMessageBox.Yes:  # give actions when answered the question
            sys.exit()

    def open_file(self):
        '''
        open file and assign data to a dictionary self.Data
        self.data['raw_x']
        self.data['raw_y']
        above two are the original data
        self.data['time_x']
        self.data['time_y']
        self.data['freq_x']
        self.data['freq_y']

        '''
        dlg = QFileDialog()
        dlg.setDirectory(read_parameter(PARAMETER_FILE)['file_name'])
        if dlg.exec_():
            file_name = dlg.selectedFiles()[0]
            save_parameter(PARAMETER_FILE, **{"file_name": file_name})
            if str(self.data_type.currentText()) == 'bin':
                raw_data = np.fromfile(file_name, '>f8')
            elif str(self.data_type.currentText()) == '.npy':
                raw_data = np.load(file_name)
            self.data = {}
            self.data['raw_x'] = raw_data[::2]
            self.data['raw_y'] = raw_data[1::2]
            self.data['time_x'] = self.data['raw_x']
            self.data['time_y'] = self.data['raw_y']
            dt = self.data['time_x'][1] - self.data['time_x'][0]
            self.f_max = 1 / (2 * dt)
            self.fourier_multithreading(self.data['time_y'])
            self.edits['time_cursor'].returnPressed.emit()

            self.draw('time')

    '''
    ################################################################################
    '''

    def draw(self, key):
        self.ax[key].clear()
        if key == 'time':
            self.ax[key].plot(self.data[key + '_x'], self.data[key + '_y'])
        elif key == 'freq':
            self.ax[key].plot(self.data[key + '_x'],
                              np.abs(self.data[key + '_y']))
        value = [
            float(x) for x in self.edits[key + '_cursor'].text().split(' ')
        ]
        self.vline[key + '_l'].set_xdata([value[0], value[0]])
        self.vline[key + '_r'].set_xdata([value[1], value[1]])

        self.canvas.draw()
        self.ax[key].ticklabel_format(
            style='sci', axis='both',
            scilimits=(0, 0))  # format the tick label of the axes
        self.ax[key].draw_artist(self.vline[key + '_l'])
        self.ax[key].draw_artist(self.vline[key + '_r'])
        self.canvas.blit(self.ax[key].bbox)
예제 #2
0
class InteractiveMPLGraph:
    def __init__(self, parent):

        self.fig = Figure(dpi=170)
        self.canvas = FigureCanvas(self.fig)
        self.ax = self.fig.add_subplot(111)
        self.cax = None
        self.selected_nodes = []
        self._node = {}
        self._adj = {}
        self._current_node = None
        self._current_node_handle = None
        self._parent = parent
        self._analysis = parent.analysis
        self._canvas_toolbar = None
        self._default_size = {}

        node_positions = self._analysis.get_current_node_positions()
        if node_positions is None:
            node_positions = self._analysis.get_node_positions_2d()
        node_labels = self._analysis.get_short_node_labels()
        edge_labels_occupancy = {
            (key.split(':')[0], key.split(':')[1]): value
            for key, value in self._analysis.get_occupancies(
                as_labels=True).items()
        }
        frame_time, frame_unit = self._parent._search_parameter['frame_time']
        edge_labels_endurance = {
            (key.split(':')[0], key.split(':')[1]): value
            for key, value in self._analysis.get_endurance_times(
                as_labels=True, frame_time=frame_time,
                frame_unit=frame_unit).items()
        }
        if self._parent._analysis_type == 'ww':
            edge_labels_nb_water = {
                (key.split(':')[0], key.split(':')[1]): value
                for key, value in self._analysis.get_nb_waters(
                    as_labels=True).items()
            }
        graph = self._analysis.initial_graph
        f = 0.55
        len2fontsize = defaultdict(
            lambda: 6 * f, {
                2: 11 * f,
                3: 11 * f,
                4: 11 * f,
                5: 11 * f,
                6: 10 * f,
                7: 9 * f,
                8: 8 * f,
                9: 7 * f,
                10: 7 * f
            })

        for node in graph.nodes:
            label_length = len(node_labels[node])
            if not self._analysis.residuewise: label_length -= 1
            subgraph = graph.subgraph([node])
            label = nx.draw_networkx_labels(
                subgraph,
                node_positions,
                labels={node: node_labels[node]},
                font_weight='bold',
                font_size=len2fontsize[label_length],
                ax=self.ax)[node]
            handle = nx.draw_networkx_nodes(subgraph,
                                            node_positions,
                                            node_color=default_colors[0],
                                            alpha=0.5,
                                            ax=self.ax)

            self._node[node] = {
                'handle': handle,
                'label': label,
                'active': True,
                'color': default_colors[0]
            }
            self._default_size['node'] = (handle.get_sizes()[0],
                                          len2fontsize[label_length])
            self._adj[node] = {}

        for u, v in graph.edges:
            subgraph = graph.subgraph([u, v])
            direction = list(subgraph.edges)[0]
            handle = nx.draw_networkx_edges(subgraph,
                                            node_positions,
                                            width=1.0,
                                            alpha=0.5,
                                            ax=self.ax)
            self._default_size['edge'] = handle.get_linewidth()
            segments = handle.get_segments()
            ta = trans_angle(segments[0][0], segments[0][1], self.ax)
            try:
                edge_label = {direction: edge_labels_occupancy[(u, v)]}
            except KeyError:
                edge_label = {direction: edge_labels_occupancy[(v, u)]}
            edge_label_occupancy = nx.draw_networkx_edge_labels(
                subgraph,
                node_positions,
                edge_labels=edge_label,
                font_weight='bold',
                font_size=len2fontsize[6],
                ax=self.ax)[direction]
            edge_label_occupancy.set_visible(False)
            edge_label_occupancy.set_rotation(ta)
            self._default_size['label'] = edge_label_occupancy.get_fontsize()

            try:
                edge_label = {direction: edge_labels_endurance[(u, v)]}
            except KeyError:
                edge_label = {direction: edge_labels_endurance[(v, u)]}
            edge_label_endurance = nx.draw_networkx_edge_labels(
                subgraph,
                node_positions,
                edge_labels=edge_label,
                font_weight='bold',
                font_size=len2fontsize[6],
                ax=self.ax)[direction]
            edge_label_endurance.set_visible(False)
            edge_label_endurance.set_rotation(ta)

            if self._parent._analysis_type == 'ww':
                try:
                    edge_label = {direction: edge_labels_nb_water[(u, v)]}
                except KeyError:
                    edge_label = {direction: edge_labels_nb_water[(v, u)]}
                edge_label_water = nx.draw_networkx_edge_labels(
                    subgraph,
                    node_positions,
                    edge_labels=edge_label,
                    font_weight='bold',
                    font_size=len2fontsize[6],
                    ax=self.ax)[direction]
                edge_label_water.set_visible(False)
                edge_label_water.set_rotation(ta)

                edge_data = {
                    'handle': handle,
                    'direction': direction,
                    'active': True,
                    'color': 'black',
                    'all_labels': {
                        'occupancy': edge_label_occupancy,
                        'endurance': edge_label_endurance,
                        'nb_water': edge_label_water
                    }
                }
            else:
                edge_data = {
                    'handle': handle,
                    'direction': direction,
                    'active': True,
                    'color': 'black',
                    'all_labels': {
                        'occupancy': edge_label_occupancy,
                        'endurance': edge_label_endurance
                    }
                }

            self._adj[u][v] = edge_data
            self._adj[v][u] = edge_data

        self.fig.tight_layout()
        self.cax = self.fig.add_axes([0.73, 0.1, 0.2, 0.01])
        self.cax.axis('off')

        self._cidpress = self.fig.canvas.mpl_connect('button_press_event',
                                                     self.on_press)
        self._cidrelease = self.fig.canvas.mpl_connect('button_release_event',
                                                       self.on_release)
        self._cidmotion = self.fig.canvas.mpl_connect('motion_notify_event',
                                                      self.on_motion)

    def on_press(self, event):
        if event.inaxes != self.ax: return
        if (self._canvas_toolbar is None) or (self._canvas_toolbar.mode != ""):
            return
        if self._current_node is not None: return

        clicked_on_node = False
        for node in self._node:
            if not self._node[node]['active']: continue
            node_handle = self._node[node]['handle']
            contains, attrd = node_handle.contains(event)
            if contains:
                clicked_on_node = True
                break
        if not clicked_on_node: return

        self.moved = False
        x0, y0 = node_handle.get_offsets()[0]
        self.press = x0, y0, event.xdata, event.ydata
        self._current_node_handle = node_handle
        self._current_node = node

        node_handle.set_animated(True)
        label = self._node[node]['label']
        label.set_animated(True)
        for other_node in self._adj[node]:
            other_node_handle = self._node[other_node]['handle']
            edge = self._adj[node][other_node]['handle']
            edge.set_animated(True)
            for label_type in self._adj[node][other_node]['all_labels']:
                label = self._adj[node][other_node]['all_labels'][label_type]
                label.set_animated(True)
            other_node_handle.set_animated(True)

        self.canvas.draw()
        self.background = self.fig.canvas.copy_from_bbox(self.ax.bbox)

        for other_node in self._adj[node]:
            other_node_handle = self._node[other_node]['handle']
            edge = self._adj[node][other_node]['handle']
            self.ax.draw_artist(edge)
            self.ax.draw_artist(other_node_handle)
        self.ax.draw_artist(node_handle)
        self.ax.draw_artist(label)

        self.canvas.blit(self.ax.bbox)

    def on_motion(self, event):
        if self._current_node is None: return
        if event.inaxes != self.ax: return
        node = self._current_node
        node_handle = self._current_node_handle
        self.moved = True
        x0, y0, xpress, ypress = self.press
        dx = event.xdata - xpress
        dy = event.ydata - ypress

        node_handle.set_offsets([x0 + dx, y0 + dy])

        for other_node in self._adj[node]:
            edge = self._adj[node][other_node]['handle']
            direction = self._adj[node][other_node]['direction']
            segments = edge.get_segments()
            index = direction.index(node)
            segments[0][index] = [x0 + dx, y0 + dy]
            edge.set_segments(segments)
            label_pos = np.array(segments[0]).sum(axis=0) / 2
            ta = trans_angle(segments[0][0], segments[0][1], self.ax)
            for label_type in self._adj[node][other_node]['all_labels']:
                edge_label = self._adj[node][other_node]['all_labels'][
                    label_type]
                edge_label.set_position(label_pos)
                edge_label.set_rotation(ta)

        label = self._node[node]['label']
        label.set_position([x0 + dx, y0 + dy])

        self.canvas.restore_region(self.background)

        for other_node in self._adj[node]:
            other_node_handle = self._node[other_node]['handle']
            edge = self._adj[node][other_node]['handle']
            for label_type in self._adj[node][other_node]['all_labels']:
                edge_label = self._adj[node][other_node]['all_labels'][
                    label_type]
                self.ax.draw_artist(edge_label)
            self.ax.draw_artist(edge)
            self.ax.draw_artist(other_node_handle)
        self.ax.draw_artist(node_handle)
        self.ax.draw_artist(label)

        self.canvas.blit(self.ax.bbox)

    def on_release(self, event):
        if self._current_node is None: return
        node_handle = self._current_node_handle
        node = self._current_node
        label = self._node[node]['label']

        if not self.moved:
            if node in self.selected_nodes:
                self.selected_nodes.remove(node)
                node_handle.set_linewidth(1.0)
                node_handle.set_edgecolor(self._node[node]['color'])
            else:
                self.selected_nodes.append(node)
                self._parent.statusbar.showMessage(
                    self.get_current_node_info())
            self.process_selected_nodes()
            self.ax.draw_artist(node_handle)
            self.canvas.blit(self.ax.bbox)

        node_handle.set_animated(False)
        label.set_animated(False)
        for other_node in self._adj[node]:
            other_node_handle = self._node[other_node]['handle']
            edge = self._adj[node][other_node]['handle']
            for label_type in self._adj[node][other_node]['all_labels']:
                edge_label = self._adj[node][other_node]['all_labels'][
                    label_type]
                edge_label.set_animated(False)
            edge.set_animated(False)
            other_node_handle.set_animated(False)

        self.background = None
        self.canvas.draw_idle()
        self.press = None
        self._current_node = None

    def edges(self):
        seen = {}
        for node, neighbours in self._adj.items():
            for neighbor, data in neighbours.items():
                if neighbor not in seen:
                    yield (node, neighbor, data)
            seen[node] = True
        del seen

    def nodes(self):
        for node in self._node:
            yield node

    def get_current_node_info(self):
        return self._current_node

    def reset_selected_nodes(self):
        self.selected_nodes = []
        for node in self._node:
            node_handle = self._node[node]['handle']
            node_handle.set_linewidth(1.0)
            node_handle.set_edgecolor(self._node[node]['color'])
        self.canvas.draw_idle()

    def process_selected_nodes(self):
        focus_widget = self._parent.focusWidget()

        if focus_widget is self._parent.line_bonds_connected_root:
            self._parent.line_bonds_connected_root.setText(self._current_node)
        elif focus_widget is self._parent.line_bonds_path_root:
            self._parent.line_bonds_path_root.setText(self._current_node)
        elif focus_widget is self._parent.line_bonds_path_goal:
            self._parent.line_bonds_path_goal.setText(self._current_node)
        elif focus_widget is self._parent.lineEdit_specific_path:
            self._parent.lineEdit_specific_path.setText(', '.join(
                self.selected_nodes))

        current_plugin = self._parent.comboBox_plugins.currentText()
        plugin_ui = self._parent._plugins[current_plugin].ui
        plugin_lineEdits = [
            getattr(plugin_ui, lineEdit) for lineEdit in
            ['lineEdit_node_picker' + str(i) for i in range(1, 4)]
            if hasattr(plugin_ui, lineEdit)
        ]
        for lineEdit in plugin_lineEdits:
            if focus_widget is lineEdit:
                lineEdit.setText(self._current_node)

        rem_nodes = []
        for node in self.selected_nodes:
            node_handle = self._node[node]['handle']
            if node not in self._analysis.filtered_graph.nodes:
                rem_nodes.append(node)
                node_handle.set_linewidth(1.0)
                node_handle.set_edgecolor(self._node[node]['color'])
            node_handle.set_linewidth(2.0)
            node_handle.set_edgecolor('black')
        for node in rem_nodes:
            self.selected_nodes.remove(node)

    def set_edge_color(self):
        for node, other_node, edge_data in self.edges():
            edge_handle = edge_data['handle']
            edge_handle.set_facecolor(edge_data['color'])
            edge_handle.set_edgecolor(edge_data['color'])
        self.canvas.draw_idle()

    def set_subgraph(self, **kwargs):
        subgraph = self._analysis.filtered_graph
        node_labels_active = self._parent.checkBox_bonds_graph_labels.isChecked(
        )
        for node in self._node:
            if node in subgraph.nodes:
                self._node[node]['active'] = True
                node_handle = self._node[node]['handle']
                node_handle.set_visible(True)
                label = self._node[node]['label']
                if node_labels_active: label.set_visible(True)
                else: label.set_visible(False)
            else:
                self._node[node]['active'] = False
                node_handle = self._node[node]['handle']
                node_handle.set_visible(False)
                label = self._node[node]['label']
                label.set_visible(False)
        for node, other_node, edge_data in self.edges():
            edge_handle = edge_data['handle']
            for edge_label_type, edge_label in edge_data['all_labels'].items():
                if (node, other_node) in subgraph.edges:
                    edge_handle.set_visible(True)
                    edge_data['active'] = True
                else:
                    edge_handle.set_visible(False)
                    edge_label.set_visible(False)
                    edge_data['active'] = False
        self.set_edge_labels(draw=False)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_colors(self, **kwargs):
        if self.ax.get_legend() is not None:
            self.ax.get_legend().remove()
        if self.cax is not None:
            self.cax.clear()
            self.cax.axis('off')

        if self._parent.radioButton_color.isChecked():
            color = self._parent.comboBox_single_color.currentText()
            if color == '': color = default_colors[0]
            if not is_color_like(color):
                Error(
                    'Color Error' + ' ' * 30,
                    "Did not understand color definition '{}'. You can use strings like green or shorthands like g or RGB codes like #15b01a."
                    .format(color))
                return
            for node in self._node:
                self._node[node]['color'] = color

        elif self._parent.radioButton_colors.isChecked():
            for node in self._node:
                segname = node.split('-')[0]
                color = self._parent._segname_colors[segname]
                if not is_color_like(color):
                    Error(
                        'Color Error' + ' ' * 30,
                        "Did not understand color definition '{}'. You can use strings like green or shorthands like g or RGB codes like #15b01a."
                        .format(color))
                    return
                self._node[node]['color'] = color
            if self._parent.checkBox_segnames_legend.isChecked():
                custom_lines = [
                    Line2D([0], [0],
                           marker='o',
                           color='w',
                           markerfacecolor=color,
                           alpha=0.6,
                           markersize=12,
                           lw=4)
                    for color in self._parent._segname_colors.values()
                ]
                segnames = [
                    segname for segname in self._parent._segname_colors.keys()
                ]
                self.ax.legend(custom_lines, segnames)

        elif self._parent.radioButton_degree.isChecked(
        ) or self._parent.radioButton_betweenness.isChecked():
            avg_type = self._parent.checkBox_centralities_avg.isChecked()
            norm_type = self._parent.checkBox_centralities_norm.isChecked()
            if self._parent.radioButton_degree.isChecked():
                centralities = self._analysis.centralities['degree'][avg_type][
                    norm_type]
            elif self._parent.radioButton_betweenness.isChecked():
                centralities = self._analysis.centralities['betweenness'][
                    avg_type][norm_type]

            max_centrality = sorted(centralities.values())[-1]
            if self._parent.radioButton_degree.isChecked() and (
                    not (avg_type or norm_type)):
                max_centrality = round(max_centrality)
            cmap = plt.get_cmap('jet')
            for node in centralities:
                centrality_value = centralities[node]
                self._node[node]['color'] = rgb_to_string(
                    cmap(centrality_value / max_centrality))
            if self._parent.checkBox_color_legend.isChecked():
                sm = plt.cm.ScalarMappable(cmap=cmap)
                sm.set_array([0.0, max_centrality])
                plt.colorbar(sm,
                             cax=self.cax,
                             ticks=[0, max_centrality],
                             orientation='horizontal')
                self.cax.set_xticklabels([str(0), str(max_centrality)])
                self.cax.axis('on')

        for node in self._node:
            node_handle = self._node[node]['handle']
            color = self._node[node]['color']
            if not self._parent.checkBox_white.isChecked():
                node_handle.set_facecolor(color)
            else:
                node_handle.set_facecolor('white')
            node_handle.set_edgecolor(color)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_node_positions(self, **kwargs):
        projection = 'PCA'
        if self._parent.radioButton_rotation_xy.isChecked(): projection = 'XY'
        elif self._parent.radioButton_rotation_zy.isChecked():
            projection = 'ZY'
        adjust_water = False
        frame = int(self._parent.label_frame.text())
        positions = self._parent.analysis.get_node_positions_2d(
            projection=projection,
            in_frame=frame,
            adjust_water_positions=adjust_water)

        all_pos = np.array([positions[key] for key in positions])
        minx, maxx, miny, maxy = np.min(all_pos[:, 0]), np.max(
            all_pos[:, 0]), np.min(all_pos[:, 1]), np.max(all_pos[:, 1])
        xmargin = (maxx - minx) / 20
        ymargin = (maxy - miny) / 20
        for node in self._node:
            node_handle = self._node[node]['handle']
            node_handle.set_offsets(positions[node])
            node_label = self._node[node]['label']
            node_label.set_position(positions[node])

        for node, other_node, edge_data in self.edges():
            edge = edge_data['handle']
            direction = edge_data['direction']
            index = direction.index(node)
            other_index = direction.index(other_node)
            edge_positions = np.array([positions[node], positions[other_node]
                                       ])[[index, other_index]]
            edge.set_segments([edge_positions])
            label_pos = np.array(edge_positions).sum(axis=0) / 2
            ta = trans_angle(edge_positions[0], edge_positions[1], self.ax)
            for label_type in edge_data['all_labels']:
                edge_label = edge_data['all_labels'][label_type]
                edge_label.set_position(label_pos)
                edge_label.set_rotation(ta)

        self.ax.set_xlim(minx - xmargin, maxx + xmargin)
        self.ax.set_ylim(miny - ymargin, maxy + ymargin)
        if ('draw' not in kwargs): self.canvas.draw_idle()

    def set_nodesize(self, **kwargs):
        for node in self._node:
            offset = self._default_size['node'][0] / 2
            size = offset + 2 / (self._default_size['node'][0]) * (
                self._parent.horizontalSlider_nodes.value() / 100 *
                self._default_size['node'][0])**2
            node_handle = self._node[node]['handle']
            node_handle.set_sizes([size])
            offset = self._default_size['node'][1] / 2
            size = offset + self._parent.horizontalSlider_nodes.value(
            ) / 100 * self._default_size['node'][1]
            label_handle = self._node[node]['label']
            label_handle.set_size(size)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_edgesize(self, **kwargs):
        for node, other_node, edge_data in self.edges():
            offset = self._default_size['edge'] / 2
            size = offset + self._default_size['edge'] * (
                self._parent.horizontalSlider_edges.value() / 100)
            edge_data['handle'].set_linewidth(size)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_labelsize(self, **kwargs):
        for node, other_node, edge_data in self.edges():
            offset = self._default_size['label'] / 2
            size = offset + self._default_size['label'] * (
                self._parent.horizontalSlider_labels.value() / 100)
            for typ, label_handle in edge_data['all_labels'].items():
                label_handle.set_fontsize(size)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_node_labels(self, **kwargs):
        labels_active = self._parent.checkBox_bonds_graph_labels.isChecked()
        for node in self._node:
            show_label = self._node[node]['active']
            label = self._node[node]['label']
            if labels_active and show_label: label.set_visible(True)
            else: label.set_visible(False)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def set_edge_labels(self, **kwargs):
        if self._parent.checkBox_bonds_occupancy.isChecked():
            active_label_type = 'occupancy'
        elif self._parent.checkBox_bonds_endurance.isChecked():
            active_label_type = 'endurance'
        elif self._parent.checkBox_nb_water.isChecked():
            active_label_type = 'nb_water'
        else:
            active_label_type = None
        for node, other_node, edge_data in self.edges():
            show_label = edge_data['active']
            labels = edge_data['all_labels']
            for label_type in labels:
                label = labels[label_type]
                if (label_type == active_label_type) and show_label:
                    label.set_visible(True)
                else:
                    label.set_visible(False)
        if ('draw' not in kwargs) or kwargs['draw']: self.canvas.draw_idle()

    def get_active_nodes(self):
        return [node for node in self._node if self._node[node]['active']]

    def set_current_pos(self):
        node_pos = {}
        for node in self._node:
            node_handle = self._node[node]['handle']
            x, y = node_handle.get_offsets()[0]
            node_pos[node] = (x, y)
        self._analysis._current_node_positions = node_pos

    def add_toolbar(self):
        self._canvas_toolbar = NavigationToolbar(self.canvas, self._parent)
        self._canvas_toolbar.home = self.set_node_positions
        self._parent.addToolBar(self._canvas_toolbar)

    def remove_toolbar(self):
        self._parent.removeToolBar(self._canvas_toolbar)

    def _disconnect(self):
        'disconnect all the stored connection ids'
        self.canvas.mpl_disconnect(self.cidpress)
        self.canvas.mpl_disconnect(self.cidrelease)
        self.canvas.mpl_disconnect(self.cidmotion)
예제 #3
0
class Base_Plot(QtCore.QObject):
    def __init__(self, parent, widget, mpl_layout):
        super().__init__(parent)
        self.parent = parent

        self.widget = widget
        self.mpl_layout = mpl_layout
        self.fig = mplfigure.Figure()
        mpl.scale.register_scale(AbsoluteLogScale)
        mpl.scale.register_scale(BiSymmetricLogScale)
        
        # Set plot variables
        self.x_zoom_constraint = False
        self.y_zoom_constraint = False
        
        self.create_canvas()        
        self.NavigationToolbar(self.canvas, self.widget, coordinates=True)
        
        # AutoScale
        self.autoScale = [True, True]

        self.i = 0
        
        # Connect Signals
        self._draw_event_signal = self.canvas.mpl_connect('draw_event', self._draw_event)
        self.canvas.mpl_connect('button_press_event', lambda event: self.click(event))
        self.canvas.mpl_connect('key_press_event', lambda event: self.key_press(event))
        # self.canvas.mpl_connect('key_release_event', lambda event: self.key_release(event))

        self._draw_event()
    
    def create_canvas(self):
        self.canvas = FigureCanvas(self.fig)
        self.mpl_layout.addWidget(self.canvas)
        self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.canvas.draw()
        
        # Set scales
        scales = {'linear': True, 'log': 0, 'abslog': 0, 'bisymlog': 0}
        for ax in self.ax:
            ax.scale = {'x': scales, 'y': deepcopy(scales)}
            ax.ticklabel_format(scilimits=(-4, 4), useMathText=True)
        
        # Get background
        self.background_data = self.canvas.copy_from_bbox(ax.bbox)
    
    def _find_calling_axes(self, event):
        for axes in self.ax:    # identify calling axis
            if axes == event or (hasattr(event, 'inaxes') and event.inaxes == axes):
                return axes
    
    def set_xlim(self, axes, x):
        if not self.autoScale[0]: return    # obey autoscale right click option
    
        if axes.get_xscale() in ['linear']:
            # range = np.abs(np.max(x) - np.min(x))
            # min = np.min(x) - range*0.05
            # if min < 0:
                # min = 0
            # xlim = [min, np.max(x) + range*0.05]
            xlim = [np.min(x), np.max(x)]
        if 'log' in axes.get_xscale():
            abs_x = np.abs(x)
            abs_x = abs_x[np.nonzero(abs_x)]    # exclude 0's
            
            if axes.get_xscale() in ['log', 'abslog', 'bisymlog']:
                min_data = np.ceil(np.log10(np.min(abs_x)))
                max_data = np.floor(np.log10(np.max(abs_x)))
                
                xlim = [10**(min_data-1), 10**(max_data+1)]
        
        if np.isnan(xlim).any() or np.isinf(xlim).any():
            pass
        elif xlim != axes.get_xlim():   # if xlim changes
            axes.set_xlim(xlim)
    
    def set_ylim(self, axes, y):
        if not self.autoScale[1]: return    # obey autoscale right click option
        
        min_data = np.array(y)[np.isfinite(y)].min()
        max_data = np.array(y)[np.isfinite(y)].max()
        
        if min_data == max_data:
            min_data -= 10**-1
            max_data += 10**-1
        
        if axes.get_yscale() == 'linear':
            range = np.abs(max_data - min_data)
            ylim = [min_data - range*0.1, max_data + range*0.1]
            
        elif axes.get_yscale() in ['log', 'abslog']:
            abs_y = np.abs(y)
            abs_y = abs_y[np.nonzero(abs_y)]    # exclude 0's
            abs_y = abs_y[np.isfinite(abs_y)]    # exclude nan, inf
            
            if abs_y.size == 0:             # if no data, assign 
                ylim = [10**-7, 10**-1]
            else:            
                min_data = np.ceil(np.log10(np.min(abs_y)))
                max_data = np.floor(np.log10(np.max(abs_y)))
                
                ylim = [10**(min_data-1), 10**(max_data+1)]
                
        elif axes.get_yscale() == 'bisymlog':
            min_sign = np.sign(min_data)
            max_sign = np.sign(max_data)
            
            if min_sign > 0:
                min_data = np.ceil(np.log10(np.abs(min_data)))
            elif min_data == 0 or max_data == 0:
                pass
            else:
                min_data = np.floor(np.log10(np.abs(min_data)))
            
            if max_sign > 0:
                max_data = np.floor(np.log10(np.abs(max_data)))
            elif min_data == 0 or max_data == 0:
                pass
            else:
                max_data = np.ceil(np.log10(np.abs(max_data)))
            
            # TODO: ylim could be incorrect for neg/neg, checked for pos/pos, pos/neg
            ylim = [min_sign*10**(min_data-min_sign), max_sign*10**(max_data+max_sign)]
        
        if ylim != axes.get_ylim():   # if ylim changes, update
            axes.set_ylim(ylim)
    
    def update_xylim(self, axes, xlim=[], ylim=[], force_redraw=True):
        data = self._get_data(axes)         

        # on creation, there is no data, don't update
        if np.shape(data['x'])[0] < 2 or np.shape(data['y'])[0] < 2:   
            return
        
        for (axis, lim) in zip(['x', 'y'], [xlim, ylim]):
            # Set Limits
            if len(lim) == 0:
                eval('self.set_' + axis + 'lim(axes, data["' + axis + '"])')
            else:
                eval('axes.set_' + axis + 'lim(lim)')
            
            # If bisymlog, also update scaling, C
            if eval('axes.get_' + axis + 'scale()') == 'bisymlog':
                self._set_scale(axis, 'bisymlog', axes)
            
            ''' # TODO: Do this some day, probably need to create 
                        annotation during canvas creation
            # Move exponent 
            exp_loc = {'x': (.89, .01), 'y': (.01, .96)}
            eval(f'axes.get_{axis}axis().get_offset_text().set_visible(False)')
            ax_max = eval(f'max(axes.get_{axis}ticks())')
            oom = np.floor(np.log10(ax_max)).astype(int)
            axes.annotate(fr'$\times10^{oom}$', xy=exp_loc[axis], 
                          xycoords='axes fraction')
            '''
        
        if force_redraw:
            self._draw_event()  # force a draw
    
    def _get_data(self, axes):      # NOT Generic
        # get experimental data for axes
        data = {'x': [], 'y': []}
        if 'exp_data' in axes.item:
            data_plot = axes.item['exp_data'].get_offsets().T
            if np.shape(data_plot)[1] > 1:
                data['x'] = data_plot[0,:]
                data['y'] = data_plot[1,:]
            
            # append sim_x if it exists
            if 'sim_data' in axes.item and hasattr(axes.item['sim_data'], 'raw_data'):
                if axes.item['sim_data'].raw_data.size > 0:
                    data['x'] = np.append(data['x'], axes.item['sim_data'].raw_data[:,0])
        
        elif 'weight_unc_fcn' in axes.item:
            data['x'] = axes.item['weight_unc_fcn'].get_xdata()
            data['y'] = axes.item['weight_unc_fcn'].get_ydata()
        
        elif any(key in axes.item for key in ['density', 'qq_data', 'sim_data']):
            name = np.intersect1d(['density', 'qq_data'], list(axes.item.keys()))[0]
            for n, coord in enumerate(['x', 'y']):
                xyrange = np.array([])
                for item in axes.item[name]:
                    if name == 'qq_data':
                        coordData = item.get_offsets()
                        if coordData.size == 0:
                            continue
                        else:
                            coordData = coordData[:,n]
                    elif name == 'density':
                        coordData = eval('item.get_' + coord + 'data()')
                    
                    coordData = np.array(coordData)[np.isfinite(coordData)]
                    if coordData.size == 0:
                        continue
                    
                    xyrange = np.append(xyrange, [coordData.min(), coordData.max()])

                xyrange = np.reshape(xyrange, (-1,2))
                data[coord] = [np.min(xyrange[:,0]), np.max(xyrange[:,1])]

        return data
    
    def _set_scale(self, coord, type, event, update_xylim=False):
        def RoundToSigFigs(x, p):
            x = np.asarray(x)
            x_positive = np.where(np.isfinite(x) & (x != 0), np.abs(x), 10**(p-1))
            mags = 10 ** (p - 1 - np.floor(np.log10(x_positive)))
            return np.round(x * mags) / mags
    
        # find correct axes
        axes = self._find_calling_axes(event)
        # for axes in self.ax:
            # if axes == event or (hasattr(event, 'inaxes') and event.inaxes == axes):
                # break
        
        # Set scale menu boolean
        if coord == 'x':
            shared_axes = axes.get_shared_x_axes().get_siblings(axes)               
        else:
            shared_axes = axes.get_shared_y_axes().get_siblings(axes)
        
        for shared in shared_axes:
            shared.scale[coord] = dict.fromkeys(shared.scale[coord], False) # sets all types: False
            shared.scale[coord][type] = True                                # set selected type: True

        # Apply selected scale
        if type == 'linear':
            str = 'axes.set_{:s}scale("{:s}")'.format(coord, 'linear')
        elif type == 'log':
            str = 'axes.set_{0:s}scale("{1:s}", nonpos{0:s}="mask")'.format(coord, 'log')
        elif type == 'abslog':
            str = 'axes.set_{:s}scale("{:s}")'.format(coord, 'abslog')
        elif type == 'bisymlog':
            # default string to evaluate 
            str = 'axes.set_{0:s}scale("{1:s}")'.format(coord, 'bisymlog')
            
            data = self._get_data(axes)[coord]
            if len(data) != 0:
                finite_data = np.array(data)[np.isfinite(data)] # ignore nan and inf
                min_data = finite_data.min()  
                max_data = finite_data.max()
                
                if min_data != max_data:
                    # if zero is within total range, find largest pos or neg range
                    if np.sign(max_data) != np.sign(min_data):  
                        processed_data = [finite_data[finite_data>=0], finite_data[finite_data<=0]]
                        C = 0
                        for data in processed_data:
                            range = np.abs(data.max() - data.min())
                            if range > C:
                                C = range
                                max_data = data.max()
                    else:
                        C = np.abs(max_data-min_data)
                    C *= 10**(OoM(max_data) + 2)  # scaling factor TODO: + 1 looks loglike, + 2 linear like
                    C = RoundToSigFigs(C, 1)    # round to 1 significant figure
                    str = 'axes.set_{0:s}scale("{1:s}", C={2:e})'.format(coord, 'bisymlog', C)
        
        eval(str)
        if type == 'linear' and coord == 'x':
            formatter = MathTextSciSIFormatter(useOffset=False, useMathText=True)
            axes.xaxis.set_major_formatter(formatter)
            
        elif type == 'linear' and coord == 'y':
            formatter = mpl.ticker.ScalarFormatter(useOffset=False, useMathText=True)
            formatter.set_powerlimits([-3, 4])
            axes.yaxis.set_major_formatter(formatter)
            
        if update_xylim:
            self.update_xylim(axes)
 
    def _animate_items(self, bool=True):
        for axis in self.ax:
            axis.xaxis.set_animated(bool)
            axis.yaxis.set_animated(bool)
            if axis.get_legend() is not None:
                axis.get_legend().set_animated(bool)
            
            for item in axis.item.values():
                if isinstance(item, list):
                    for subItem in item:
                        if isinstance(subItem, dict):
                            subItem['line'].set_animated(bool)
                        else:
                            subItem.set_animated(bool)
                else:
                    item.set_animated(bool)
    
    def _draw_items_artist(self):
        self.canvas.restore_region(self.background_data)           
        for axis in self.ax:
            axis.draw_artist(axis.xaxis)
            axis.draw_artist(axis.yaxis)
            for item in axis.item.values():
                if isinstance(item, list):
                    for subItem in item:
                        if isinstance(subItem, dict):
                            axis.draw_artist(subItem['line'])
                        else:
                            axis.draw_artist(subItem) 
                else:
                    axis.draw_artist(item)
           
            if axis.get_legend() is not None:
                axis.draw_artist(axis.get_legend())
          
        self.canvas.update()
    
    def set_background(self):
        self.canvas.mpl_disconnect(self._draw_event_signal)
        self.canvas.draw() # for when shock changes. Without signal disconnect, infinite loop
        self._draw_event_signal = self.canvas.mpl_connect('draw_event', self._draw_event)
        self.background_data = self.canvas.copy_from_bbox(self.fig.bbox)
    
    def _draw_event(self, event=None):   # After redraw (new/resizing window), obtain new background
        self._animate_items(True)
        self.set_background()
        self._draw_items_artist()
        #self.canvas.draw_idle()
    
    def clear_plot(self, ignore=[], draw=True):
        for axis in self.ax:
            if axis.get_legend() is not None:
                axis.get_legend().remove()
                
            for item in axis.item.values():
                if hasattr(item, 'set_offsets'):    # clears all data points
                    if 'scatter' not in ignore:
                        item.set_offsets(([np.nan, np.nan]))
                elif hasattr(item, 'set_xdata') and hasattr(item, 'set_ydata'):
                    if 'line' not in ignore:
                        item.set_xdata([np.nan, np.nan]) # clears all lines
                        item.set_ydata([np.nan, np.nan])
                elif hasattr(item, 'set_text'): # clears all text boxes
                    if 'text' not in ignore:
                        item.set_text('')
        if draw:
            self._draw_event()

    def click(self, event):
        if event.button == 3: # if right click
            if not self.toolbar.mode:
                self._popup_menu(event)
            # if self.toolbar._active is 'ZOOM':  # if zoom is on, turn off
                # self.toolbar.press_zoom(event)  # cancels current zooom
                # self.toolbar.zoom()             # turns zoom off
            elif event.dblclick:                  # if double right click, go to default view
                self.toolbar.home()

    def key_press(self, event):
        if event.key == 'escape':
            if self.toolbar.mode == 'zoom rect':  # if zoom is on, turn off
                self.toolbar.zoom()               # turns zoom off
            elif self.toolbar.mode == 'pan/zoom':
                self.toolbar.pan()
        # elif event.key == 'shift':
        elif event.key == 'x':  # Does nothing, would like to make sticky constraint zoom/pan
            self.x_zoom_constraint = not self.x_zoom_constraint
        elif event.key == 'y':  # Does nothing, would like to make sticky constraint zoom/pan
            self.y_zoom_constraint = not self.y_zoom_constraint
        elif event.key in ['s', 'l', 'L', 'k']: pass
        else:
            key_press_handler(event, self.canvas, self.toolbar)
    
    # def key_release(self, event):
        # print(event.key, 'released')
    
    def NavigationToolbar(self, *args, **kwargs):
        ## Add toolbar ##
        self.toolbar = CustomNavigationToolbar(self.canvas, self.widget, coordinates=True)
        self.mpl_layout.addWidget(self.toolbar)

    def _popup_menu(self, event):
        axes = self._find_calling_axes(event)   # find axes calling right click
        if axes is None: return
        
        pos = self.parent.mapFromGlobal(QtGui.QCursor().pos())
        
        popup_menu = QMenu(self.parent)
        xScaleMenu = popup_menu.addMenu('x-scale')
        yScaleMenu = popup_menu.addMenu('y-scale')
        
        for coord in ['x', 'y']:
            menu = eval(coord + 'ScaleMenu')
            for type in axes.scale[coord].keys():
                action = QAction(type, menu, checkable=True)
                if axes.scale[coord][type]: # if it's checked
                    action.setEnabled(False)
                else:
                    action.setEnabled(True)
                menu.addAction(action)
                action.setChecked(axes.scale[coord][type])
                fcn = lambda event, coord=coord, type=type: self._set_scale(coord, type, axes, True)
                action.triggered.connect(fcn)
        
        # Create menu for AutoScale options X Y All
        popup_menu.addSeparator()
        autoscale_options = ['AutoScale X', 'AutoScale Y', 'AutoScale All']
        for n, text in enumerate(autoscale_options):
            action = QAction(text, menu, checkable=True)
            if n < len(self.autoScale):
                action.setChecked(self.autoScale[n])
            else:
                action.setChecked(all(self.autoScale))
            popup_menu.addAction(action)
            action.toggled.connect(lambda event, n=n: self._setAutoScale(n, event, axes))
                    
        popup_menu.exec_(self.parent.mapToGlobal(pos))    
    
    def _setAutoScale(self, choice, event, axes):
        if choice == len(self.autoScale):
            for n in range(len(self.autoScale)):
                self.autoScale[n] = event
        else:
            self.autoScale[choice] = event
        
        if event:   # if something toggled true, update limits
            self.update_xylim(axes)
예제 #4
0
class MplWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.scroll = QtWidgets.QScrollArea(self)
        self.scroll.setParent(None)
        #self.fig =Figure(tight_layout=True)
        self.fig = Figure()
        left = 0.0
        bottom = 0.0
        width = 1
        height = 1
        self.fig.add_axes([left, bottom, width, height])
        self.canvas = FigureCanvas(self.fig)
        self.fig.set_facecolor([0.23, 0.23, 0.23, 0.5])
        self.canvas.axes = self.canvas.figure.gca()

        #self.canvas.figure.tight_layout(pad=0)
        self.vertical_layout = QVBoxLayout()
        self.vertical_layout.addWidget(self.canvas)
        self.mpl_toolbar = my_toolbar(self.canvas, self)
        self.mpl_toolbar.setParentClass(self)
        self.mpl_toolbar.setMinimumWidth(100)

        self.mpl_toolbar.setFixedHeight(26)
        self.mpl_toolbar.setStyleSheet(
            "QToolBar { opacity: 1;border: 0px; background-color: rgb(133, 196, 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.mpl_toolbar.setObjectName("myToolBar")

        #self.canvas.mpl_connect("resize_event", self.resize)
        self.vertical_layout.addWidget(self.mpl_toolbar)
        self.setLayout(self.vertical_layout)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(0)
        self.rect = Rectangle((0, 0), 1, 1)
        self.updateSecondImage = None
        self.patchesTotal = 0
        self.typeOfAnnotation = "autoDetcted"
        self.frameAtString = "Frame 0"
        self.currentSelectedOption = None

        self.AllBoxListDictionary = {
            "eraseBox": [],
            "oneWormLive": [],
            "multiWormLive": [],
            "oneWormDead": [],
            "multiWormDead": [],
            "miscBoxes": [],
            "autoDetcted": []
        }

        self.eraseBoxXYValues = self.AllBoxListDictionary["eraseBox"]
        self.addBoxXYValues = self.AllBoxListDictionary["miscBoxes"]
        self.oneWormLiveBoxXYValues = self.AllBoxListDictionary["oneWormLive"]
        self.multiWormLiveBoxXYValues = self.AllBoxListDictionary[
            "multiWormLive"]
        self.oneWormDeadBoxXYValues = self.AllBoxListDictionary["oneWormDead"]
        self.multiWormDeadBoxXYValues = self.AllBoxListDictionary[
            "multiWormDead"]
        self.autoDetectedBoxXYValues = self.AllBoxListDictionary["autoDetcted"]
        self.tempList = []

    def resetAllBoxListDictionary(self):
        self.AllBoxListDictionary = {
            "eraseBox": [],
            "oneWormLive": [],
            "multiWormLive": [],
            "oneWormDead": [],
            "multiWormDead": [],
            "miscBoxes": [],
            "autoDetcted": []
        }

    def updateAllBoxListDictionary(self):
        self.AllBoxListDictionary["eraseBox"] = self.eraseBoxXYValues
        self.AllBoxListDictionary["miscBoxes"] = self.addBoxXYValues
        self.AllBoxListDictionary["oneWormLive"] = self.oneWormLiveBoxXYValues
        self.AllBoxListDictionary[
            "multiWormLive"] = self.multiWormLiveBoxXYValues
        self.AllBoxListDictionary["oneWormDead"] = self.oneWormDeadBoxXYValues
        self.AllBoxListDictionary[
            "multiWormDead"] = self.multiWormDeadBoxXYValues
        self.AllBoxListDictionary["autoDetcted"] = self.autoDetectedBoxXYValues

    def updateAllListFromAllBoxListDictionary(self):
        self.eraseBoxXYValues = self.AllBoxListDictionary["eraseBox"]
        self.addBoxXYValues = self.AllBoxListDictionary["miscBoxes"]
        self.oneWormLiveBoxXYValues = self.AllBoxListDictionary["oneWormLive"]
        self.multiWormLiveBoxXYValues = self.AllBoxListDictionary[
            "multiWormLive"]
        self.oneWormDeadBoxXYValues = self.AllBoxListDictionary["oneWormDead"]
        self.multiWormDeadBoxXYValues = self.AllBoxListDictionary[
            "multiWormDead"]
        self.autoDetectedBoxXYValues = self.AllBoxListDictionary["autoDetcted"]

    def setFrameAtString(self, text):
        self.frameAtString = text

    def getFrameAtString(self):
        return self.frameAtString

    def getCurrentSelectedOption(self):
        return self.currentSelectedOption

    def setCurrentSelectedOption(self, option):
        self.currentSelectedOption = option

    def setDarkTheme(self):
        self.mpl_toolbar.setStyleSheet(
            "QToolBar#myToolBar{ border: 0px; background-color: rgb(133, 0,s 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.fig.set_facecolor([0.23, 0.23, 0.23, 0.5])
        #self.fig.set_facecolor('grey')
        self.canvas.draw()

    def setGreenTheme(self):
        self.mpl_toolbar.setStyleSheet(
            "QToolBar { border: 0px; background-color: rgb(133, 196, 65); border-bottom: 1px solid #19232D;padding: 2px;  font-weight: bold;spacing: 2px; } "
        )
        self.fig.set_facecolor('grey')
        self.canvas.draw()

    def setTypeOfAnnotation(self, text):
        self.typeOfAnnotation = text

    def restrictCanvasMinimumSize(self, size):
        self.canvas.setMinimumSize(size)

    def unmountWidgetAndClear(self):
        self.vertical_layout.removeWidget(self.canvas)
        self.vertical_layout.removeWidget(self.scroll)
        self.scroll.setParent(None)
        self.canvas.setParent(None)
        sip.delete(self.scroll)
        del self.canvas
        self.scroll = None
        self.canvas = None
        self.canvas = FigureCanvas(Figure())
        self.canvas.axes = self.canvas.figure.gca()
        #self.canvas.figure.tight_layout()
        self.scroll = QtWidgets.QScrollArea(self)
        self.scroll.setWidgetResizable(True)

    def connectClickListnerToCurrentImageForCrop(self,
                                                 givenController,
                                                 updateSecondImage=None,
                                                 listOfControllers=None,
                                                 keyForController=None):
        self.cid1 = self.canvas.mpl_connect("button_press_event",
                                            self.on_press_for_crop)
        self.cid2 = self.canvas.mpl_connect("motion_notify_event",
                                            self.onmove_for_crop)
        self.cid3 = self.canvas.mpl_connect("button_release_event",
                                            self.on_release_for_crop)
        self.givenControllerObject = givenController
        self.updateSecondImage = updateSecondImage
        self.pressevent = None
        self.listOfControllers = listOfControllers
        self.keyForController = keyForController

    def on_press_for_crop(self, event):
        if (self.mpl_toolbar.mode):
            return

        try:
            self.rect.remove()
        except:
            pass
        self.addedPatch = None
        self.x0 = event.xdata
        self.y0 = event.ydata
        self.rect = Rectangle((self.x0, self.y0), 1, 1)
        self.rect._alpha = 0.5
        self.rect._linewidth = 2
        self.rect.set_color("C2")
        self.rect.set
        self.pressevent = 1
        self.addedPatch = self.canvas.axes.add_patch(self.rect)

    def on_release_for_crop(self, event):
        if (self.mpl_toolbar.mode):
            return

        self.pressevent = None

        minMaxVertices = [
            int(np.ceil(min(self.x0, self.x1))),
            int(np.ceil(min(self.y0, self.y1))),
            int(np.round(max(self.x0, self.x1))),
            int(np.round(max(self.y0, self.y1))),
        ]
        self.givenControllerObject.updateManualCropCoordinates(minMaxVertices)
        image = self.givenControllerObject.showManualCropImage()
        self.canvas.axes.clear()
        self.canvas.axes.axis("off")
        self.canvas.axes.imshow(image)
        self.canvas.draw()
        if self.updateSecondImage is not None:
            self.updateSecondImage.canvas.axes.clear()
            self.updateSecondImage.canvas.axes.axis("off")
            self.updateSecondImage.canvas.axes.imshow(
                self.givenControllerObject.getCroppedImage(0))
            self.updateSecondImage.canvas.draw()
            self.listOfControllers[
                self.keyForController] = self.givenControllerObject

    def onmove_for_crop(self, event):

        if self.pressevent is None:
            return
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))
        self.canvas.draw()

    def disconnectClickListnerFromCurrentImageForCrop(self):
        try:
            self.canvas.mpl_disconnect(self.cid1)
            self.canvas.mpl_disconnect(self.cid2)
            self.canvas.mpl_disconnect(self.cid3)
            self.updateSecondImage = None
        except:
            pass

    def getCurrentScrollParam(self):
        self.currentVerticalSliderValue = self.scroll.verticalScrollBar(
        ).value()
        self.currentHorizontalSliderValue = self.scroll.horizontalScrollBar(
        ).value()

    def resetCurrentScrollParam(self):
        self.scroll.verticalScrollBar().setValue(
            self.currentVerticalSliderValue)
        self.scroll.horizontalScrollBar().setValue(
            self.currentHorizontalSliderValue)

    def resize(self, event):
        # on resize reposition the navigation toolbar to (0,0) of the axes.
        x, y = self.fig.axes[0].transAxes.transform((0, 0))
        figw, figh = self.fig.get_size_inches()
        ynew = figh * self.fig.dpi - y - self.mpl_toolbar.frameGeometry(
        ).height()
        self.mpl_toolbar.move(x, ynew)

    def connectClickListnerToCurrentImageForAnnotate(self,
                                                     givenController,
                                                     updateSecondImage=None):
        self.cid4 = self.canvas.mpl_connect("button_press_event",
                                            self.on_press_for_annotate)

        self.cid7 = self.canvas.mpl_connect('pick_event', self.onpick)
        #self.cid7 = self.canvas.mpl_connect('button_press_event', self.right_click_press_for_annotate)
        self.givenControllerObject = givenController
        self.updateSecondImage = updateSecondImage
        self.pressevent = None

    def autoAnnotateOnOverlay(self, autoDetectedObjects):

        for index, row in autoDetectedObjects.iterrows():
            print(row.bbox3)

            #if self.pressevent is None:
            #    return
            #self.x1 = event.xdata
            #self.y1 = event.ydata
            self.rect.set_width(row.bbox3 - row.bbox1)
            self.rect.set_height(row.bbox2 - row.bbox0)
            self.rect.set_xy((row.bbox1, row.bbox0))

            self.canvas.draw()

            self.rect = Rectangle((row.bbox1, row.bbox0), 1, 1, picker=True)
            self.rect._alpha = 1
            self.rect._edgecolor = (0, 1, 0, 1)
            self.rect._facecolor = (0, 0, 0, 0)

            self.rect._linewidth = 1
            self.rect.set_linestyle('dashed')
            self.rect.addName = self.typeOfAnnotation
            self.pressevent = 1
            self.canvas.axes.add_patch(self.rect)
            self.patchesTotal = self.patchesTotal + 1

            if [row.bbox1, row.bbox0, row.bbox3,
                    row.bbox2] not in self.autoDetectedBoxXYValues:
                self.autoDetectedBoxXYValues.append(
                    [row.bbox1, row.bbox0, row.bbox3, row.bbox2])

            # Update latest values
            self.updateAllBoxListDictionary()
            #print(self.typeOfAnnotation)
            '''if self.typeOfAnnotation == "eraseBox":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation not in ["eraseBox", "oneWormLive", "multiWormLive", "oneWormDead", "multiWormDead"]:
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "oneWormLive":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "multiWormLive":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "oneWormDead":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])

            if self.typeOfAnnotation == "multiWormDead":
                if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                    self.tempList.append([self.x0, self.y0, self.x1, self.y1])'''

            #self.canvas.draw()

        #return(self.canvas)

    def on_press_for_annotate(self, event):
        # try:
        #     self.rect.remove()
        # except:
        #     pass
        if (self.mpl_toolbar.mode):
            return

        if event.button == 1:
            self.cid5 = self.canvas.mpl_connect("motion_notify_event",
                                                self.onmove_for_annotate)
            self.cid6 = self.canvas.mpl_connect("button_release_event",
                                                self.on_release_for_annotate)

            self.x0 = event.xdata
            self.y0 = event.ydata

            self.rect = Rectangle((self.x0, self.y0), 1, 1, picker=True)
            self.rect._alpha = 1
            if self.typeOfAnnotation not in [
                    "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                    "multiWormDead"
            ]:
                self.rect._edgecolor = (0, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "autoDetcted":
                self.rect._edgecolor = (0, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "eraseBox":
                self.rect._edgecolor = (0, 0, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "oneWormLive":
                self.rect._edgecolor = (0, 0, 1, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "multiWormLive":
                self.rect._edgecolor = (1, 1, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "oneWormDead":
                self.rect._edgecolor = (1, 0, 0, 1)
                self.rect._facecolor = (0, 0, 0, 0)
            elif self.typeOfAnnotation == "multiWormDead":
                self.rect._edgecolor = (1, 1, 1, 1)
                self.rect._facecolor = (0, 0, 0, 0)

            self.rect._linewidth = 1
            self.rect.set_linestyle('dashed')
            self.rect.addName = self.typeOfAnnotation
            self.pressevent = 1
            self.canvas.axes.add_patch(self.rect)
            self.patchesTotal = self.patchesTotal + 1

    def on_release_for_annotate(self, event):
        if (self.mpl_toolbar.mode):
            return

        if event.button == 1:
            self.canvas.mpl_disconnect(self.cid5)
            if (self.rect.get_height() == 1) and (self.rect.get_width() == 1):
                self.rect.remove()
            self.pressevent = None
            self.canvas.mpl_disconnect(self.cid6)

        if self.typeOfAnnotation == "eraseBox":
            #print(self.typeOfAnnotation)
            self.eraseBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation not in [
                "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                "multiWormDead"
        ]:
            #print(self.typeOfAnnotation)
            self.addBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "oneWormLive":
            self.oneWormLiveBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "multiWormLive":
            self.multiWormLiveBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "oneWormDead":
            self.oneWormDeadBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        if self.typeOfAnnotation == "multiWormDead":
            self.multiWormDeadBoxXYValues.append(self.tempList[-1])
            self.tempList = []

        # updateAllBoxListDictionary(self)
        self.updateAllBoxListDictionary()

        # self.givenControllerObject.updateManualCropCoordinates(minMaxVertices)
        # image = self.givenControllerObject.showManualCropImage()
        # self.canvas.axes.clear()
        # self.canvas.axes.axis("off")
        # self.canvas.axes.imshow(image)
        # self.canvas.draw()
        # if self.updateSecondImage is not None:
        #     self.updateSecondImage.canvas.axes.clear()
        #     self.updateSecondImage.canvas.axes.axis("off")
        #     self.updateSecondImage.canvas.axes.imshow(self.givenControllerObject.getCroppedImage(0))
        #     self.updateSecondImage.canvas.draw()

    def onmove_for_annotate(self, event):

        if self.pressevent is None:
            return
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rect.set_width(self.x1 - self.x0)
        self.rect.set_height(self.y1 - self.y0)
        self.rect.set_xy((self.x0, self.y0))

        #print(self.typeOfAnnotation)
        if self.typeOfAnnotation == "eraseBox":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation not in [
                "eraseBox", "oneWormLive", "multiWormLive", "oneWormDead",
                "multiWormDead"
        ]:
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "oneWormLive":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "multiWormLive":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "oneWormDead":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        if self.typeOfAnnotation == "multiWormDead":
            if [self.x0, self.y0, self.x1, self.y1] not in self.tempList:
                self.tempList.append([self.x0, self.y0, self.x1, self.y1])

        self.canvas.draw()

    def getEraseBoxXYValues(self):
        return (self.eraseBoxXYValues)

    def getAutoDetctedBoxXYValues(self):
        return (self.autoDetectedBoxXYValues)

    def getAddBoxXYValues(self):
        return (self.addBoxXYValues)

    def getOneWormLiveBoxXYValues(self):
        return (self.oneWormLiveBoxXYValues)

    def getMultiWormLiveBoxXYValues(self):
        return (self.multiWormLiveBoxXYValues)

    def getOneWormDeadBoxXYValues(self):
        return (self.oneWormDeadBoxXYValues)

    def getMultiWormDeadBoxXYValues(self):
        return (self.multiWormDeadBoxXYValues)

    def resetEraseBoxXYValues(self):
        self.eraseBoxXYValues = []

    def resetAutoDetctedBoxXYValues(self):
        self.autoDetectedBoxXYValues = []

    def resetAddBoxXYValues(self):
        self.addBoxXYValues = []

    def resetOneWormLiveBoxXYValues(self):
        self.oneWormLiveBoxXYValues = []

    def resetMultiWormLiveBoxXYValues(self):
        self.multiWormLiveBoxXYValues = []

    def resetOneWormDeadBoxXYValues(self):
        self.oneWormDeadBoxXYValues = []

    def resetMultiWormDeadBoxXYValues(self):
        self.multiWormDeadBoxXYValues = []

    def disconnectClickListnerFromCurrentImageForAnnotate(self):
        try:
            self.canvas.mpl_disconnect(self.cid4)

            self.canvas.mpl_disconnect(self.cid7)
            self.updateSecondImage = None
        except:
            pass

    def onpick(self, event):
        #if event.button == 3:       #"3" is the right button
        # print "you click the right button"
        # print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
        # event.button, event.x, event.y, event.xdata, event.ydata)
        #Get the coordinates of the mouse click
        #I create the action
        if (self.mpl_toolbar.mode):
            return
        if event.mouseevent.button == 3:
            self.objectPicked = event.artist
            noteAction_1 = QtWidgets.QAction('Delete Box', self)
            noteAction_2 = QtWidgets.QAction('Classify', self)
            #noteAction_5 = QtWidgets.QAction('Add Once',self)
            #noteAction_2 = QtWidgets.QAction('Add Through',self)
            #noteAction_3 = QtWidgets.QAction('Mask Here',self)
            #noteAction_4 = QtWidgets.QAction('Mask Through',self)
            #noteAction_6 = QtWidgets.QAction('Live here',self)
            #noteAction_7 = QtWidgets.QAction('Live all',self)
            #noteAction_8 = QtWidgets.QAction('Dead here',self)
            #noteAction_9 = QtWidgets.QAction('Dead all',self)

            #I create the context menu
            self.popMenu = QtWidgets.QMenu(self)
            self.popMenu.addAction(noteAction_1)
            self.popMenu.addAction(noteAction_2)
            # self.popMenu.addAction(noteAction_2)
            # self.popMenu.addAction(noteAction_3)
            # self.popMenu.addAction(noteAction_4)
            # self.popMenu.addAction(noteAction_5)
            # self.popMenu.addAction(noteAction_6)
            # self.popMenu.addAction(noteAction_7)
            # self.popMenu.addAction(noteAction_8)
            # self.popMenu.addAction(noteAction_9)

            cursor = QtGui.QCursor()
            #self.connect(self.figure_canvas, SIGNAL("clicked()"), self.context_menu)
            #self.popMenu.exec_(self.mapToGlobal(event.globalPos()))
            noteAction_1.triggered.connect(lambda: self.removeThisArea(1))
            noteAction_2.triggered.connect(
                lambda: self.classifyAsCurrentSelection(1))
            # noteAction_2.triggered.connect(lambda :self.removeThisArea(2))
            # noteAction_3.triggered.connect(lambda :self.removeThisArea(3))
            # noteAction_4.triggered.connect(lambda :self.removeThisArea(4))
            # noteAction_5.triggered.connect(lambda :self.removeThisArea(5))
            # noteAction_6.triggered.connect(lambda :self.removeThisArea(5))
            # noteAction_7.triggered.connect(lambda :self.removeThisArea(2))
            # noteAction_8.triggered.connect(lambda :self.removeThisArea(3))
            # noteAction_9.triggered.connect(lambda :self.removeThisArea(4))

            self.popMenu.popup(cursor.pos())
        else:
            return

    def right_click_press_for_annotate(self, event):
        if (self.mpl_toolbar.mode):
            return
        if event.button == 3:  #"3" is the right button
            # print "you click the right button"
            # print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(
            # event.button, event.x, event.y, event.xdata, event.ydata)
            #Get the coordinates of the mouse click
            #I create the action
            noteAction_1 = QtWidgets.QAction('Remove', self)
            noteAction_2 = QtWidgets.QAction('Add', self)

            #I create the context menu
            self.popMenu = QtWidgets.QMenu(self)
            self.popMenu.addAction(noteAction_1)
            self.popMenu.addAction(noteAction_2)
            cursor = QtGui.QCursor()

            #self.connect(self.figure_canvas, SIGNAL("clicked()"), self.context_menu)
            #self.popMenu.exec_(self.mapToGlobal(event.globalPos()))
            noteAction_1.triggered.connect(
                lambda eventData=object: self.removeThisArea(eventData))
            noteAction_2.triggered.connect(
                lambda eventData=object: self.classifyAsCurrentSelection(
                    eventData))
            self.popMenu.popup(cursor.pos())

    def classifyAsCurrentSelection(self, caseNumber):

        # Get all the list values for this frame
        self.updateAllListFromAllBoxListDictionary()

        print("INSIDE classifyAsCurrentSelection")

        try:
            if caseNumber == 1:  # green delete
                print(type(self.objectPicked))
                X0 = self.objectPicked.get_xy()[0]
                Y0 = self.objectPicked.get_xy()[1]
                X1 = X0 + self.objectPicked.get_width()
                Y1 = Y0 + self.objectPicked.get_height()

                selectedBoxCoords = [X0, Y0, X1, Y1]

                if self.currentSelectedOption == "eraseBox":
                    #self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    #self.eraseBoxXYValues.append(selectedBoxCoords)
                    print("Use Delte Option! Right Click -> Delete Box")

                if self.currentSelectedOption == "autoDetcted":
                    #self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    #self.addBoxXYValues.append(selectedBoxCoords)
                    print("Already Selected!")

                if self.currentSelectedOption not in [
                        "oneWormLive", "multiWormLive", "oneWormDead",
                        "multiWormDead", "autoDetcted"
                ]:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.addBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (0, 1, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "oneWormLive" and selectedBoxCoords not in self.oneWormLiveBoxXYValues:

                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.oneWormLiveBoxXYValues.append(selectedBoxCoords)

                    self.canvas.draw()

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (0, 0, 1, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                    self.canvas.draw()

                if self.currentSelectedOption == "multiWormLive" and selectedBoxCoords not in self.multiWormLiveBoxXYValues:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.multiWormLiveBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 1, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "oneWormDead" and selectedBoxCoords not in self.oneWormDeadBoxXYValues:

                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.oneWormDeadBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 0, 0, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

                if self.currentSelectedOption == "multiWormDead" and selectedBoxCoords not in self.multiWormDeadBoxXYValues:
                    self.autoDetectedBoxXYValues.remove(selectedBoxCoords)
                    self.multiWormDeadBoxXYValues.append(selectedBoxCoords)

                    self.rect.set_width(X1 - X0)
                    self.rect.set_height(Y1 - Y0)
                    self.rect.set_xy((X0, Y0))

                    self.rect = Rectangle((X0, Y0), 1, 1, picker=True)
                    self.rect._alpha = 1
                    self.rect._edgecolor = (1, 1, 1, 1)
                    self.rect._facecolor = (0, 0, 0, 0)

                    self.canvas.draw()

                    self.rect._linewidth = 1
                    self.rect.set_linestyle('dashed')
                    self.rect.addName = self.typeOfAnnotation
                    self.pressevent = 1
                    self.canvas.axes.add_patch(self.rect)

        except:
            print("Delete and Redraw!")
        # updateAllBoxListDictionary(self)
        self.updateAllBoxListDictionary()

    def removeThisArea(self, caseNumber):

        # Get all the list values for this frame
        self.updateAllListFromAllBoxListDictionary()

        if caseNumber == 1:  # green delete
            print(type(self.objectPicked))
            X0 = self.objectPicked.get_xy()[0]
            Y0 = self.objectPicked.get_xy()[1]
            X1 = X0 + self.objectPicked.get_width()
            Y1 = Y0 + self.objectPicked.get_height()

            removeBoxCoords = [X0, Y0, X1, Y1]
            #print(removeBoxCoords)
            self.objectPicked.remove()
            self.patchesTotal = self.patchesTotal - 1

            try:
                if removeBoxCoords in self.eraseBoxXYValues:
                    self.eraseBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.addBoxXYValues:
                    self.addBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.oneWormLiveBoxXYValues:
                    #print(self.oneWormLiveBoxXYValues)
                    self.oneWormLiveBoxXYValues.remove(removeBoxCoords)
                    #print(self.oneWormLiveBoxXYValues)

                if removeBoxCoords in self.multiWormLiveBoxXYValues:
                    self.multiWormLiveBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.oneWormDeadBoxXYValues:
                    self.oneWormDeadBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.multiWormDeadBoxXYValues:
                    self.multiWormDeadBoxXYValues.remove(removeBoxCoords)

                if removeBoxCoords in self.autoDetectedBoxXYValues:
                    print(len(self.autoDetectedBoxXYValues))
                    self.autoDetectedBoxXYValues.remove(removeBoxCoords)
                    print(len(self.autoDetectedBoxXYValues))
            except:
                pass

        # elif caseNumber == 2:     # orange add all
        #     self.objectPicked._facecolor = (1.0, 0.64, 0.0,0.5)
        #     self.objectPicked._alpha  = 0.5
        #     self.objectPicked.addName ="addAll"
        # elif caseNumber == 3:     # black
        #     self.objectPicked._facecolor = (0,0, 0, 0.8)
        #     self.objectPicked._alpha = 0.8
        #     self.objectPicked.addName ="eraseBox"
        # elif caseNumber == 4:
        #     self.objectPicked._facecolor = ( 0, 0, 0, 0.2)
        #     self.objectPicked._alpha = 0.2
        #     self.objectPicked.addName ="deleteAll"
        # elif caseNumber == 5:
        #     self.objectPicked.set_color("C2")
        #     self._edgecolor = (0, 0, 0, 0)
        #     self.objectPicked.addName ="addBox"

        self.canvas.draw()
        #print(len(self.canvas.axes.patches))
        #self.canvas.draw()
        #self.on_release_for_annotate(None)

    def initializeAnnotationDictionary(self):
        self.currentAnnotationFrame = None
        self.annotationRecordDictionary = {}

    def updateAnnotationDictionary(self):

        # When you move away from current Frame call this
        previousFrame = self.currentAnnotationFrame
        if previousFrame is not None:
            self.annotationRecordDictionary[str(
                previousFrame)] = self.canvas.axes.patches

    def getAnnotationDictionary(self):
        return self.annotationRecordDictionary

    def applyAnnotationDictionary(self, frameNumber):
        self.currentAnnotationFrame = frameNumber
        self.canvas.axes.patches = []
        if str(frameNumber) in self.annotationRecordDictionary.keys():
            for patch in self.annotationRecordDictionary[str(frameNumber)]:
                self.canvas.axes.add_patch(patch)

    def setAnnotationDictionary(self):
        pass