예제 #1
0
class UIApplication:
    def __init__(self):
        self.ui = None
        self.thread_pool = None
        self.main_window = None

    def start_window(self):
        app = QtWidgets.QApplication(sys.argv)
        file = QFile("ui/style.qss")
        file.open(QFile.ReadOnly | QFile.Text)
        stream = QTextStream(file)
        app.setStyleSheet(stream.readAll())

        self.main_window = QtWidgets.QMainWindow()
        self.ui = UIMainWindow()
        self.ui.setupUi(self.main_window)

        self.ui.actionOpen.triggered.connect(self.create_new_media_set_tab)
        self.main_window.show()
        self.thread_pool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.thread_pool.maxThreadCount())
        sys.exit(app.exec_())

    def create_new_media_set_tab(self):
        dir_path = str(
            QFileDialog.getExistingDirectory(None, "Select Directory"))
        new_tab = UIMediaSetTab(
            Path(dir_path).name, dir_path, self.thread_pool)
        self.ui.media_set_tab.addTab(new_tab, Path(dir_path).name)
        new_tab.load()
예제 #2
0
class appWin(QMainWindow):
    def __init__(self):
        super(appWin, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.threadpool = QThreadPool()
        print('Multithreading with maximum {} thread'.format(
            self.threadpool.maxThreadCount()))

        self.timer = QTimer()
        self.timer.setInterval(0.1)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.timer.start()
        self.count = 0

        self.ui.pushButton.clicked.connect(self.on_btn)

    def on_timer_timeout(self):
        self.count += 1
        self.ui.label.setText(str(self.count))

    def on_btn(self):
        # for i in range(5):
        #     # QApplication.processEvents()
        #     self.ui.label_2.setText(str(i+1))
        #     time.sleep(1)
        worker1 = Worker([1, 2, 3, 4], 'Ali', ui=self.ui, test='pp')
        self.threadpool.start(worker1)
예제 #3
0
class LivePlot(QtWidgets.QWidget):
    '''
    A basic PyQt Widget for plotting live data received from Mantis

    Data handling is done by a new thread using the Worker Class,
    as otherwise the UI freezes and doesn't update the plot.
    '''
    def __init__(self):
        super().__init__()
        self.w = QtGui.QWidget()

        # Plot Widgets
        self.plotWidget = pg.PlotWidget()
        self.plotWidget2 = pg.PlotWidget()

        # Plot objects
        self.trace = self.plotWidget.plot()
        self.avgTrace = self.plotWidget.plot(pen='c')
        self.stats = self.plotWidget2.plot(pen='r',
                                           symbol='o',
                                           symbolPen='r',
                                           symbolBrush='r')

        # Add data properties to plot objects to store data
        self.stats.data = []

        # Button for initiating sockets with Mantis
        self.commsButton = QtWidgets.QPushButton('Start Mantis Comms', self)
        self.commsButton.clicked.connect(self.startPlot)

        # UI layout
        self.layout = QtGui.QGridLayout()
        self.w.setLayout(self.layout)
        self.layout.addWidget(self.plotWidget)
        self.layout.addWidget(self.plotWidget2)
        self.layout.addWidget(self.commsButton)
        self.w.show()

        # Ininiate the thread pool
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    @pyqtSlot()
    def startPlot(self):
        '''
        Slot for sockets the initiation button
        '''
        worker = Worker(mantisComms, plotLiveData, [self.trace, self.stats])
        self.threadpool.start(worker)
        print('push')

    def testFunc(self):
        print("test")
예제 #4
0
파일: worker.py 프로젝트: sinhnn/ssh
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.counter = 0

        layout = QVBoxLayout()

        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)

        layout.addWidget(self.l)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    def progress_fn(self, progress):
        p, m = (progress)
        print("%d%% done %s" % (p, m))

    def execute_this_fn(self, progress_callback):
        for n in range(0, 5):
            time.sleep(1)
            progress_callback.emit((n * 100 / 4, 'blabla'))
        return "Done."

    def print_output(self, s):
        print(s)

    def thread_complete(self):
        print("THREAD COMPLETE!")

    def oh_no(self):
        # Pass the function to execute
        worker = Worker(
            self.execute_this_fn
        )  # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.print_output)
        worker.signals.finished.connect(self.thread_complete)
        worker.signals.progress.connect(self.progress_fn)
        # Execute
        self.threadpool.start(worker)
예제 #5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.counter = 0
        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)

        layout = QVBoxLayout()

        layout.addWidget(self.l)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    def oh_no(self):
        worker = Worker(iterations=random.randint(10, 50))
        worker.signals.result.connect(self.worker_output)
        worker.signals.finished.connect(self.worker_complete)
        worker.signals.error.connect(self.worker_error)
        self.threadpool.start(worker)

    # Worker ouptut function/slot
    def worker_output(self, s):
        print("RESULT", s)

    # worker complete function/slot
    def worker_complete(self):
        print("THREAD COMPLETE!")

    # worker error function/slot
    def worker_error(self, e):
        print("ERROR: %s" % e)

    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Counter: %d" % self.counter)
예제 #6
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.urls = [
            "https://www.learnpyqt.com/",
            "https://www.mfitzp.com/",
            "https://www.google.com",
            "https://www.udemy.com/create-simple-gui-applications-with-python-and-qt/",
        ]

        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        button = QPushButton("GO GET EM!")
        button.pressed.connect(self.execute)

        layout.addWidget(self.text)
        layout.addWidget(button)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

        self.parsers = {
            # Regular expression parsers, to extract data from the HTML.
            "title": re.compile(r"<title.*?>(.*?)<\/title>", re.M | re.S),
            "h1": re.compile(r"<h1.*?>(.*?)<\/h1>", re.M | re.S),
            "h2": re.compile(r"<h2.*?>(.*?)<\/h2>", re.M | re.S),
        }

    def execute(self):
        for n, url in enumerate(self.urls):
            worker = Worker(n, url, self.parsers)
            worker.signals.data.connect(self.display_output)

            # Execute
            self.threadpool.start(worker)

    def display_output(self, data):
        id, s = data
        self.text.appendPlainText("WORKER %d: %s" % (id, s))
예제 #7
0
    def run(self):
        class ProcessRunnable(QRunnable):
            def __init__(self, run_task):
                super().__init__()
                self.setAutoDelete(True)
                self.task = run_task
                self.results = []

            def run(self):
                print('processing...', self.task.filename)

                if self.task.load_data():
                    print('data loaded...', self.task.filename)
                else:
                    print('data not loaded...', self.task.filename)

                # Emit signal that task may have results
                self.task.results_ready.emit(QVariant(self.task))

        print('BackgroundProcessForImporters starting load threads')
        pool = QThreadPool()

        # Disable expiration
        pool.setExpiryTimeout(-1)

        print('MaxThread count: ', pool.maxThreadCount())

        # Starting all threads for importation
        runnable_list = []
        for task in self.tasks:
            # Connect signals
            task.update_progress.connect(self.update_current_task_progress)
            # Add to list
            runnable_list.append(ProcessRunnable(task))
            # Connect results ready signals
            task.results_ready.connect(self.results_ready)
            # Start last inserted runnable
            pool.start(runnable_list[-1], priority=QThread.NormalPriority)

        # Wait for all runnable threads
        if pool.waitForDone():
            print('All threads done!')
예제 #8
0
class Fuzzer(QObject):
    communication = None

    def __init__(self, communication, max_thread_number, inputs, wordlist):
        super(Fuzzer, self).__init__()
        self.communication = communication
        self.max_thread_number = max_thread_number
        self.pool = QThreadPool()
        self.pool.globalInstance()
        self.inputs = inputs
        self.wordlist = wordlist
        self.socket_data = [inputs[0], inputs[1], inputs[2]]

    def start(self):
        num_of_chunks = len(self.wordlist) // int(self.max_thread_number)
        new_fuzz_list = list(self.listChunks(self.wordlist, num_of_chunks))

        self.pool.setMaxThreadCount(self.max_thread_number)

        for sub_list in new_fuzz_list:
            QCoreApplication.processEvents()
            for word in sub_list:
                QCoreApplication.processEvents()
                if self.pool.activeThreadCount() < self.pool.maxThreadCount():
                    fuzz_thread = Fuzz(self.communication,
                                       self.socket_data, self.inputs[3],
                                       str(word), self.inputs[5])
                    fuzz_thread.setAutoDelete(True)
                    self.pool.start(fuzz_thread)
                else:
                    self.pool.waitForDone()

    def __del__(self):
        pass

    def listChunks(self, myList, numOfChunks):
        for i in range(0, len(myList), numOfChunks):
            yield myList[i:i + numOfChunks]
예제 #9
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.counter = 0
        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)

        layout = QVBoxLayout()

        layout.addWidget(self.l) 
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout) 

        self.setCentralWidget(w)
        
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

        self.threadpool = QThreadPool()
        print(
            "Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()
        )

    def oh_no(self):
        worker = Worker("some", "args", k=2)
        self.threadpool.start(worker)

    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Counter: %d" % self.counter)
예제 #10
0
class MainWindow(QMainWindow):
    """
    You can use @pyqtSlot(int) syntax (with parameters), or you can pass this,
    but it make code more readable.
    Вы можете использовать синтаксис объявления слотов @pyqtSlot(int)
    с указанием типа передаваемых значений, или опустить его вовсе,
    однако это делает код нагляднее
    и позволяет быстро понять, что слот, а что - функция.
    """

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

        self._counter = 0
        self.init_ui()

        self._threadpool = QThreadPool()
        #self._threadpool = QtCore.QThreadPool.globalInstance()
        #self._threadpool.setMaxThreadCount(2)
        print("Multithreading with maximum {} threads" .format(self._threadpool.maxThreadCount()))

        self._timer = QTimer()
        self._timer.setInterval(1000)
        self._timer.timeout.connect(self.recurring_timer)
        self._timer.start()

    def init_ui(self):
        layout = QVBoxLayout()

        self._label = QLabel("Start")
        b = QPushButton("Start QRunnable")
        b.pressed.connect(self.start_new_runnable)

        layout.addWidget(self._label)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

    @pyqtSlot(int)
    def thread_progress_fn(self, n):
        print("{}% done".format(n))

    @pyqtSlot(object)
    def thread_print_output(self, s):
        print('Result: {}'.format(s))

    @pyqtSlot()
    def thread_complete(self):
        print("QRunnable worker COMPLETE!")

    @pyqtSlot(tuple)
    def thread_error(self, err):
        QMessageBox.warning(self, "Warning!", err[1], QMessageBox.Ok)
        print('Error {}\n{}'.format(err[1], err[2]))

    @pyqtSlot()
    def start_new_runnable(self):
        # Pass the function to execute
        worker = Worker(1, debug=True) # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.thread_print_output)
        worker.signals.finished.connect(self.thread_complete)
        worker.signals.progress.connect(self.thread_progress_fn)
        worker.signals.error.connect(self.thread_error)
        worker.setAutoDelete(True)
        # Execute (tryStart() better than start() )
        if self._threadpool.tryStart(worker) is False:
            print("Can't create worker!")
            QMessageBox.warning(self, "Warning!", "Can't create worker!", QMessageBox.Ok)

    @pyqtSlot()
    def recurring_timer(self):
        self._counter += 1
        self._label.setText("Counter: {}".format(self._counter))
        print('Active thread count: {}'.format(self._threadpool.activeThreadCount()))

    def closeEvent(self, event):
        """Main window closed, override PyQt5 widget function"""
        print('Try to exit, active thread count: {}'.format(self._threadpool.activeThreadCount()))
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self._threadpool.waitForDone()
            self._timer.stop()
            event.accept()
        else:
            event.ignore()
예제 #11
0
class Run_gui(QMainWindow):
    def __init__(self):
        super().__init__()

        self.cwd = os.getcwd()
        self.load_()

        # Enable antialiasing for prettier plots
        self.initUI()

    def initUI(self):

        ################### MENU BARS START ##################
        MyBar = QMenuBar(self)

        fileMenu = MyBar.addMenu("File")

        self.fileSave = fileMenu.addAction("Save thinfilm config")
        self.fileSave.triggered.connect(self.save_)
        self.fileSave.setShortcut('Ctrl+S')

        self.fileLoadAs = fileMenu.addAction("Load config section")
        self.fileLoadAs.triggered.connect(self.load_config_dialog)

        fileClose = fileMenu.addAction("Close")
        fileClose.triggered.connect(self.close)  # triggers closeEvent()
        fileClose.setShortcut('Ctrl+X')

        self.loadMenu = MyBar.addMenu("Load data")
        loadSubOlis = self.loadMenu.addAction("OLIS sub")
        loadSubFilmOlis = self.loadMenu.addAction("OLIS sub + thin film")
        loadSubFTIR = self.loadMenu.addAction("FTIR sub")
        loadSubFilmFTIR = self.loadMenu.addAction("FTIR sub + thin film")

        loadSubOlis.triggered.connect(self.loadSubOlisDialog)
        loadSubFilmOlis.triggered.connect(self.loadSubFilmOlisDialog)
        loadSubFTIR.triggered.connect(self.loadSubFTIRDialog)
        loadSubFilmFTIR.triggered.connect(self.loadSubFilmFTIRDialog)

        self.emailMenu = MyBar.addMenu("E-mail")
        self.emailSettings = self.emailMenu.addAction("E-mail settings")
        self.emailSettings.triggered.connect(self.email_set_dialog)
        self.emailData = self.emailMenu.addAction("E-mail data")
        self.emailData.triggered.connect(self.email_data_dialog)

        helpMenu = MyBar.addMenu("Help")
        helpParam = helpMenu.addAction("Instructions")
        helpParam.triggered.connect(self.helpParamDialog)
        contact = helpMenu.addAction("Contact")
        contact.triggered.connect(self.contactDialog)

        ################### MENU BARS END ##################

        # status info which button has been pressed
        Start_lbl = QLabel("PLOTS and analysis steps", self)
        Start_lbl.setStyleSheet("color: blue")

        self.Step0_Button = QPushButton("Raw data", self)
        self.Step0_Button.setToolTip("STEP 0. Plot raw data for OLIS and FTIR")
        self.button_style(self.Step0_Button, 'black')

        self.Step1_Button = QPushButton("Tmin and Tmax", self)
        self.Step1_Button.setToolTip(
            "STEP 1. Find all the minima and maxima positions using Gaussian filter"
        )
        self.button_style(self.Step1_Button, 'black')

        self.Step2_Button = QPushButton("Std.Dev. in d", self)
        self.Step2_Button.setToolTip(
            "STEP 2. Minimize standard deviation in the film thickness d")
        self.button_style(self.Step2_Button, 'black')

        self.Step3_Button = QPushButton("Index n", self)
        self.Step3_Button.setToolTip(
            "STEP 3. Plot refractive indicies n1 and n2")
        self.button_style(self.Step3_Button, 'black')

        self.Step4_Button = QPushButton("Absorption alpha", self)
        self.Step4_Button.setToolTip(
            "STEP 4. Plot abosorption alpha based on n2")
        self.button_style(self.Step4_Button, 'black')

        self.Step5_Button = QPushButton("Wavenumber k", self)
        self.Step5_Button.setToolTip("STEP 5. Plot wavenumber k based on n2")
        self.button_style(self.Step5_Button, 'black')

        ####################################################

        # status info which button has been pressed
        self.NewFiles = QLabel('No files created yet!', self)
        self.NewFiles.setStyleSheet("color: blue")

        newfont = QFont("Times", 10, QFont.Normal)
        self.NewFiles.setFont(newfont)
        '''
		self.NewFiles = numpy.zeros(5,dtype=object)
		for i in range(4):
			self.NewFiles[i] = QLabel(''.join([str(i+1),': ']), self)
			self.NewFiles[i].setStyleSheet("color: magenta")
		'''

        ####################################################
        loads_lbl = QLabel("RAW data files", self)
        loads_lbl.setStyleSheet("color: blue")

        configFile_lbl = QLabel("Current thinfilm", self)
        self.config_file_lbl = QLabel("", self)
        self.config_file_lbl.setStyleSheet("color: green")

        loadSubOlis_lbl = QLabel("OLIS sub", self)
        self.loadSubOlisFile_lbl = QLabel("", self)
        self.loadSubOlisFile_lbl.setStyleSheet("color: magenta")

        loadSubFilmOlis_lbl = QLabel("OLIS sub + thin film", self)
        self.loadSubFilmOlisFile_lbl = QLabel("", self)
        self.loadSubFilmOlisFile_lbl.setStyleSheet("color: magenta")

        loadSubFTIR_lbl = QLabel("FTIR sub", self)
        self.loadSubFTIRFile_lbl = QLabel("", self)
        self.loadSubFTIRFile_lbl.setStyleSheet("color: magenta")

        loadSubFilmFTIR_lbl = QLabel("FTIR sub + thin film", self)
        self.loadSubFilmFTIRFile_lbl = QLabel("", self)
        self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: magenta")

        self.cb_sub_olis = QCheckBox('', self)
        self.cb_sub_olis.toggle()
        self.cb_subfilm_olis = QCheckBox('', self)
        self.cb_subfilm_olis.toggle()
        self.cb_sub_ftir = QCheckBox('', self)
        self.cb_sub_ftir.toggle()
        self.cb_subfilm_ftir = QCheckBox('', self)
        self.cb_subfilm_ftir.toggle()

        plot_X_lbl = QLabel("Plot X axis in", self)
        self.combo2 = QComboBox(self)
        self.mylist2 = ["eV", "nm"]
        self.combo2.addItems(self.mylist2)
        self.combo2.setFixedWidth(70)

        ####################################################

        lbl1 = QLabel("GAUSSIAN filter settings", self)
        lbl1.setStyleSheet("color: blue")

        interpol_lbl = QLabel("Interpolation method", self)
        self.combo4 = QComboBox(self)
        self.mylist4 = ["spline", "linear"]
        self.combo4.setToolTip(
            "Interpolation method for local minima Tmin and local maxima Tmax can only be linear or spline."
        )
        self.combo4.addItems(self.mylist4)
        self.combo4.setFixedWidth(70)

        factors_lbl = QLabel("Gaussian factors", self)
        self.factorsEdit = QLineEdit("", self)
        self.factorsEdit.setToolTip(
            "HIGH gaussian factor = broadband noise filtering.\nLOW gaussian factor = narrowband noise filtering.\nHigh gauissian factors (>2) will result in relatively large deviation from the raw data.\nGauissian factors of zero or near zero (<0.5) will closely follow trend of the raw data."
        )
        self.factorsEdit.setFixedWidth(200)

        borders_lbl = QLabel("Gaussian borders [eV]", self)
        self.bordersEdit = QLineEdit("", self)
        self.bordersEdit.setToolTip(
            "Gaussian borders should be typed in ascending order and the number of\nborders is always one more compared with the number of Gaussian factors."
        )
        self.bordersEdit.setFixedWidth(200)

        ##############################################

        lbl2 = QLabel("ABSORPTION alpha and n1 and n2", self)
        lbl2.setStyleSheet("color: blue")

        poly_lbl = QLabel("Polyfit order", self)
        self.combo1 = QComboBox(self)
        self.mylist1 = ["1", "2", "3", "4", "5"]
        self.combo1.addItems(self.mylist1)
        self.combo1.setFixedWidth(70)

        polybord_lbl = QLabel("Polyfit range(s) [eV]", self)
        self.poly_bordersEdit = QLineEdit("", self)
        self.poly_bordersEdit.setFixedWidth(140)

        self.cb_polybord = QCheckBox('', self)
        self.cb_polybord.toggle()

        ignore_data_lbl = QLabel("No. of ignored points", self)
        self.ignore_data_ptsEdit = QLineEdit("", self)
        self.ignore_data_ptsEdit.setFixedWidth(140)

        corr_slit_lbl = QLabel("Correction slit width [nm]", self)
        self.corr_slitEdit = QLineEdit("", self)
        self.corr_slitEdit.setToolTip(
            "Finite spectrometer bandwidth (slit width) in the transmission spectrum."
        )
        self.corr_slitEdit.setFixedWidth(140)

        ##############################################

        lbl4 = QLabel("STORAGE location (folder/file)", self)
        lbl4.setStyleSheet("color: blue")
        self.filenameEdit = QLineEdit("", self)
        #self.filenameEdit.setFixedWidth(180)

        self.cb_save_figs = QCheckBox('Save figs', self)
        self.cb_save_figs.toggle()

        ##############################################

        self.lcd = QLCDNumber(self)
        self.lcd.setStyleSheet("color: red")
        self.lcd.setFixedHeight(60)
        self.lcd.setSegmentStyle(QLCDNumber.Flat)
        self.lcd.setToolTip("Timetrace for saving files")
        self.lcd.setNumDigits(11)

        ##############################################

        self.initUI_()

        ##############################################

        # Add all widgets
        g1_0 = QGridLayout()
        g1_0.addWidget(MyBar, 0, 0)
        g1_1 = QGridLayout()
        g1_1.addWidget(loads_lbl, 0, 0)
        g1_1.addWidget(configFile_lbl, 1, 0)
        g1_1.addWidget(self.config_file_lbl, 1, 1)
        g1_1.addWidget(loadSubOlis_lbl, 2, 0)
        g1_1.addWidget(self.loadSubOlisFile_lbl, 2, 1)
        g1_1.addWidget(self.cb_sub_olis, 2, 2)
        g1_1.addWidget(loadSubFilmOlis_lbl, 3, 0)
        g1_1.addWidget(self.loadSubFilmOlisFile_lbl, 3, 1)
        g1_1.addWidget(self.cb_subfilm_olis, 3, 2)
        g1_1.addWidget(loadSubFTIR_lbl, 4, 0)
        g1_1.addWidget(self.loadSubFTIRFile_lbl, 4, 1)
        g1_1.addWidget(self.cb_sub_ftir, 4, 2)
        g1_1.addWidget(loadSubFilmFTIR_lbl, 5, 0)
        g1_1.addWidget(self.loadSubFilmFTIRFile_lbl, 5, 1)
        g1_1.addWidget(self.cb_subfilm_ftir, 5, 2)
        g1_1.addWidget(plot_X_lbl, 6, 0)
        g1_1.addWidget(self.combo2, 6, 1)

        g1_2 = QGridLayout()
        g1_2.addWidget(lbl1, 0, 0)
        g1_3 = QGridLayout()
        g1_3.addWidget(interpol_lbl, 0, 0)
        g1_3.addWidget(self.combo4, 0, 1)
        g1_3.addWidget(factors_lbl, 1, 0)
        g1_3.addWidget(self.factorsEdit, 1, 1)
        g1_3.addWidget(borders_lbl, 2, 0)
        g1_3.addWidget(self.bordersEdit, 2, 1)

        g1_4 = QGridLayout()
        g1_4.addWidget(lbl2, 0, 0)
        g1_5 = QGridLayout()
        g1_5.addWidget(poly_lbl, 0, 0)
        g1_5.addWidget(self.combo1, 0, 1)
        g1_5.addWidget(polybord_lbl, 1, 0)
        g1_5.addWidget(self.poly_bordersEdit, 1, 1)
        g1_5.addWidget(self.cb_polybord, 1, 2)
        g1_5.addWidget(ignore_data_lbl, 2, 0)
        g1_5.addWidget(self.ignore_data_ptsEdit, 2, 1)
        g1_5.addWidget(corr_slit_lbl, 3, 0)
        g1_5.addWidget(self.corr_slitEdit, 3, 1)

        g4_0 = QGridLayout()
        g4_0.addWidget(lbl4, 0, 0)
        g4_0.addWidget(self.cb_save_figs, 0, 1)
        g4_1 = QGridLayout()
        g4_1.addWidget(self.filenameEdit, 0, 0)

        v1 = QVBoxLayout()
        v1.addLayout(g1_0)
        v1.addLayout(g1_1)
        v1.addLayout(g1_2)
        v1.addLayout(g1_3)
        v1.addLayout(g1_4)
        v1.addLayout(g1_5)
        v1.addLayout(g4_0)
        v1.addLayout(g4_1)

        ###################################################

        g1_6 = QGridLayout()
        g1_6.addWidget(Start_lbl, 0, 0)
        g1_7 = QGridLayout()
        g1_7.addWidget(self.Step0_Button, 0, 0)
        g1_7.addWidget(self.Step1_Button, 1, 0)
        g1_7.addWidget(self.Step2_Button, 2, 0)
        g1_7.addWidget(self.Step3_Button, 3, 0)
        g1_7.addWidget(self.Step4_Button, 4, 0)
        g1_7.addWidget(self.Step5_Button, 5, 0)

        g1_8 = QGridLayout()
        g1_8.addWidget(self.NewFiles, 0, 0)
        g1_8.addWidget(self.lcd, 1, 0)

        v0 = QVBoxLayout()
        v0.addLayout(g1_6)
        v0.addLayout(g1_7)
        v0.addLayout(g1_8)

        # SET ALL VERTICAL COLUMNS TOGETHER
        hbox = QHBoxLayout()
        hbox.addLayout(v1)
        hbox.addLayout(v0)

        ###############################################################################

        # reacts to choises picked in the menu
        self.combo1.activated[str].connect(self.onActivated1)
        self.combo2.activated[str].connect(self.onActivated2)
        self.combo4.activated[str].connect(self.onActivated4)

        # reacts to choises picked in the menu
        self.Step0_Button.clicked.connect(self.set_run)
        self.Step1_Button.clicked.connect(self.set_run)
        self.Step2_Button.clicked.connect(self.set_run)
        self.Step3_Button.clicked.connect(self.set_run)
        self.Step4_Button.clicked.connect(self.set_run)
        self.Step5_Button.clicked.connect(self.set_run)

        # reacts to choises picked in the checkbox
        self.cb_sub_olis.stateChanged.connect(self.sub_olis_check)
        self.cb_subfilm_olis.stateChanged.connect(self.subfilm_olis_check)
        self.cb_sub_ftir.stateChanged.connect(self.sub_ftir_check)
        self.cb_subfilm_ftir.stateChanged.connect(self.subfilm_ftir_check)
        self.cb_save_figs.stateChanged.connect(self.save_figs_check)
        self.cb_polybord.stateChanged.connect(self.polybord_check)

        self.threadpool = QThreadPool()
        print("Multithreading in TEST_gui_v1 with maximum %d threads" %
              self.threadpool.maxThreadCount())
        self.isRunning = False

        self.move(0, 0)
        #self.setGeometry(50, 50, 800, 500)
        hbox.setSizeConstraint(hbox.SetFixedSize)
        self.setWindowTitle("Swanepoel method for thin film analysis")

        w = QWidget()
        w.setLayout(hbox)
        self.setCentralWidget(w)
        self.show()

    def bool_(self, txt):

        if txt == "True":
            return True
        elif txt == "False":
            return False

    def initUI_(self):

        self.config_file_lbl.setText(self.last_used_scan)

        self.loadSubOlisFile_lbl.setText(self.loadSubOlis_str)

        self.loadSubFilmOlisFile_lbl.setText(self.loadSubFilmOlis_str)

        self.loadSubFTIRFile_lbl.setText(self.loadSubFTIR_str)

        self.loadSubFilmFTIRFile_lbl.setText(self.loadSubFilmFTIR_str)

        ##############################################

        self.sub_olis_check(self.loadSubOlis_check)
        self.cb_sub_olis.setChecked(self.loadSubOlis_check)

        self.subfilm_olis_check(self.loadSubFilmOlis_check)
        self.cb_subfilm_olis.setChecked(self.loadSubFilmOlis_check)

        self.sub_ftir_check(self.loadSubFTIR_check)
        self.cb_sub_ftir.setChecked(self.loadSubFTIR_check)

        self.subfilm_ftir_check(self.loadSubFilmFTIR_check)
        self.cb_subfilm_ftir.setChecked(self.loadSubFilmFTIR_check)

        self.save_figs_check(self.save_figs)
        self.cb_save_figs.setChecked(self.save_figs)
        self.filenameEdit.setText(self.filename_str)

        ##############################################

        if len(self.fit_poly_ranges) == 0:
            self.fit_poly_ranges_check = False
            self.polybord_check(self.fit_poly_ranges_check)
            self.cb_polybord.setChecked(self.fit_poly_ranges_check)
        else:
            self.polybord_check(self.fit_poly_ranges_check)
            self.cb_polybord.setChecked(self.fit_poly_ranges_check)

        ##############################################

        self.factorsEdit.setText(self.gaussian_factors)
        self.bordersEdit.setText(self.gaussian_borders)

        ##############################################

        self.combo1.setCurrentIndex(self.mylist1.index(self.fit_poly_order))
        self.combo2.setCurrentIndex(self.mylist2.index(self.plot_X))
        self.combo4.setCurrentIndex(self.mylist4.index(self.fit_linear_spline))

        ##############################################

        self.poly_bordersEdit.setText(self.fit_poly_ranges)
        self.ignore_data_ptsEdit.setText(self.ignore_data_pts)
        self.corr_slitEdit.setText(self.corr_slit)

        ##############################################

        self.NewFiles.setToolTip(''.join([
            "Display newly created and saved files in ", os.sep,
            self.filename_str, os.sep
        ]))
        self.lcd.display(self.timetrace)

    def button_style(self, button, color):

        button.setStyleSheet(''.join([
            'QPushButton {background-color: lightblue; font-size: 18pt; color: ',
            color, '}'
        ]))
        button.setFixedWidth(260)
        button.setFixedHeight(65)

    def loadSubOlisDialog(self):

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "Open files",
            ''.join(['data', os.sep]),
            "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)",
            options=options)
        for afile in files:
            head, tail = os.path.split(str(afile))
            self.loadSubOlis_str = tail
            self.loadSubOlisFile_lbl.setText(tail)
            self.cb_sub_olis.setEnabled(True)

            self.loadSubOlis_check = True
            self.cb_sub_olis(self.loadSubOlis_check)

    def loadSubFilmOlisDialog(self):

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "Open files",
            ''.join(['data', os.sep]),
            "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)",
            options=options)
        for afile in files:
            head, tail = os.path.split(str(afile))
            self.loadSubFilmOlis_str = tail
            self.loadSubFilmOlisFile_lbl.setText(tail)
            self.cb_subfilm_olis.setEnabled(True)

            self.loadSubFilmOlis_check = True
            self.cb_subfilm_olis(self.loadSubFilmOlis_check)

    def loadSubFTIRDialog(self):

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "Open files",
            ''.join(['data', os.sep]),
            "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)",
            options=options)
        for afile in files:
            head, tail = os.path.split(str(afile))
            self.loadSubFTIR_str = tail
            self.loadSubFTIRFile_lbl.setText(tail)
            self.cb_sub_ftir.setEnabled(True)

            self.loadSubFTIR_check = True
            self.cb_sub_ftir(self.loadSubFTIR_check)

    def loadSubFilmFTIRDialog(self):

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "Open files",
            ''.join(['data', os.sep]),
            "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)",
            options=options)
        for afile in files:
            head, tail = os.path.split(str(afile))
            self.loadSubFilmFTIR_str = tail
            self.loadSubFilmFTIRFile_lbl.setText(tail)
            self.cb_subfilm_ftir.setEnabled(True)

            self.loadSubFilmFTIR_check = True
            self.cb_subfilm_ftir.setChecked(self.loadSubFilmFTIR_check)

    def load_config_dialog(self):

        self.Load_config_dialog = Load_config_dialog.Load_config_dialog(
            self, self.config, self.load_, self.initUI_, self.cwd)
        self.Load_config_dialog.exec()

    def email_data_dialog(self):

        self.Send_email_dialog = Send_email_dialog.Send_email_dialog(
            self, self.cwd)
        self.Send_email_dialog.exec()

    def email_set_dialog(self):

        self.Email_dialog = Email_settings_dialog.Email_dialog(
            self, self.lcd, self.cwd)
        self.Email_dialog.exec()

    def helpParamDialog(self):

        helpfile = ''
        with open('config_Swanepoel_forklaringer.py', 'r') as f:
            for line in f:
                helpfile = helpfile + line

        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setText(
            "Apply the Swanepoel method using the following analysis steps:")
        msg.setInformativeText(helpfile)
        msg.setWindowTitle("Help")
        #msg.setDetailedText(helpfile)
        msg.setStandardButtons(QMessageBox.Ok)
        #msg.setGeometry(1000, 0, 1000+250, 350)

        msg.exec_()

    def contactDialog(self):

        QMessageBox.information(
            self, "Contact information",
            "Suggestions, comments or bugs can be reported to [email protected]"
        )

    def onActivated1(self, text):

        self.fit_poly_order = int(text)

    def onActivated2(self, text):

        self.plot_X = str(text)

    def onActivated4(self, text):

        self.fit_linear_spline = str(text)

    def save_figs_check(self, state):

        if state in [Qt.Checked, True]:
            self.save_figs = True
        else:
            self.save_figs = False

    def sub_olis_check(self, state):

        if state in [Qt.Checked, True]:
            self.loadSubOlis_check = True
            self.loadSubOlisFile_lbl.setStyleSheet("color: magenta")
            self.cb_sub_olis.setText('incl')
        else:
            self.loadSubOlis_check = False
            self.loadSubOlisFile_lbl.setStyleSheet("color: grey")
            self.cb_sub_olis.setText('exc')

    def subfilm_olis_check(self, state):

        if state in [Qt.Checked, True]:
            self.loadSubFilmOlis_check = True
            self.loadSubFilmOlisFile_lbl.setStyleSheet("color: magenta")
            self.cb_subfilm_olis.setText('incl')
        else:
            self.loadSubFilmOlis_check = False
            self.loadSubFilmOlisFile_lbl.setStyleSheet("color: grey")
            self.cb_subfilm_olis.setText('exc')

    def sub_ftir_check(self, state):

        if state in [Qt.Checked, True]:
            self.loadSubFTIR_check = True
            self.loadSubFTIRFile_lbl.setStyleSheet("color: magenta")
            self.cb_sub_ftir.setText('incl')
        else:
            self.loadSubFTIR_check = False
            self.loadSubFTIRFile_lbl.setStyleSheet("color: grey")
            self.cb_sub_ftir.setText('exc')

    def subfilm_ftir_check(self, state):

        if state in [Qt.Checked, True]:
            self.loadSubFilmFTIR_check = True
            self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: magenta")
            self.cb_subfilm_ftir.setText('incl')
        else:
            self.loadSubFilmFTIR_check = False
            self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: grey")
            self.cb_subfilm_ftir.setText('exc')

    def polybord_check(self, state):

        if state in [Qt.Checked, True]:
            self.fit_poly_ranges_check = True
            self.poly_bordersEdit.setEnabled(True)
            self.cb_polybord.setText('incl')
        else:
            self.fit_poly_ranges_check = False
            self.poly_bordersEdit.setEnabled(False)
            self.cb_polybord.setText('exc')

    ############################################################

    # Check input if a number, ie. digits or fractions such as 3.141
    # Source: http://www.pythoncentral.io/how-to-check-if-a-string-is-a-number-in-python-including-unicode/
    def is_int(self, s):
        try:
            int(s)
            return True
        except ValueError:
            return False

    def is_number(self, s):
        try:
            float(s)
            return True
        except ValueError:
            pass

        try:
            import unicodedata
            unicodedata.numeric(s)
            return True
        except (TypeError, ValueError):
            pass

        return False

    def create_file(self, mystr):

        head, ext = os.path.splitext(mystr)

        totalpath = ''.join([self.cwd, os.sep, head, '_', self.timetrace])

        my_dir = os.path.dirname(totalpath)
        if not os.path.isdir(my_dir):
            QMessageBox.warning(
                self, "Message",
                "".join(["Folder(s) named ", my_dir, " will be created!"]))

        try:
            os.makedirs(my_dir, exist_ok=True)
        except Exception as e:
            QMessageBox.critical(
                self, "Message",
                "".join(["Folder named ", head, " not valid!\n\n",
                         str(e)]))
            return ""

        return totalpath

    def set_run(self):

        # Save all the currently changed varaibles
        self.save_()
        # Register the sender of the command (a button or similar)
        sender = self.sender()

        ## gaussian_borders and gaussian_factors warnings and errors
        gaus_bord = str(self.bordersEdit.text()).split(',')
        for tal in gaus_bord:
            if not self.is_number(tal):
                QMessageBox.critical(self, 'Message',
                                     "Gaussian borders must be real numbers!")
                return
            elif float(tal) < 0.0:
                QMessageBox.critical(
                    self, 'Message',
                    "Gaussian borders must be positive or zero!")
                return

        if len(gaus_bord) < 2:
            QMessageBox.critical(
                self, 'Message', "You must enter at least 2 gaussian borders!")
            return

        if not numpy.array_equal([numpy.float(i) for i in gaus_bord],
                                 numpy.sort(
                                     [numpy.float(i) for i in gaus_bord])):
            QMessageBox.critical(
                self, 'Message',
                "The gaussian borders must be entered in the ascending order!")
            return

        gaus_fact = str(self.factorsEdit.text()).split(',')
        for tal in gaus_fact:
            if not self.is_number(tal):
                QMessageBox.critical(self, 'Message',
                                     "Gaussian factors must be real numbers!")
                return
            elif float(tal) < 0.0:
                QMessageBox.critical(
                    self, 'Message',
                    "Gaussian factors must be positive or zero!")
                return

        if len(gaus_fact) < 1:
            QMessageBox.critical(self, 'Message',
                                 "You must enter at least 1 gaussian factor!")
            return

        if len(gaus_bord) != len(gaus_fact) + 1:
            QMessageBox.critical(
                self, 'Message',
                "The number of gaussian factors is exactly one less than the number of gaussian borders!"
            )
            return

        ## ignored data points warnings and errors
        ign_pts = str(self.ignore_data_ptsEdit.text())
        if not self.is_int(ign_pts):
            QMessageBox.critical(
                self, 'Message', "The number of ignored points is an integer!")
            return
        elif int(ign_pts) < 0:
            QMessageBox.critical(
                self, 'Message',
                "The number of ignored points is a positive integer!")
            return

        ## correction slit width warnings and errors
        corr_pts = str(self.corr_slitEdit.text())
        if not self.is_number(corr_pts):
            QMessageBox.critical(
                self, 'Message', "The correction slit width is a real number!")
            return
        elif float(corr_pts) < 0:
            QMessageBox.critical(
                self, 'Message',
                "The correction slit width is a positive number!")
            return

        ## fit_poly_ranges warnings and errors
        if self.fit_poly_ranges_check == True:
            polyfit_bord = str(self.poly_bordersEdit.text()).split(',')
            for tal in polyfit_bord:
                if not self.is_number(tal):
                    QMessageBox.critical(
                        self, 'Message',
                        "The polyfit range enteries must be real numbers!")
                    return
                elif float(tal) < 0.0:
                    QMessageBox.critical(
                        self, 'Message',
                        "The polyfit range enteries must be positive or zero!")
                    return

            if len(polyfit_bord) < 2 or len(polyfit_bord) % 2 != 0:
                QMessageBox.critical(
                    self, 'Message',
                    "The polyfit range list accepts minimum 2 or even number of enteries!"
                )
                return

            if not numpy.array_equal(
                [numpy.float(i) for i in polyfit_bord],
                    numpy.sort([numpy.float(i) for i in polyfit_bord])):
                QMessageBox.critical(
                    self, 'Message',
                    "The polyfit range list must be entered in ascending order!"
                )
                return

        # When all user defined enteries are approved save the data
        self.create_file(str(self.filenameEdit.text()))

        if sender.text() != 'Raw data':

            ## raw data files warnings and errors
            if not self.loadSubOlis_check and not self.loadSubFilmOlis_check:
                pass
            elif self.loadSubOlis_check and self.loadSubFilmOlis_check:
                pass
            else:
                QMessageBox.critical(
                    self, 'Message',
                    "Select both OLIS data files subfilmRAW and subRAW!")
                return

            if not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check:
                pass
            elif self.loadSubFTIR_check and self.loadSubFilmFTIR_check:
                pass
            else:
                QMessageBox.critical(
                    self, 'Message',
                    "Select both FTIR data files subfilmRAW and subRAW!")
                return

            if not self.loadSubOlis_check and not self.loadSubFilmOlis_check and not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check:
                QMessageBox.critical(self, 'Message',
                                     "No data files selected!")
                return

        if sender.text() == 'Raw data':

            if not self.loadSubOlis_check and not self.loadSubFilmOlis_check and not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check:
                QMessageBox.critical(self, 'Message',
                                     "No raw data files selected!")
                return

            self.button_style(self.Step0_Button, 'red')
            self.button_style(self.Step1_Button, 'grey')
            self.button_style(self.Step2_Button, 'grey')
            self.button_style(self.Step3_Button, 'grey')
            self.button_style(self.Step4_Button, 'grey')
            self.button_style(self.Step5_Button, 'grey')

        elif sender.text() == 'Tmin and Tmax':

            self.button_style(self.Step1_Button, 'red')
            self.button_style(self.Step0_Button, 'grey')
            self.button_style(self.Step2_Button, 'grey')
            self.button_style(self.Step3_Button, 'grey')
            self.button_style(self.Step4_Button, 'grey')
            self.button_style(self.Step5_Button, 'grey')

        elif sender.text() == 'Std.Dev. in d':

            self.button_style(self.Step2_Button, 'red')
            self.button_style(self.Step0_Button, 'grey')
            self.button_style(self.Step1_Button, 'grey')
            self.button_style(self.Step3_Button, 'grey')
            self.button_style(self.Step4_Button, 'grey')
            self.button_style(self.Step5_Button, 'grey')

        elif sender.text() == 'Index n':

            self.button_style(self.Step3_Button, 'red')
            self.button_style(self.Step0_Button, 'grey')
            self.button_style(self.Step1_Button, 'grey')
            self.button_style(self.Step2_Button, 'grey')
            self.button_style(self.Step4_Button, 'grey')
            self.button_style(self.Step5_Button, 'grey')

        elif sender.text() == 'Absorption alpha':

            self.button_style(self.Step4_Button, 'red')
            self.button_style(self.Step0_Button, 'grey')
            self.button_style(self.Step1_Button, 'grey')
            self.button_style(self.Step2_Button, 'grey')
            self.button_style(self.Step3_Button, 'grey')
            self.button_style(self.Step5_Button, 'grey')

        elif sender.text() == 'Wavenumber k':

            self.button_style(self.Step5_Button, 'red')
            self.button_style(self.Step0_Button, 'grey')
            self.button_style(self.Step1_Button, 'grey')
            self.button_style(self.Step2_Button, 'grey')
            self.button_style(self.Step3_Button, 'grey')
            self.button_style(self.Step4_Button, 'grey')

        else:
            return

        worker = Worker(sender.text(), self.cwd)

        worker.signals.pass_plots.connect(self.pass_plots)
        worker.signals.critical.connect(self.critical)
        worker.signals.finished.connect(self.finished)

        # Execute
        self.threadpool.start(worker)
        self.isRunning = True

    def pass_plots(self, obj):

        self.my_plots, sender = obj

        my_str = 'Data files:\n'
        try:
            self.datafiles = self.my_plots.make_plots()
            for i, ii in zip(self.datafiles, range(len(self.datafiles))):
                head, tail = os.path.split(i)
                my_str += ''.join([str(ii + 1), ': ', tail, '\n'])

            self.NewFiles.setText(my_str)
            self.my_plots.show_plots()

        except Exception as inst:
            QMessageBox.critical(self, 'Message', str(inst))

    def load_(self):

        # Initial read of the config file
        self.config = configparser.ConfigParser()

        try:
            self.config.read(''.join([self.cwd, os.sep, "config.ini"]))
            self.last_used_scan = self.config.get('LastScan', 'last_used_scan')

            self.loadSubOlis_str = self.config.get(
                self.last_used_scan, "loadsubolis").strip().split(':')[0]
            self.loadSubOlis_check = self.bool_(
                self.config.get(self.last_used_scan,
                                'loadsubolis').strip().split(':')[1])
            self.loadSubFilmOlis_str = self.config.get(
                self.last_used_scan, 'loadsubfilmolis').strip().split(':')[0]
            self.loadSubFilmOlis_check = self.bool_(
                self.config.get(self.last_used_scan,
                                'loadsubfilmolis').strip().split(':')[1])
            self.loadSubFTIR_str = self.config.get(
                self.last_used_scan, 'loadsubftir').strip().split(':')[0]
            self.loadSubFTIR_check = self.bool_(
                self.config.get(self.last_used_scan,
                                'loadsubftir').strip().split(':')[1])
            self.loadSubFilmFTIR_str = self.config.get(
                self.last_used_scan, 'loadsubfilmftir').strip().split(':')[0]
            self.loadSubFilmFTIR_check = self.bool_(
                self.config.get(self.last_used_scan,
                                'loadsubfilmftir').strip().split(':')[1])
            self.fit_linear_spline = self.config.get(self.last_used_scan,
                                                     'fit_linear_spline')
            self.gaussian_factors = self.config.get(self.last_used_scan,
                                                    'gaussian_factors')
            self.gaussian_borders = self.config.get(self.last_used_scan,
                                                    'gaussian_borders')
            self.ignore_data_pts = self.config.get(self.last_used_scan,
                                                   'ignore_data_pts')
            self.corr_slit = self.config.get(self.last_used_scan, 'corr_slit')
            self.fit_poly_order = self.config.get(self.last_used_scan,
                                                  'fit_poly_order')
            self.fit_poly_ranges = self.config.get(
                self.last_used_scan, 'fit_poly_ranges').strip().split(':')[0]
            self.fit_poly_ranges_check = self.bool_(
                self.config.get(self.last_used_scan,
                                'fit_poly_ranges').strip().split(':')[1])
            self.filename_str = self.config.get(self.last_used_scan,
                                                'filename')
            self.timetrace = self.config.get(self.last_used_scan, 'timetrace')
            self.save_figs = self.bool_(
                self.config.get(self.last_used_scan, 'save_figs'))
            self.plot_X = self.config.get(self.last_used_scan, 'plot_x')
            self.emailset_str = self.config.get(self.last_used_scan,
                                                'emailset').strip().split(',')
            self.emailrec_str = self.config.get(self.last_used_scan,
                                                'emailrec').strip().split(',')

        except configparser.NoOptionError as nov:
            QMessageBox.critical(
                self, 'Message', ''.join([
                    "Main FAULT while reading the config.ini file\n",
                    str(nov)
                ]))
            raise

    def save_(self):

        self.timetrace = time.strftime("%y%m%d-%H%M")
        self.lcd.display(self.timetrace)

        self.config.read(''.join([self.cwd, os.sep, "config.ini"]))
        self.config.set('LastScan', "last_used_scan", self.last_used_scan)
        self.config.set(
            self.last_used_scan, "loadSubOlis",
            ':'.join([self.loadSubOlis_str,
                      str(self.loadSubOlis_check)]))
        self.config.set(
            self.last_used_scan, "loadSubFilmOlis", ':'.join(
                [self.loadSubFilmOlis_str,
                 str(self.loadSubFilmOlis_check)]))
        self.config.set(
            self.last_used_scan, "loadSubFTIR",
            ':'.join([self.loadSubFTIR_str,
                      str(self.loadSubFTIR_check)]))
        self.config.set(
            self.last_used_scan, "loadSubFilmFTIR", ':'.join(
                [self.loadSubFilmFTIR_str,
                 str(self.loadSubFilmFTIR_check)]))
        self.config.set(self.last_used_scan, "fit_linear_spline",
                        self.fit_linear_spline)
        self.config.set(self.last_used_scan, "gaussian_factors",
                        str(self.factorsEdit.text()))
        self.config.set(self.last_used_scan, "gaussian_borders",
                        str(self.bordersEdit.text()))
        self.config.set(self.last_used_scan, "ignore_data_pts",
                        str(self.ignore_data_ptsEdit.text()))
        self.config.set(self.last_used_scan, "corr_slit",
                        str(self.corr_slitEdit.text()))
        self.config.set(self.last_used_scan, "fit_poly_order",
                        str(self.fit_poly_order))
        self.config.set(
            self.last_used_scan, "fit_poly_ranges", ':'.join([
                str(self.poly_bordersEdit.text()),
                str(self.fit_poly_ranges_check)
            ]))
        self.config.set(self.last_used_scan, "filename",
                        str(self.filenameEdit.text()))
        self.config.set(self.last_used_scan, "timetrace", self.timetrace)
        self.config.set(self.last_used_scan, "save_figs", str(self.save_figs))
        self.config.set(self.last_used_scan, "plot_x", self.plot_X)

        with open(''.join([self.cwd, os.sep, "config.ini"]),
                  "w") as configfile:
            self.config.write(configfile)

    def finished(self):

        self.my_plots.close_plots()

        self.load_()

        if self.emailset_str[1] == "yes":
            self.send_notif()
        if self.emailset_str[2] == "yes":
            self.send_data()

        self.button_style(self.Step0_Button, 'black')
        self.button_style(self.Step1_Button, 'black')
        self.button_style(self.Step2_Button, 'black')
        self.button_style(self.Step3_Button, 'black')
        self.button_style(self.Step4_Button, 'black')
        self.button_style(self.Step5_Button, 'black')

        self.isRunning = False

    def allButtons_torf(self, trueorfalse, *argv):

        if argv[0] == 'allfalse':
            self.cb_sub_olis.setEnabled(False)
            self.cb_subfilm_olis.setEnabled(False)
            self.cb_sub_ftir.setEnabled(False)
            self.cb_subfilm_ftir.setEnabled(False)

            self.poly_bordersEdit.setEnabled(False)

        self.fileSave.setEnabled(trueorfalse)
        self.loadMenu.setEnabled(trueorfalse)
        self.emailMenu.setEnabled(trueorfalse)

        self.cb_save_figs.setEnabled(trueorfalse)
        self.cb_polybord.setEnabled(trueorfalse)

        self.Step0_Button.setEnabled(trueorfalse)
        self.Step1_Button.setEnabled(trueorfalse)
        self.Step2_Button.setEnabled(trueorfalse)
        self.Step3_Button.setEnabled(trueorfalse)
        self.Step4_Button.setEnabled(trueorfalse)
        self.Step5_Button.setEnabled(trueorfalse)

        self.combo1.setEnabled(trueorfalse)
        self.combo2.setEnabled(trueorfalse)
        self.combo4.setEnabled(trueorfalse)

        self.factorsEdit.setEnabled(trueorfalse)
        self.bordersEdit.setEnabled(trueorfalse)
        self.ignore_data_ptsEdit.setEnabled(trueorfalse)
        self.corr_slitEdit.setEnabled(trueorfalse)

        self.filenameEdit.setEnabled(trueorfalse)

    def warning(self, mystr):

        QMessageBox.warning(self, "Message", mystr)

    def send_notif(self):

        contents = [
            "The scan is done. Please visit the experiment site and make sure that all light sources are switched off."
        ]
        subject = "The scan is done"

        obj = type(
            "obj", (object, ), {
                "subject": subject,
                "contents": contents,
                "settings": self.emailset_str,
                "receivers": self.emailrec_str
            })

        worker = Send_Email_Worker(obj)
        worker.signals.critical.connect(self.critical)
        worker.signals.warning.connect(self.warning)
        worker.signals.finished.connect(self.finished1)

        # Execute
        self.md = Indicator_dialog.Indicator_dialog(
            self, "...sending notification...",
            "indicators/ajax-loader-ball.gif")
        self.threadpool.start(worker)
        self.isRunning = True

    def send_data(self):

        contents = [
            "The scan is  done and the logged data is attached to this email. Please visit the experiment site and make sure that all light sources are switched off."
        ]
        contents.extend(self.datafiles)
        subject = "The scan data from the latest scan!"

        obj = type(
            "obj", (object, ), {
                "subject": subject,
                "contents": contents,
                "settings": self.emailset_str,
                "receivers": self.emailrec_str
            })

        worker = Send_Email_Worker(obj)
        worker.signals.critical.connect(self.critical)
        worker.signals.warning.connect(self.warning)
        worker.signals.finished.connect(self.finished1)

        # Execute
        self.md = Indicator_dialog.Indicator_dialog(
            self, "...sending files...", "indicators/ajax-loader-ball.gif")
        self.threadpool.start(worker)
        self.isRunning = True

    def finished1(self):

        self.isRunning = False
        self.md.close_()

    def critical(self, mystr):

        QMessageBox.critical(self, 'Message', mystr)

    def closeEvent(self, event):

        reply = QMessageBox.question(self, 'Message', "Quit now?",
                                     QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            if self.isRunning:
                QMessageBox.warning(
                    self, 'Message',
                    "Analysis in progress. Wait the analysis to finish and then quit!"
                )
                event.ignore()
            else:
                event.accept()
        elif reply == QMessageBox.No:
            event.ignore()
예제 #12
0
class Main(QMainWindow): #MAIN WINDOW
    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.dealerStep = DM.DealerStepper() #setup motors
        self.dealerDC = DM.DealerDC()
        self.display(0)
        

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

        self.ui.page1label1.setText("ARTOPS: Blackjack")

        self.ui.page3hitButton.clicked.connect(lambda: self.roundMainTrigger(0)) #setup the UI button functions
        self.ui.page3stickButton.clicked.connect(lambda: self.roundMainTrigger(1))
        self.ui.page7statsButton.clicked.connect(lambda: self.statisticsPage())
        self.ui.page7resetButton.clicked.connect(lambda: self.resetTrigger())
        self.ui.page8resetButton.clicked.connect(lambda: self.resetTrigger())
        self.ui.pageErrorButton1.clicked.connect(lambda: self.resetTrigger())
        self.shortcut = QShortcut(QKeySequence("Ctrl+E"), self)
        self.shortcut.activated.connect(self.exitApp)
        self.shortcut = QShortcut(QKeySequence("Ctrl+R"), self)
        self.shortcut.activated.connect(self.resetTrigger)
        
        self.showFullScreen()
        self.initialise()

    def initialise(self):
        """Ran at start of each game - resets variables and text"""
        self.playerScore,self.dealerScore,self.playerCards,self.dealerCards = 0,0,0,0
        self.playerCardList = []
        self.dealerCardList = []
        self.playerCamera = 0
        self.dealerCamera = 2
        self.roundNum = 0
        self.ui.page2label1.setText("Shuffling and dealing...")
        self.display(0)
        worker = Worker(self.waitForStart) 
        self.threadpool.start(worker)
        

    def waitForStart(self):
        """wait for button press to start"""
        GPIO.output(7, 1) #button LED on
        while True:
            button_state = GPIO.input(15)
            if button_state == False:
                print('Button Pressed...')
                GPIO.output(7, 0) #button LED off
                return self.shuffle() 
                
    def shuffle(self): 
        """gui side shuffle"""
        self.display(1)
        self.shuffleComplete = False
        # Pass the function to execute
        worker = Worker(self.shuffleThread) 
        self.threadpool.start(worker)
        

    def shuffleThread(self): 
        """multithreaded shuffle"""
        #Connect to Arduino
        ser = serial.Serial('/dev/ttyACM0',9600, timeout = 0.1)
        time.sleep(1)
        ser.flushInput()

        #Send Request to Shuffle Cards
        ser.write(b'1')
        print('Shuffling')

        #Wait until Confirmation (handshake)
        self.shuffleComplete = False
        while self.shuffleComplete == False:
            data = ser.readline()
            if data:
                print('Shuffled')
                self.shuffleComplete = True
        self.dealerDC.pullBack() #pull in the cards
        self.startingDeal()


    def startingDeal(self): 
        """Deal initial cards, and prepare for hit/stick page"""
        #deal first two cards and read them for both sides
        self.dealerStep.gotoPlayerSide()
        self.dealCard('playerSide') #deal two cards
        self.ui.page2label1.setText("Please take your cards")
        self.dealerStep.gotoDealerSide()
        self.dealCard('dealerSide')
        #set 'My first card was a ...' text on hit/stick page
        if self.dealerCardList[0] == 1:
            self.ui.page3label2.setText('Ace')
        elif self.dealerCardList[0] == 11:
            self.ui.page3label2.setText('Jack')
        elif self.dealerCardList[0] == 12:
            self.ui.page3label2.setText('Queen')
        elif self.dealerCardList[0] == 13:
            self.ui.page3label2.setText('King')
        else:
            self.ui.page3label2.setText(str(self.dealerCardList[0]))
        #switch to hit or stick
        worker = Worker(self.dealerStep.gotoPlayerSide)
        self.threadpool.start(worker)
        self.display(2)


    def dealCard(self,X): 
        """general single card deal then read method."""
        worker = Worker(self.dealerDC.dealOneCard)
        self.threadpool.start(worker)

        if X == 'playerSide': #card detection for playerside card deal
            try:
                openCV = CD.CardDetection(self.playerCamera)
            except:
                self.dealCard(X)
            if openCV.card_rank > 10:
                self.playerScore += 10 #if the card is a jack queen or king add ten to the score
            else:
                self.playerScore += openCV.card_rank
            self.playerCards += 1
            self.playerCardList.append(openCV.card_rank)
            if self.playerCards<2: #if its the first round call the read card function again
                self.dealCard(X)
            print(self.playerCardList)
            
        elif X == 'dealerSide': #card detection for dealerside card deal
            try:
                openCV = CD.CardDetection(self.dealerCamera)
            except:
                self.dealCard(X)
            if openCV.card_rank > 10:
                self.dealerScore += 10
            else:
                self.dealerScore += openCV.card_rank
            self.dealerCards += 1
            self.dealerCardList.append(openCV.card_rank)
            if self.dealerCards<2:
                self.dealCard(X)
            print(self.dealerCardList)
    
    def errorPage(self): 
        """general error trigger"""
        self.display(8)

    def roundMainTrigger(self, playerAction): 
        """GUI side main round trigger"""
        self.ui.page4label2.setText('???')
        self.display(3)
        self.playerAction = playerAction
        worker = Worker(self.roundMain)
        self.threadpool.start(worker)

    def roundMain(self): 
        """main round method"""
        print('round main')
        #playerAction 0 is hit, 1 is stick
        self.roundNum += 1
        if self.playerAction == 0:
            self.dealerStep.gotoPlayerSide()
            self.dealCard('playerSide')
        self.dealerStep.gotoDealerSide()
        
        decision = self.decision(self.dealerCardList) #run decision method on dealers current cards
        if decision == 0:
            self.ui.page4label2.setText('HIT!')
            self.dealCard('dealerSide')
        elif decision == 1:
            self.ui.page4label2.setText('STICK!')
            time.sleep(1)
        self.dealerStep.gotoPlayerSide()
        if self.playerAction == 1 and decision == 1: #if both players choose to stick
            self.display(4)
            time.sleep(4)
            return self.finishGame()
        elif self.playerScore > 21 or self.dealerScore > 21: #if either player has gone bust
            return self.finishGame()
        else:
            return self.display(2) #return to hit or stick page

    def decision(self,cards):  
        """Dealer decision method, provides 1(hit) or 0(stick) from current cards"""
        if cards == []:
            return 1
        total_val = 340 #total value of all cards
        score = 0
        for i in cards: 
            if i > 10: #score calculator left from previous file
                i = 10
            score += i
            print(score)
        total_val -= score 
        prediction = total_val/(52-len(cards)) #find the average remaining card score
        if score + prediction <= 21:
            return 0 #hit
        else:
            return 1 #stick
        
    def finishGame(self):
        """finish the game and update running total"""
        self.calculateScore() 
        os.getcwd
        f = open("running_total.txt", 'r+')  #reading then updating running_total txt file for total games won
        self.dealerTotal = int(f.readline()) 
        self.dealerTotal += self.dealerResult
        self.playerTotal = int(f.readline())
        self.playerTotal += self.playerResult
        f.truncate(0)
        f.seek(0,0)
        f.write(str(self.dealerTotal))
        f.write('\n' + str(self.playerTotal))
        f.close()
        self.ui.page8label3.setText(str(self.dealerTotal)) #setup results page
        self.ui.page8label5.setText(str(self.playerTotal))
        print(self.playerCardList, self.dealerCardList)
        self.display(5)


    def calculateScore(self): 
        """calculte the player and dealers score and find the winner. Update the gui """
        if self.dealerScore >21:
            self.dealerScore = 0
            self.ui.page7label3.setText('BUST')
        else:
            self.ui.page7label3.setText(str(self.dealerScore))
        
        if self.playerScore >21:
            self.playerScore = 0
            self.ui.page7label5.setText('BUST')
        else:
            self.ui.page7label5.setText(str(self.playerScore))
        if self.dealerScore > self.playerScore:
            self.dealerResult = 1
            self.playerResult = 0
            self.ui.page7label6.setText('I Win!')
        elif self.playerScore > self.dealerScore:
            self.dealerResult = 0
            self.playerResult = 1
            self.ui.page7label6.setText('You Win!')
        else:
            self.dealerResult = 0
            self.playerResult = 0
            self.ui.page7label6.setText('Draw!')
        return

    def statisticsPage(self): 
        """stats page control"""
        print("stats")
        self.display(6)
    
    def resetTrigger(self):
        """reset gui trigger"""
        print("PLAY AGAIN")
        self.display(7) #display collect cards message
        worker = Worker(self.reset)
        self.threadpool.start(worker)


    def reset(self): 
        """reset game for playing again"""
        self.dealerStep.gotoPlayerSide() #deal remaining pack onto player side
        self.dealerDC.dealWholePack()
        time.sleep(10)
        self.dealerStep.gotoShuffler()
        self.initialise()

    def display(self,i):
        """display the chosen stacked widget ie the page of the gui"""
        print('setting index', i)
        self.ui.stackedWidget.setCurrentIndex(i)


    @pyqtSlot()
    def exitApp(self):
        #exit method
        self.dealerStep.gotoShuffler
        GPIO.cleanup()
        sys.exit()
예제 #13
0
class RCMMainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        pack_info = rcm_utils.pack_info()

        title = "Remote Connection Manager - CINECA - v" + pack_info.rcmVersion
        self.setWindowTitle(title)

        width = 1000
        height = 370

        screen_width = QDesktopWidget().width()
        screen_height = QDesktopWidget().height()

        self.setGeometry((screen_width / 2) - (width / 2),
                         (screen_height / 2) - (height / 2), width, height)

        self.setMinimumHeight(height)
        self.setMinimumWidth(width)

        self.build_menu()

        self.main_widget = MainWidget(self)
        self.setCentralWidget(self.main_widget)

        self.thread_pool = QThreadPool()

        logger.info("Welcome to RCM!")
        logger.debug("Multithreading with maximum %d threads" %
                     self.thread_pool.maxThreadCount())

    def build_menu(self):
        """
        build and add menu to the application
        :return:
        """

        # Create new action
        new_action = QAction(QIcon(resource_path('gui/icons/new.png')), '&New',
                             self)
        new_action.setShortcut('Ctrl+N')
        new_action.setStatusTip('New VNC session')
        new_action.triggered.connect(self.new_vnc_session)

        # Create new action
        open_action = QAction(QIcon(resource_path('gui/icons/open.png')),
                              '&Open', self)
        open_action.setShortcut('Ctrl+O')
        open_action.setStatusTip('Open VNC session')
        open_action.triggered.connect(self.open_vnc_session)

        # Create exit action
        exit_action = QAction(QIcon(resource_path('gui/icons/exit.png')),
                              '&Exit', self)
        exit_action.setShortcut('Ctrl+Q')
        exit_action.setStatusTip('Exit application')
        exit_action.triggered.connect(self.exit)

        # Create the settings action
        edit_settings_action = QAction('&Settings', self)
        edit_settings_action.setShortcut('Ctrl+S')
        edit_settings_action.setStatusTip('Custom the application settings')
        edit_settings_action.triggered.connect(self.edit_settings)

        # Create the about action
        about_action = QAction('&About', self)
        about_action.setShortcut('Ctrl+A')
        about_action.setStatusTip('About the application')
        about_action.triggered.connect(self.about)

        # Create menu bar and add actions
        menu_bar = self.menuBar()
        file_menu = menu_bar.addMenu('&File')
        file_menu.addAction(new_action)
        file_menu.addAction(open_action)
        file_menu.addAction(exit_action)
        edit_menu = menu_bar.addMenu('&Edit')
        edit_menu.addAction(edit_settings_action)
        help_menu = menu_bar.addMenu('&Help')
        help_menu.addAction(about_action)

    def new_vnc_session(self):
        last_tab_id = self.main_widget.tabs.count() - 1
        last_tab_uuid = self.main_widget.tabs.widget(last_tab_id).uuid

        kill_btn = QPushButton()
        kill_btn.setIcon(self.style().standardIcon(
            QStyle.SP_DialogCloseButton))
        kill_btn.clicked.connect(lambda: self.on_close(last_tab_uuid))
        kill_btn.setToolTip('Close session')

        self.main_widget.tabs.setTabText(last_tab_id, "Login...")
        self.main_widget.tabs.tabBar().setTabButton(last_tab_id,
                                                    QTabBar.RightSide,
                                                    kill_btn)
        self.main_widget.add_new_tab("", False)

    def open_vnc_session(self):

        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "Open...",
            "",
            "VNC Files (*.vnc);;All Files (*)",
            options=options)

        current_session_widget = self.main_widget.tabs.currentWidget()

        if filename:
            # check if session needs tunneling
            file = open(filename, 'r')
            if 'rcm_tunnel' in file.read():
                file.seek(0)
                lines = file.readlines()
                for line in lines:
                    if 'rcm_tunnel' in line:
                        node = line.split('=')[1].rstrip()
                        if not current_session_widget.is_logged:
                            logger.error(
                                "You are not logged in the current session. Please log in."
                            )
                            return
                        if node == current_session_widget.host:
                            user = current_session_widget.user
                        else:
                            logger.error(
                                "The host of the current session (" +
                                current_session_widget.host +
                                ") is different from the host of the vnc file ("
                                + node + ")")
                            return
                    if 'host' in line:
                        hostname = line.split('=')[1].rstrip()
                    if 'port' in line:
                        port = line.split('=')[1].rstrip()
                        display = int(port) - 5900
                    if 'password' in line:
                        password = line.split('=')[1].rstrip()

                session = rcm.rcm_session(node=hostname,
                                          tunnel='y',
                                          display=display,
                                          nodelogin=node,
                                          username=user,
                                          vncpassword=password)
                current_session_widget.remote_connection_manager.vncsession(
                    session=session)
                logger.info("Connected to remote display " + str(display) +
                            " on " + node + " as " + str(user) +
                            " with tunnel")
            else:
                current_session_widget.remote_connection_manager.vncsession(
                    configFile=filename)

    def closeEvent(self, QCloseEvent):
        self.exit()

    def exit(self):
        """
        kill all the pending threads, then close the application
        """
        for tab_id in range(0, self.main_widget.tabs.count()):
            widget = self.main_widget.tabs.widget(tab_id)
            widget.kill_all_threads()
        self.close()

    def edit_settings(self):
        edit_settings_dlg = QEditSettingsDialog(self)
        edit_settings_dlg.setModal(True)
        edit_settings_dlg.exec()

    def about(self):
        QMessageBox.about(self, "RCM", self.windowTitle())
        return

    @pyqtSlot()
    def on_close(self, uuid):
        # loop over the tabs and found the tab with the right uuid
        for tab_id in range(0, self.main_widget.tabs.count()):
            widget = self.main_widget.tabs.widget(tab_id)
            if widget.uuid == uuid:
                if self.main_widget.tabs.currentIndex(
                ) == self.main_widget.tabs.count() - 2:
                    self.main_widget.tabs.setCurrentIndex(tab_id - 1)
                self.main_widget.tabs.removeTab(tab_id)
                return
예제 #14
0
class GridOperator(QObject):

    update_logger = pyqtSignal(name='update_logger')
    exec_pending = pyqtSignal(name='exec_pending')

    def __init__(self, grid):
        super().__init__()
        logging.debug('__init__() called on GridOperator')
        self.grid = grid
        self.stop_flag = False
        self.retry_counter = 0
        self.delay = 0
        self.threadpool = QThreadPool()
        self.b_debug_window = False
        self.pending_return = []
        self.exec_pending.connect(self.checkPending)
        mp.set_start_method('spawn')
        logging.debug('__init__() GridOperator, threadCount: {}'.format(
            self.threadpool.maxThreadCount()))

    def startExec(self, start_pos, record=None):

        logging.debug('startExec() called, start_pos = {}'.format(start_pos))

        try:
            element = self.grid.itemAtPosition(*start_pos).widget()
        except AttributeError as e:
            return

        if self.stop_flag:
            return

        self.update_logger.emit()
        executor = Executor(element, record, self.delay)
        executor.signals.finished.connect(self.execDone)
        element.highlightStart()
        self.threadpool.start(executor)

    def execDone(self, prg_return):

        logging.debug('execDone() called GridOperator from {}'.format(
            prg_return.source))

        element = self.grid.itemAtPosition(*prg_return.source).widget()

        if (issubclass(prg_return.record_0.__class__, BaseException)):
            logging.error('Target {}|{} Exception found: {}'.format(
                prg_return.source[0], alphabet[prg_return.source[1]],
                prg_return.record_0))
            element.highlightException()
            self.exceptwindow = ExceptWindow(str(prg_return.record_0),
                                             prg_return.source)
            self.exceptwindow.window_closed.connect(self.highlightStop)
            return

        # when the log fiel is set
        if prg_return.log:
            if prg_return.log_txt:
                logging.info('Message {}|{} : {}'.format(
                    prg_return.source[0], alphabet[prg_return.source[1]],
                    prg_return.log_txt))
            if prg_return.log_output:
                log = prg_return.log_output
            else:
                log = prg_return.record_0

            logging.info('Output  {}|{} : {}'.format(
                prg_return.source[0], alphabet[prg_return.source[1]], log))

        # when the log button is enabled
        if element.b_debug:

            if prg_return.log_output:
                log_message = prg_return.log_output
            else:
                log_message = str(prg_return.record_0)

            logging.debug('execDone() b_debug_window = {}'.format(
                self.b_debug_window))
            if not self.b_debug_window:
                self.debugWindow = DebugWindow(log_message, prg_return.source)
                self.debugWindow.proceed_execution.connect(
                    lambda: self.proceedExec(prg_return))
                self.debugWindow.raiseWindow()
                self.b_debug_window = True
            else:
                # Aktuellen stand für erneute ausführung vormerken
                self.pending_return.append(prg_return)

        else:
            # highlight stop =!

            element.highlightStop()
            self.goNext(prg_return)

    def checkPending(self):

        logging.debug('checkPending() called')

        if self.pending_return:
            prg_return = self.pending_return.pop(0)
            self.execDone(prg_return)

    def proceedExec(self, prg_return):

        element = self.grid.itemAtPosition(*prg_return.source).widget()
        element.highlightStop()
        self.b_debug_window = False
        self.exec_pending.emit()
        self.goNext(prg_return)

    def goNext(self, prg_return):

        if prg_return.target_0:
            logging.debug('goNext() called with next target_0: {}'.format(
                prg_return.target_0))
            logging.debug('goNext() called with record_0: {}'.format(
                prg_return.record_0))
            self.startExec(prg_return.target_0, prg_return.record_0)

        if prg_return.target_1:
            logging.debug(
                'goNext() called with additional target_1: {}'.format(
                    prg_return.target_1))
            logging.debug('goNext() called with record_1: {}'.format(
                prg_return.record_1))
            self.startExec(prg_return.target_1, prg_return.record_1)

    def highlightStop(self, position):
        logging.debug(
            'highlightStop() called for position {}'.format(position))
        element = self.grid.itemAtPosition(*position).widget()
        element.highlightStop()

    def stop_execution(self):
        logging.debug('stop_execution() called')
        self.stop_flag = True
예제 #15
0
class JetsonWindow(QMainWindow):
    # class constructor
    def __init__(self):
        # call QWidget constructor
        super().__init__()
        self.ui = Ui_JetsonWindow()
        self.ui.setupUi(self)

        self.root = tk.Tk()
        self.w = self.root.winfo_screenwidth()
        self.h = self.root.winfo_screenheight()
        self.queue = Queue()
        self.image = None
        self.box = None
        self.shortcut = QShortcut(QKeySequence("Ctrl+Esc"), self)
        self.shortcut.activated.connect(self.closeApp)

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

        # self.server_url = 'http://192.168.1.3:5001/'

        self.p = pyaudio.PyAudio()
        self.stream = self.p.open(rate=16000,
                                  channels=1,
                                  format=pyaudio.paInt16,
                                  input=True,
                                  frames_per_buffer=512,
                                  input_device_index=11,
                                  stream_callback=self.callback)
        self.stream.start_stream()
        self.list = []
        with open('DATA.csv', newline='') as f:
            reader = list(csv.reader(f))
            for data in reader:
                self.list.append(data[0])
        self.server_url = self.list.pop()
        self.list.append('NOT IDENTIFIED')
        print(f"Server url: {self.server_url}")
        print(f"ID List: {self.list}")

        # self.list = ['1752015', '1752259', '1752041', 'NOT INDENTIFIED']

        # create a timer
        self.timer = QTimer()
        # set timer timeout callback function that check temporary ID
        self.timer.timeout.connect(self.Attendance)

        #Run Face Recognition
        self.cap = cv2.VideoCapture(self.gstreamer_pipeline(),
                                    cv2.CAP_GSTREAMER)
        self.flag = 0

        self.timer.start(20)

    def closeApp(self):
        app.quit()

    def callback(self, in_data, frame_count, time_info, status):
        self.queue.put(in_data)
        return (in_data, pyaudio.paContinue)

    def gstreamer_pipeline(
        self,
        capture_width=1280,
        capture_height=720,
        display_width=1280,
        display_height=720,
        framerate=90,
        flip_method=0,
    ):
        return (
            "nvarguscamerasrc ! "
            "video/x-raw(memory:NVMM), "
            "width=(int)%d, height=(int)%d, "
            "format=(string)NV12, framerate=(fraction)%d/1 ! "
            "nvvidconv flip-method=%d ! "
            "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
            "videoconvert ! "
            "video/x-raw, format=(string)BGR ! appsink" % (
                capture_width,
                capture_height,
                framerate,
                flip_method,
                display_width,
                display_height,
            ))

    def progress_fn(self, n):
        n = int(n)
        print("%d%% done" % n)
        if n == 0:
            self.ui.infor_label.setText("Recording |")
        if n == 20:
            self.ui.infor_label.setText("Recording /")
        if n == 40:
            self.ui.infor_label.setText("Recording -")
        if n == 60:
            self.ui.infor_label.setText("Recording \\")
        if n == 80:
            self.ui.infor_label.setText("Recording |")
        if n == 91:
            self.ui.infor_label.setText("Done Recording")

    def execute_voice(self, progress_callback):  # main function
        voiceframes = []
        p = pyaudio.PyAudio()
        stream = p.open(
            rate=16000,
            channels=1,
            format=pyaudio.paInt16,
            input=True,
            frames_per_buffer=512,
            input_device_index=11,
        )
        stream.start_stream()
        for i in range(0, int(16000 / 512 * 3)):
            voiceframes.append(stream.read(512))
            progress_callback.emit(i)

        p.terminate()
        stream.close()
        return voiceframes

    def print_output(self, voice):
        # send server
        voice = list(voice)
        print("Output printing...")
        encapsulate_face = pickle.dumps(self.image,
                                        protocol=pickle.HIGHEST_PROTOCOL)
        encapsulate_voice = pickle.dumps(voice,
                                         protocol=pickle.HIGHEST_PROTOCOL)
        face_response = requests.post(self.server_url + 'face',
                                      data=encapsulate_face).json()
        face_result = np.array(face_response['data'])
        voice_response = requests.post(self.server_url + 'voice',
                                       data=encapsulate_voice).json()['data']
        voice_result = np.array(voice_response)
        # result =  np.add(face_result*0.8, voice_result*0.2)
        result = 2 * face_result * voice_result / (face_result + voice_result)
        if np.any(result > 0.9):
            name = "Device 1 \n" + self.list[result.argmax(
            )] + f': {round(result[result.argmax()] * 100 , 1)}'
            requests.post(url_check,
                          data={
                              'roomId': 'A4405',
                              'stuId': self.list[result.argmax()]
                          })
        else:
            name = "Device 1 \n" + self.list[-1]
        self.ui.infor_label.setText(name)

    def thread_complete(self):
        print("THREAD COMPLETE!")
        self.p = pyaudio.PyAudio()
        self.stream = self.p.open(rate=16000,
                                  channels=1,
                                  format=pyaudio.paInt16,
                                  input=True,
                                  frames_per_buffer=512,
                                  input_device_index=11,
                                  stream_callback=self.callback)
        self.stream.start_stream()

    def recording(self):
        self.p.terminate()
        self.stream.close()
        # Pass the function to execute
        record = Record(
            self.execute_voice
        )  # Any other args, kwargs are passed to the run function
        record.signals.result.connect(self.print_output)
        record.signals.finished.connect(self.thread_complete)
        record.signals.progress.connect(self.progress_fn)

        # Execute
        self.threadpool.start(record)

    def Attendance(self):
        ret, self.image = self.cap.read()
        img = self.image
        # cv2.rectangle(img, (480, 180), (800, 600), (0, 0, 0), thickness=2)
        procimage = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # get image infos
        height, width, channel = procimage.shape
        step = channel * width

        # create QImage from image
        qImg = QImage(procimage.data, width, height, step,
                      QImage.Format_RGB888)
        # show image in img_label
        wi = self.ui.image_label.width()
        he = self.ui.image_label.height()

        self.ui.image_label.setPixmap(
            QPixmap.fromImage(qImg).scaled(wi, he, QtCore.Qt.KeepAspectRatio))

        if self.queue.qsize() > 0:
            while self.queue.qsize() > 32:
                self.queue.get()
            buff = []
            if self.queue.qsize() >= 32:
                while self.queue.qsize() > 0:
                    buff.append(self.queue.get())
            ans = detection.detector.RunDetection(b''.join(buff))
            if ans == 1:
                print("success")
                self.recording()

        return 0
예제 #16
0
# -*- coding: utf-8 -*-

# async guidance from
#  https://martinfitzpatrick.name/article/multithreading-pyqt-applications-with-qthreadpool/
# (didn't use inbuilt python async/await since it requires an event/thread loop which it seems
#  qt itself isn't playing nice with... maybe?)


from PyQt5.QtCore import QRunnable, pyqtSlot, QThreadPool

threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % threadpool.maxThreadCount())

class Worker(QRunnable):
    '''
    Worker thread

    Inherits from QRunnable to handler worker thread setup, signals and wrap-up.

    :param callback: The function callback to run on this worker thread. Supplied args and
                     kwargs will be passed through to the runner.
    :type callback: function
    :param args: Arguments to pass to the callback function
    :param kwargs: Keywords to pass to the callback function

    '''

    def __init__(self, fn, *args, **kwargs):
        super(Worker, self).__init__()
        # Store constructor arguments (re-used for processing)
        self.fn = fn
예제 #17
0
class Ui(QtWidgets.QMainWindow, ihesync_app.Ui_MainWindow):
    def __init__(self, context, parent=None):
        super(Ui, self).__init__(parent)
        self.logger = logging.getLogger()
        self.network_available = False
        self.network_watchdog = None

        self.setupUi(self)
        self.context = context
        self.changed = False
        self.label_ihewebsite.setText('Visit IHE Website : <a href="http://www.ihe.net">www.ihe.net</a>')
        self.label_ihewebsite.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
        self.label_ihewebsite.setOpenExternalLinks(True)

        self.modifed_label = QLabel("Status: No change")
        self.network_label = QLabel("No network!")

        self.statusBar().setStyleSheet('border: 0; background-color: #FFF8DC;')
        self.statusBar().setStyleSheet("QStatusBar::item {border: none;}")
        self.statusBar().addPermanentWidget(VLine())
        self.statusBar().addPermanentWidget(self.network_label)
        self.statusBar().addPermanentWidget(VLine())
        self.statusBar().addPermanentWidget(self.modifed_label)

        self.threadpool = QThreadPool()
        self.threadpool.setMaxThreadCount(4)

        self.doc_model = documents_model.DocumentsModel([])
        self.tableView.setModel(self.doc_model)
        self.tableView.horizontalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.ResizeToContents
        )
        icon_delegate = OpenFolderDelegate(self.tableView)
        self.tableView.setItemDelegateForColumn(4, icon_delegate)
        self.tableView.clicked.connect(self.open_documents_folder)
        self.logger.info("Starts with %d threads" % self.threadpool.maxThreadCount())

        self.tabWidget.currentChanged.connect(self.current_tab_changed)

        if platform.system() in STYLES:
            self.setStyleSheet(STYLES[platform.system()])

    def main(self):
        conf_loaded = self.context.load_configuration()

        # default size
        (w, h) = (800, 700)
        if platform.system() in MAIN_WINDOW_DEFAULT_SIZE:
            (w, h) = MAIN_WINDOW_DEFAULT_SIZE[platform.system()]
        # overwritten size = user prefs
        if self.context.sync.geometry != (0, 0):
            (w, h) = self.context.sync.geometry
        self.centralwidget.parentWidget().resize(w, h)

        self.show()
        self.start_network_watchdog()

        if not conf_loaded:
            self.change_status("Configuration loading error : check network")

        self.refresh_configuration()
        self.refresh_information_counts()
        self.refresh_domain_list()
        self.refresh_public_comment()

        if self.context.local_file_count_ondisk != self.context.local_file_count:
            self.msgbox_out_of_sync()

    # -- Messages boxes ---
    # ---------------------
    def msgbox_out_of_sync(self):
        msg = QMessageBox.about(
            self,
            "Information...",
            (
                f"Out of sync ! Local files on disk {self.context.local_file_count_ondisk}"
                f" vs in configuration {self.context.local_file_count}\n"
                f" Sync needed"
            ),
        )
        msg.setIcon(QMessageBox.Warning)

    def msgbox_network_unavailable(self):
        QMessageBox.critical(self,
                             "Network unavailable", (
                                 f"No network"
                                 f" Check\n"), )

    # -- Messages boxes ---

    # -- Check Network
    def update_network_status(self, data):
        (ip, self.network_available) = data
        self.logger.debug(f"network status updated availaible = {self.network_available}")
        if self.network_available:
            self.network_label.setText("Connected")
            self.network_label.setStyleSheet('border: 0; color:  green;')
        else:
            self.network_label.setText("no Network!")
            self.network_label.setStyleSheet('border: 0; color:  red;')

    def start_network_watchdog(self):
        self.network_watchdog = sync_worker.NetworkWorker(ihesync.sync.IHE_URL, self.context.sync.proxy,
                                                          self.context.sync.ping_delay)
        self.network_watchdog.signals.progress.connect(self.update_network_status)
        self.threadpool.start(self.network_watchdog)

    def stop_network_watchdog(self):
        self.logger.debug("Stop network watchdog...")
        self.network_watchdog.abort()

    # -- Refresh counts

    def refresh_public_comment(self):
        state = (
            QtCore.Qt.Checked
            if self.context.sync.public_comment
            else QtCore.Qt.Unchecked
        )
        self.checkComments.setCheckState(state)

    def refresh_last_checked(self):
        """
            Refresh date of the last check
        :return: -
        """
        if self.context.sync.last_check:
            self.labelLastCheckDate.setText(
                self.context.sync.last_check.strftime("%Y-%m-%d %H:%M")
            )

    def refresh_domain_list(self) -> None:
        """
            Refresh the domain table
                - sorted by domain name
                - get the count of local files
        :return:
        """
        self.logger.info("refresh_domain_list")
        self.doc_model.log()

        self.labelDomainCountValue.setText(str(len(self.context.domains)))

        self.doc_model.set_documents(None)

        data = []
        for domain in sorted(self.context.domains, key=lambda v: v["name"]):
            local_count = self.context.sync.count_local_files(domain["name"])
            self.logger.debug(f"> domain >> {domain} - local cout = {local_count}")

            data.append(
                {
                    "checked": domain["name"] in self.context.selected_domains or domain["checked"],
                    "domain": domain["name"],
                    "title": DOMAIN_DICT[domain["name"]]
                    if domain["name"] in DOMAIN_DICT
                    else "",
                    "down": local_count,
                    "total": domain["files"],
                    "link": local_count > 0,
                    "local": local_count,
                    "error": 0
                }
            )

        self.doc_model.set_documents(data)
        self.tableView.model().layoutChanged.emit()

    def refresh_documents_directory_geometry(self):
        # get configuration directory geometry for height
        (conf_x, conf_y, conf_w, conf_h) = self.textConfDir.geometry().getRect()
        (x, y, w, h) = self.textDocDir.geometry().getRect()
        if len(self.context.doc_directory) > 60:
            h = conf_h * 2
        else:
            h = conf_h
        self.textDocDir.setGeometry(x, y, w, h)

    def refresh_configuration(self) -> None:
        """
            Refresh the configuration tab
        :return: -
        """
        self.textConfDir.setText(str(self.context.conf_directory))
        self.textDocDir.setText(str(self.context.doc_directory))
        self.refresh_documents_directory_geometry()
        self.newDocsGroupBox.setVisible(False)

        self.textLoggingFilename.setText(str(self.context.sync.log_filename))
        rad = dict(INFO=self.infoRadioButton, ERROR=self.errorRadioButton, DEBUG=self.debugRadioButton)
        if self.context.sync.log_level in rad:
            rad[self.context.sync.log_level].setChecked(True)
        self.textPingDelay.setText(str(self.context.sync.ping_delay))

        if self.context.sync.proxy:
            self.textProxyAddress.setText(self.context.sync.proxy['address'])
            self.textProxyPort.setText(self.context.sync.proxy['port'])
            if self.context.sync.proxy["active"]:
                self.specificProxyRadioButton.setChecked(self.context.sync.proxy["active"])
                self.noProxyRadioButton.setChecked(not self.context.sync.proxy["active"])
            self.update_proxy_state()
        else:
            self.noProxyRadioButton.setChecked(True)

    def refresh_information_counts(self) -> None:
        """
            Refresh counters and date last checked
        :return:
        """
        self.logger.debug("refresh_information_counts")
        self.newDocsGroupBox.setVisible(False)
        self.refresh_last_checked()
        self.context.scan_local_dirs()
        self.context.refresh_counts_current()
        self.labelDocumentCountValue.setText(str(self.context.file_count))
        self.labelLocalFilesCountValue.setText(str("{}/{}"
                                                   .format(self.context.local_file_count_ondisk,
                                                           self.context.local_file_count)))
        diff = self.context.check_updates_available()
        if diff > 0:
            self.newDocLabel.setText(f"{diff} document changes")
            self.newDocsGroupBox.setVisible(True)

    def change_status(self, msg=None, changed=None, duration=3000):
        if changed:
            self.changed = changed

        self.modifed_label.setText("Status: Changed !" if self.changed else "Status: No change")

        if msg:
            self.statusbar.showMessage(msg, duration)

    # -- UI callback

    @pyqtSlot()
    def on_checkComments_clicked(self):
        self.context.sync.public_comment = self.checkComments.checkState() == QtCore.Qt.Checked
        self.change_status(changed=True)

    @pyqtSlot()
    def on_aboutPushButton_clicked(self):
        dlg = dialogs.AboutDialog(self)
        dlg.main()

    @pyqtSlot()
    def on_infoRadioButton_clicked(self):
        self.context.sync.update_logger_config(level="INFO")
        if self.context.sync.log_level != "INFO":
            self.change_status(changed=True)

    @pyqtSlot()
    def on_errorRadioButton_clicked(self):
        self.context.sync.update_logger_config(level="ERROR")
        if self.context.sync.log_level != "ERROR":
            self.change_status(changed=True)

    @pyqtSlot()
    def on_debugRadioButton_clicked(self):
        self.context.sync.update_logger_config(level="DEBUG")
        if self.context.sync.log_level != "DEBUG":
            self.change_status(changed=True)

    @pyqtSlot()
    def on_noProxyRadioButton_clicked(self):
        self.change_status(changed=True)
        self.context.sync.proxy["active"] = False
        self.textProxyAddress.setDisabled(True)
        self.textProxyPort.setDisabled(True)

    @pyqtSlot()
    def on_specificProxyRadioButton_clicked(self):
        self.change_status(changed=True)
        self.context.sync.proxy["active"] = True
        self.textProxyAddress.setDisabled(False)
        self.textProxyPort.setDisabled(False)

    @pyqtSlot()
    def on_changeProxyPushButton_clicked(self):
        self.change_status(changed=True)
        self.context.sync.proxy['address'] = str(self.textProxyAddress.toPlainText())
        self.context.sync.proxy['port'] = str(self.textProxyPort.toPlainText())
        self.update_proxy_state()

    @pyqtSlot()
    def on_changeLogPushButton_clicked(self):
        self.context.sync.update_logger_config(filename=self.textLoggingFilename.toPlainText())
        self.change_status(changed=True)

    @pyqtSlot()
    def on_deleteLogPushButton_clicked(self):
        try:
            os.remove(self.textLoggingFilename.toPlainText())
        except OSError as e:
            self.logger.error(f"Can't remove {self.textLoggingFilename.toPlainText()} : {str(e)}")

    @pyqtSlot()
    def on_openLogPushButton_clicked(self):
        if os.path.exists(self.textLoggingFilename.toPlainText()):
            webbrowser.open_new(f"file://{self.textLoggingFilename.toPlainText()}")
        else:
            self.logger.error(f"Can't open file {self.textLoggingFilename.toPlainText()} which does not exist!")

    @pyqtSlot()
    def on_textConfDir_textChanged(self):
        self.context.conf_directory = self.textConfDir.toPlainText()
        self.change_status(changed=True)

    @pyqtSlot()
    def on_textDocDir_textChanged(self):
        self.context.doc_directory = self.textDocDir.toPlainText()
        self.change_status(changed=True)

    @pyqtSlot()
    def on_confSelectButton_clicked(self):
        previous = self.textConfDir.toPlainText()
        confdir = QFileDialog.getExistingDirectory(self, "Select Directory", previous, QFileDialog.ShowDirsOnly)
        if len(confdir):
            self.context.conf_directory = str(confdir)
            self.textConfDir.setText(self.context.conf_directory)
            self.change_status(changed=True)

    @pyqtSlot()
    def on_docSelectButton_clicked(self):
        previous = self.textDocDir.toPlainText()
        docdir = QFileDialog.getExistingDirectory(self, "Select Directory", previous, QFileDialog.ShowDirsOnly)
        if len(docdir):
            self.context.doc_directory = str(docdir)
            self.textDocDir.setText(self.context.doc_directory)
            self.change_status(changed=True)
            self.refresh_documents_directory_geometry()

    @pyqtSlot()
    def on_syncButton_clicked(self):
        if self.network_available:
            self.prepare_synchronization()
        else:
            self.msgbox_network_unavailable()

    @pyqtSlot()
    def on_changeConnectionPushButton_clicked(self):
        # get values before change
        new_delay = self.context.sync.ping_delay
        try:
            new_delay = int(self.textPingDelay.toPlainText())
        except ValueError as d_err:
            self.change_status("Delay value must be numeric !!!")
            self.logger.error(f"Configuration error while setting non numeric value for delay {d_err}")
            self.textPingDelay.setText(str(new_delay))

        if new_delay != self.context.sync.ping_delay:
            self.context.sync.ping_delay = new_delay
            self.stop_network_watchdog()
            self.start_network_watchdog()
            self.change_status("Ping informations changed.")

    @pyqtSlot()
    def on_synchronize_confirmed(self):
        self.logger.debug("on_synchronize_confirmed")
        self.do_synchronization()

    @pyqtSlot()
    def on_synchronize_rejected(self):
        self.context.revert_sync()

    def current_tab_changed(self, tab_number):
        if tab_number == 0:
            self.refresh_information_counts()
            self.refresh_domain_list()

    def closeEvent(self, event):
        # save new data
        self.logger.debug(f"Close - change ? {self.changed}")
        if self.changed or self.context.no_config_file:
            self.context.sync.save_infos()
            self.context.sync.save_configuration()
        else:
            self.logger.info("No changes")
        event.accept()
        self.stop_network_watchdog()

    def resizeEvent(self, event):
        h = self.centralwidget.parentWidget().size().height()
        w = self.centralwidget.parentWidget().size().width()
        self.context.sync.geometry = (w, h)

    # -- > Actions --
    # --------------

    def prepare_synchronization(self):
        """
            get the selected domains
            prepare elements to sync
            launch the UI dialog showing the compute of sync
        :return:
        """
        # get selected domains
        self.logger.debug("prepare_synchronization")
        domains = self.doc_model.checked()
        self.logger.info(domains)
        self.context.prepare_sync(domains)

        pd = dialogs.ProgressSyncDialog(
            dialogs.ProgressSyncDialog.REMOTE_INFO_TEXT, parent=self
        )
        worker = sync_worker.PrepareWorker(self.context)
        worker.signals.finished.connect(pd.accept)
        worker.signals.finished.connect(self.synchronize_dialog)
        worker.signals.aborted.connect(pd.reject)
        pd.main(worker)
        self.threadpool.start(worker)

    def synchronize_dialog(self):
        """
            Launch UI for synchro
        :return:
        """
        if self.network_available:
            sd = dialogs.SyncDialog(parent=self)
            sd.confirm_signal.connect(self.on_synchronize_confirmed)
            sd.reject_signal.connect(self.on_synchronize_rejected)

            sd.old_domains = self.context.infos["old_domain"]
            sd.new_domains = self.context.infos["new_domain"]
            sd.old_docs = self.context.infos["to_del"]
            sd.new_docs = self.context.infos["to_download"]
            if len(sd.old_domains) > 0 or len(sd.new_docs) > 0:
                self.change_status(changed=True)
            sd.main()
        else:
            self.msgbox_network_unavailable()

    def do_synchronization(self):
        self.doc_model.log()

        self.context.sync.display_available_docs()
        sd = dialogs.ProgressSyncDialog(
            dialogs.ProgressSyncDialog.SYNC_INFO_TEXT, parent=self
        )
        worker = sync_worker.SyncWorker(self.context)

        worker.signals.finished.connect(sd.accept)
        worker.signals.finished.connect(self.sync_finished)
        worker.signals.progress.connect(self.doc_model.update_documents)
        worker.signals.aborted.connect(sd.reject)
        sd.main(worker)
        self.threadpool.start(worker)

        self.context.confirm_sync()

    def sync_finished(self):
        """
            Syncho done.
            - display information in status bar
            - refresh informations counts
            - refresh doc table information
        """
        downloaded, error = self.doc_model.summary()
        self.change_status(f"{downloaded} download(s), {error} error(s)")

        self.refresh_information_counts()
        self.tableView.model().layoutChanged.emit()

    # -- < Actions

    def open_documents_folder(self, index: QtCore.QModelIndex) -> None:
        docinfo = index.model().docs[index.row()]
        if docinfo['link'] and index.column() == 4:
            dom = self.context.local_path_domain(docinfo['domain'])
            webbrowser.open_new(f"file://{dom}")

    def update_proxy_state(self):
        self.stop_network_watchdog()
        self.network_watchdog.set_proxy(self.context.sync.proxy)
        self.start_network_watchdog()
예제 #18
0
class BCWorkerPool(QObject):
    """A worker pool allows to process data using pyqt multithreading
    """
    __MAP_MODE_OFF = 0
    __MAP_MODE_ALL = 1
    __MAP_MODE_NONONE = 2
    __MAP_MODE_AGGREGATE = 3

    def __init__(self, maxWorkerCount=None):
        super(BCWorkerPool, self).__init__()
        self.__threadpool = QThreadPool()
        #self.__threadpool = QThreadPool.globalInstance()

        if isinstance(
                maxWorkerCount, int
        ) and maxWorkerCount >= 1 and maxWorkerCount <= self.__threadpool.maxThreadCount(
        ):
            self.__maxWorkerCount = maxWorkerCount
        else:
            self.__maxWorkerCount = self.__threadpool.maxThreadCount()

        self.__current = 0
        self.__locked = 0
        self.__started = 0
        self.__allStarted = False
        self.__size = 0
        self.__nbWorkers = self.__threadpool.maxThreadCount()
        self.__workers = []
        self.__stopProcess = False
        self.__dataList = []
        self.__results = []
        self.__mapResults = BCWorkerPool.__MAP_MODE_OFF

        self.signals = BCWorkerSignals()

    def __lock(self):
        """Lock ensure that no worker will try to access to same item"""
        while self.__locked:
            BCTimer.sleep(1)
        self.__locked = True

    def __unlock(self):
        self.__locked = False

    def __onProcessed(self, processedNfo):
        """an item has been processed"""
        if self.__mapResults != BCWorkerPool.__MAP_MODE_OFF:
            index, item = processedNfo
            if self.__mapResults == BCWorkerPool.__MAP_MODE_ALL and not index is None:
                self.__results[index] = item
            elif self.__mapResults == BCWorkerPool.__MAP_MODE_NONONE and not item is None:
                self.__results.append(item)
            elif self.__mapResults == BCWorkerPool.__MAP_MODE_AGGREGATE and isinstance(
                    item, dict):
                for key in item:
                    self.__results[key] += item[key]
        self.signals.processed.emit(processedNfo)

    def __onFinished(self):
        """Do something.. ?"""
        self.__started -= 1
        if self.__allStarted and self.__started == 0:
            self.__workers.clear()
            self.signals.finished.emit()

    def stopProcessingAsked(self):
        return self.__stopProcess

    def getNext(self):
        """Get next item to process"""
        self.__lock()

        if self.__current is None:
            self.__unlock()
            return (None, None)
        returnedIndex = self.__current
        self.__current += 1

        if self.__current >= self.__size:
            self.__current = None

        self.__unlock()
        return (returnedIndex, self.__dataList[returnedIndex])

    def startProcessing(self, dataList, callback, *callbackArgv):
        """Start all current thread execution"""
        # ensure to stop current processing before creating a new one
        if self.__stopProcess == True:
            return
        else:
            self.stopProcessing()

        if not (isinstance(dataList, list) or isinstance(dataList, set)
                or isinstance(dataList, tuple)):
            raise EInvalidType('Given `dataList` must be a list')

        self.__size = len(dataList)

        if self.__size == 0:
            return

        self.__dataList = [v for v in dataList]

        if self.__mapResults == BCWorkerPool.__MAP_MODE_ALL:
            self.__results = [None] * self.__size
        elif self.__mapResults != BCWorkerPool.__MAP_MODE_AGGREGATE:
            # already initialised by aggregate() method
            self.__results = []

        # if number of items to process is less than number of possible threads,
        # don't use all threads
        self.__nbWorkers = min(self.__size, self.__maxWorkerCount)

        self.__started = 0
        self.__current = 0
        self.__workers.clear()

        # for test, force to 1 thread only
        #self.__nbWorkers = 1

        self.__allStarted = False
        for index in range(self.__nbWorkers):
            self.__workers.append(BCWorker(self, callback, *callbackArgv))
            self.__workers[index].signals.processed.connect(self.__onProcessed)
            self.__workers[index].signals.finished.connect(self.__onFinished)
            self.__workers[index].setAutoDelete(True)
            self.__started += 1
            self.__threadpool.start(self.__workers[index])

        self.__allStarted = True
        if self.__started == 0:
            self.__workers.clear()
            self.signals.finished.emit()
            self.__allStarted = False

    def stopProcessing(self):
        """Stop all current thread execution"""
        if self.__started > 0:
            self.__stopProcess = True
            while self.__started > 0:
                # check every 5ms if all thread are finished
                BCTimer.sleep(5)
            self.__stopProcess = False

    def waitProcessed(self):
        """Wait until all items in pool are processed"""
        # why self.__threadpool.waitForDone() don't work??
        while self.__started > 0:
            BCTimer.sleep(1)

    def map(self, dataList, callback, *callbackArgv):
        """Apply `callback` function to each item `datalist` list and return a list

        Similar to python map() method, but for Qt threads
            https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool.map
        """
        if len(dataList) == 0:
            return []

        self.__mapResults = BCWorkerPool.__MAP_MODE_ALL
        self.startProcessing(dataList, callback, *callbackArgv)
        self.waitProcessed()
        self.__mapResults = BCWorkerPool.__MAP_MODE_OFF
        return self.__results

    def mapNoNone(self, dataList, callback, *callbackArgv):
        """Apply `callback` function to each item `datalist` list and return a list
        If callback return None value, value is not added to result

        Similar to python map() method, but for Qt threads
            https://docs.python.org/3/library/multiprocessing.html#multiprocessing.pool.Pool.map
        """
        if len(dataList) == 0:
            return []

        self.__mapResults = BCWorkerPool.__MAP_MODE_NONONE
        self.startProcessing(dataList, callback, *callbackArgv)
        self.waitProcessed()
        self.__mapResults = BCWorkerPool.__MAP_MODE_OFF
        return self.__results

    def aggregate(self, dataList, returnedStruct, callback, *callbackArgv):
        """Apply `callback` function to each item `datalist` list and return a dictionary with aggregated
        results
        """
        if len(dataList) == 0:
            return returnedStruct

        self.__mapResults = BCWorkerPool.__MAP_MODE_AGGREGATE
        self.__results = returnedStruct
        self.startProcessing(dataList, callback, *callbackArgv)
        self.waitProcessed()
        self.__mapResults = BCWorkerPool.__MAP_MODE_OFF
        return self.__results
예제 #19
0
class WizardUIClass(Ui_Wizard):
    def __init__(self):
        '''Initialize the super class
        '''
        super().__init__()
        self.inputFileHandler = FileHandler()
        self.outputFileHandler = FileHandler()
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.updateProgressBar)
        self.threadpool = QThreadPool()
        self.failed = False
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    def setupUi(self, W):
        ''' Setup the UI of the super class, and add here code
        that relates to the way we want our UI to operate.
        '''
        super().setupUi(W)

        # Register mandatory fields
        self.wizardPage1.registerField("lineEdit_ApiKey*",
                                       self.lineEdit_ApiKey)
        self.wizardPage1.registerField("lineEdit_InputFilePath*",
                                       self.lineEdit_InputFilePath)
        self.wizardPage1.registerField("lineEdit_OutputFilePath*",
                                       self.lineEdit_OutputFilePath)
        self.wizardPage2.registerField(
            "progressBar*",
            self.progressBar,
            property="value",
            changedSignal=self.progressBar.valueChanged)

        # close the lower part of the splitter to hide the
        # debug window under normal operations
        self.splitter.setSizes([300, 0])

        # Set the initial value of the progress bar
        self.progress = 0
        self.progressBar.setValue(self.progress)

    def debugPrint(self, msg):
        '''Print the message in the text edit at the bottom of the
        horizontal splitter.
        '''
        self.debugTextBrowser.append(msg)

    def refreshAll(self):
        '''
        Updates the widgets whenever an interaction happens.
        Typically some interaction takes place, the UI responds,
        and informs the model of the change.  Then this method
        is called, pulling from the model information that is
        updated in the GUI.
        '''
        self.lineEdit_InputFilePath.setText(
            self.inputFileHandler.getFileName())
        self.lineEdit_OutputFilePath.setText(
            self.outputFileHandler.getFileName())
        self.lineEdit_ReadOnlyOutPath.setText(
            self.outputFileHandler.getFileName())

    # slot
    def testKeyPressedSlot(self):
        self.debugPrint('Test Key Button Pressed')
        api_key = self.lineEdit_ApiKey.text()
        try:
            sps.spsf.createLocator(api_key)

            m = QtWidgets.QMessageBox()
            m.setWindowTitle("Valid API key")
            m.setText("API Key accepted.")
            m.setIcon(QtWidgets.QMessageBox.Information)
            m.setStandardButtons(QtWidgets.QMessageBox.Ok)
            ret = m.exec_()
            self.debugPrint("Valid API Key")
        except:
            m = QtWidgets.QMessageBox()
            m.setWindowTitle("Invalid API key")
            m.setText("Invalid API Key!")
            m.setInformativeText(" Please check that you have entered a valid \
                                 Google Cloud Geocoding API key. For more \
                                 details, check the User Manual.")
            m.setIcon(QtWidgets.QMessageBox.Warning)
            m.setStandardButtons(QtWidgets.QMessageBox.Ok
                                 | QtWidgets.QMessageBox.Cancel)
            m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            ret = m.exec_()
            self.lineEdit_ApiKey.setText("")
            self.debugPrint("Invalid API Key")

    # slot
    def inputReturnPressedSlot(self):
        ''' Called when the user enters a string in the line edit and
        presses the ENTER key.
        '''
        self.debugPrint("RETURN key pressed in input LineEdit widget")

        fileName = self.lineEdit_InputFilePath.text()
        if self.inputFileHandler.isValid(fileName):
            try:
                self.inputFileHandler.assertFormat(fileName)
            except Exception as e:
                m = QtWidgets.QMessageBox()
                m.setWindowTitle("Error Reading File!")
                m.setText("Invalid file!")
                m.setInformativeText(str(e))
                m.setIcon(QtWidgets.QMessageBox.Warning)
                m.setStandardButtons(QtWidgets.QMessageBox.Ok
                                     | QtWidgets.QMessageBox.Cancel)
                m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
                ret = m.exec_()
                self.lineEdit_InputFilePath.setText("")
                self.refreshAll()
                self.debugPrint("Invalid file specified: " + fileName)
            else:
                self.inputFileHandler.setFileName(
                    self.lineEdit_InputFilePath.text())
                self.refreshAll()
        else:
            m = QtWidgets.QMessageBox()
            m.setWindowTitle("Error Reading File!")
            m.setText("Invalid file name!\n" + fileName)
            m.setIcon(QtWidgets.QMessageBox.Warning)
            m.setStandardButtons(QtWidgets.QMessageBox.Ok
                                 | QtWidgets.QMessageBox.Cancel)
            m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            ret = m.exec_()
            self.lineEdit_InputFilePath.setText("")
            self.refreshAll()
            self.debugPrint("Invalid file specified: " + fileName)

    # slot
    def inputBrowseSlot(self):
        ''' Called when the user presses the Browse button
        '''
        self.debugPrint("Input Browse button pressed")
        options = QtWidgets.QFileDialog.Options()
        #options |= QtWidgets.QFileDialog.DontUseNativeDialog
        fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
            None,
            "Open Placment and Student Data",
            "",
            "Excel Files (*.xlsx);;All Files (*)",
            options=options)
        if fileName:
            try:
                self.inputFileHandler.assertFormat(fileName)
            except Exception as e:
                m = QtWidgets.QMessageBox()
                m.setWindowTitle("Error Reading File!")
                m.setText("Invalid file!")
                m.setInformativeText(str(e))
                m.setIcon(QtWidgets.QMessageBox.Warning)
                m.setStandardButtons(QtWidgets.QMessageBox.Ok
                                     | QtWidgets.QMessageBox.Cancel)
                m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
                ret = m.exec_()
                self.lineEdit_InputFilePath.setText("")
                self.refreshAll()
                self.debugPrint("Invalid file specified: " + fileName)
            else:
                self.debugPrint("setting file name: " + fileName)
                self.inputFileHandler.setFileName(fileName)
                self.refreshAll()

    # slot
    def outputReturnPressedSlot(self):
        ''' Called when the user enters a string in the line edit and
        presses the ENTER key.
        '''
        self.debugPrint("RETURN key pressed in output LineEdit widget")

        fileName = self.lineEdit_InputFilePath.text()
        if self.outputFileHandler.isValid(fileName):
            self.outputFileHandler.setFileName(
                self.lineEdit_OutputFilePath.text())
            self.refreshAll()
        else:
            m = QtWidgets.QMessageBox()
            m.setWindowTitle("Error Reading File!")
            m.setText("Invalid file name!\n" + fileName)
            m.setIcon(QtWidgets.QMessageBox.Warning)
            m.setStandardButtons(QtWidgets.QMessageBox.Ok
                                 | QtWidgets.QMessageBox.Cancel)
            m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            ret = m.exec_()
            self.lineEdit_OutputFilePath.setText("")
            self.refreshAll()
            self.debugPrint("Invalid file specified: " + fileName)

    # slot
    def outputBrowseSlot(self):
        ''' Called when the user presses the Browse button
        '''
        self.debugPrint("Output Browse button pressed")
        options = QtWidgets.QFileDialog.Options()
        #options |= QtWidgets.QFileDialog.DontUseNativeDialog
        fileName, _ = QtWidgets.QFileDialog.getSaveFileName(
            None,
            "Save Destination",
            "",
            "Excel Files (*.xlsx);;All Files (*)",
            options=options)
        self.debugPrint("Chosen filename: " + fileName)
        if fileName:
            self.debugPrint("setting file name: " + fileName)
            self.outputFileHandler.setFileName(fileName, isnewfile=True)
            self.refreshAll()

    # slot
    def startSlot(self):
        ''' 
        Called when the use presses the Start button. 
        Begins the algorithm for sorting the students and updates the
        progress bar.
        '''
        input_filepath = str(self.wizardPage1.field("lineEdit_InputFilePath"))
        output_filepath = str(
            self.wizardPage1.field("lineEdit_OutputFilePath"))
        api_key = str(self.wizardPage1.field("lineEdit_ApiKey"))

        self.startButton.setText("Calculating...")
        self.startButton.setEnabled(False)

        print("Starting algorithm with " + str(input_filepath))
        self.startWorker(sps.sortPlacements, input_filepath, output_filepath,
                         api_key)
        self.timer.start(300)

    def startWorker(self, func, *args, **kwargs):
        # Pass the function to execute
        worker = Worker(
            func, *args,
            **kwargs)  # Any other args, kwargs are passed to the run function
        worker.signals.error.connect(self.algorithmErrorHandler)
        worker.signals.finished.connect(self.threadComplete)
        worker.signals.progress.connect(self.updateProgressBar)

        # Execute
        self.threadpool.start(worker)

    def algorithmErrorHandler(self, error):
        exctype, value, traceback = error
        self.timer.stop()
        self.failed = True
        m = QtWidgets.QMessageBox()
        m.setWindowTitle("Error Sorting Students!")
        m.setText("An error occured!")
        m.setInformativeText(
            "There was an error while using the data provided. " +
            "Please check the data is formatted according to " +
            "the User Manual, then try again.")
        m.setIcon(QtWidgets.QMessageBox.Critical)
        m.setStandardButtons(QtWidgets.QMessageBox.Ok
                             | QtWidgets.QMessageBox.Cancel)
        m.setDefaultButton(QtWidgets.QMessageBox.Cancel)
        ret = m.exec_()
        sys.exit()

    def threadComplete(self):
        print("THREAD COMPLETE!")

        if not self.failed:
            m = QtWidgets.QMessageBox()
            m.setWindowTitle("Sorting Complete")
            m.setText("Your data has been sorted. Click 'Next' to continue.")
            m.setIcon(QtWidgets.QMessageBox.Information)
            m.setStandardButtons(QtWidgets.QMessageBox.Ok)
            ret = m.exec_()

    def updateProgressBar(self, progress_callback=None):
        if progress_callback:
            self.progress = progress_callback
        else:
            self.progress += 1
        if self.progress >= 100:
            self.timer.stop()
        self.progressBar.setValue(self.progress)
예제 #20
0
파일: main.py 프로젝트: vespos/svd_gui
class svd_interface(pydm.Display):
    displaySignal = pyqtSignal(dict)

    def __init__(self, parent=None, args=None, macros=None):
        self.threadpool = QThreadPool(
            maxThreadCount=12)  # should be before super.__init__. Why?
        print('Threadpool with {} threads.'.format(
            self.threadpool.maxThreadCount()))

        super(svd_interface, self).__init__(parent=parent,
                                            args=args,
                                            macros=macros)

        # for l in self.__dir__():
        #     if 'waveform' in l:
        #     print(l)

        self._ana_count = 0

        # Signals for workers (multitreading)
        self.newDataSignal = WorkerSignal_ndarray()
        self.newFitSignal = WorkerSignal_dict()

        # connect stuff together
        self.waveformGraph.connect_attr('newDataSignal', self.newDataSignal)
        self.regressorWidget.connect_attr('graph', self.waveformGraph)

        # Setup the analysis timer
        self.timer = QTimer(interval=int(1 / config.RATE *
                                         1000))  # timer in ms
        self.timer.timeout.connect(self.waveformGraph.get_data)
        self.timer.start()

        # Processing
        self.newDataSignal.signal.connect(self.fit_data)
        self.newFitSignal.signal.connect(self.trigger_display)

        # Stripcharts
        self.stripchartsView.make_stripcharts(2, useRemote=False)
        self.stripcharts = Svd_stripchart(stripchartsView=self.stripchartsView)
        self.regressorWidget.newRegressorSignal.connect(
            self.stripcharts.make_ravgs)
        self.newFitSignal.signal.connect(self.stripcharts.update_ravgs)
        # self.timer.timeout.connect(self.stripchartsView.update_test)

        # Update display
        self.displaySignal.connect(self.waveformGraph.display_data_fit)
        self.displaySignal.connect(self.stripcharts.update_stripchartsView)

        return

    def ui_filename(self):
        return 'main.ui'

    def ui_filepath(self):
        return path.join(path.dirname(path.realpath(__file__)),
                         self.ui_filename())

    @pyqtSlot(np.ndarray)
    def fit_data(self, data):
        self.worker = FitWfWorker(data=data,
                                  roi=self.waveformGraph.get_roi(),
                                  regressor=self.regressorWidget.regressor,
                                  signal=self.newFitSignal)
        self.threadpool.tryStart(self.worker)
        return

    @pyqtSlot(dict)
    def trigger_display(self, data_dict):
        if self._ana_count < config.DISPLAY_RATE_RATIO:
            self._ana_count += 1
        else:
            self._ana_count = 0
            self.displaySignal.emit(data_dict)

    # def make_stripchart(self, n=0, ts_len=100, alpha=None, n_pulse=1):
    #     self.stripcharts = Svd_stripchart(
    #         n=n, ts_len=ts_len, alpha=alpha, n_pulse=n_pulse, stripchartsView=self.stripchartsView)
    #     return

    def print_time(self):
        time = QDateTime.currentDateTime()
        print(time.toString('yyyy-MM-dd hh:mm:ss dddd'))
        return


# if __name__ == '__main__':
#     app = QApplication(sys.argv)
#     thisapp = svd_interface()
#     thisapp.show()
#     sys.exit(app.exec_())
예제 #21
0
class MainPage(QMainWindow):
    def __init__(self):
        super(MainPage, self).__init__()
        loadUi('./ui/ui_mainwindow.ui', self)
        self.mainapp = MainApp()  # main.py 에서 연결
        self.mainapp.gui_framework = self
        self.threadpool = QThreadPool()
        self._stopflag = False  # main app 정지 신호
        self._exitflag = False  # main app 종료 신호
        self.EXIT_CODE_REBOOT = -123456789

        # 초기 출력
        self.print_setting()  # mainwindow 의 textBrowser_setting 에 현재 설정 출력
        self.textBrowser.append("Multithreading with maximum %d threads" %
                                self.threadpool.maxThreadCount())

        # 시그널/슬롯 생성
        self.actionSimulationSetting.triggered.connect(
            self.executeConfigPage)  # 페이지(윈도우) 연결
        self.actionRun.triggered.connect(self.run_program)  # Run mainapp
        self.actionStop.triggered.connect(self.stop_program)
        # self.actionSaveAgent.triggered.connect(self.save_agent)
        self.actionLoadAgent.triggered.connect(self.load_agent)
        self.actionLoadAni.triggered.connect(self.load_animation)
        self.actionReboot.triggered.connect(self.reboot_program)

    def closeEvent(self, event):
        reply = QMessageBox.question(
            self, "Message",
            "Are you sure you want to quit? Any unsaved work will be lost.",
            QMessageBox.Close | QMessageBox.Cancel, QMessageBox.Cancel)

        if reply == QMessageBox.Close:
            self._stopflag = True
            self._exitflag = True
            event.accept()
        else:
            event.ignore()

    def run_program(self):
        worker = Worker(self.mainapp)
        # 정지설정 False / run & 설정버튼 비활성화
        self._stopflag = False
        self.actionRun.setEnabled(False)
        self.actionSimulationSetting.setEnabled(False)
        # Execute
        self.threadpool.start(worker)
        self.write_console("Multithreading with %d of %d threads" %
                           (self.threadpool.activeThreadCount(),
                            self.threadpool.maxThreadCount()))

        # Alternative: def run_program2(self):  # 외부에서 self.actionRun.triggered.connect(self.run_program2)        #
        #     self.thread = Thread(target=self.mainapp.run_main)
        #     self.thread.daemon = True
        #     self.thread.start()

    def stop_program(self):
        self._stopflag = True
        self.actionRun.setEnabled(True)
        self.actionSimulationSetting.setEnabled(True)

    def reboot_program(self):
        reply = QMessageBox.question(
            self, "Message",
            "Are you sure you want to reboot? Any unsaved work will be lost.",
            QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel)
        if reply == QMessageBox.Ok:
            self._stopflag = True
            self._exitflag = True
            qApp.exit(self.EXIT_CODE_REBOOT)

    # def save_agent(self):
    #     if not self.mainapp.env:
    #         QMessageBox.warning(self, "Message", "Any agent/environment isn't loaded.")
    #     elif self.mainapp.agent.name == 'rl':
    #         self.mainapp.agent.save_file(self.mainapp.log_dir, self.mainapp.iter)
    #         QMessageBox.information(self, "Message", "RL agent file is saved")
    #     elif self.mainapp.agent.name == 'greedy':
    #         QMessageBox.warning(self, "Message", "Greedy agent file CANNOT be saved")

    def load_agent(self):
        options = QFileDialog.Options()
        # filter: "All Files (*)", "Python Files (*.py)", "PKL Files (*.pkl)"
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "PKL Files (*.pkl)",
            options=options)
        if fileName:
            QMessageBox.information(self, "Message",
                                    "agent file is loaded \n %s" % fileName)
            self.mainapp.agent_name = fileName
            self.print_setting()

    def load_animation(self):
        options = QFileDialog.Options()
        # filter: "All Files (*)", "Python Files (*.py)", "PKL Files (*.pkl)"
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "PKL Files (*.pkl)",
            options=options)
        if fileName:
            QMessageBox.information(
                self, "Message", "animation file is loaded \n %s" % fileName)
            with open(fileName,
                      'rb') as file:  # james.p 파일을 바이너리 읽기 모드(rb)로 열기
                ani_data = pickle.load(file)
            temp_ani = GraphicDisplay(ani_data['width'],
                                      ani_data['height'],
                                      unit_pixel=ani_data['unit'])
            temp_ani.data = ani_data['data']
            temp_ani.mainloop()

    def print_setting(self):
        self.textBrowser_setting.setText("[ Current Setting ]\n")
        if self.mainapp.agent_name.lower() in ('rl', 'reinforcement learning'):
            self.textBrowser_setting.append("Agent: Reinforcement Learning")
        elif self.mainapp.agent_name.lower() == 'greedy':
            self.textBrowser_setting.append("Agent: %s" %
                                            self.mainapp.agent_name)
        else:
            self.textBrowser_setting.append("Agent: Loaded %s" %
                                            self.mainapp.agent_name)
        self.textBrowser_setting.append("Task: %s" % self.mainapp.task)
        self.textBrowser_setting.append("Num Battery: %d" % self.mainapp.b_num)
        self.textBrowser_setting.append("Num Flight: %d" % self.mainapp.f_num)
        self.textBrowser_setting.append("Flight Time Interval: %.2f" %
                                        self.mainapp.f_interval)
        self.textBrowser_setting.append("Defense range (map width): %.2f" %
                                        self.mainapp.map_width)
        self.textBrowser_setting.append("Termination Type: %s" %
                                        str(self.mainapp.termination[0]))
        self.textBrowser_setting.append("Termination Criteria: %s" %
                                        str(self.mainapp.termination[1]))
        self.textBrowser_setting.append("Autosave cycle: %d iter" %
                                        self.mainapp.autosave_iter)

    def executeConfigPage(self):
        simconfig_page = SimconfigPage(self, self.mainapp)
        simconfig_page.exec_()

    def write_console(self, text, box='textBrowser'):
        if box == 'textBrowser_setting':
            self.textBrowser_setting.append(str(text))
            self.textBrowser_setting.moveCursor(QtGui.QTextCursor.End)
        else:
            self.textBrowser.append(str(text))
            self.textBrowser.moveCursor(QtGui.QTextCursor.End)
예제 #22
0
class MainWindow(QMainWindow):
    """ This window is for the control of the monochromator"""
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(
            *args, **kwargs)  # This runs the init method of QMainWindow

        # Load the ui.py file and prepare the UI
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # ------------------------------- initialize attribute values - ------------------------------------------------
        # These are attributes of the MainWindow class, not of the ui instance (which is an instance of Ui_MainWindow)
        # They are used as attributes of the program.
        self.mono_instance = None
        self.resource = None
        self.gr_dens = 1200
        self.backlash_compensation = True
        self.debug_mode = False
        self.select_resource_text = '----- Select Resource -----'
        self.backlash_amount = 10
        self.speed = 50
        self.initialized = False
        self.stop_scan = False
        self.zero_wavelength = 0

        # ------------------------------- Initialize GUI Object States -------------------------------------------------
        # These are methods/attributes of the ui instance. They all refer to specific objects which are part of the ui
        # e.g. buttons, spinners, comboboxes, etc.
        # self.ui.visa_resource_combobox.addItem('test')
        self.ui.backlash_checkbox.setCheckState(QtCore.Qt.Checked)
        self.ui.groove_density_combobox.setCurrentIndex(2)
        self.ui.tab_container.setCurrentIndex(0)
        self.ui.visa_resource_combobox.addItem(self.select_resource_text)
        self.ui.backlash_amount_spinner.setValue(self.backlash_amount)
        self.ui.speed_value_spinner.setValue(self.speed)
        # ------------------------------------ Run any initialization Functions ----------------------------------------

        self.check_resources()  # Find all com ports with attached resources.

        # ------------------------ MULTI-THREADING STUFF ---------------------------------------------------------------
        self.thread_pool = QThreadPool()

        print("Multithreading with maximum %d threads" %
              self.thread_pool.maxThreadCount())

    # ------------------------------------- Non Slot Method Definitions ------------------------------------------------
    def check_resources(
        self
    ):  # If this is only called once, isn't it better not to make it a function?
        rm = pyvisa.ResourceManager()
        all_resources = rm.list_resources()
        if len(all_resources) > 0:
            for ii in all_resources:
                self.ui.visa_resource_combobox.addItem(ii)
        else:
            return

    def update_wavelength(self):
        ii = 1
        while self.mono_instance.continue_updating is True:
            time.sleep(0.01)
            self.ui.current_wl_output_lineedit.setText(
                str(self.mono_instance.current_wavelength))
            ii += 1

    def check_for_status_updates(self):
        print('in the check_for_status_updates fn')
        tmp_message = ''
        ii = 1
        counter = 0
        while True:
            if tmp_message == self.mono_instance.status_message:
                counter += 1
            else:
                counter = 0

            time.sleep(0.1)
            if counter > 100:
                self.mono_instance.status_message = ''
                counter = 0

            tmp_message = self.mono_instance.status_message

            self.ui.statusbar.showMessage(tmp_message, 10000)
            ii += 1

    def initialization_tasks_thread(self):
        try:
            self.mono_instance.initialize_mono()
            self.ui.statusbar.showMessage('Setting Parameters', 5000)
            print('Initialization Success, setting parameters...')
            # self.ui.statusbar.showMessage('Mono Initialized', 5000)
            # self.mono_instance.status_message = 'Setting Speed'
            self.mono_instance.set_speed(self.speed)
            self.initialized = True
            self.mono_instance.status_message = 'Initialization Complete - Remember to Set Current Wavelength'
        except:  # Fix this to make it less broad sometime
            print(
                'Exception Occurred During Initialization - Add this error to code'
            )
            print(str(sys.exc_info()[0]))
            print(str(sys.exc_info()[1]))
            print(str(sys.exc_info()[2]))

        self.ui.current_wl_output_lineedit.setText(
            str(self.mono_instance.current_wavelength))
        print('self.mono_instance.connected: ' +
              str(self.mono_instance.connected))
        self.mono_instance.busy = False
        self.ui.statusbar.showMessage(
            'Initialization Complete - Remember to Set Home Wavelength', 5000)
        print(
            '-------------------------------------initialization Complete------------------------------------------'
        )

    def scan_worker(self, scan_points, cycles, delay):
        num_wls = len(scan_points)
        for jj in range(0, cycles):
            if self.stop_scan is True:
                break
            else:
                for ii in range(0, num_wls):
                    if self.stop_scan is True:
                        break
                    else:
                        self.ui.statusbar.showMessage(
                            'Moving to ' + str(scan_points[ii]) + ' nm', 5000)
                        self.mono_instance.go_to_wavelength(
                            scan_points[ii], self.mono_instance.speed,
                            self.backlash_amount, self.backlash_compensation)
                        self.ui.statusbar.showMessage(
                            'Pausing at ' + str(scan_points[ii]) + ' nm', 5000)
                        time.sleep(delay)

        time.sleep(0.1)  # This just felt right
        self.ui.statusbar.showMessage('Scan Complete', 5000)
        self.mono_instance.open_visa()
        self.mono_instance.current_wavelength = self.mono_instance.get_current_pos(
        )
        self.mono_instance.close_visa()
        self.ui.current_wl_output_lineedit.setText(
            str(self.mono_instance.current_wavelength))
        self.stop_scan = False
        self.mono_instance.busy = False
        print(
            '----------------------------------Scanning Complete ---------------------------------------------'
        )

    # ------------------------------------------------ HOOK UP SLOTS ---------------------------------------------------
    # SET MONO TAB -------------------------------------
    @QtCore.pyqtSlot(
    )  # It's unclear if these decorators are actually needed, I think it works without them
    def set_com_port(self):
        print(
            '-----------------------------------Set Com Port ----------------------------------------------'
        )
        self.resource = self.ui.visa_resource_combobox.currentText()
        if self.resource == self.select_resource_text:
            self.resource = None
        self.ui.statusbar.showMessage(self.resource, 2000)

    @QtCore.pyqtSlot()
    def set_groove_density(self):
        print(
            '-------------------------------------Set Groove Density-------------------------------------'
        )
        gr_dens_str = self.ui.groove_density_combobox.currentText()
        self.gr_dens = int(gr_dens_str)
        self.ui.statusbar.showMessage(
            'Groove Density set to ' + gr_dens_str + ' gr/mm', 5000)
        if isinstance(self.mono_instance, MonoDriver):
            self.mono_instance.groove_density = self.gr_dens
            self.mono_instance.get_k_number()

    @QtCore.pyqtSlot()
    def clicked_initialize_button(self):
        print(
            '-----------------------------------------Initializing-------------------------------------------------'
        )
        if isinstance(
                self.resource,
                str):  # Ideally the conditions here would verify more clearly
            self.mono_instance = MonoDriver(self.resource, self.gr_dens)
            self.mono_instance.busy = True
            self.ui.statusbar.showMessage('Initializing...')
            # If first time initializing, add an updates thread to monitor status constantly
            # This is nice in this script, but it is not exactly the best use of a thread...
            # if self.initialized is False:
            #     print('beginning constant status updates')
            #     updates_thread = Worker(self.check_for_status_updates)
            #     self.thread_pool.start(updates_thread)

            initialization_thread = Worker(self.initialization_tasks_thread)
            self.thread_pool.start(initialization_thread)

        else:
            self.mono_instance.status_message = 'INITIALIZATION FAILED - Resource Selection Failed'
            # self.ui.statusbar.showMessage('INITIALIZATION FAILED - Resource Selection Failed', 5000)
            return

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_home_button(self):
        """ This sets the position (in steps), that the monochromator considers " 0 steps ". Absolute moves are
         with respect to this position. I think it's ok if you move to a different wavelength than the "natural zero"
         i.e. the one it naturally arrives at after initialization, you just have to set the value to what wavelength
         the mono reads """
        print(
            '------------------------------------Setting Home ------------------------------------'
        )
        if self.mono_instance.busy is False:
            print('self.mono_instance.connected inside home btn: ' +
                  str(self.mono_instance.connected))
            self.zero_wavelength = self.ui.calib_wl_spinner.value()
            self.mono_instance.calibration_wavelength = self.zero_wavelength
            self.mono_instance.set_zero_position()
            self.mono_instance.current_wavelength = self.mono_instance.calibration_wavelength
            print('Home wavelength is: ' + str(self.zero_wavelength))
            self.ui.current_wl_output_lineedit.setText(
                str(self.mono_instance.current_wavelength))
            self.ui.statusbar.showMessage('Home Wavelength Set', 5000)

    @QtCore.pyqtSlot()
    def state_changed_bl_compensation(self):
        self.backlash_compensation = self.ui.backlash_checkbox.isChecked()

    @QtCore.pyqtSlot()
    def value_changed_backlash_spinner(self):
        self.backlash_amount = self.ui.backlash_amount_spinner.value()

    # SETUP TAB -------------------------------------
    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_go_to_wl_button(self):
        print(
            '------------------------------------go to wavelength--------------------------------------'
        )
        destination = self.ui.goto_wl_spinner.value()

        if self.mono_instance.busy is False:
            self.mono_instance.busy = True

            self.mono_instance.open_visa()

            worker = Worker(self.mono_instance.go_to_wavelength, destination,
                            self.mono_instance.speed, self.backlash_amount,
                            self.backlash_compensation)
            self.thread_pool.start(worker)

            time.sleep(0.2)

            self.mono_instance.continue_updating = True
            get_pos_worker = Worker(self.update_wavelength)
            self.thread_pool.start(get_pos_worker)

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_nudge_down_button(self):
        print(
            '---------------------------------------nudge down---------------------------------------------'
        )
        if self.mono_instance.busy is False:
            self.mono_instance.busy = True
            nudge_amount = self.ui.nudge_amount_spinner.value()

            nudge_thread = Worker(self.mono_instance.nudge,
                                  amount_nm=nudge_amount,
                                  higher=False)
            self.thread_pool.start(nudge_thread)

            self.ui.statusbar.showMessage(self.mono_instance.status_message,
                                          5000)
            self.ui.current_wl_output_lineedit.setText(
                str(self.mono_instance.current_wavelength))

            time.sleep(0.2)

            print('trying to update_wavelength')
            self.mono_instance.continue_updating = True
            get_pos_worker = Worker(self.update_wavelength)
            self.thread_pool.start(get_pos_worker)

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_nudge_up_button(self):
        print(
            '---------------------------------------nudge up---------------------------------------'
        )
        if self.mono_instance.busy is False:
            self.mono_instance.busy = True

            nudge_amount = self.ui.nudge_amount_spinner.value()
            nudge_thread = Worker(self.mono_instance.nudge,
                                  amount_nm=nudge_amount,
                                  higher=True)
            self.thread_pool.start(nudge_thread)

            self.ui.statusbar.showMessage(self.mono_instance.status_message,
                                          5000)
            self.ui.current_wl_output_lineedit.setText(
                str(self.mono_instance.current_wavelength))

            time.sleep(0.2)

            self.mono_instance.continue_updating = True
            get_pos_worker = Worker(self.update_wavelength)
            self.thread_pool.start(get_pos_worker)

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_stop_nudge_button(self):
        print(
            '---------------------------------------stop nudge---------------------------------------'
        )
        self.mono_instance.stop_motion_bool = True
        self.mono_instance.stop_motion()
        self.ui.current_wl_output_lineedit.setText(
            str(self.mono_instance.current_wavelength))
        self.mono_instance.busy = False

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_speed_set_button(self):
        print(
            '---------------------------------------speed set---------------------------------------'
        )
        speed = self.ui.speed_value_spinner.value()
        self.mono_instance.set_speed(speed)
        self.ui.statusbar.showMessage(self.mono_instance.status_message, 5000)

    # SCAN TAB -------------------------------------
    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_start_scan_button(self):
        print(
            '----------------------------------Start Scan--------------------------------------------'
        )
        start_wl = self.ui.scan_start_wl_spinner.value()
        stop_wl = self.ui.scan_stop_wl_spinner.value()
        step_wl = self.ui.scan_step_spinner.value()
        delay = self.ui.scan_pause_spinner.value()
        cycles = self.ui.scan_cycles_spinner.value()
        self.stop_scan = False

        scan_points, number_wavelengths = calculate_scan_points(
            start_wl, stop_wl, step_wl)
        if self.mono_instance.busy is False:
            self.mono_instance.busy = True
            worker = Worker(self.scan_worker, scan_points, cycles, delay)
            self.thread_pool.start(worker)

    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_stop_scan_button(self):
        print(
            '-------------------------------------Stop Scan------------------------------------------'
        )
        self.stop_scan = True

    # DEBUG TAB ----------------------------------
    @check_mono_instance
    @QtCore.pyqtSlot()
    def clicked_debug_write_button(self):
        print(
            '---------------------------------------debug write---------------------------------------'
        )
        string_to_write = self.ui.debug_write_str_textbox.toPlainText()
        self.mono_instance.open_visa()
        self.mono_instance.write_str(string_to_write)
        print('closing visa (debug write)')
        self.mono_instance.close_visa()
        self.ui.debug_read_textbox.setPlainText(self.mono_instance.readout)

    @QtCore.pyqtSlot()
    def state_changed_debug_checkbox(self):
        self.debug_mode = self.ui.debug_checkbox.isChecked()

        if self.debug_mode is True:
            self.ui.visa_resource_combobox.addItem('test')
            self.ui.statusbar.showMessage('Now in Debug mode', 5000)
        if self.debug_mode is False:
            test_idx = self.ui.visa_resource_combobox.findText('test')
            self.ui.visa_resource_combobox.removeItem(test_idx)
            self.ui.statusbar.showMessage('Leaving Debug Mode', 5000)
예제 #23
0
class ExampleThread(Qt.QWidget):
    def __init__(self, parent=None):
        super(ExampleThread, self).__init__(parent)

        layout = Qt.QVBoxLayout(self)
        self.lbl = Qt.QLabel("Start")
        layout.addWidget(self.lbl)
        self.btnA = Qt.QPushButton("Запустить AThread(QThread)")
        layout.addWidget(self.btnA)
        self.btnB = Qt.QPushButton("Запустить SomeObject(QObject)")
        layout.addWidget(self.btnB)
        self.btnC = Qt.QPushButton("Запустить Worker(QRunnable)")
        layout.addWidget(self.btnC)
        self.progressBar = Qt.QProgressBar()
        self.progressBar.setProperty("value", 0)
        layout.addWidget(self.progressBar)

        self.setGeometry(550, 65, 300, 300)
        self.setWindowTitle('3 разных и простых способа работы с потоками.')

        self.btnA.clicked.connect(self.using_q_thread)
        self.btnB.clicked.connect(self.using_move_to_thread)
        self.btnC.clicked.connect(self.using_q_runnable)

        self.msg = MsgBoxAThread()
        self.thread = None

        self.msgSomeObject = MsgBoxSomeObject()
        self.objThread = None

        self.counter = 0
        self.timer = Qt.QTimer()
        self.timer.setInterval(1000)
        # -------- timeout -------> def recurring_timer(self):
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

        self.threadpool = QThreadPool()
        print("Max потоков, кот. будут использоваться=`%d`" % self.threadpool.maxThreadCount())
        self.msgWorker = MsgBoxWorker()

        self.threadtest = QThread(self)
        self.idealthreadcount = self.threadtest.idealThreadCount()
        print("Ваша машина может обрабатывать `{}` потокa оптимально.".format(self.idealthreadcount))

    def recurring_timer(self):
        self.counter += 1
        self.lbl.setText("СЧЁТЧИК цикл GUI: %d" % self.counter)

    # ---- AThread(QThread) -----------#
    def using_q_thread(self):
        if self.thread is None:
            self.thread = AThread()
            self.thread.threadSignalAThread.connect(self.on_threadSignalAThread)
            self.thread.finished.connect(self.finishedAThread)
            self.thread.start()
            self.btnA.setText("Stop AThread(QThread)")
        else:
            self.thread.terminate()
            self.thread = None
            self.btnA.setText("Start AThread(QThread)")

    def finishedAThread(self):
        self.thread = None
        self.btnA.setText("Start AThread(QThread)")

    def on_threadSignalAThread(self, value):
        self.msg.label.setText(str(value))
        # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает.
        # .setVisible(true) или .show() устанавливает виджет в видимое состояние,
        # если видны все его родительские виджеты до окна.
        if not self.msg.isVisible():
            self.msg.show()

    # --END-- AThread(QThread) -------------------#

    # ---- SomeObject(QObject) -------------------#
    def using_move_to_thread(self):
        if self.objThread is None:
            self.objThread = QThread()
            self.obj = SomeObject()
            self.obj.moveToThread(self.objThread)  # Переместить в поток для выполнения

            self.obj.threadSignalSomeObject.connect(self.on_threadSignalSomeObject)
            self.obj.finishedSomeObject.connect(self.finishedSomeObject)
            self.objThread.started.connect(self.obj.long_running)
            self.objThread.start()

            self.btnB.setText("Wait SomeObject(QObject)")
            self.btnB.setEnabled(False)
        else:
            pass

    def finishedSomeObject(self):
        self.objThread.terminate()
        self.objThread.wait(1)

        self.objThread = None
        self.btnB.setEnabled(True)
        self.btnB.setText("Start SomeObject(QObject)")

    def on_threadSignalSomeObject(self, value):
        self.msgSomeObject.label.setText(str(value))
        # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает.
        if not self.msgSomeObject.isVisible():
            self.msgSomeObject.show()

    # --END-- SomeObject(QObject) -------------------#

    # ---- Worker(QRunnable) ------------------------#
    def using_q_runnable(self):
        # Передайте функцию для выполнения
        # Любые другие аргументы, kwargs передаются функции run
        worker = Worker(self.execute_this_fn)
        worker.signals.result.connect(self.print_output)
        worker.signals.finish.connect(self.thread_complete)
        worker.signals.progress.connect(self.progress_fn)
        self.threadpool.start(worker)

    def progress_fn(self, n):
        self.progressBar.setValue(n)
        self.msgWorker.label.setText(str(n))
        # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает.
        if not self.msgWorker.isVisible():
            self.msgWorker.show()

    def execute_this_fn(self, progress_callback):
        for n in range(0, 11):
            Qt.QThread.msleep(600)
            progress_callback.emit(n * 100 / 10)
        return "Готово."

    def print_output(self, s):
        print("\ndef print_output(self, s):", s)

    def thread_complete(self):
        print("\nTHREAD ЗАВЕРШЕН!, self->", self)

    # --END-- Worker QRunnable) -------------------#

    # ==============================================###
    # потоки или процессы должны быть завершены    ###
    def closeEvent(self, event):
        reply = Qt.QMessageBox.question \
            (self, 'Информация',
             "Вы уверены, что хотите закрыть приложение?",
             Qt.QMessageBox.Yes,
             Qt.QMessageBox.No)
        if reply == Qt.QMessageBox.Yes:
            if self.thread:
                self.thread.quit()
            del self.thread
            self.msg.close()

            if self.objThread:
                self.objThread.setTerminationEnabled(True)
                self.objThread.terminate()
                self.objThread.wait(1)
            self.msgSomeObject.close()

            # закрыть поток Worker(QRunnable)
            self.msgWorker.close()

            super(ExampleThread, self).closeEvent(event)
        else:
            event.ignore()
예제 #24
0
class GUI(QMainWindow, Ui_MainWindow, Ui_extras):
    def __init__(self, app):
        super(GUI, self).__init__()

        self.app = app
        self.setupUi(self)
        self.setWindowTitle("Tacotron2 + Waveglow GUI v%s" % 0.2)

        self.drawGpuSwitch(self)
        self.initWidgets(self)
        self.GpuSwitch.toggled.connect(self.set_cuda)

        self.model = None
        self.waveglow = None
        self.hparams = None
        self.current_thread = None
        self.t_1 = None

        self.TTModelCombo.currentIndexChanged.connect(
            self.set_reload_model_flag)
        self.WGModelCombo.currentIndexChanged.connect(
            self.set_reload_model_flag)
        self.TTSDialogButton.clicked.connect(self.start_synthesis)
        self.TTSSkipButton.clicked.connect(self.skip_infer_playback)

        self.logs = []
        self.logs2 = []
        self.max_log_lines = 3
        self.max_log2_lines = 100
        self.TTmodel_dir = []  # Stores list of paths
        self.WGmodel_dir = []
        self.reload_model_flag = True

        # Because of bug in streamelements timestamp filter, need 2 variables for previous time
        self.startup_time = datetime.datetime.utcnow().isoformat()
        #self.startup_time = '0' # For debugging
        self.prev_time = datetime.datetime.utcnow().isoformat()
        #self.prev_time = '0' # for debugging
        self.offset = 0

        self.ClientSkipBtn.clicked.connect(self.skip_wav)
        self.channel_id = ''
        self.client_flag = False
        self.LoadTTButton.clicked.connect(self.add_TTmodel_path)
        self.LoadWGButton.clicked.connect(self.add_WGmodel_path)
        self.update_log_window("Begin by loading a model")
        pygame.mixer.quit()
        pygame.mixer.init(frequency=22050, size=-16, channels=1)
        self.channel = pygame.mixer.Channel(0)

        self.ClientStartBtn.clicked.connect(self.start)
        self.ClientStopBtn.clicked.connect(self.stop)
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())
        self.signals = GUISignals()
        self.signals.progress.connect(self.update_log_bar)
        self.signals.elapsed.connect(self.on_elapsed)

        self.se_opts = {
            'approve only': 2,
            'block large numbers': 0,
            'read dono amount': 2,
        }

        # Callback functions
        self.fns = {
            'GUI: start of polling loop': self.fns_gui_startpolling,
            'GUI: end of polling loop': self.fns_gui_endpolling,
            'Wav: playback': self.fns_wav_playback,
            'Var: offset': self.fns_var_offset,
            'Var: prev_time': self.fns_var_prevtime,
            'GUI: progress bar 2 text': self.fns_gui_pbtext
        }

        self.OptLimitCpuBtn.stateChanged.connect(self.toggle_cpu_limit)
        self.OptLimitCpuCombo.currentIndexChanged.connect(
            self.change_cpu_limit)
        self.OptApproveDonoBtn.stateChanged.connect(self.toggle_approve_dono)
        self.OptBlockNumberBtn.stateChanged.connect(self.toggle_block_number)
        self.OptDonoNameAmountBtn.stateChanged.connect(self.toggle_dono_amount)
        self.py_opts = {
            'cpu limit': None,
        }

    @pyqtSlot(int)
    def toggle_cpu_limit(self, state):
        self.label_10.setEnabled(state)
        self.OptLimitCpuCombo.setEnabled(state)

    @pyqtSlot(int)
    def change_cpu_limit(self, indx):
        num_thread = indx + 1
        torch.set_num_threads(num_thread)
        self.py_opts['cpu limit'] = num_thread
        os.environ['OMP_NUM_THREADS'] = str(num_thread)

    @pyqtSlot(int)
    def toggle_approve_dono(self, state):
        self.se_opts['approve only'] = state

    @pyqtSlot(int)
    def toggle_block_number(self, state):
        self.se_opts['block large numbers'] = state

    @pyqtSlot(int)
    def toggle_dono_amount(self, state):
        self.se_opts['read dono amount'] = state

    def fns_gui_startpolling(self, arg=None):
        self.ClientStartBtn.setDisabled(True)
        self.ClientStopBtn.setEnabled(True)
        self.ClientSkipBtn.setEnabled(True)
        self.tab.setDisabled(True)
        self.ClientAmountLine.setDisabled(True)

    def fns_gui_endpolling(self, arg=None):
        self.update_log_bar2(0)
        self.progressBar2Label.setText('')
        self.ClientStartBtn.setEnabled(True)
        self.ClientStopBtn.setDisabled(True)
        self.ClientSkipBtn.setDisabled(True)
        self.tab.setEnabled(True)
        self.ClientAmountLine.setEnabled(True)

    def fns_wav_playback(self, wav):
        if self.tabWidget.currentIndex() == 0:
            self.TTSSkipButton.setEnabled(True)
        else:
            self.ClientSkipBtn.setEnabled(True)
        if wav.dtype != np.int16:
            # Convert from float32 or float16 to signed int16 for pygame
            wav = (wav / np.amax(wav) * 32767).astype(np.int16)
        sound = pygame.mixer.Sound(wav)
        self.channel.queue(sound)

    def fns_var_offset(self, arg):
        self.offset = arg

    def fns_var_prevtime(self, arg):
        self.prev_time = arg

    def fns_gui_pbtext(self, tup):
        current, total = tup
        self.progressBar2Label.setText('{}/{}'.format(current, total))

    @pyqtSlot(tuple)
    def on_fncallback(self, tup):
        option, arg = tup
        self.fns[option](arg)

    @pyqtSlot(str)
    def on_textready(self, text):
        # Function to send text from client thread to GUI thread
        # Format of text: <Obj>:<Message>
        obj = text[0:4]
        msg = text[5:]
        if obj == 'Log1':
            if len(self.logs) > self.max_log_lines:
                self.logs.pop(0)
            self.logs.append(msg)
            log_text = '\n'.join(self.logs)
            self.log_window1.setText(log_text)
        if obj == 'Log2':
            if len(self.logs2) > self.max_log2_lines:
                self.logs2.pop(0)
            self.logs2.append(msg)
            log_text = '\n'.join(self.logs2)
            self.log_window2.setPlainText(log_text)
            self.log_window2.verticalScrollBar().setValue(
                self.log_window2.verticalScrollBar().maximum())
        if obj == 'Sta2':
            self.statusbar.setText(msg)

    @pyqtSlot(int)
    def update_log_bar(self, val):
        self.progressBar.setValue(val)
        #self.progressBar.setTextVisible(val != 0)

    @pyqtSlot(int)
    def update_log_bar2(self, val):
        self.progressBar2.setValue(val)
        #self.progressBar2.setTextVisible(val != 0)

    @pyqtSlot(int)
    def on_elapsed(self, val):
        if self.tabWidget.currentIndex() == 0:
            self.update_log_window('Elapsed: ' + str(val) + 's',
                                   mode='overwrite')
        else:
            pass  # No elapsed time for tab2

    def on_finished(self):
        #print("THREAD COMPLETE!")
        pass

    def on_result(self, s):
        #print(s)
        pass

    def start(self):
        # Pass the function to execute
        global _running2, _running3
        if not self.validate_se():
            return
        if self.reload_model_flag:
            self.reload_model()
            self.reload_model_flag = False
        min_donation = self.get_min_donation()
        TOKEN = self.get_token()
        _mutex2.lock()
        _running2 = True
        _mutex2.unlock()
        _mutex3.lock()
        _running3 = True
        _mutex3.unlock()
        worker = Worker(self.execute_this_fn, TOKEN, min_donation,
                        self.channel, self.se_opts, self.use_cuda, self.model,
                        self.waveglow, self.offset, self.prev_time,
                        self.startup_time)
        # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.on_result)
        worker.signals.finished.connect(self.on_finished)
        worker.signals.progress.connect(self.update_log_bar2)
        worker.signals.textready.connect(self.on_textready)
        worker.signals.elapsed.connect(self.on_elapsed)
        worker.signals.fncallback.connect(self.on_fncallback)

        # Execute
        self.threadpool.start(worker)

    def stop(self):
        global _running2, _running3
        _mutex2.lock()
        _running2 = False
        _mutex2.unlock()
        _mutex3.lock()
        _running3 = False
        _mutex3.unlock()
        self.skip_wav()

    def skip(self):
        global _running3
        _mutex3.lock()
        _running3 = False
        _mutex3.unlock()
        self.skip_wav()

    # def progress_fn(self, n):
    #     print("%d%% done" % n)

    def get_interruptflag2(self):
        _mutex3.lock()
        val = _running3
        _mutex3.unlock()
        return val

    def execute_this_fn(self, TOKEN, min_donation, channel, se_opts, use_cuda,
                        model, waveglow, offset, prev_time, startup_time,
                        progress_callback, elapsed_callback, text_ready,
                        fn_callback):
        # TODO: refactor this messy block
        fn_callback.emit(('GUI: start of polling loop', None))
        text_ready.emit("Sta2:Connecting to StreamElements")
        url = "https://api.streamelements.com/kappa/v2/tips/" + self.channel_id
        headers = {
            'accept': 'application/json',
            "Authorization": "Bearer " + TOKEN
        }
        text_ready.emit('Log2:Initializing')
        text_ready.emit('Log2:Minimum amount for TTS: ' + str(min_donation))
        while True:
            _mutex2.lock()
            if _running2 == False:
                _mutex2.unlock()
                break
            else:
                _mutex2.unlock()
            if not channel.get_busy():
                #print('Polling', datetime.datetime.utcnow().isoformat())
                text_ready.emit("Sta2:Waiting for incoming donations . . .")
                current_time = datetime.datetime.utcnow().isoformat()
                # TODO: possible bug: missed donations once time pasts midnight
                querystring = {
                    "offset": offset,
                    "limit": "1",
                    "sort": "createdAt",
                    "after": startup_time,
                    "before": current_time
                }
                response = requests.request("GET",
                                            url,
                                            headers=headers,
                                            params=querystring)
                data = json.loads(response.text)
                for dono in data['docs']:
                    text_ready.emit("Sta2:Processing donations")
                    dono_time = dono['createdAt']
                    offset += 1
                    if dono_time > prev_time:  # Str comparison
                        amount = dono['donation']['amount']  # Int
                        if float(amount) >= min_donation and dono[
                                'approved'] == 'allowed':
                            name = dono['donation']['user']['username']
                            msg = dono['donation']['message']
                            if msg.isspace(): break  # Check for empty line
                            ## TODO Allow multiple speaker in msg
                            currency = dono['donation']['currency']
                            dono_id = dono['_id']
                            text_ready.emit(
                                "Log2:\n###########################")
                            text_ready.emit("Log2:" + name + ' donated ' +
                                            currency + str(amount))
                            text_ready.emit("Log2:" + msg)
                            lines = preprocess_text(msg)
                            if se_opts[
                                    'read dono amount'] == 1:  # reads dono name and amount
                                msg = '{} donated {} {}.'.format(
                                    name, str(amount),
                                    cleaners.expand_currency(currency))
                                lines.insert(0, msg)  # Add to head to list
                            output = []
                            for count, line in enumerate(lines):
                                fn_callback.emit(
                                    ('GUI: progress bar 2 text', (count,
                                                                  len(lines))))
                                sequence = np.array(
                                    text_to_sequence(
                                        line, ['english_cleaners']))[None, :]
                                # Inference
                                device = torch.device(
                                    'cuda' if use_cuda else 'cpu')
                                sequence = torch.autograd.Variable(
                                    torch.from_numpy(sequence)).to(
                                        device).long()
                                # Decode text input
                                mel_outputs, mel_outputs_postnet, _, alignments = model.inference(
                                    sequence)
                                with torch.no_grad():
                                    audio = waveglow.infer(
                                        mel_outputs_postnet,
                                        sigma=0.666,
                                        progress_callback=progress_callback,
                                        elapsed_callback=None,
                                        get_interruptflag=self.
                                        get_interruptflag2)
                                    if type(audio) != torch.Tensor:
                                        # Catches when waveglow is interrupted and returns none
                                        break
                                    fn_callback.emit(
                                        ('GUI: progress bar 2 text',
                                         (count + 1, len(lines))))
                                    wav = audio[0].data.cpu().numpy()
                                output.append(wav)
                            _mutex3.lock()
                            if _running3 == True:
                                _mutex3.unlock()
                                outwav = np.concatenate(output)
                                # Playback
                                fn_callback.emit(('Wav: playback', outwav))
                            else:
                                _mutex3.unlock()
                            prev_time = dono_time  # Increment time
            time.sleep(0.5)
        fn_callback.emit(('GUI: end of polling loop', None))
        text_ready.emit('Log2:\nDisconnected')
        text_ready.emit('Sta2:Ready')
        fn_callback.emit(('Var: offset', offset))
        fn_callback.emit(('Var: prev_time', prev_time))
        return  #'Return value of execute_this_fn'

    def set_reload_model_flag(self):
        self.reload_model_flag = True

    def set_cuda(self):
        self.use_cuda = self.GpuSwitch.isChecked()
        self.reload_model_flag = True

    def startup_update(self):
        if not self.tab_2.isEnabled():
            self.tab_2.setEnabled(True)
        if not self.TTSDialogButton.isEnabled():
            self.TTSDialogButton.setEnabled(True)

    def add_TTmodel_path(self):
        fpath = str(
            QFileDialog.getOpenFileName(self,
                                        'Select Tacotron2 model',
                                        filter='*.pt')[0])
        if not fpath:  # If no folder selected
            return
        if fpath not in self.TTmodel_dir:
            head, tail = os.path.split(
                fpath)  # Split into parent and child dir
            self.TTmodel_dir.append(fpath)  # Save full path
            self.populate_modelcombo(tail, self.TTModelCombo)
            self.update_log_window("Added Tacotron 2 model: " + tail)
            if self.WGModelCombo.count() > 0:
                self.startup_update()

    def add_WGmodel_path(self):
        fpath = str(
            QFileDialog.getOpenFileName(self,
                                        'Select Waveglow model',
                                        filter='*.pt')[0])
        if not fpath:  # If no folder selected
            return
        if fpath not in self.WGmodel_dir:
            head, tail = os.path.split(
                fpath)  # Split into parent and child dir
            self.WGmodel_dir.append(fpath)  # Save full path
            self.populate_modelcombo(tail, self.WGModelCombo)
            self.update_log_window("Added Waveglow model: " + tail)
            if self.TTModelCombo.count() > 0:
                self.startup_update()

    def populate_modelcombo(self, item, combobox):
        combobox.addItem(item)
        combobox.setCurrentIndex(combobox.count() - 1)
        if not combobox.isEnabled():
            combobox.setEnabled(True)

    def get_current_TTmodel_dir(self):
        return self.TTmodel_dir[self.TTModelCombo.currentIndex()]

    def get_current_WGmodel_dir(self):
        return self.WGmodel_dir[self.WGModelCombo.currentIndex()]

    def get_current_TTmodel_fname(self):
        return self.TTModelCombo.currentText()

    def get_current_WGmodel_fname(self):
        return self.WGModelCombo.currentText()

    def update_log_window(self, line, mode="newline"):
        if mode == "newline" or not self.logs:
            self.logs.append(line)
            if len(self.logs) > self.max_log_lines:
                del self.logs[0]
        elif mode == "append":
            self.logs[-1] += line
        elif mode == "overwrite":
            self.logs[-1] = line
        elif mode == "clear":
            self.logs = [line]
        log_text = '\n'.join(self.logs)

        self.log_window1.setText(log_text)
        #self.app.processEvents()

    def playback_wav(self, wav):
        #if self.tabWidget.currentIndex()==0:
        #    self.TTSSkipButton.setEnabled(True)
        #else:
        #    self.ClientSkipBtn.setEnabled(True)
        if self.tabWidget.currentIndex() == 1:
            self.ClientSkipBtn.setEnabled(True)
        if wav.dtype != np.int16:
            # Convert from float32 or float16 to signed int16 for pygame
            wav = (wav / np.amax(wav) * 32767).astype(np.int16)
        sound = pygame.mixer.Sound(wav)
        self.channel.queue(sound)
        # TODO Disable skip btn on playback end

    def skip_wav(self):
        if self.channel.get_busy():
            self.channel.stop()
        self.ClientSkipBtn.setDisabled(True)

    def skip_infer_playback(self):
        global _running1
        if self.channel.get_busy():
            self.channel.stop()
        _mutex1.lock()  # We could also use a signal/slot mechanism
        if _running1:
            self.progressBarLabel.setText('Interrupting...')
            _running1 = False  # instead of mutex since inference is on QThread
        _mutex1.unlock()
        self.TTSSkipButton.setDisabled(True)

    def reload_model(self):
        TTmodel_fpath = self.get_current_TTmodel_dir()
        WGmodel_fpath = self.get_current_WGmodel_dir()
        # Setup hparams
        self.hparams = create_hparams()
        self.hparams.sampling_rate = 22050
        # Load Tacotron 2 from checkpoint
        self.model = load_model(self.hparams, self.use_cuda)
        device = torch.device('cuda' if self.use_cuda else 'cpu')
        self.model.load_state_dict(
            torch.load(TTmodel_fpath, map_location=device)['state_dict'])
        if self.use_cuda:
            _ = self.model.cuda().eval().half()
        else:
            _ = self.model.eval()
        #  Load WaveGlow for mel2audio synthesis and denoiser
        self.waveglow = torch.load(WGmodel_fpath, map_location=device)['model']
        self.waveglow.use_cuda = self.use_cuda
        if self.use_cuda:
            self.waveglow.cuda().eval().half()
        else:
            self.waveglow.eval()
        for k in self.waveglow.convinv:
            k.float()
        #denoiser = Denoiser(waveglow,use_cuda=self.use_cuda)

    def start_synthesis(self):
        # Runs in main gui thread. Synthesize blocks gui.
        # Can update gui directly in this function.
        text = self.TTSTextEdit.toPlainText()
        if text.isspace(): return
        global _running1
        self.t_1 = time.time()
        self.TTSDialogButton.setDisabled(True)
        self.TTModelCombo.setDisabled(True)
        self.WGModelCombo.setDisabled(True)
        self.TTSTextEdit.setDisabled(True)
        self.LoadTTButton.setDisabled(True)
        self.LoadWGButton.setDisabled(True)
        self.TTSSkipButton.setEnabled(True)
        self.tab_2.setDisabled(True)
        self.update_log_bar(0)
        self.update_log_window('Initializing', 'clear')
        self.update_status_bar("Creating voice")
        # We use a signal callback here to stick to the same params type in synthesize.py
        if self.reload_model_flag:
            self.reload_model()
            self.reload_model_flag = False
        # Prepare text input
        _mutex1.lock()
        _running1 = True
        _mutex1.unlock()
        self.current_thread = inferThread(text,
                                          self.use_cuda,
                                          self.model,
                                          self.waveglow,
                                          self.signals.progress,
                                          None,
                                          self.t_1,
                                          parent=self)
        self.current_thread.audioSignal.connect(self.on_inferThread_complete)
        self.current_thread.timeElapsed.connect(self.on_elapsed)
        self.current_thread.iterSignal.connect(self.on_itersignal)
        self.current_thread.interruptSignal.connect(self.on_interrupt)

    @pyqtSlot(np.ndarray)
    def on_inferThread_complete(self, wav):
        global _running1
        _mutex1.lock()
        _running1 = False
        _mutex1.unlock()
        #audio_denoised = denoiser(audio, strength=0.01)[:, 0]
        #wav = audio_denoised.cpu().numpy()
        self.playback_wav(wav)
        self.TTSDialogButton.setEnabled(True)
        self.TTModelCombo.setEnabled(True)
        self.WGModelCombo.setEnabled(True)
        self.TTSTextEdit.setEnabled(True)
        self.LoadTTButton.setEnabled(True)
        self.LoadWGButton.setEnabled(True)
        self.tab_2.setEnabled(True)
        elapsed = (time.time() - self.t_1)
        wav_length = (len(wav) / self.hparams.sampling_rate)
        rtf = elapsed / wav_length
        line = 'Generated {:.1f}s of audio in {:.1f}s ({:.2f} real-time factor)'.format(
            wav_length, elapsed, rtf)
        self.update_log_window(line, 'overwrite')
        tps = elapsed / len(wav)
        print(" > Run-time: {}".format(elapsed))
        print(" > Real-time factor: {}".format(rtf))
        print(" > Time per step: {}".format(tps))
        self.update_status_bar("Ready")

        # TODO get pygame mixer callback on end or use sounddevice

    @pyqtSlot(tuple)
    def on_itersignal(self, tup):
        current, total = tup
        self.progressBarLabel.setText('{}/{}'.format(current, total))

    @pyqtSlot()
    def on_interrupt(self):
        # Reenable buttons
        self.TTSDialogButton.setEnabled(True)
        self.TTModelCombo.setEnabled(True)
        self.WGModelCombo.setEnabled(True)
        self.TTSTextEdit.setEnabled(True)
        self.LoadTTButton.setEnabled(True)
        self.LoadWGButton.setEnabled(True)
        self.tab_2.setEnabled(True)
        # Refresh progress bar
        self.update_log_bar(0)
        self.progressBarLabel.setText('')
        # Write to log window
        self.update_log_window('Interrupted', 'overwrite')
        # Write to status bar
        self.update_status_bar("Ready")

    def update_log_window_2(self, line, mode="newline"):
        if mode == "newline" or not self.logs2:
            self.logs2.append(line)
        elif mode == "append":
            self.logs2[-1] += line
        elif mode == "overwrite":
            self.logs2[-1] = line
        log_text = '\n'.join(self.logs2)

        self.log_window2.setPlainText(log_text)
        self.log_window2.verticalScrollBar().setValue(
            self.log_window2.verticalScrollBar().maximum())
        self.app.processEvents()

    def update_status_bar(self, line):
        self.statusbar.setText(line)
        #self.app.processEvents()

    def get_token(self):
        TOKEN = ''.join(self.APIKeyLine.text().split())
        return TOKEN
        #tokenobj = TOKEN()
        #return tokenobj.token

    def set_client_flag(self, val):
        self.client_flag = val

    def validate_se(self):
        # Connect to streamelement and saves channel id
        # return true if chn id and token returns valid
        # Test Channel ID
        self.update_status_bar("Validating StreamElements")
        CHANNEL_NAME = ''.join(self.ChannelName.text().split())
        url = "https://api.streamelements.com/kappa/v2/channels/" + CHANNEL_NAME
        response = requests.request("GET",
                                    url,
                                    headers={'accept': 'application/json'})
        if response.status_code == 200:
            # Test JWT Token
            self.channel_id = json.loads(response.text)['_id']
            url = "https://api.streamelements.com/kappa/v2/tips/" + self.channel_id
            querystring = {
                "offset": "0",
                "limit": "10",
                "sort": "createdAt",
                "after": "0",
                "before": "0"
            }
            TOKEN = self.get_token()
            headers = {
                'accept': 'application/json',
                "Authorization": "Bearer " + TOKEN
            }
            response2 = requests.request("GET",
                                         url,
                                         headers=headers,
                                         params=querystring)
            if response2.status_code == 200:
                self.update_log_window_2("\nConnected to " + CHANNEL_NAME)
                self.set_client_flag(True)
                return True
            else:
                self.update_log_window_2("\nError: Double check your token")
                self.update_status_bar("Invalid StreamElements")
                print(response2.text)
        else:
            self.update_log_window_2("\nError: Double check your channel name")
            self.update_status_bar("Invalid StreamElements")
            print(response.text)

        return False

    def get_min_donation(self):
        return float(self.ClientAmountLine.value())
예제 #25
0
class MS257_TEST_dialog(QDialog):
	
	def __init__(self, parent, inst_list):
		super().__init__(parent)
		
		# constants
		self.inst_list = inst_list
		
		# Initial read of the config file
		self.config = configparser.ConfigParser()
		
		try:
			self.config.read('config.ini')
			self.last_used_scan = self.config.get('LastScan','last_used_scan')
			
			self.grating = self.config.get(self.last_used_scan,'grating')
			self.unit_str = self.config.get(self.last_used_scan,'unit')
			self.shutter_str = self.config.get(self.last_used_scan,'shutter')
			self.ms257inport_str=self.config.get("Instruments",'ms257inport').strip().split(',')[0]
			self.ms257outport_str=self.config.get("Instruments",'ms257outport').strip().split(',')[0]
		except configparser.NoOptionError as e:
			QMessageBox.critical(self, 'Message',''.join(["Main FAULT while reading the config.ini file\n",str(e)]))
			raise
		
		self.setupUi()
		
		# close both MS257 serial ports if open
		if self.inst_list.get("MS257_in"):
			if self.inst_list.get("MS257_in").is_open():
				self.inst_list.get("MS257_in").close()
		self.inst_list.pop('MS257_in', None)
		
		if self.inst_list.get("MS257_out"):
			if self.inst_list.get("MS257_out").is_open():
				self.inst_list.get("MS257_out").close()
		self.inst_list.pop('MS257_out', None)
		
	def setupUi(self):
		self.serialport = QLabel("Serial port (input)",self)
		
		self.combo1 = QComboBox(self)
		mylist1=[self.ms257inport_str ,self.ms257outport_str]
		self.ms257port_str=self.ms257inport_str
		self.combo1.addItems(mylist1)
		self.combo1.setCurrentIndex(mylist1.index(self.ms257inport_str))
		self.combo1.setFixedWidth(70)
		self.combo1.setEditable(True)
		
		grat_lbl = QLabel("Grating",self)
		grat_lbl.setFixedWidth(150)
		self.combo0 = QComboBox(self)
		mylist0=["0","1","2","3","4","home"]
		self.combo0.addItems(mylist0)
		self.combo0.setCurrentIndex(mylist0.index(self.grating))
		self.combo0.setFixedWidth(70)
		
		setUnits_lbl = QLabel("Set unit",self)
		setUnits_lbl.setFixedWidth(150)
		self.combo2 = QComboBox(self)
		self.mylist2=["nm","um","wn"]
		self.combo2.addItems(self.mylist2)
		self.combo2.setCurrentIndex(self.mylist2.index(self.unit_str))
		self.combo2.setFixedWidth(70)
		
		setShutter_lbl = QLabel("Set shutter",self)
		setShutter_lbl.setFixedWidth(150)
		self.combo3 = QComboBox(self)
		self.mylist3=["on","off", " "]
		self.combo3.addItems(self.mylist3)
		self.combo3.setCurrentIndex(self.mylist3.index(" "))
		self.combo3.setFixedWidth(70)
		
		self.goWLButton = QPushButton("Go to wavelength",self)
		self.goWLButton.setFixedWidth(150)
		self.goWLButtonEdit = QLineEdit("",self)
		self.goWLButtonEdit.setFixedWidth(70)
		
		self.goPosButton = QPushButton("Go to position",self)
		self.goPosButton.setFixedWidth(150)
		self.goPosButtonEdit = QLineEdit("",self)
		self.goPosButtonEdit.setFixedWidth(70)
		
		self.clearButton = QPushButton("Clear",self)
		#self.clearButton.setFixedWidth(200)
		##############################################
		
		g0_1 = QGridLayout()
		g0_1.addWidget(self.serialport,0,0)
		g0_1.addWidget(self.combo1,0,1)
		g0_1.addWidget(grat_lbl,1,0)
		g0_1.addWidget(self.combo0,1,1)
		g0_1.addWidget(setUnits_lbl,2,0)
		g0_1.addWidget(self.combo2,2,1)
		g0_1.addWidget(setShutter_lbl,3,0)
		g0_1.addWidget(self.combo3,3,1)
		g0_1.addWidget(self.goWLButton,4,0)
		g0_1.addWidget(self.goWLButtonEdit,4,1)
		g0_1.addWidget(self.goPosButton,5,0)
		g0_1.addWidget(self.goPosButtonEdit,5,1)
		g0_1.addWidget(self.clearButton,6,0,1,2)
		
		##############################################
		
		# set graph  and toolbar to a new vertical group vcan
		self.pw1 = pg.PlotWidget()
		
		##############################################
		
		# create table
		self.tableWidget = self.createTable()

		##############################################
		
		# SET ALL VERTICAL COLUMNS TOGETHER
		hbox = QHBoxLayout()
		hbox.addLayout(g0_1)
		hbox.addWidget(self.tableWidget)
		
		vbox = QVBoxLayout()
		vbox.addLayout(hbox)
		vbox.addWidget(self.pw1)
		
		self.threadpool = QThreadPool()
		print("Multithreading in the MS257 dialog with maximum %d threads" % self.threadpool.maxThreadCount())
		self.isRunning=False
		
		self.setLayout(vbox)
		self.setWindowTitle("Test MS257 monochromator")
		
		# PLOT 2 settings
		# create plot and add it to the figure canvas
		self.p1 = self.pw1.plotItem
		self.curve1=self.p1.plot(pen='w')
		# create plot and add it to the figure
		self.p0_1 = pg.ViewBox()
		self.curve2=pg.PlotCurveItem(pen='r')
		self.p0_1.addItem(self.curve2)
		# connect respective axes to the plot 
		#self.p1.showAxis('left')
		self.p1.getAxis('left').setLabel("Wavelength", units='m', color='yellow')
		self.p1.showAxis('right')
		self.p1.getAxis('right').setLabel("Position", units="", color='red')
		self.p1.scene().addItem(self.p0_1)
		self.p1.getAxis('right').linkToView(self.p0_1)
		self.p0_1.setXLink(self.p1)
		
		self.p1.getAxis('bottom').setLabel("Point no.", units="", color='yellow')
		# Use automatic downsampling and clipping to reduce the drawing load
		self.pw1.setDownsampling(mode='peak')
		self.pw1.setClipToView(True)
		
		# Initialize and set titles and axis names for both plots
		self.clear_vars_graphs()
		self.combo0.activated[str].connect(self.onActivated0)
		self.combo1.activated[str].connect(self.onActivated1)
		self.combo2.activated[str].connect(self.onActivated2)
		self.combo3.activated[str].connect(self.onActivated3)
		
		# run or cancel the main script
		self.clearButton.clicked.connect(self.clear_vars_graphs)
		self.clearButton.setEnabled(False)
		
		self.goPosButton.clicked.connect(self.set_runPosWl)
		self.goWLButton.clicked.connect(self.set_runPosWl)
	
	
	def is_number(self,s):
		try:
			float(s)
			return True
		except ValueError:
			pass

		try:
			import unicodedata
			unicodedata.numeric(s)
			return True
		except (TypeError, ValueError):
			pass

		return False
	
	
	def createTable(self):
		tableWidget = QTableWidget()
 
		# set row count
		#tableWidget.setRowCount(20)
		
		# set column count
		tableWidget.setColumnCount(5)
		
		# hide grid
		tableWidget.setShowGrid(False)
		
		# hide vertical header
		vh = tableWidget.verticalHeader()
		vh.setVisible(False)
		
		# set the font
		font = QFont("Courier New", 9)
		tableWidget.setFont(font)
		tableWidget.setStyleSheet("color: blue")
		
		# place content into individual table fields
		#tableWidget.setItem(0,0, QTableWidgetItem("abe"))
		
		tableWidget.setHorizontalHeaderLabels(["Port","Grat.","Point no.","Position","Wavelength"])
		#tableWidget.setVerticalHeaderLabels(["aa","bb","cc","dd"])
		
		# set horizontal header properties
		hh = tableWidget.horizontalHeader()
		hh.setStretchLastSection(True)
        
		# set column width to fit contents
		tableWidget.resizeColumnsToContents()
		
		# enable sorting
		#tableWidget.setSortingEnabled(True)
		
		return tableWidget
	
	
	def onActivated0(self, text):
		if not hasattr(self, 'MS257'):
			try:
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo0.setCurrentIndex(self.mylist0.index(self.grating))
					return
			self.MS257.set_timeout(60)
		
		else:
			try:
				if self.MS257.is_open():
					self.MS257.close()
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo0.setCurrentIndex(self.mylist0.index(self.grating))
					return
			self.MS257.set_timeout(60)
		
		self.grating=str(text)
		self.clearButton.setEnabled(False)
		self.combo0.setEnabled(False)
		self.combo1.setEnabled(False)
		self.combo2.setEnabled(False)
		self.combo3.setEnabled(False)
		
		self.goWLButton.setEnabled(False)
		self.goWLButtonEdit.setEnabled(False)
		self.goPosButton.setEnabled(False)
		self.goPosButtonEdit.setEnabled(False)
		self.isRunning=True
		
		obj=type('obj',(object,),{ 'ms257':self.MS257, 'set_':"grating", 'val':str(text) })
		
		self.worker=MS257_Worker(obj)	
		self.worker.signals.finished.connect(self.finished)
		
		# Execute
		self.threadpool.start(self.worker)
			
			
	def onActivated1(self, text):
		
		self.ms257port_str=str(text)
		if self.ms257port_str=="COM3":
			self.serialport.setText("Serial port (output)")
			QMessageBox.warning(self, "Shutter warning", ''.join(["Shutter not available on port ", self.ms257port_str]))
			self.combo3.setEnabled(False)
		elif self.ms257port_str=="COM4":
			self.serialport.setText("Serial port (input)")
			self.combo3.setEnabled(True)
			
		print("Monochromator serial port changed to", str(text))
	
	
	def onActivated2(self, text):
		if not hasattr(self, 'MS257'):
			try:
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo2.setCurrentIndex(self.mylist2.index(self.unit_str))
					return
			self.MS257.set_timeout(60)
		
		else:
			try:
				if self.MS257.is_open():
					self.MS257.close()
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo2.setCurrentIndex(self.mylist2.index(self.unit_str))
					return
			self.MS257.set_timeout(60)
		
		self.unit_str=str(text)
		self.clearButton.setEnabled(False)
		self.combo0.setEnabled(False)
		self.combo1.setEnabled(False)
		self.combo2.setEnabled(False)
		self.combo3.setEnabled(False)
		
		self.goWLButton.setEnabled(False)
		self.goWLButtonEdit.setEnabled(False)
		self.goPosButton.setEnabled(False)
		self.goPosButtonEdit.setEnabled(False)
		self.isRunning=True
		
		obj=type('obj',(object,),{ 'ms257':self.MS257, 'set_':"unit", 'val':str(text) })
		
		self.worker=MS257_Worker(obj)	
		self.worker.signals.finished.connect(self.finished)
		
		# Execute
		self.threadpool.start(self.worker)
		
		
	def onActivated3(self, text):
		if not hasattr(self, 'MS257'):
			try:
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo3.setCurrentIndex(self.mylist3.index(self.shutter_str))
					return
			self.MS257.set_timeout(60)
		
		else:
			try:
				if self.MS257.is_open():
					self.MS257.close()
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					self.combo3.setCurrentIndex(self.mylist3.index(self.shutter_str))
					return
			self.MS257.set_timeout(60)
		
		if str(text)==" ":
			QMessageBox.warning(self, 'Message',"Set the shutter to position on or position off.")
			self.combo3.setCurrentIndex(self.mylist3.index(self.shutter_str))
			return
		
		self.shutter_str=str(text)
		self.clearButton.setEnabled(False)
		self.combo0.setEnabled(False)
		self.combo1.setEnabled(False)
		self.combo2.setEnabled(False)
		self.combo3.setEnabled(False)
		
		self.goWLButton.setEnabled(False)
		self.goWLButtonEdit.setEnabled(False)
		self.goPosButton.setEnabled(False)
		self.goPosButtonEdit.setEnabled(False)
		self.isRunning=True
		
		obj=type('obj',(object,),{ 'ms257':self.MS257, 'set_':"shutter", 'val':str(text) })
		
		self.worker=MS257_Worker(obj)	
		self.worker.signals.finished.connect(self.finished)
		
		# Execute
		self.threadpool.start(self.worker)
		
		
	def set_runPosWl(self):
		
		if not hasattr(self, 'MS257'):
			try:
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					return
			self.MS257.set_timeout(60)
		
		else:
			try:
				if self.MS257.is_open():
					self.MS257.close()
				self.MS257 = MS257.MS257(self.ms257port_str, False)
			except Exception as e:
				reply = QMessageBox.critical(self, 'MS257 TEST MODE', ''.join(["MS257 could not return valid echo signal. Check the port name and check the connection.\n",str(e),"\n\nShould the program proceeds into the TEST MODE?"]), QMessageBox.Yes | QMessageBox.No)
				if reply == QMessageBox.Yes:
					self.MS257 = MS257.MS257(self.ms257port_str, True)
				else:
					return
			self.MS257.set_timeout(60)
		
		sender=self.sender()
		
		if sender.text()=="Go to wavelength":
			set_ = "wl"
			val = str(self.goWLButtonEdit.text())
			
			if not val or not self.is_number(val):
				QMessageBox.warning(self, 'Message',"MS257 wavelength should be a numeric value")
				return
			if self.unit_str=='nm':
				if float(val)<0 or float(val)>2500:
					QMessageBox.warning(self, 'Message',"MS257 wavelength range is from 0 nm to 2500 nm")
					return
			if self.unit_str=='um':
				if float(val)<0.0 or float(val)>2.500:
					QMessageBox.warning(self, 'Message',"MS257 wavelength range is from 0 um to 2.5 um")
					return
				
		elif sender.text()=="Go to position":
			set_ = "pos"
			val = str(self.goPosButtonEdit.text())
			
			if not val or not self.is_number(val):
				QMessageBox.warning(self, 'Message',"MS257 position should be a numeric value")
				return
			
		self.clearButton.setEnabled(False)
		self.combo0.setEnabled(False)
		self.combo1.setEnabled(False)
		self.combo2.setEnabled(False)
		self.combo3.setEnabled(False)
		
		self.goWLButton.setEnabled(False)
		self.goWLButtonEdit.setEnabled(False)
		self.goPosButton.setEnabled(False)
		self.goPosButtonEdit.setEnabled(False)
		self.isRunning=True
		
		obj=type('obj',(object,),{ 'ms257':self.MS257, 'set_':set_, 'val':val })
		
		self.worker=MS257_Worker(obj)	
		self.worker.signals.update0.connect(self.update0)
		self.worker.signals.finished.connect(self.finished)

		# Execute
		self.threadpool.start(self.worker)
		
		
	def update0(self,my_obj):
		pos, wl, grat = my_obj
		self.tal+=1
		
		# set row height
		self.tableWidget.setRowCount(self.tal+1)
		self.tableWidget.setRowHeight(self.tal, 12)
		
		# add row elements
		self.tableWidget.setItem(self.tal, 0, QTableWidgetItem(self.ms257port_str))
		self.tableWidget.setItem(self.tal, 1, QTableWidgetItem(grat))
		self.tableWidget.setItem(self.tal, 2, QTableWidgetItem(str(self.tal)))
		self.tableWidget.setItem(self.tal, 3, QTableWidgetItem(str(pos)))
		self.tableWidget.setItem(self.tal, 4, QTableWidgetItem(str(wl)))
		
		self.tals.extend([ self.tal ])
		self.plot_pos_tr.extend([ pos ])
		self.plot_wl_tr.extend([ wl ])
		#self.plot_time_tr.extend([ timelist ])
		
		## Handle view resizing 
		def updateViews():
			## view has resized; update auxiliary views to match
			self.p0_1.setGeometry(self.p1.vb.sceneBoundingRect())
			#p3.setGeometry(p1.vb.sceneBoundingRect())

			## need to re-update linked axes since this was called
			## incorrectly while views had different shapes.
			## (probably this should be handled in ViewBox.resizeEvent)
			self.p0_1.linkedViewChanged(self.p1.vb, self.p0_1.XAxis)
			#p3.linkedViewChanged(p1.vb, p3.XAxis)
			
		updateViews()
		self.p1.vb.sigResized.connect(updateViews)
		self.curve1.setData(self.tals, self.plot_wl_tr)
		self.curve2.setData(self.tals, self.plot_pos_tr)
		
		
	def finished(self):
		self.isRunning=False
		self.combo0.setEnabled(True)
		self.combo1.setEnabled(True)
		self.combo2.setEnabled(True)
		self.combo3.setEnabled(True)
		
		self.goWLButton.setEnabled(True)
		self.goWLButtonEdit.setEnabled(True)
		self.goPosButton.setEnabled(True)
		self.goPosButtonEdit.setEnabled(True)
		
		self.clearButton.setEnabled(True)
		self.clearButton.setText("Clear")
		
		
	def clear_vars_graphs(self):
		self.tal=-1
		self.tals=[]
		self.all_time_tr=[]
		self.plot_pos_tr=[]
		self.plot_wl_tr=[]
		#self.plot_time_tr=[]
		self.curve1.clear()
		self.curve2.clear()
		self.tableWidget.clearContents()
		
		self.clearButton.setEnabled(False)
		self.clearButton.setText("Cleared")
		
		
	def closeEvent(self, event):
		reply = QMessageBox.question(self, 'Message', "Quit now? Changes will not be saved!", QMessageBox.Yes | QMessageBox.No)
		if reply == QMessageBox.Yes:
			if hasattr(self, 'MS257'):
				if not hasattr(self, 'worker'):
					if self.MS257.is_open():
						self.MS257.close()
				else:
					if self.isRunning:
						QMessageBox.warning(self, 'Message', "Run in progress. Cancel the scan then quit!")
						event.ignore()
						return None
					else:
						if self.MS257.is_open():
							self.MS257.close()
			event.accept()
		else:
		  event.ignore() 
class MainWindow(QWidget):
    
	def __init__(self, inList):
		super().__init__()
		self.inList = inList
		self.nameFrom = 'Folder'
		self.codec = 'utvideo'
		self.alpha = False
		self.frameRate = 24
		self.defaulStyle = ''
		
		self.okIcon = QIcon(self.style().standardIcon(QStyle.SP_CustomBase))
		self.okPix = QPixmap(self.okIcon.pixmap(QSize(13, 13)))
		self.goodIcon = QIcon(self.style().standardIcon(QStyle.SP_DialogApplyButton))
		self.goodPix = QPixmap(self.goodIcon.pixmap(QSize(13, 13)))
		self.badIcon = QIcon(self.style().standardIcon(QStyle.SP_MessageBoxCritical))
		self.badPix = QPixmap(self.badIcon.pixmap(QSize(13, 13)))
		self.processingIcon = QIcon(self.style().standardIcon(QStyle.SP_ArrowRight))
		self.processingPix = QPixmap(self.processingIcon.pixmap(QSize(13, 13)))
		self.removeIcon = QIcon(self.style().standardIcon(QStyle.SP_DockWidgetCloseButton))
		self.removePix = QPixmap(self.removeIcon.pixmap(QSize(19, 19)))
		self.folderIcon = QIcon(self.style().standardIcon(QStyle.SP_FileDialogNewFolder))
		self.folderPix = QPixmap(self.folderIcon.pixmap(QSize(19, 19)))
		
		self.pbList = []
		self.chList = []
		self.lblList = []
		self.rmbList = []
		#self.newFolders = []
		self.initUI()

	def initUI(self):
		self.resize(720, 300)
		self.setWindowTitle('FFMpeg Python Compressor')
		self.verticalLayout = QVBoxLayout(self)
		self.verticalLayout.setContentsMargins(11, 11, 11, 11)
		self.verticalLayout.setSpacing(11)
		
		#COMBOBOX LABELS
		self.gridLayoutControlls = QGridLayout()
		self.codecLabel = QLabel('Codec', self)
		self.codecLabel.setMinimumHeight(13)
		self.alphaLabel = QLabel('Alpha' , self)
		self.alphaLabel.setMinimumHeight(13)
		self.frameRateLabel = QLabel('Frame Rate' , self)
		self.frameRateLabel.setMinimumHeight(13)
		self.gridLayoutControlls.addWidget(self.codecLabel, 0, 0, 1, 1)
		self.gridLayoutControlls.addWidget(self.alphaLabel, 0, 1, 1, 1)
		self.gridLayoutControlls.addWidget(self.frameRateLabel, 0, 2, 1, 1)
		
		#COMBOBOXES AND COMPRESS BUTTON
		self.codecComboBox = QComboBox(self)
		self.codecComboBox.setMinimumSize(80,23)
		self.codecComboBox.addItem("UT Video")
		self.codecComboBox.activated[str].connect(self.chooseCodec)
		
		self.alphaComboBox = QComboBox(self)
		self.alphaComboBox.setMinimumSize(80,23)
		self.alphaComboBox.addItem("No Alpha")
		self.alphaComboBox.addItem("with Alpha")
		self.alphaComboBox.activated[str].connect(self.chooseAlpha)
		
		self.frameRateComboBox = QComboBox(self)
		self.frameRateComboBox.setMinimumSize(80,23)
		self.frameRateComboBox.addItem("23.976")
		self.frameRateComboBox.addItem("24.00")
		self.frameRateComboBox.addItem("29.97")
		self.frameRateComboBox.addItem("30.00")
		self.frameRateComboBox.setCurrentIndex(1)
		self.frameRateComboBox.activated[str].connect(self.chooseFrameRate)
		
		self.compressButton = QPushButton('Compress', self)
		self.compressButton.setMinimumSize(80,23)
		self.compressButton.clicked[bool].connect(self.compressPress)
			
		self.gridLayoutControlls.addWidget(self.codecComboBox, 1, 0, 1, 1)
		self.gridLayoutControlls.addWidget(self.alphaComboBox, 1, 1, 1, 1)
		self.gridLayoutControlls.addWidget(self.frameRateComboBox, 1, 2, 1, 1)
		self.gridLayoutControlls.addWidget(self.compressButton, 1, 3, 1, 1)
			
		#RADIO BUTTON GROUP
		self.groupBox = QButtonGroup(self)
		self.radio1 = QRadioButton('Output file name from Folder name', self)
		self.radio1.setMinimumSize(80,25)
		self.radio2 = QRadioButton('Output file name from File name', self)
		self.radio2.setMinimumSize(80,25)
		self.radio1.setChecked(True)
		self.groupBox.addButton(self.radio1,1)
		self.groupBox.addButton(self.radio2,2)
		self.groupBox.buttonClicked[int].connect(self.radioBtnState)
		
		self.gridLayoutControlls.addWidget(self.radio1, 2, 0, 1, 2)
		self.gridLayoutControlls.addWidget(self.radio2, 2, 2, 1, 2)
		
		#LINE
		self.line = QFrame(self)
		self.line.setLineWidth(2)
		self.line.setMinimumHeight(3)
		self.line.setFrameShape(QFrame.HLine)
		self.line.setFrameShadow(QFrame.Sunken)
		
		self.gridLayoutControlls.addWidget(self.line, 3, 0, 1, 4)
		
		#PROGRESS BAR 
		self.gridLayoutProgress = QGridLayout()
		self.gridLayoutProgress.setVerticalSpacing(11)
		self.gridLayoutProgress.setHorizontalSpacing(6)
		self.gridLayoutProgress.setSizeConstraint(QLayout.SetNoConstraint)
		
		self.removeGroupBox = QButtonGroup(self)
		self.addProgressBarUI(self.inList)			
		self.removeGroupBox.buttonClicked[int].connect(self.removeButtonClicked)

		#ADD MORE AREA
		self.gridLayoutAddMore = QGridLayout()
		self.gridLayoutAddMore.setContentsMargins(0, 0, 0, 0)
		
		self.dragAndDropLabel_1 = QLabel("Drag and Drop folders here", self)
		self.dragAndDropLabel_1.setMinimumSize(QSize(120, 40))
		self.dragAndDropLabel_1.setAlignment(Qt.AlignCenter)
		
		self.dragAndDropLabel_2 = QLabel("", self)
		self.dragAndDropLabel_2.setFixedSize(QSize(20, 40))
		self.dragAndDropLabel_2.setAlignment(Qt.AlignCenter)
		self.dragAndDropLabel_2.setPixmap(self.folderPix)
		
		sI = QSpacerItem(40, 40,QSizePolicy.Expanding, QSizePolicy.Minimum)
		sI2 = QSpacerItem(40, 40,QSizePolicy.Expanding, QSizePolicy.Minimum)
		
		self.gridLayoutAddMore.addItem(sI, 1, 0, 1, 1)
		self.gridLayoutAddMore.addWidget(self.dragAndDropLabel_2, 1, 1, 1, 1)
		self.gridLayoutAddMore.addWidget(self.dragAndDropLabel_1, 1, 2, 1, 1)
		self.gridLayoutAddMore.addItem(sI2, 1, 3, 1, 1)
		
		#DEBUG AREA
		self.gridLayoutDebug = QGridLayout()
		self.line_2 = QFrame(self)
		self.line_2.setLineWidth(2)
		self.line_2.setFrameShape(QFrame.HLine)
		self.line_2.setFrameShadow(QFrame.Sunken)
		
		self.exploreOutputBtn = QPushButton('Explore Output',self)
		self.exploreOutputBtn.clicked[bool].connect(self.exploreOutput)

		self.hideShowLog = QPushButton('Show Log',self)
		self.hideShowLog.setCheckable(True)
		self.hideShowLog.clicked[bool].connect(self.showDebugLog)
		#self.hideShowLog.setMinimumSize(QSize(0, 20))
		
		self.logText = QPlainTextEdit('',self)
		self.logText.setReadOnly(True)
		self.logText.hide()
		
		self.spacerItem = QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding)
		
		self.gridLayoutDebug.addWidget(self.line_2, 0, 0, 1, 1)
		self.gridLayoutDebug.addWidget(self.exploreOutputBtn, 1, 0, 1, 1)
		self.gridLayoutDebug.addWidget(self.hideShowLog, 2, 0, 1, 1)
		self.gridLayoutDebug.addWidget(self.logText, 3, 0, 1, 1)
		self.gridLayoutDebug.addItem(self.spacerItem, 4, 0, 1, 1)
		
		self.verticalLayout.addLayout(self.gridLayoutControlls)
		self.verticalLayout.addLayout(self.gridLayoutProgress)
		self.verticalLayout.addLayout(self.gridLayoutAddMore)
		self.verticalLayout.addLayout(self.gridLayoutDebug)
		
		# Enable dragging and dropping onto the GUI
		self.setAcceptDrops(True)
		
		#QtCore.QMetaObject.connectSlotsByName(self)
		self.show()
		self.setMinimumSize(self.size())
		
		self.threadpool = QThreadPool()
		self.threadpool.setMaxThreadCount(1)
		print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
    
	
	
	'''
	Progress bar populate function
	'''
	def addProgressBarUI(self, arr):
		pbCount = len(self.pbList)
		for i in range(len(arr)):
			tempCheckBox = QCheckBox(self)
			tempCheckBox.setChecked(True)
			tempCheckBox.setMinimumSize(14,21)
			
			tempRemoveButton = QPushButton(self)
			tempRemoveButton.setIcon(self.removeIcon)
			tempRemoveButton.setFlat(True)
			tempRemoveButton.setIconSize(QSize(19,19))
			tempRemoveButton.setFixedSize(QSize(19,21))
			
			
			tempPB = QProgressBar(self)
			tempPB.setMinimumSize(50,21)
			tempPB.setMinimum(0)
			tempPB.setMaximum(100)
			tempPB.setTextVisible(True)
			tempPB.setFormat(str(arr[i])+" %p%")
			tempPB.setAlignment(Qt.AlignCenter)
			tempPB.setValue(0)
			if i==0:
				self.defaulStyle = tempPB.styleSheet()
			
			tempStatusLabel = QLabel(self)			
			tempStatusLabel.setPixmap(self.okPix)
			tempStatusLabel.setMinimumSize(13,21)
			
			self.gridLayoutProgress.addWidget(tempCheckBox, pbCount+i, 0, 1, 1)
			self.gridLayoutProgress.addWidget(tempPB, pbCount+i, 1, 1, 1)
			self.gridLayoutProgress.addWidget(tempStatusLabel, pbCount+i, 2, 1, 1)
			self.gridLayoutProgress.addWidget(tempRemoveButton, pbCount+i, 3, 1, 1)
			self.removeGroupBox.addButton(tempRemoveButton, pbCount+i)
			
			self.pbList.append(tempPB)
			self.chList.append(tempCheckBox)
			self.lblList.append(tempStatusLabel)
			self.rmbList.append(tempRemoveButton)
	
		
	'''
	Drag+Drop Functions
	'''
	# The following three methods set up dragging and dropping for the app
	def dragEnterEvent(self, e):
		if e.mimeData().hasUrls:
			e.accept()
		else:
			e.ignore()

	def dragMoveEvent(self, e):
		if e.mimeData().hasUrls:
			e.accept()
		else:
			e.ignore()

	def dropEvent(self, e):
		"""
		Drop files directly onto the widget
		File locations are stored in fname
		:param e:
		:return:
		"""
		newFolders = []
		if e.mimeData().hasUrls:
			e.setDropAction(Qt.CopyAction)
			e.accept()
			# Workaround for OSx dragging and dropping
			for url in e.mimeData().urls():
				if op_sys == 'Darwin':
					#check for dir here as well
					fname = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
				else:
					fname = str(url.toLocalFile())
					if os.path.isdir(fname) == True:
						newFolders.append(fname)
					#print(fname)

			#self.fname = fname
			#print(self.fname)
			#self.load_image()
			self.addNewFolders(newFolders)
			self.inList = self.inList + newFolders
		else:
			e.ignore()
	

	def addNewFolders(self, newFolders):
		self.addProgressBarUI(newFolders)
		self.setMinimumHeight(self.height()+len(newFolders)*32)
		#self.resize(self.width(),self.height()+200)
		self.update()
		self.adjustSize()
		self.setMinimumSize(self.size())
	'''
	Button Functions
	'''
	def chooseAlpha(self, text):
		switcher={
			"No Alpha":False,
			"with Alpha":True
		}
		self.alpha = switcher.get(text,"Invalid day of week")
		#print (self.alpha)

	def chooseCodec(self, text):
		switcher={
			"UT Video":"utvideo"
		}
		self.codec =  switcher.get(text,"Invalid day of week")
		#print (self.codec)
		
	def chooseFrameRate(self, text):
		self.frameRate =  float(text)
		#print (self.frameRate)
	
	
	def currentData(self, widget):
		return widget.currentText() 

	def radioBtnState(self, text):
		switcher={
			1:'Folder',
			2:'File'
		}
		self.nameFrom = switcher.get(text,"Invalid day of week")
		#print(self.nameFrom)
	
	def removeButtonClicked(self, i):
		#print('remove trigger on id '+str(i))
		
		#self.pbList.pop(i)
		'''
		self.pbList[i].hide()
		self.chList[i].setChecked(False)
		self.chList[i].hide()
		self.lblList[i].hide()
		self.rmbList[i].hide()
		'''
		print(self.gridLayoutProgress.rowCount())
		self.pbList[i].setParent(None)
		self.chList[i].setChecked(False)
		self.chList[i].setParent(None)
		self.lblList[i].setParent(None)
		self.rmbList[i].setParent(None)
		
		self.removeGroupBox.removeButton(self.rmbList[i])

		self.gridLayoutProgress.removeWidget(self.pbList[i])
		self.gridLayoutProgress.removeWidget(self.chList[i])
		self.gridLayoutProgress.removeWidget(self.lblList[i])
		self.gridLayoutProgress.removeWidget(self.rmbList[i])
		self.gridLayoutProgress.invalidate()
		self.gridLayoutProgress = QGridLayout()
		self.gridLayoutProgress.setVerticalSpacing(11)
		self.gridLayoutProgress.setHorizontalSpacing(6)
		self.gridLayoutProgress.setSizeConstraint(QLayout.SetDefaultConstraint)
		self.verticalLayout.insertLayout(1,self.gridLayoutProgress)
		
		print(self.gridLayoutProgress.rowCount())
		'''
		print(self.pbList)
		print(self.chList)
		print(self.lblList)
		print(self.rmbList)
		'''
		
		self.pbList.pop(i)
		self.chList.pop(i)
		self.lblList.pop(i)
		self.rmbList.pop(i)
		self.inList.pop(i)		
		

		#clear the gridLayout
		for j in reversed(range(len(self.pbList))):
			self.pbList[j].setParent(None)
			self.chList[j].setParent(None)
			self.lblList[j].setParent(None)
			self.rmbList[j].setParent(None)
		
		
		#reorder the gridLayout
		for j in range(len(self.pbList)):
			self.gridLayoutProgress.addWidget(self.chList[j], j, 0, 1, 1)
			self.gridLayoutProgress.addWidget(self.pbList[j], j, 1, 1, 1)
			self.gridLayoutProgress.addWidget(self.lblList[j], j, 2, 1, 1)
			self.gridLayoutProgress.addWidget(self.rmbList[j], j, 3, 1, 1)
			self.removeGroupBox.setId(self.rmbList[j],j)

		
		
		self.setMinimumHeight(self.height()-30)
		#self.setMinimumHeight(100)
		self.adjustSize()
		self.setMinimumSize(self.size())
		print(self.gridLayoutProgress.rowCount())
		#self.correctSize()
		'''
		for j in range(len(self.removeGroupBox.buttons())):
			button = self.removeGroupBox.buttons()[j]
			#print(button)
			#print('original id '+str(self.removeGroupBox.id(button)))
			#print('new id '+str(j))
			self.removeGroupBox.setId(button,j)
		'''
	
	def correctSize(self):
			self.logText.show()
			self.gridLayoutDebug.removeItem(self.spacerItem)
			self.adjustSize()
			self.setMinimumSize(self.size())
			self.repaint()
			self.gridLayoutDebug.addItem(self.spacerItem)
			self.logText.hide()
			self.setMinimumHeight(100)
			self.adjustSize()
			self.setMinimumSize(self.size())
	
	def showDebugLog(self, bol):
		if bol:
			self.logText.show()
			self.hideShowLog.setText('Hide Log')
			self.gridLayoutDebug.removeItem(self.spacerItem)
			self.adjustSize()
			#self.resize(self.width(), self.height()+80)
			self.setMinimumSize(self.size())
		else:
			self.gridLayoutDebug.addItem(self.spacerItem)
			self.logText.hide()
			self.hideShowLog.setText('Show Log')
			self.setMinimumHeight(100)
			self.adjustSize()
			self.setMinimumSize(self.size())
			#self.resize(self.width(), 100)
			#self.setGeometry(0,0,self.width(),100)
	
	'''
	Execution Functions
	'''
	def execute_this_fn(self, path, codec, alpha, frameRate, nameFrom, i, progress_callback, errorFFMPEG_callback):
		#print(path)
		pyCompression = pyFFMEGCompress(path, codec, alpha, frameRate, nameFrom)
		ffProcess = pyCompression.ffmpegCompress()
		self.lblList[i].setPixmap(self.processingPix)
		
		#with kwargs
		kwargs = {'progress_callback':progress_callback, 'errorFFMPEG_callback':errorFFMPEG_callback}
		pyCompression.printProcess(ffProcess, **kwargs)

		return (pyCompression.debugString,pyCompression.error,i)
 
	def printOutput(self, s):
		print("Printing output "+ str(s))
		
	def threadComplete(self, r):
		#print("THREAD COMPLETE! WITH ERROR " + str(r[2]) )
		if r[1] == False:
			self.lblList[r[2]].setPixmap(self.goodPix)
			self.pbList[r[2]].setStyleSheet("QProgressBar::chunk {background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #44dd14,stop: 0.4999 #39c10f,stop: 0.5 #39c10f,stop: 1 #39c10f );border-radius: 3px; border: 1px solid #29880b;}QProgressBar{color:white}")
			self.pbList[r[2]].setValue(100)

	def errorPB(self, err):
		for i in range(len(self.pbList)):
			if self.pbList[i].format() == err:
				self.pbList[i].setValue(100)
				self.pbList[i].setStyleSheet("QProgressBar::chunk {background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #FF0350,stop: 0.4999 #FF0020,stop: 0.5 #FF0019,stop: 1 #FF0000 );border-radius: 3px; border: 1px solid #a60233;}QProgressBar{color:white}")
				self.pbList[i].setFormat(self.pbList[i].format()+" - Error")
				self.chList[i].setChecked(False)
				self.lblList[i].setPixmap(self.badPix)
				
	def resetProgressBar(self, pb, text, lbl):
		pb.setValue(0)
		pb.setFormat(text + ' %p%')
		pb.setStyleSheet(self.defaulStyle)
		lbl.setPixmap(self.okPix)
	

	def compressPress(self):
		for i in range(len(self.pbList)):				
			if self.chList[i].isChecked():
				self.resetProgressBar(self.pbList[i],self.inList[i],self.lblList[i])
				
				worker = Worker(self.execute_this_fn, self.inList[i], self.codec, self.alpha, self.frameRate, self.nameFrom, i) # Any other args, kwargs are passed to the run function
				#worker.signals.result.connect(self.printOutput)
				worker.signals.result.connect(self.logText.appendPlainText)
				worker.signals.progress.connect(self.pbList[i].setValue)
				worker.signals.errorFFMPEG.connect(self.errorPB)
				worker.signals.error.connect(self.errorPB)
				worker.signals.finished.connect(self.threadComplete)
				#worker.signals.finished.connect(self.logText.appendPlainText)
				
				# Execute
				self.threadpool.start(worker)

	def exploreOutput(self):
		FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe')
		explorePath = os.path.normpath('C:\\ExportedMOVs')
		subprocess.run([FILEBROWSER_PATH, explorePath])
예제 #27
0
class WaveformGraphWidget(QWaveformGraph, Ui_waveformGraph):
    newBkgSignal = pyqtSignal()

    def __init__(self, parent=None):
        """ Notes:
        Needs a newDataSignal to be defined from the parent using self.connect_attr
        """
        super(WaveformGraphWidget, self).__init__(
            parent=parent
        )  # passing parent here is important so that widget is properly displayed in parent widget.
        self.setupUi(self)

        try:
            self.threadpool = self.parent().threadpool
        except AttributeError:
            self.threadpool = QThreadPool(maxThreadCount=4)
            print('Threadpool with {} threads started.'.format(
                self.threadpool.maxThreadCount()))

        # epics PV setup
        self.pv = PV(config.DEFAULT_CHANNEL)
        self.channelEdit.setText(config.DEFAULT_CHANNEL)
        self.channelEdit.returnPressed.connect(self.change_pv)

        # graph (using remote lead to problems with QObjects (cant be pickled))
        self.wfPlot = pg.PlotWidget()
        self.pgLayout.addWidget(self.wfPlot)
        self.wfCurve = utils.initialize_line_plot(self.wfPlot,
                                                  color=config.COLORS[0])
        self.wfFit = utils.initialize_line_plot(self.wfPlot,
                                                color=config.COLORS[1])
        # self.view = pg.widgets.RemoteGraphicsView.RemoteGraphicsView()
        # self.wfPlot = self.view.pg.PlotItem()
        # self.pgLayout.addWidget(self.view)
        self.lr = pg.LinearRegionItem([0, 100])
        self.lr.setZValue(-10)
        self.wfPlot.addItem(self.lr)
        self.lr.sigRegionChangeFinished.connect(self.get_roi)

        # background function
        self.new_bkg()
        self.bkgEdit.returnPressed.connect(self.new_bkg)
        return

    def connect_attr(self, name, attr):
        setattr(self, name, attr)
        return

    @pyqtSlot()
    def change_pv(self):
        self.pv = PV(self.channelEdit.text())
        return

    @pyqtSlot()
    def get_roi(self):
        self.roi = np.round(self.lr.getRegion()).astype(int)
        return self.roi

    @pyqtSlot()
    def get_data(self):
        self.worker = GetWfWorker(self.pv,
                                  bkg_fun=self.bkg_fun,
                                  signal=self.newDataSignal)
        self.threadpool.tryStart(
            self.worker
        )  # skip (no queuing) if no thread available (if rate is too high)
        # self.worker.signals.signal.connect(self.display_data)
        return

    @pyqtSlot(dict)
    def display_data_fit(self, data_dict):
        data = data_dict['data']
        fit = data_dict['fit']
        # print(data.shape)
        self.wfCurve.setData(data[0], data[1])
        # self.wfPlot.plot(data[0],data[1], clear=True)
        if fit is not None:
            self.wfFit.setData(fit[0], fit[1])
        return

    @pyqtSlot()
    def new_bkg(self):
        bkg_idx = int(self.bkgEdit.text())
        if (bkg_idx <= 0) or (bkg_idx is None):
            self.bkg_fun = lambda wf: 0
            print('Background subtraction removed.')
        else:
            self.bkg_fun = lambda wf: utils.background(wf, bkg_idx=bkg_idx)
            print('Background subtraction updated.')
        self.newBkgSignal.emit()
        return
예제 #28
0
class ccbcGUI(QMainWindow, Ui_MainWindow):
    # TODO: Make generalized dictionary look up that includes exception handling

    def __init__(self, ard_dictionary, tsensor_names, psensor_names,
                 heater_names, pump_names):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.ard_dictionary = ard_dictionary
        self.tsensor_names = tsensor_names
        self.psensor_names = psensor_names
        self.heater_names = heater_names
        self.pump_names = pump_names
        self.thread = QThread()
        self.threadpool = QThreadPool()
        self.logger = Logger(self.ard_dictionary)
        self.logger_timer = QTimer()
        self.CBHeater1TSensor.addItems(tsensor_names)
        self.CBHeater2TSensor.addItems(tsensor_names)
        self.CBHeater3TSensor.addItems(tsensor_names)
        self.CBHeater1TSensor.currentIndexChanged.connect(
            self.update_heater1_tsensor)
        self.CBHeater2TSensor.currentIndexChanged.connect(
            self.update_heater2_tsensor)
        self.CBHeater3TSensor.currentIndexChanged.connect(
            self.update_heater3_tsensor)
        self.CBPump1PSensor.addItems(psensor_names)
        self.CBPump2PSensor.addItems(psensor_names)
        self.CBPump3PSensor.addItems(psensor_names)
        self.CBPump1PSensor.currentIndexChanged.connect(
            self.update_pump1_psensor)
        self.CBPump2PSensor.currentIndexChanged.connect(
            self.update_pump2_psensor)
        self.CBPump3PSensor.currentIndexChanged.connect(
            self.update_pump3_psensor)
        self.LabelHeater1TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    heater_names[0]]['tsensor_name']))
        self.LabelHeater2TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    heater_names[1]]['tsensor_name']))
        self.LabelHeater3TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    heater_names[2]]['tsensor_name']))
        self.Button_startSerial.clicked.connect(self.start_everything)
        self.ButtonUpdateHeater1Setpoints.clicked.connect(
            self.update_heater1_setpoint)
        self.ButtonUpdateHeater2Setpoints.clicked.connect(
            self.update_heater2_setpoint)
        self.ButtonUpdateHeater3Setpoints.clicked.connect(
            self.update_heater3_setpoint)
        self.ButtonUpdateHeater1MaxTemp.clicked.connect(
            self.update_heater1_maxtemp)
        self.ButtonUpdateHeater2MaxTemp.clicked.connect(
            self.update_heater2_maxtemp)
        self.ButtonUpdateHeater3MaxTemp.clicked.connect(
            self.update_heater3_maxtemp)
        self.ButtonUpdatePump1Setpoints.clicked.connect(
            self.update_pump1_setpoint)
        self.ButtonUpdatePump2Setpoints.clicked.connect(
            self.update_pump2_setpoint)
        self.ButtonUpdatePump3Setpoints.clicked.connect(
            self.update_pump3_setpoint)
        self.ButtonUpdatePump1VolCalcInputs.clicked.connect(
            self.update_pump1_vol_calc_inputs)
        self.ButtonUpdatePump2VolCalcInputs.clicked.connect(
            self.update_pump2_vol_calc_inputs)
        self.ButtonUpdatePump3VolCalcInputs.clicked.connect(
            self.update_pump3_vol_calc_inputs)
        self.update_static_labels()
        self.update_labels()
        self.label_timer = QTimer()
        self.Clock = Clock(parent=self.centralwidget)
        self.Clock.setGeometry(QtCore.QRect(840, 10, 161, 61))
        self.Clock.setObjectName("Clock")
        self.BrewingTime = BrewingTime(parent=self.centralwidget)
        self.BrewingTime.setGeometry(QtCore.QRect(840, 60, 161, 61))
        self.BrewingTimeWidget.setObjectName("BrewingTime")
        self.start_time_edit.setDateTime(QDateTime.currentDateTime())
        self.PausePushButton.clicked.connect(self.pause_or_resume_brew_time)
        self.StartNowButton.clicked.connect(self.start_brew_time)
        self.show()
        self.start_everything()
        print("Multithreading with maximum {} threads".format(
            self.threadpool.maxThreadCount()))

    def check_table_setpoints(self):
        """ This routine looks up the setpoint tables and updates the values accordingly
        """
        pass

    def update_heater1_tsensor(self, i):
        """ Updates the heater 1 sensor to be the name given in the drop down menu"""

        self.ard_dictionary['heaters'][self.heater_names[0]][
            'tsensor_name'] = self.CBHeater1TSensor.currentText()

    def update_heater2_tsensor(self, i):
        """ Updates the heater 2 sensor to be the name given in the drop down menu"""

        self.ard_dictionary['heaters'][self.heater_names[1]][
            'tsensor_name'] = self.CBHeater2TSensor.currentText()

    def update_heater3_tsensor(self, i):
        """ Updates the heater 3 sensor to be the name given in the drop down menu"""

        self.ard_dictionary['heaters'][self.heater_names[2]][
            'tsensor_name'] = self.CBHeater3TSensor.currentText()

    def update_pump1_psensor(self, i):
        """ Updates the pump1 sensor to be the one in the drop down menu"""

        self.ard_dictionary['pumps'][self.pump_names[0]][
            'psensor_name'] = self.CBPump1PSensor.currentText()

    def update_pump2_psensor(self, i):
        """ Updates the pump1 sensor to be the one in the drop down menu"""

        self.ard_dictionary['pumps'][self.pump_names[1]][
            'psensor_name'] = self.CBPump2PSensor.currentText()

    def update_pump3_psensor(self, i):
        """ Updates the pump1 sensor to be the one in the drop down menu"""

        self.ard_dictionary['pumps'][self.pump_names[2]][
            'psensor_name'] = self.CBPump3PSensor.currentText()

    def update_pump_setpoint(self, upper_input_text, lower_input_text,
                             pump_name):
        """ Changes the setpoints of a pump"""

        # Grab the values inside of the input boxes
        upper_limit = upper_input_text.text()
        lower_limit = lower_input_text.text()

        # Backfill the old setpoint values if none were entered
        if upper_limit == "":
            upper_limit = self.ard_dictionary['pumps'][pump_name][
                'upper limit']
        else:
            upper_limit = float(upper_limit)
        if lower_limit == "":
            lower_limit = self.ard_dictionary['pumps'][pump_name][
                'lower limit']
        else:
            lower_limit = float(lower_limit)

        upper_limit, lower_limit = self.check_component_setpoints(
            pump_name, upper_limit, lower_limit)

        # Set the values in the ard_dictionary
        self.ard_dictionary['pumps'][pump_name]['upper limit'] = upper_limit
        self.ard_dictionary['pumps'][pump_name]['lower limit'] = lower_limit

        # Clear the inputs
        for setpoint_input in [upper_input_text, lower_input_text]:
            setpoint_input.clear()

    def update_pump1_setpoint(self):
        worker = Worker(self.update_pump_setpoint, self.InputPump1VolUpper,
                        self.InputPump1VolLower, self.pump_names[0])
        worker.run()

    def update_pump2_setpoint(self):
        worker = Worker(self.update_pump_setpoint, self.InputPump2VolUpper,
                        self.InputPump2VolLower, self.pump_names[1])
        worker.run()

    def update_pump3_setpoint(self):
        worker = Worker(self.update_pump_setpoint, self.InputPump3VolUpper,
                        self.InputPump3VolLower, self.pump_names[2])
        worker.run()

    def update_pump_vol_calc_inputs(self, slope_obj, intercept_obj, pump_name):

        slope = slope_obj.text()
        intercept = intercept_obj.text()

        if slope == "":
            slope = self.ard_dictionary['pumps'][pump_name]['psi_to_gal_slope']
        else:
            slope = float(slope)

        if intercept == "":
            intercept = self.ard_dictionary['pumps'][pump_name][
                'psi_to_gal_intercept']
        else:
            intercept = float(intercept)

        self.ard_dictionary['pumps'][pump_name]['psi_to_gal_slope'] = round(
            slope, 2)
        self.ard_dictionary['pumps'][pump_name][
            'psi_to_gal_intercept'] = round(intercept, 2)

        # clear the inputs
        for setpoint_input in [slope_obj, intercept_obj]:
            setpoint_input.clear()

    def update_pump1_vol_calc_inputs(self):
        self.update_pump_vol_calc_inputs(self.InputPump1VolSlope,
                                         self.InputPump1VolIntercept,
                                         self.pump_names[0])

    def update_pump2_vol_calc_inputs(self):
        self.update_pump_vol_calc_inputs(self.InputPump2VolSlope,
                                         self.InputPump2VolIntercept,
                                         self.pump_names[1])

    def update_pump3_vol_calc_inputs(self):
        self.update_pump_vol_calc_inputs(self.InputPump3VolSlope,
                                         self.InputPump3VolIntercept,
                                         self.pump_names[2])

    def update_heater_setpoint(self, upper_input_text, lower_input_text,
                               heater_name):
        """ Changes the setpoints of a heater"""

        # Grab the values inside of the input boxes
        upper_limit = upper_input_text.toPlainText()
        lower_limit = lower_input_text.toPlainText()

        # Backfill the old setpoint values if none were entered
        if upper_limit == "":
            upper_limit = self.ard_dictionary['heaters'][heater_name][
                'upper limit']
        else:
            upper_limit = float(upper_limit)
        if lower_limit == "":
            lower_limit = self.ard_dictionary['heaters'][heater_name][
                'lower limit']
        else:
            lower_limit = float(lower_limit)

        # Check the inputs
        upper_limit, lower_limit = self.check_component_setpoints(
            heater_name, upper_limit, lower_limit)

        # Set the values in the ard_dictionary
        self.ard_dictionary['heaters'][heater_name]['upper limit'] = float(
            upper_limit)
        self.ard_dictionary['heaters'][heater_name]['lower limit'] = float(
            lower_limit)

        # Clear the inputs
        for setpoint_input in [upper_input_text, lower_input_text]:
            setpoint_input.clear()

    def check_component_setpoints(self, component_name, upper, lower):
        """ Does a simple check of the heater inputs"""

        # Check to make sure that the new upper value is above the lower setpoint
        if upper < lower:
            print(
                ("Upper limit {} for {} is lower than the lower setpoint {}.\n"
                 "Changing upper to be 1 degree above setpoint").format(
                     upper, component_name, lower))
            upper = lower + 1.0

        # Check to make sure that the new lower value is less than the upper setpoint
        if lower > upper:
            print((
                "Lower limit {} for {} is higher than the higher setpoint {}.\n"
                "Changing lower limit to be 1 degree below upper setpoint"
            ).format(lower, component_name, upper))
            lower = upper - 1.0

        return upper, lower

    def update_heater1_setpoint(self):
        worker = Worker(self.update_heater_setpoint, self.InputHeater1Upper,
                        self.InputHeater1Lower, self.heater_names[0])
        worker.run()

    def update_heater2_setpoint(self):
        worker = Worker(self.update_heater_setpoint, self.InputHeater2Upper,
                        self.InputHeater2Lower, self.heater_names[1])
        worker.run()

    def update_heater3_setpoint(self):
        worker = Worker(self.update_heater_setpoint, self.InputHeater3Upper,
                        self.InputHeater3Lower, self.heater_names[2])
        worker.run()

    def update_heater1_maxtemp(self):
        setpoint = self.InputHeater1MaxTemp.toPlainText()
        self.ard_dictionary['heaters'][
            self.heater_names[0]]['maxtemp'] = setpoint
        self.InputHeater1MaxTemp.clear()

    def update_heater2_maxtemp(self):
        setpoint = self.InputHeater2MaxTemp.toPlainText()
        self.ard_dictionary['heaters'][
            self.heater_names[1]]['maxtemp'] = setpoint
        self.InputHeater2MaxTemp.clear()

    def update_heater3_maxtemp(self):
        setpoint = self.InputHeater3MaxTemp.toPlainText()
        self.ard_dictionary['heaters'][
            self.heater_names[2]]['maxtemp'] = setpoint
        self.InputHeater3MaxTemp.clear()

    def update_static_labels(self):
        # Update the status page text variables

        self.LabelT1.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[0]]['name'])
        self.LabelT2.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[1]]['name'])
        self.LabelT3.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[2]]['name'])
        self.LabelT4.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[3]]['name'])
        self.LabelT5.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[4]]['name'])
        self.LabelT6.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[5]]['name'])
        self.LabelT7.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[6]]['name'])
        self.LabelT8.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[7]]['name'])
        self.LabelT9.setText(
            self.ard_dictionary['tempsensors'][self.tsensor_names[8]]['name'])

        self.LabelPress1.setText(
            self.ard_dictionary['presssensors'][self.psensor_names[0]]['name'])
        self.LabelPress2.setText(
            self.ard_dictionary['presssensors'][self.psensor_names[1]]['name'])
        self.LabelPress3.setText(
            self.ard_dictionary['presssensors'][self.psensor_names[2]]['name'])
        self.LabelPress4.setText(
            self.ard_dictionary['presssensors'][self.psensor_names[3]]['name'])

        self.VariablePress1.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[0]]
                ['pressure']))
        self.VariablePress2.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[1]]
                ['pressure']))
        self.VariablePress3.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[2]]
                ['pressure']))
        self.VariablePress4.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[3]]
                ['pressure']))

        self.LabelH1.setText(
            self.ard_dictionary['heaters'][self.heater_names[0]]['name'])
        self.LabelH2.setText(
            self.ard_dictionary['heaters'][self.heater_names[1]]['name'])
        self.LabelH3.setText(
            self.ard_dictionary['heaters'][self.heater_names[2]]['name'])

        self.VariableH1.setText(
            self.ard_dictionary['heaters'][self.heater_names[0]]['status'])
        self.VariableH2.setText(
            self.ard_dictionary['heaters'][self.heater_names[1]]['status'])
        self.VariableH3.setText(
            self.ard_dictionary['heaters'][self.heater_names[2]]['status'])

        self.LabelPump1.setText(
            self.ard_dictionary['pumps'][self.pump_names[0]]['name'])
        self.LabelPump2.setText(
            self.ard_dictionary['pumps'][self.pump_names[1]]['name'])
        self.LabelPump3.setText(
            self.ard_dictionary['pumps'][self.pump_names[2]]['name'])

        self.VariablePump1.setText(
            self.ard_dictionary['pumps'][self.pump_names[0]]['status'])
        self.VariablePump2.setText(
            self.ard_dictionary['pumps'][self.pump_names[1]]['status'])
        self.VariablePump3.setText(
            self.ard_dictionary['pumps'][self.pump_names[2]]['status'])

        self.VariableH1SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['upper limit']))
        self.VariableH2SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['upper limit']))
        self.VariableH3SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['upper limit']))

        # Heater 1 Page
        self.VariableHeater1Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[0]]['tsensor_name']]['value']))))
        self.VariableHeater1Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[0]]['status'])
        self.VariableHeater1Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['upper limit']))
        self.VariableHeater1Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['lower limit']))
        self.VariableHeater1MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['maxtemp']))

        # Heater 2 Page
        self.VariableHeater2Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[1]]['tsensor_name']]['value']))))
        self.VariableHeater2Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[1]]['status'])
        self.VariableHeater2Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['upper limit']))
        self.VariableHeater2Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['lower limit']))
        self.VariableHeater2MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['maxtemp']))

        # Heater 3 Page
        self.VariableHeater3Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[2]]['tsensor_name']]['value']))))
        self.VariableHeater3Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[2]]['status'])
        self.VariableHeater3Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['upper limit']))
        self.VariableHeater3Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['lower limit']))
        self.VariableHeater3MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['maxtemp']))

    def update_labels(self):

        # Utilize the shared ccbc.ard_dictionary to populate these numbers
        # ccbc.ard_dictionary['tempsensors'][t_sensor.name]['value']
        self.VariableT1.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[0]]
                ['value']))
        self.VariableT2.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[1]]
                ['value']))
        self.VariableT3.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[2]]
                ['value']))
        self.VariableT4.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[3]]
                ['value']))
        self.VariableT5.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[4]]
                ['value']))
        self.VariableT6.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[5]]
                ['value']))
        self.VariableT7.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[6]]
                ['value']))
        self.VariableT8.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[7]]
                ['value']))
        self.VariableT9.setText(
            str(self.ard_dictionary['tempsensors'][self.tsensor_names[8]]
                ['value']))

        self.VariablePress1.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[0]]
                ['pressure']))
        self.VariablePress2.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[1]]
                ['pressure']))
        self.VariablePress3.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[2]]
                ['pressure']))
        self.VariablePress4.setText(
            str(self.ard_dictionary['presssensors'][self.psensor_names[3]]
                ['pressure']))

        self.VariableH1.setText(
            self.ard_dictionary['heaters'][self.heater_names[0]]['status'])
        self.VariableH2.setText(
            self.ard_dictionary['heaters'][self.heater_names[1]]['status'])
        self.VariableH3.setText(
            self.ard_dictionary['heaters'][self.heater_names[2]]['status'])

        self.VariablePump1.setText(
            self.ard_dictionary['pumps'][self.pump_names[0]]['status'])
        self.VariablePump2.setText(
            self.ard_dictionary['pumps'][self.pump_names[1]]['status'])
        self.VariablePump3.setText(
            self.ard_dictionary['pumps'][self.pump_names[2]]['status'])

        self.VariableH1SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['upper limit']))
        self.VariableH2SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['upper limit']))
        self.VariableH3SetPoint.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['upper limit']))

        # Heater 1 Page
        self.VariableHeater1Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[0]]['tsensor_name']]['value']))))
        self.VariableHeater1Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[0]]['status'])
        self.VariableHeater1Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['upper limit']))
        self.VariableHeater1Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['lower limit']))
        self.VariableHeater1MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[0]]
                ['maxtemp']))
        self.LabelHeater1TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    self.heater_names[0]]['tsensor_name']))

        # Heater 2 Page
        self.VariableHeater2Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[1]]['tsensor_name']]['value']))))
        self.VariableHeater2Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[1]]['status'])
        self.VariableHeater2Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['upper limit']))
        self.VariableHeater2Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['lower limit']))
        self.VariableHeater2MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[1]]
                ['maxtemp']))
        self.LabelHeater2TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    self.heater_names[1]]['tsensor_name']))

        # Heater 3 Page
        self.VariableHeater3Temp.setText(
            str(((self.ard_dictionary['tempsensors'][self.ard_dictionary[
                'heaters'][self.heater_names[2]]['tsensor_name']]['value']))))
        self.VariableHeater3Status.setText(
            self.ard_dictionary['heaters'][self.heater_names[2]]['status'])
        self.VariableHeater3Upper.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['upper limit']))
        self.VariableHeater3Lower.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['lower limit']))
        self.VariableHeater3MaxTemp.setText(
            str(self.ard_dictionary['heaters'][self.heater_names[2]]
                ['maxtemp']))
        self.LabelHeater3TSensor.setText(
            'Controlling Temperature Sensor: {}'.format(
                self.ard_dictionary['heaters'][
                    self.heater_names[2]]['tsensor_name']))

        # Pump 1 Page
        self.VariablePump1Volume.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[0]]['gallons']))
        self.LabelPump1Status.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[0]]['status']))
        self.VariablePump1Upper.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[0]]
                ['upper limit']))
        self.VariablePump1Lower.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[0]]
                ['lower limit']))
        self.VariablePump1Pressure.setText((str(
            self.ard_dictionary['presssensors'][self.ard_dictionary['pumps'][
                self.pump_names[0]]['psensor_name']]['pressure'])))
        self.VariablePump1VolSlope.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[0]]
                ['psi_to_gal_slope']))
        self.VariablePump1VolIntercept.setText(
            (str(self.ard_dictionary['pumps'][self.pump_names[0]]
                 ['psi_to_gal_intercept'])))
        self.LabelPump1PSensor.setText(
            'Controlling Pressure Sensor: {}'.format(
                self.ard_dictionary['pumps'][
                    self.pump_names[0]]['psensor_name']))

        # Pump 2 Page
        self.VariablePump2Volume.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[1]]['gallons']))
        self.LabelPump2Status.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[1]]['status']))
        self.VariablePump2Upper.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[1]]
                ['upper limit']))
        self.VariablePump2Lower.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[1]]
                ['lower limit']))
        self.VariablePump2Pressure.setText((str(
            self.ard_dictionary['presssensors'][self.ard_dictionary['pumps'][
                self.pump_names[1]]['psensor_name']]['pressure'])))
        self.VariablePump2VolSlope.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[1]]
                ['psi_to_gal_slope']))
        self.VariablePump2VolIntercept.setText(
            (str(self.ard_dictionary['pumps'][self.pump_names[1]]
                 ['psi_to_gal_intercept'])))
        self.LabelPump2PSensor.setText(
            'Controlling Pressure Sensor: {}'.format(
                self.ard_dictionary['pumps'][
                    self.pump_names[1]]['psensor_name']))

        # Pump 3 Page
        self.VariablePump3Volume.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[2]]['gallons']))
        self.LabelPump3Status.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[2]]['status']))
        self.VariablePump3Upper.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[2]]
                ['upper limit']))
        self.VariablePump3Lower.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[2]]
                ['lower limit']))
        self.VariablePump3Pressure.setText((str(
            self.ard_dictionary['presssensors'][self.ard_dictionary['pumps'][
                self.pump_names[2]]['psensor_name']]['pressure'])))
        self.VariablePump3VolSlope.setText(
            str(self.ard_dictionary['pumps'][self.pump_names[2]]
                ['psi_to_gal_slope']))
        self.VariablePump3VolIntercept.setText(
            (str(self.ard_dictionary['pumps'][self.pump_names[2]]
                 ['psi_to_gal_intercept'])))
        self.LabelPump3PSensor.setText(
            'Controlling Pressure Sensor: {}'.format(
                self.ard_dictionary['pumps'][
                    self.pump_names[2]]['psensor_name']))

    def start_brew_time(self):
        self.BrewingTime.brew_time = 0
        self.BrewingTime.active = True
        self.logger.start()
        self.logger_timer.timeout.connect(self._update_logger)
        self.logger_timer.start(30000)

    def pause_or_resume_brew_time(self):
        # Brewing is currently going. After pressing button, brewing pauses and button should say resume
        if self.BrewingTime.active:
            self.BrewingTime.change_status()
            self.PausePushButton.setText("Resume")
        else:
            # Brewing is paused. After pressing the button, brewing continues and the button should say pause
            self.BrewingTime.change_status()
            self.PausePushButton.setText("Pause")

    def heater1_table_setpoint(self):
        pass

    def refresh_dynamic_labels(self):
        worker = Worker(self.update_labels)
        self.threadpool.start(worker)

    def _update_logger(self):
        self.logger.update()

    def start_everything(self):
        self.label_timer.timeout.connect(self.refresh_dynamic_labels)
        self.label_timer.start(250)
예제 #29
0
class SelectModelWidget(QWidget):
    """QTabWidget that holds all of the selectable models and the accompanying ModelDialog for each.
    """
    update_progressbar = pyqtSignal(int, bool)

    def __init__(self, parent=None):
        super(SelectModelWidget, self).__init__(parent)
        self.logger = logging.getLogger(__name__)
        self.parent = parent
        self.threadpool = QThreadPool()
        self.logger.info(
            f"Multithreading enabled with a maximum of {self.threadpool.maxThreadCount()} threads."
        )

        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())
        self.training_data = pd.DataFrame()
        self.training_predictions = pd.DataFrame()
        self.selected_version = CONFIG.get('PATHS', 'DefaultModelDirectory')
        self.comms = Communicate()

        self.selected_models = {}
        self.selected_models['sklearn'] = {}
        self.selected_models['tensorflow'] = {}
        self.model_checkboxes = []
        # * Initialize training parameter dict.
        # * Has entry for both model base types
        self.training_params = {}
        self.training_params['sklearn'] = {}
        self.training_params['sklearn']['type'] = None
        self.training_params['sklearn']['value'] = None
        self.training_params['tensorflow'] = {}
        # * Init tuning param dict
        # * Currently only using gridsearch
        self.tuning_params = {}
        self.tuning_params['gridsearch'] = {
            'n_iter': 20,
            'cv': 3,
            'n_jobs': -1,
            'scoring': ['accuracy'],
            'tune_stacker': False
        }

        self.sklearn_model_dialogs = []
        self.sklearn_model_dialog_btns = []
        self.sklearn_training_inputs = []

        self.tensorflow_training_inputs = []
        self.tensorflow_model_dialogs = []
        self.tensorflow_model_dialog_btns = []

        self.main_layout = QVBoxLayout()
        self.upper_hbox = QHBoxLayout()

        self.version_form = QFormLayout()
        self.header_hbox = QHBoxLayout()
        self.header_hbox.addLayout(self.version_form)
        self.header_hbox.addStretch()
        self.tune_models_chkbox = QCheckBox("Tune Models")
        self.header_hbox.addWidget(self.tune_models_chkbox)
        self.tune_models_chkbox.stateChanged.connect(
            lambda state: self._enable_tuning_ui(state))
        self.main_layout.addLayout(self.header_hbox)
        self.main_layout.addLayout(self.upper_hbox)

        self.model_vbox = QVBoxLayout()
        self.tuning_vbox = QVBoxLayout()

        self.upper_hbox.addLayout(self.model_vbox)
        self.upper_hbox.addSpacing(10)
        self.upper_hbox.addLayout(self.tuning_vbox)
        self.upper_hbox.addSpacing(200)
        # * Build sklearn ui components
        self.sklearn_hbox = QHBoxLayout()
        self.sklearn_groupbox = QGroupBox("Sklearn")
        self.sklearn_groupbox.setLayout(self.sklearn_hbox)

        self.skmodel_groupbox = QGroupBox("Model Selection")
        self.sklearn_hbox.addWidget(self.skmodel_groupbox)
        self.sklearn_model_form = QFormLayout()
        self.sklearn_model_form.setFormAlignment(Qt.AlignTop)
        self.skmodel_groupbox.setLayout(self.sklearn_model_form)

        # * Sklearn training and tuning ui components
        self.sklearn_training_groupbox = QGroupBox("Training")
        self.sklearn_training_form = QFormLayout()
        self.sklearn_training_groupbox.setLayout(self.sklearn_training_form)
        self.sklearn_hbox.addWidget(self.sklearn_training_groupbox)

        self.model_vbox.addWidget(self.sklearn_groupbox)

        # * Build Tensorflow ui components
        self.tensorflow_hbox = QHBoxLayout()
        self.tensorflow_groupbox = QGroupBox("Tensorflow")
        self.tensorflow_groupbox.setLayout(self.tensorflow_hbox)

        self.tensorflow_model_groupbox = QGroupBox("Model Selection")
        self.tensorflow_hbox.addWidget(self.tensorflow_model_groupbox)
        self.tensorflow_model_form = QFormLayout()

        self.tensorflow_model_groupbox.setLayout(self.tensorflow_model_form)
        self.tensorflow_training_groupbox = QGroupBox("Training")
        self.tensorflow_training_form = QFormLayout()
        self.tensorflow_training_groupbox.setLayout(
            self.tensorflow_training_form)
        self.tensorflow_hbox.addWidget(self.tensorflow_training_groupbox)

        # * This is the tensorflow groupbox for models and training params.
        # self.model_vbox.addWidget(self.tensorflow_groupbox)

        self.tuning_groupbox = QGroupBox("Tuning")
        self.tuning_form = QFormLayout()
        self.tuning_groupbox.setLayout(self.tuning_form)
        self.tuning_vbox.addWidget(self.tuning_groupbox)
        self.tuning_groupbox.setEnabled(False)
        self.model_form_grid = QGridLayout()

        self.setup_model_selection_ui()
        self.setup_training_ui()
        self.setup_tuning_ui()
        # * QTextEdit box for training/tuning status
        self.training_logger = QTextEdit()
        self.training_logger.setReadOnly(True)
        self.training_logger.setAcceptRichText(True)
        self.training_logger.insertHtml(
            "<i>Multithreading with maximum %d threads</i><br>" %
            self.threadpool.maxThreadCount())
        self.training_logger.setMinimumHeight(400)
        self.main_layout.addWidget(self.training_logger)
        self.clear_btn_hbox = QHBoxLayout()
        self.clear_text_btn = QPushButton('Clear')
        self.clear_text_btn.setMaximumWidth(50)
        self.clear_text_btn.clicked.connect(
            lambda: self.training_logger.clear())
        self.clear_btn_hbox.addStretch()
        self.clear_btn_hbox.addWidget(self.clear_text_btn)

        self.main_layout.addLayout(self.clear_btn_hbox)

        self.main_layout.addStretch()
        self.run_btn = QPushButton("&Train Models")
        self.run_btn.setMinimumWidth(200)
        self.run_btn.clicked.connect(lambda: self.train_models())
        self.run_btn.setEnabled(False)

        self.stop_btn = QPushButton('Sto&p')
        self.stop_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)

        self.comms.enable_training_btn.connect(self.set_training_btn_state)
        self.button_hbox = QHBoxLayout()

        icon = QIcon()
        icon.addPixmap(QPixmap('icons/Programming-Save-icon.png'))
        self.save_results_btn = QPushButton()
        self.save_results_btn.setIcon(icon)
        self.save_results_btn.setEnabled(False)
        self.save_results_btn.setToolTip(
            'Save model evaluation predictions, agreement ratio, and bamboozled score'
        )
        self.save_results_btn.clicked.connect(lambda: self.save_predictions())

        self.button_hbox.addWidget(self.run_btn)
        self.button_hbox.addWidget(self.stop_btn)
        self.button_hbox.addStretch()
        self.button_hbox.addWidget(self.save_results_btn)
        self.main_layout.addLayout(self.button_hbox)
        self.setLayout(self.main_layout)

        # Trigger update to load model parameters
        self._update_version(self.version_selection.currentData())

    def setup_model_selection_ui(self):
        """
        Setup model selection ui.

        The order of the parameters in ModelDialog matters.  model_data must come first!
        """
        self.version_selection_label = QLabel("Select version: ")
        self.version_selection = QComboBox(objectName='version_select')
        self.version_selection.setMinimumWidth(100)
        # Changed default models to a unique directory.  This
        # is where default models will be saved.
        # self.version_selection.addItem(
        #     'default', '.\\package\\data\\default_models\\default')
        available_versions = os.listdir(BASE_VERSION_DIR)
        for version in available_versions:
            v_path = os.path.join(BASE_VERSION_DIR, version)
            if os.path.isdir(v_path):
                self.version_selection.addItem(version, v_path)
        self.version_selection.currentIndexChanged.connect(
            lambda x, y=self.version_selection: self._update_version(
                y.currentData()))
        self.version_form.addRow(self.version_selection_label,
                                 self.version_selection)

        # Load base TF-IDF features
        # and feature selection data
        try:
            with open(CONFIG.get('PATHS', 'BaseTfidfDirectory'), 'r') as f:
                tfidf_data = json.load(f)
        except IOError as ioe:
            self.logger.error("Error loading base TFIDF params", exc_info=True)
            exceptionWarning(
                'Error occurred while loading base TFIDF parameters.',
                repr(ioe))
        try:
            with open(CONFIG.get('PATHS', 'BaseFeatureSeletionDirectory'),
                      'r') as f:
                self.fs_params = json.load(f)
        except IOError as ioe:
            self.logger.error("Error loading base feature selector params",
                              exc_info=True)
            exceptionWarning(
                'Error occurred while loading base feature selector parameters.',
                repr(ioe))
        # Dynamically generate ModelDialogs for each model in the base model directory.
        # Only considers *.json file extension.
        try:
            row = 0
            for filename in os.listdir(
                    CONFIG.get('PATHS', 'BaseModelDirectory')):
                if filename.endswith('.json'):
                    with open(
                            os.path.join(
                                CONFIG.get('PATHS', 'BaseModelDirectory'),
                                filename), 'r') as f:
                        model_data = json.load(f)
                        model = model_data['model_class']
                        model_base = model_data['model_base']
                        model_module = model_data['model_module']
                        #! The order of the arguments matters!  model_data must come first.
                        if model_base == 'tensorflow':
                            continue
                            # model_dialog = SkModelDialog(self, model_data)
                        if model_module == 'tpot':
                            model_dialog = TPOTModelDialog(
                                self, model_data, tfidf_data)
                        else:
                            model_dialog = SkModelDialog(
                                self, model_data, tfidf_data, self.fs_params)
                        self.comms.version_change.connect(
                            model_dialog.update_version)
                        # Initialize model as unselected
                        self.selected_models[model_base][model] = False
                        btn = QPushButton(model, objectName=model + '_btn')
                        # Partial allows the connection of dynamically generated QObjects
                        btn.clicked.connect(
                            partial(self.open_dialog, model_dialog))
                        chkbox = QCheckBox(objectName=model)
                        chkbox.stateChanged.connect(
                            lambda state, x=model, y=model_base: self.
                            _update_selected_models(x, y, state))
                        if model_base == 'tensorflow':
                            self.tensorflow_model_form.addRow(chkbox, btn)
                            self.tensorflow_model_dialogs.append(model_dialog)
                            self.tensorflow_model_dialog_btns.append(btn)
                        else:
                            self.sklearn_model_form.addRow(chkbox, btn)
                            self.sklearn_model_dialogs.append(model_dialog)
                            self.sklearn_model_dialog_btns.append(btn)
                        self.model_checkboxes.append(chkbox)
                        row += 1
        except OSError as ose:
            self.logger.error("OSError opening model config files",
                              exc_info=True)
            exceptionWarning('OSError opening model config files!', ose)
            tb = traceback.format_exc()
            print(tb)
        except Exception as e:
            self.logger.error("Error opening model config files",
                              exc_info=True)
            exceptionWarning('Error occured.', e)
            tb = traceback.format_exc()
            print(tb)

    def setup_training_ui(self):
        """
        Build ui components for training parameters for both Sklearn and Tensorflow
        """
        # Sklearn training first
        self.cv_n_fold_input = QSpinBox(objectName='n_folds')
        self.cv_n_fold_input.setRange(2, 10)
        self.cv_n_fold_input.setValue(5)
        self.cv_n_fold_input.setEnabled(False)
        self.cv_n_fold_input.valueChanged.connect(
            lambda state, x=self.cv_n_fold_input: self.update_training_params(
                'sklearn', 'cv', x.value()))
        self.cv_radio_btn = QRadioButton("Cross-validation", objectName='cv')
        self.cv_radio_btn.toggled.connect(
            lambda state, x=self.cv_n_fold_input: self.
            _update_sklearn_training_type('cv', x.value()))
        self.sklearn_training_form.addRow(self.cv_radio_btn,
                                          self.cv_n_fold_input)

        self.sk_validation_radio_btn = QRadioButton("Validation set")
        self.sk_validation_percent_input = QDoubleSpinBox(
            objectName='test_split')
        self.sk_validation_percent_input.setRange(0.05, 1)
        self.sk_validation_percent_input.setSingleStep(0.1)
        self.sk_validation_percent_input.setEnabled(False)
        self.sk_validation_percent_input.valueChanged.connect(
            lambda state, x=self.sk_validation_percent_input: self.
            update_training_params('sklearn', 'validation', x.value()))

        self.sk_validation_radio_btn.toggled.connect(
            lambda state, x=self.sk_validation_percent_input: self.
            _update_sklearn_training_type('validation', x.value()))
        # NOTE: Removing validation split option from evaluation.  It seems less than useful and
        # requires time that could be spent elsewhere as we near the end of our time together.
        # self.sklearn_training_form.addRow(self.sk_validation_radio_btn, self.sk_validation_percent_input)

        self.no_eval_btn = QRadioButton("No evaluation set",
                                        objectName='no_eval')
        self.no_eval_btn.toggled.connect(
            lambda: self._update_sklearn_training_type(None, None))
        self.sklearn_training_form.addRow(self.no_eval_btn)
        # TENSORFLOW TRAINING UI.  Removed as of 10/04/19

        # Toggle to set params on load
        self.cv_radio_btn.toggle()

        # * Select stacker
        # self.stacker_groupbox = QGroupBox('Stacking algorithm')
        # self.stacker_vbox = QVBoxLayout()
        # self.train_stacker

    def setup_tuning_ui(self):
        self.tuning_n_iter_label = QLabel("Number of iterations:")
        self.tuning_n_iter_input = QSpinBox(objectName='n_iter')
        self.tuning_n_iter_input.setRange(2, 1000)
        self.tuning_n_iter_input.setSingleStep(1)
        self.tuning_n_iter_input.setValue(10)
        self.tuning_n_iter_input.valueChanged.connect(
            lambda state, x=self.tuning_n_iter_input: self.
            update_tuning_params('gridsearch', 'n_iter', x.value()))
        self.tuning_form.addRow(self.tuning_n_iter_label,
                                self.tuning_n_iter_input)

        self.tuning_cv_label = QLabel("CV folds:")
        self.tuning_cv_input = QSpinBox(objectName='cv')
        self.tuning_cv_input.setRange(2, 10)
        self.tuning_cv_input.setValue(3)
        self.tuning_cv_input.valueChanged.connect(
            lambda state, x=self.tuning_cv_input: self.update_tuning_params(
                'gridsearch', 'cv', x.value()))
        self.tuning_form.addRow(self.tuning_cv_label, self.tuning_cv_input)

        self.tuning_n_jobs_label = QLabel("Number of parallel jobs:")
        self.tuning_n_jobs_input = QSpinBox(objectName='n_jobs')
        self.tuning_n_jobs_input.setRange(-1, 4)
        self.tuning_n_jobs_input.setValue(-1)
        self.tuning_n_jobs_input.valueChanged.connect(
            lambda state, x=self.tuning_n_jobs_input: self.
            update_tuning_params('gridsearch', 'n_jobs', x.value()))
        self.tuning_form.addRow(self.tuning_n_jobs_label,
                                self.tuning_n_jobs_input)

        self.scoring_metric_groupbox = QGroupBox('Scoring metrics')

        self.scoring_metric_vbox = QVBoxLayout()
        # * The following code is for metric radio buttons.  Left in for posterity
        # self.acc_checkbox = QRadioButton('Accuracy')
        # self.acc_checkbox.setChecked(True)
        # self.acc_checkbox.toggled.connect(
        #     lambda state, x=self.acc_checkbox:
        #     self.update_tuning_params('gridsearch', 'scoring', 'accuracy')
        # )
        # self.scoring_metric_vbox.addWidget(self.acc_checkbox)

        # self.f1_weighted_checkbox = QRadioButton('F1 weighted')
        # self.f1_weighted_checkbox.setChecked(False)
        # self.f1_weighted_checkbox.toggled.connect(
        #     lambda state, x=self.f1_weighted_checkbox:
        #     self.update_tuning_params('gridsearch', 'scoring', 'f1_weighted')
        # )
        # self.scoring_metric_vbox.addWidget(self.f1_weighted_checkbox)

        # self.prec_weighted_checkbox = QRadioButton('Precision weighted')
        # self.prec_weighted_checkbox.setChecked(False)
        # self.prec_weighted_checkbox.toggled.connect(
        #     lambda state, x=self.prec_weighted_checkbox:
        #     self.update_tuning_params(
        #         'gridsearch', 'scoring', 'precision_weighted')
        # )
        # self.scoring_metric_vbox.addWidget(self.prec_weighted_checkbox)

        self.acc_checkbox = QCheckBox('Accuracy')
        self.acc_checkbox.setChecked(True)
        self.acc_checkbox.stateChanged.connect(
            lambda state, x=self.acc_checkbox: self.update_tuning_params(
                'gridsearch', 'accuracy', state, True))
        self.scoring_metric_vbox.addWidget(self.acc_checkbox)

        self.f1_weighted_checkbox = QCheckBox('F1 weighted')
        self.f1_weighted_checkbox.setChecked(False)
        self.f1_weighted_checkbox.stateChanged.connect(
            lambda state, x=self.f1_weighted_checkbox: self.
            update_tuning_params('gridsearch', 'f1_weighted', state, True))
        self.scoring_metric_vbox.addWidget(self.f1_weighted_checkbox)

        self.prec_weighted_checkbox = QCheckBox('Precision weighted')
        self.prec_weighted_checkbox.setChecked(False)
        self.prec_weighted_checkbox.stateChanged.connect(
            lambda state, x=self.
            prec_weighted_checkbox: self.update_tuning_params(
                'gridsearch', 'precision_weighted', state, True))
        self.scoring_metric_vbox.addWidget(self.prec_weighted_checkbox)

        self.scoring_metric_groupbox.setLayout(self.scoring_metric_vbox)

        self.tune_stacker_checkbox = QCheckBox('Tune Stacking Algorithm')
        self.tune_stacker_checkbox.setChecked(False)
        self.tune_stacker_checkbox.stateChanged.connect(
            lambda state, x=self.tune_stacker_checkbox: self.
            update_tuning_params('gridsearch', 'tune_stacker', state))
        self.tuning_form.addRow(self.scoring_metric_groupbox)
        self.tuning_form.addRow(self.tune_stacker_checkbox)

    def open_dialog(self, dialog):
        """
        Opens the passed ModelDialog via the save_params function, allowing the user
        to specify hyperparameters for each available version field.  

            # Arguments
                dialog: ModelDialog, Specified model dialog.
        """
        dialog.save_params()

    @pyqtSlot(str)
    def add_new_version(self, v_dir):
        """
        pyqtSlot to receive new version created pyqtSignal.

            # Arguments
                v_dir: string, directory of newly created version.
        """
        version = v_dir.split('\\')[-1]
        self.version_selection.addItem(version, v_dir)
        self.version_selection.model().sort(0)

    @pyqtSlot(pd.DataFrame)
    def load_data(self, data):
        """
        pyqtSlot to receive pandas DataFrame after DataLoader has completed it's work

            # Arguments
                data: pandas.DataFrame, training data
        """
        self.training_data = data
        self.comms.enable_training_btn.emit(True)

    @pyqtSlot(Qt.CheckState)
    def set_training_btn_state(self):
        """
        Sets the run button enabled state.
        Checks that there are models selected in sklearn or tensorflow 
        """
        if (not self.training_data.empty
                and (1 in self.selected_models['sklearn'].values()
                     or 1 in self.selected_models['tensorflow'].values())):
            self.run_btn.setEnabled(True)
        else:
            self.run_btn.setEnabled(False)

    @pyqtSlot(str, bool)
    def model_exists(self, model_name, truth):
        """
        Adds styling to button if a trained model exists for the model in the selected version

            # Arguments
                model_name: string, name of the model designated by the button.
                truth: bool, true if there exists any trained model of type model_name in the current
                    version.
        """
        btn = self.findChild(QPushButton, model_name + '_btn')
        if btn:
            text = btn.text()
            if text.endswith("*"):
                text = text[:-2]
            if truth:
                btn.setText(text + " *")
            else:
                btn.setText(text)
        else:
            return

    def train_models(self):
        try:
            tune_models = self.tune_models_chkbox.isChecked()
            self.model_trainer = ModelTrainer(
                selected_models=self.selected_models,
                version_directory=self.selected_version,
                training_eval_params=self.training_params,
                training_data=self.training_data,
                tune_models=tune_models,
                tuning_params=self.tuning_params)
            self.model_trainer.signals.update_training_logger.connect(
                self.update_training_logger)
            self.update_progressbar.emit(1, True)
            self.model_trainer.signals.training_complete.connect(
                self.training_complete)
            self.comms.stop_training.connect(self.model_trainer.stop_thread)
            self.run_btn.setEnabled(False)
            self.stop_btn.clicked.connect(lambda: self._abort_training())

            self.training_predictions = pd.DataFrame()
            self.threadpool.start(self.model_trainer)
        except Exception as e:
            self.logger.error("SelectModelWidget.train_models", exc_info=True)
            exceptionWarning('Exception occured when training models.', e)
            tb = traceback.format_exc()
            print(tb)

    @pyqtSlot(str, bool, bool)
    def update_training_logger(self, msg, include_time=True, use_html=True):
        '''
        Slot that receives signals updating the terminal.  
        
            # Arguments
                msg: string, Message to display in terminal
                include_time: bool, prepend time to message
                use_html: bool, insert text as html 
        '''
        if (include_time):
            current_time = time.localtime()
            outbound = f"{time.strftime('%Y-%m-%d %H:%M:%S', current_time)} - {msg}<br>"
        else:
            outbound = f"{msg}<br>"
        if (use_html):
            self.training_logger.insertHtml(outbound)
            self.training_logger.moveCursor(QTextCursor.End)
        else:
            self.training_logger.insertPlainText(msg)

    @pyqtSlot(pd.DataFrame)
    def training_complete(self, prediction_df=None):
        """
        Resets progressbar, unchecks 'Train models', and emits signal to refresh the parameter
        values in each ModelDialog

            # Arguments
                val: int or float, value used to set progressbar
                pulse: bool, used to toggle progressbar pulse
        """
        self.update_progressbar.emit(0, False)
        self.run_btn.setEnabled(True)
        self.run_btn.setText("Train models")
        self.tune_models_chkbox.setChecked(False)
        self.save_results_btn.setEnabled(True)

        if (prediction_df is not None and not prediction_df.empty):
            self.training_predictions = prediction_df
        # Emitting a version change here reloads all parameters.  i.e. we update the
        # parameters displayed in the dialog.
        self.comms.version_change.emit(self.selected_version)

    def save_predictions(self):
        '''
        Save predictions to user specified file.  Opens a QFileDialog to choose save directory.
        '''
        try:
            if self.training_predictions.empty:
                exceptionWarning('No predictions to save')
                return
            file_name, filter = QFileDialog.getSaveFileName(
                self, 'Save to CSV', os.getenv('HOME'), 'CSV(*.csv)')
            if file_name:
                self.training_predictions.to_csv(file_name,
                                                 index_label='testnum',
                                                 quoting=1,
                                                 encoding='utf-8')
                self.comms.update_statusbar.emit(
                    "Predictions saved successfully.")
        except PermissionError as pe:
            self.logger.warning("SelectModelWidget.save_predictions",
                                exc_info=True)
            exceptionWarning(
                f'Permission denied while attempting to save {file_name}')
        except Exception as e:
            self.logger.error("SelectModelWidget.save_predictions",
                              exc_info=True)
            exceptionWarning(
                "Exception occured.  SelectModelWidget.save_predictions.",
                exception=e)
            tb = traceback.format_exc()
            print(tb)

    def _abort_training(self):
        '''
        Notifies the ModelTrainer to abort training.
        ! Note: training ends only after the current training or tuning event ends.
        '''
        self.comms.stop_training.emit()

    def _update_version(self, directory):
        """
        Parses selected version directory and emits pyqtSignal to update each ModelDialog

            # Arguments
                directory: string, directory selected by user.
        """
        self.selected_version = directory
        # Emit pyqtSignal
        self.comms.version_change.emit(directory)

    def _update_selected_models(self, model, model_base, state):
        """
        Update the models selected by the user.  This function is connected to the
        checkboxes associated with each model.

            # Arguments:
                model: string, name of the selected model
                state: bool, the truth of the selection.  True->selected, False->unselected
        """
        truth = False
        if state == Qt.Checked:
            truth = True
        self.selected_models[model_base][model] = truth
        self.comms.enable_training_btn.emit(truth)

    def _enable_tuning_ui(self, state):
        """
        Helper function to enable/disable the tuning parameter UI if selected 
        by the user.

            # Arguments:
                state: bool, the state of tuning.  False->no tuning, True->tune models
        """
        self.run_btn.setText("Tune Models" if state else "Train Models")
        self.tuning_groupbox.setEnabled(state)

    def update_tuning_params(self, model_base, param, value, scorer=False):
        '''
        Updates the tuning parameters passed to ModelTrainer.

            # Arguments
                model_base: string, Signifies which type of tuning parameter to update.  Currently, only
                    used by RandomizedSearchCV (sklearn)
                param: string, parameter name
                value: [int, float, string], parameter value
        '''
        if model_base is None or param is None:
            return
        try:
            if scorer:
                if value:
                    self.tuning_params[model_base]['scoring'].append(param)
                else:
                    if param in self.tuning_params[model_base]['scoring']:
                        self.tuning_params[model_base]['scoring'].remove(param)
            else:
                self.tuning_params[model_base][param] = value
        except KeyError as ke:
            self.tuning_params[model_base][param] = {}
            self.tuning_params[model_base][param] = value
        except Exception as e:
            self.logger.error("SelectModelWidget.update_tuning_params",
                              exc_info=True)
            exceptionWarning('Exception occured when training models.', e)
            tb = traceback.format_exc()
            print(tb)
        print(self.tuning_params)

    def update_training_params(self, model_base, param, value):
        """
        Update the various training parameters with values supplied by the user.
        Needs work as the sklearn training parameters are mutually exclusive.

            # Arguments
                model_base: string, model base for specified training params
                param: string, parameter name
                value: string, int, or double, value of specified parameter
        """
        if model_base is None or param is None:
            return
        try:
            # FIXME: This is super hackish and brittle.  Can it be done more eloquently?
            if model_base == 'sklearn':
                self._update_sklearn_training_type(param, value)
            else:
                self.training_params[model_base][param] = value
        except KeyError as ke:
            print(ke)

    def _update_sklearn_training_type(self, eval_type, value):
        """
        SKlearn model tuning is mutually exclusive.  This helper function
        Enables/disables the appropriate field and updates the appropriate
        parameters of self.training_params

        Currently, for Sklearn models, only cross-validation (cv) or a holdout set
        (validation) or None are model evaluation options.  

            # Arguments
                eval_type: string, The type of model evaluation specified by the user.
                value: int or double, value corresponding to selected type
        """
        truth = False
        if eval_type == 'cv':
            self.cv_n_fold_input.setEnabled(not truth)
            self.sk_validation_percent_input.setEnabled(truth)
        elif eval_type == 'validation':
            self.cv_n_fold_input.setEnabled(truth)
            self.sk_validation_percent_input.setEnabled(not truth)
        elif eval_type == None:
            self.cv_n_fold_input.setEnabled(False)
            self.sk_validation_percent_input.setEnabled(False)
        else:
            raise ValueError("eval_type %s is invalid" % (eval_type))

        self.training_params['sklearn']['type'] = eval_type
        self.training_params['sklearn']['value'] = value
예제 #30
0
class AppWindow(QMainWindow):
    def __init__(self):
        super(AppWindow,self).__init__()
        self.ui=Ui_MainWindow()
        self.ui.setupUi(self)
        yaml=os.path.join(os.getcwd(),'config.yml')
        print(yaml)
        self.cfg=util.import_yaml(yaml)

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

        util.Qlogging(self.ui.textBrowser, 'The config File is loaded \n',"g")
        cfg_str=pprint.pformat(self.cfg)
        # print(cfg_str)
        util.Qlogging(self.ui.textBrowser,cfg_str,'b')
        self.Ui_config_()


    def Ui_config_(self):
        self.ui.btn_train.clicked.connect(self.btn_train)
        self.ui.btn_designNet.clicked.connect(self.btn_design_model)
        self.ui.btn_model_eval.clicked.connect(self.on_btn_eval)

        self.ui.cmbox_data_dir.addItems(self.cfg['data_dir'])
        self.ui.cmbox_model_select.addItems(self.cfg['model_names'])

        self.ui.in_num_classes.setText(str(self.cfg['num_classes']))
        self.ui.in_num_classes.setEnabled(False)

        self.ui.in_batch_size.setText(str(self.cfg['batch_size']))
        self.ui.in_epoches.setText(str(self.cfg['num_epochs']))

    def btn_design_model(self):
        model_cfg=util.import_yaml('.\models\model_001.yml')
        net=TR.AliNet(model_cfg['model_layers'])
        util.Qlogging(str(net.modules()),'r')

    def update_cfg(self):
        self.new_cfg={}
        self.new_cfg.update({'model_name': self.ui.cmbox_model_select.currentText()})
        self.new_cfg.update({'data_dir': self.ui.cmbox_data_dir.currentText()})
        self.new_cfg.update({'num_classes': self.ui.in_num_classes.text()})
        self.new_cfg.update({'batch_size': self.ui.in_batch_size.text()})
        self.new_cfg.update({'num_epochs': self.ui.in_epoches.text()})
        self.new_cfg.update({'feature_extract': self.ui.in_rdbtn_Feature.isChecked()})
        self.new_cfg.update({'use_pretrained': self.ui.in_chbox_pretrained.isChecked()})
        print(self.new_cfg)




    def btn_train(self):
        self.update_cfg()
        cfg=self.new_cfg
        model_ft, input_size = TR.initialize_model(cfg['model_name'],
                                                   int(cfg['num_classes']),
                                                   cfg['feature_extract'],
                                                   use_pretrained=cfg['use_pretrained'])
        util.Qlogging(self.ui.textBrowser, 'The Model is loaded\n', "r")

        data_transforms = TR.Data_Augmrntation_Normalization(input_size)

        print("Initializing Datasets and Dataloaders...")
        #
        # # Create training and validation datasets
        image_datasets = {x: datasets.ImageFolder(os.path.join(cfg['data_dir'], x), data_transforms[x]) for x in
                          ['train', 'val']}
        # # Create training and validation dataloaders
        self.dataloaders_dict = {
            x: torch.utils.data.DataLoader(image_datasets[x], batch_size=int(cfg['batch_size']), shuffle=True, num_workers=4) for x
            in ['train', 'val']}
        #
        # # Detect if we have a GPU available
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        # KK = TR.AliNet(2)
        # model_ft= nn.Sequential(model_ft,nn.Linear(2,200),
        #                         nn.Linear(200,2),KK)





        print(model_ft)


        # Send the model to GPU
        model_ft = model_ft.to(device)

        params_to_update = model_ft.parameters()
        print("Params to learn:")
        if cfg['feature_extract']:
            params_to_update = []
            for name, param in model_ft.named_parameters():
                if param.requires_grad == True:
                    params_to_update.append(param)
                    print("\t", name)
        else:
            for name, param in model_ft.named_parameters():
                if param.requires_grad == True:
                    print("\t", name)

        # Observe that all parameters are being optimized
        optimizer_ft = optim.SGD(params_to_update, lr=0.001, momentum=0.9)

        # Setup the loss fxn
        criterion = nn.CrossEntropyLoss()

        # Train and evaluate
        # model_ft, hist = TR.train_model(model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=int(cfg['num_epochs']),
        #                              is_inception=(cfg['model_name'] == "inception"))
        worker_train= Worker(TR.train_model,model_ft,self.dataloaders_dict,criterion,optimizer_ft, num_epochs=int(cfg['num_epochs']),is_inception=(cfg['model_name'] == "inception"))
        worker_train.signals.result.connect(self.on_Thread_resulat)
        self.threadpool.start(worker_train)

    def on_Thread_resulat(self,model):
        print("Thread has done.")
        self.model=model[0]
        print(model[0])

    def on_btn_eval(self):
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        self.model.eval()
        inputs , labels= next(iter(self.dataloaders_dict['val']))
        print('Actual labels:\n',labels)
        inputs = inputs.to(device)
        labels = labels.to(device)

        pred= self.model(inputs)
        # pred.data.cpu().numpy()
        print(pred.shape)
        print('Predicted labels: \n', pred.data.cpu().numpy())
예제 #31
0
class MADByTE_Main(QMainWindow):
    def __init__(self):
        __version__ = '1.3.0'
        super(MADByTE_Main, self).__init__()
        uic.loadUi(os.path.join(BASE, 'static','MADByTE_GUI.ui'),self)

        # setup threadpool for processing
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
        ### setup window details
        self.Version_Label.setText(__version__)
        self.setWindowIcon(QIcon(LOGO_PATH))
        self.Hppm_Input.setText('0.05')
        self.Cppm_Input.setText('0.40')
        self.Hppm_Input_2.setText('0.03')
        self.Cppm_Input_2.setText('0.40')
        self.Consensus_Error_Input.setText('0.03')
        self.Similarity_Ratio_Input.setText('0.50')
        self.Overlap_Score_lineEdit.setText('0.30')
        Banner_Pixmap = QPixmap(Banner_Path)
        Logo_Pixmap = QPixmap(LOGO_PATH)
        self.Logo_Space.setPixmap(Logo_Pixmap.scaled(121,101,Qt.KeepAspectRatio,Qt.SmoothTransformation))
        self.Banner_Space.setPixmap(Banner_Pixmap.scaled(681,121,Qt.KeepAspectRatio,Qt.SmoothTransformation))
        self.Extract_Node_Size_Box.setText('15')
        self.Feature_Node_Size_Box.setText('10')
        self.Spin_Max_Size.setText('20')
        self.Dereplicate_Button.setEnabled(False)
        self.SMART_Export_Button.setEnabled(False)
        self.Export_Derep_File_Button.setEnabled(False)
        self.Plot_Proton_Button.setEnabled(False)
        self.VIEWHSQC_2.setEnabled(False)
        self.VIEWTOCSY_2.setEnabled(False)
        self.MADByTE_Button_2.setEnabled(False)
        self.TOCSY_Net_Button_2.setEnabled(False)
        self.Multiplet_Merger_Checkbox.setChecked(True)
        for NMR_Datatype in ['Bruker','Mestrenova','CSV']:#,'JOEL','Agilent','NMRPipe','Peak Lists]:
            self.NMR_Data_Type_Combo_Box.addItem(NMR_Datatype)
        self.Network_Filename_Input.setText("MADByTE")
        ### Bioactivity Layering values ###
        self.High_Activity_Box.setText('1.0')
        self.Mild_Activity_Box.setText('0.66')
        self.Low_Activity_Box.setText('0.33')
        self.Generate_Bioactivity_Plot_Button.clicked.connect(self.Bioactivity_Plotting_Fx)
        self.Select_Bioactivity_File_Button.clicked.connect(self.Select_Bioactivity_File_Fx)
        self.Select_Network_To_Layer_Button.clicked.connect(self.Select_Network_To_Layer_Fx)
        self.Bioactivity_Network_Name_Box.setText("Bioactivity_Network")
        self.SMART_Export_Button.clicked.connect(self.SMART_Export_Fx)
        self.Export_Derep_File_Button.clicked.connect(self.Export_Derep_File)
        ###Connect Buttons to Fx ###
        self.NMR_Data_Directory_Select.clicked.connect(self.Select_NMR_Data_Directory)
        self.Select_Project_Directory.clicked.connect(self.Select_Project_Directory_Fx)
        self.RemoveSampleFromListButton.clicked.connect(self.Remove_From_Sample_List)
        self.MADByTE_Button_2.clicked.connect(self.prompt_MADByTE)
        self.ViewNetwork.clicked.connect(self.ViewNetwork_launch)
        self.TOCSY_Net_Button_2.clicked.connect(self.MADByTE_Networking_Launch)
        self.actionDocumentation.triggered.connect(self.Launch_Documentation)
        self.actionExamples.triggered.connect(self.Launch_Example)
        self.Plot_Proton_Button.clicked.connect(self.View_1D_Data)
        self.VIEWHSQC_2.clicked.connect(self.View_HSQC_Data)
        self.VIEWTOCSY_2.clicked.connect(self.View_TOCSY_Data)
        self.Update_Log.clicked.connect(self.Update_Log_Fx)
        self.Dereplicate_Button.clicked.connect(self.Dereplication_Report)
        self.Extract_Node_Color_Button.clicked.connect(self.Select_Extract_Color)
        self.Spin_Node_Color_Button.clicked.connect(self.Select_Spin_Color)
        self.Load_Parameters_Button.clicked.connect(self.Load_Parameters)
        self.Export_Derep_Button.clicked.connect(self.Export_Derep_Results)
        self.Load_Derep_Library_Button.clicked.connect(self.Select_Dereplication_Library)
        ###Create the Plotting Window for the NMR Data####
        Plotted = self.plot
        global vLine
        global hLine
        vLine = InfiniteLine(angle=90, movable=False)
        hLine = InfiniteLine(angle=0, movable=False)
        Plotted.enableAutoRange(True)
        Plotted.addItem(vLine, ignoreBounds=True)
        Plotted.addItem(hLine, ignoreBounds=True)
        Plotted.setMouseTracking(True)
        Plotted.showGrid(x=True,y=True,alpha=0.75)
        Plotted.scene().sigMouseMoved.connect(self.mouseMoved)
        self.Solvent_comboBox.addItems(['DMSO-D6','MeOD','CDCl3','D2O'])
        ###Default Values for colors for networking###
        global Spin_color
        Spin_color = "#009999"
        global Extract_color
        Extract_color = "#ff3333"
        # Load sample networks if there...
        if not os.path.isdir(DEFAULT_NETWORKS):
            os.mkdir(DEFAULT_NETWORKS)

        for Network in os.listdir(DEFAULT_NETWORKS):
            if 'html' in Network:
                self.Drop_Down_List_Networks.addItem(Network)

    ###Functions####
    def Launch_Documentation(self):
        try: 
            subprocess.call(["open", os.path.join('Documentation','MADByTE_User_Manual.pdf')])
        except: 
            subprocess.Popen([os.path.join('Documentation','MADByTE_User_Manual.pdf')],shell=True)
    def Launch_Example(self):
        try: 
            subprocess.call(["open", os.path.join('Documentation','MADByTE_Quick_Start_Tutorial.pdf')])
        except:
            subprocess.Popen([os.path.join('Documentation','MADByTE_Quick_Start_Tutorial.pdf')],shell=True)

    def Load_Existing_Networks(self,MasterOutput):
        try:
            for Network in os.listdir(os.path.join(MasterOutput)):
                if 'html' in Network:
                    self.Drop_Down_List_Networks.addItem(Network)
        except:
            pass
        for Network in os.listdir(DEFAULT_NETWORKS):
            if 'html' in Network:
                self.Drop_Down_List_Networks.addItem(Network)

    def Load_Parameters(self):
        ID = 'temp'
        global Entity
        Entity = "Extract"
        global Hppm_Error
        Hppm_Error = float(self.Hppm_Input.text())
        global Cppm_Error
        Cppm_Error = float(self.Cppm_Input.text())
        global Tocsy_Error
        Tocsy_Error = float(self.Consensus_Error_Input.text())
        if self.Multiplet_Merger_Checkbox.isChecked()== True:
            Multiplet_Merger = True
        elif self.Multiplet_Merger_Checkbox.isChecked() == False:
            Multiplet_Merger = False
        Similarity_Cutoff = float(self.Similarity_Ratio_Input.text())
        
        try:
            MasterOutput
            DataDirectory
            self.MADByTE_Button_2.setEnabled(True)
        except:
            try: 
                DataDirectory
            except: 
                PopUP('Please Select NMR Data Directory','Please select an NMR data directory before proceeding.','Error')
            try:
                MasterOutput
            except:
                PopUP('Please Select Project Directory','Please select a project directory before proceeding.','Error')
         
        if MasterOutput == DataDirectory:
                PopUP('Please Differentiate Directories','The NMR data directory is where the processed NMR datafiles are, and the project directory is the MADByTE output location. They must be different.','Error')
        else:
            PopUP("Parameters Loaded","MADByTE parameters Loaded.","Info")

    def Select_Extract_Color(self):
        global Extract_color
        Extract_color = QColorDialog.getColor()
        Extract_color = Extract_color.name()
        self.Extract_Node_Color_Button.setStyleSheet(str("background-color:"+Extract_color+';'))
        return Extract_color

    def Select_Spin_Color(self):
        global Spin_color
        Spin_color = QColorDialog.getColor()
        Spin_color = Spin_color.name()
        self.Spin_Node_Color_Button.setStyleSheet(str("background-color:"+Spin_color+';'))
        return Spin_color

    def Select_NMR_Data_Directory(self):
        Directory_Location = QFileDialog.getExistingDirectory()
        global DataDirectory
        DataDirectory = Directory_Location
        self.BatchSamplesList.clear()
        for item in os.listdir(DataDirectory):
            self.BatchSamplesList.addItem(item)
        for NMR_Dataset in os.listdir(DataDirectory):
            self.NMR_Data_View_Selector.addItem(NMR_Dataset)
            self.Plot_Proton_Button.setEnabled(True)
        self.Ready_Check()
        return DataDirectory #Raw Data Directory (analogous to input_dir)

    def Select_Project_Directory_Fx(self):
        Directory_Location = QFileDialog.getExistingDirectory(self)
        if Directory_Location == '':
            PopUP('Please Select A Project Directory', 'Please select a directory to store the project results in. It is recommended to create a new project directory for each experiment processing or batch of samples.','Error')
            return
        global MasterOutput
        MasterOutput = os.path.join(Directory_Location)
        for Processed_Dataset in os.listdir(MasterOutput):
            self.Dereplication_Report_Sample_Select.addItem(Processed_Dataset)
        if len(os.listdir(MasterOutput))>0:
            self.Dereplicate_Button.setEnabled(True)
            self.SMART_Export_Button.setEnabled(True)
            self.Export_Derep_File_Button.setEnabled(True)
        for Network in os.listdir(MasterOutput):
            if 'html' in Network:
                self.Drop_Down_List_Networks.addItem(Network)
        self.VIEWHSQC_2.setEnabled(True)
        self.VIEWTOCSY_2.setEnabled(True)
        self.Ready_Check()
        if 'correlation_matrix.json' in os.listdir(MasterOutput): 
            self.TOCSY_Net_Button_2.setEnabled(True)
        return MasterOutput #Output Directory

    def Remove_From_Sample_List(self):
        Item_List = self.BatchSamplesList.selectedItems()
        if not Item_List: return
        for item in Item_List:
            self.BatchSamplesList.takeItem(self.BatchSamplesList.row(item)) #removes selected sample from list

    def openFileNameDialog(self):
        try:
            fileName,_ = QFileDialog.getOpenFileName(self)
            return fileName
        except:
            PopUP('Select Directory',"Please select a directory.",'Error')

    def MADByTE_Networking_Launch(self):
        self.MADByTE_Networking(Spin_color,Extract_color)

    def MADByTE_Networking(self,Spin_color,Extract_color):
        # Generates Network - allows for regen of network without reprocessing of files (updates size/colors)
        # Relevant Values: Colors and Sizes
        self.Drop_Down_List_Networks.clear()
        Extract_Node_Size = int(self.Extract_Node_Size_Box.text())
        Feature_Node_Size = int(self.Feature_Node_Size_Box.text())
        Filename = self.Network_Filename_Input.text() or "MADByTE" # Default if nothing entered
        Similarity_Cutoff = float(self.Similarity_Ratio_Input.text())
        Max_Spin_Size = int(self.Spin_Max_Size.text())
        colors = {'spin':Spin_color,'extract':Extract_color,'standard':"#0ffbff"}
        try: 
            MADByTE.generate_network(
                MasterOutput,
                Similarity_Cutoff,
                Filename,
                Cppm_Error,
                Hppm_Error,
                colors,
                Extract_Node_Size,
                Feature_Node_Size,
                Max_Spin_Size
            )
            self.Load_Existing_Networks(MasterOutput)
            PopUP("Networking Completed","MADByTE networking completed. Please select the network from the drop down list to view it.",'Info')
            self.Update_Log_Fx()
        except:
            try: 
                Cppm_Error
            except:
                PopUP('Load Parameters Before Proceeding','Please load the MADByTE parameters before generating a network.','Error')
            PopUP('Networking Error','Network constructin could not be completed due to an error.','Error')


    #################################################################
    ## The Dereplication Report was made to do dereplication through HSQC pattern matching ##
    ## The HSQC matching is only done when one of the spin systems has been found in the sample ## 

    def Dereplication_Report(self):
        print('Comparing sample against the dereplication library... ')
        def point_comparison(observed_value, expectedVal, tolerance):
            observed_value = float(observed_value)
            expectedVal = float(expectedVal)
            if (expectedVal - tolerance < observed_value) & (expectedVal + tolerance > observed_value):
                return True
            return False
        def HSQC_Scoring(Database_Sample_ID,Sample_Analyzed,MasterOutput,ID,result_dict):
            if Database_Sample_ID not in Sample_Analyzed: 
                Sample_Dataset = pd.read_json(os.path.join(MasterOutput,ID,ID+'_HSQC_Preprocessed.json')).drop(["Intensity"],axis=1)
                Database_Sample = pd.read_json(os.path.join(Dereplication_Database,Database_Sample_ID,"DDF_"+Database_Sample_ID+'_HSQC.json'))
                Number_Of_Resonances_Sample = len(Sample_Dataset)
                Number_Of_Resonances_Database_Item = len(Database_Sample)
                Match_Counter = 0
                for i in range(Number_Of_Resonances_Database_Item):
                    Database_Proton = Database_Sample.iloc[i-1].H_PPM
                    Database_Carbon = Database_Sample.iloc[i-1].C_PPM
                    for i in range(Number_Of_Resonances_Sample):
                        Sample_Proton = Sample_Dataset.iloc[i-1].H_PPM
                        Sample_Carbon = Sample_Dataset.iloc[i-1].C_PPM
                        if point_comparison(Database_Proton,Sample_Proton,Hppm_Error)==True:
                            if point_comparison(Database_Carbon,Sample_Carbon,Cppm_Error)==True:
                                Match_Counter+=1
                Compound_Match_Ratio = str(Match_Counter)+'/'+str(Number_Of_Resonances_Database_Item)
                if Match_Counter >= Number_Of_Resonances_Database_Item:
                    Compound_Match_Ratio = '1'
                Sample_Analyzed.append(Database_Sample_ID)
                result_dict[Database_Sample_ID]=Compound_Match_Ratio
                return result_dict
        ID = self.Dereplication_Report_Sample_Select.currentText()
        Hppm_Error = float(self.Hppm_Input_2.text())
        Cppm_Error = float(self.Cppm_Input_2.text())
        list_of_Database_compounds = os.listdir(os.path.join(Dereplication_Database))
        self.Dereplication_Report_Table.setColumnCount(2)
        self.Dereplication_Report_Table.setRowCount(len(list_of_Database_compounds)+1)
        self.Dereplication_Report_Table.setHorizontalHeaderLabels(["Compound","Matching Ratio"])
        Spin_System_Confirmed = False
        Sample_Analyzed = list()
        Not_Detected = list()
        result_dict=dict()
        if self.Require_Spin_System_checkBox.isChecked()==True: 
            with open(os.path.join(os.path.join(MasterOutput,ID,ID+'_spin_systems.json'))) as f: 
                Sample_Spin_Systems = json.load(f)
                df_sample = pd.DataFrame([{"ID": k, "H_ppm": x[0], "C_ppm": x[1]} for k,v in Sample_Spin_Systems.items() for x in v])
                df_DDFs = utils.load_spin_systems(os.path.join(Dereplication_Database))
                df = pd.concat([df_sample,df_DDFs])
                idxs = df_sample["ID"].unique()
                idys = df_DDFs["ID"].unique()
                for idx,idy in itertools.product(idxs,idys):
                        ratio = utils.ratio_two_systems(idx, idy, df, Hppm_Error, Cppm_Error)
                        if 'HND_' in idy: 
                            Database_Sample_ID = str("_".join(idy.split("_")[1:-1]))
                        elif 'HND_' not in idy: 
                            Database_Sample_ID= str("_".join(idy.split("_")[:-1]))
                        if ratio>float(self.Overlap_Score_lineEdit.text()):
                            HSQC_Scoring(Database_Sample_ID,Sample_Analyzed,MasterOutput,ID,result_dict)
                        if ratio <=float(self.Overlap_Score_lineEdit.text()):
                            Not_Detected.append(Database_Sample_ID)
                            if Database_Sample_ID not in Sample_Analyzed:
                                result_dict[Database_Sample_ID]='Not Detected'
        elif self.Require_Spin_System_checkBox.isChecked()==False:
            for Database_Sample_ID in os.listdir(Dereplication_Database): 
                result_dict = HSQC_Scoring(Database_Sample_ID,Sample_Analyzed,MasterOutput,ID,result_dict)
        compound_number=0
        for Database_Value in result_dict:
            self.Dereplication_Report_Table.setItem(compound_number,0, QTableWidgetItem(str(Database_Value)))
            self.Dereplication_Report_Table.setItem(compound_number,1, QTableWidgetItem(result_dict[Database_Value]))
            compound_number+=1
        print('Completed.')
    def SMART_Export_Fx(self):
        ID = self.Dereplication_Report_Sample_Select.currentText()
        Sample_Dataset = pd.read_json(os.path.join(MasterOutput,ID,ID+'_HSQC_Preprocessed.json')).drop(["Intensity"],axis=1)
        Sample_Dataset.columns = ['1H','13C']
        Sample_Dataset = Sample_Dataset.sort_values(by=['1H'],ascending = True).round({'1H':2,'13C':1})
        Sample_Dataset.to_csv(os.path.join(MasterOutput,ID,ID+'_SMART_Peak_List.csv'))
        PopUP('Dataset Exported',str('The HSQC Data for'+ID+' has been converted to a CSV formatted for direct import into SMART. Go to SMART.ucsd.edu to search this dataset against over 40k HSQC spectra'),'Info')
    def Export_Derep_File(self):
        from shutil import copyfile
        ID = self.Dereplication_Report_Sample_Select.currentText()
        Sample_Dataset = pd.read_json(os.path.join(MasterOutput,ID,ID+'_HSQC_Preprocessed.json')).drop(["Intensity"],axis=1)
        Sample_Dataset["Identity"] = ID
        if 'HND_' in ID: 
            ID2 = ID
            ID = ID.replace("HND_","")
        os.mkdir(os.path.join('Dereplication_Database',ID))
        try:
            ID2 
            copyfile(os.path.join(MasterOutput,ID2,ID2+'_spin_systems.json'),os.path.join('Dereplication_Database',ID,ID+'_spin_systems.json'))
        except: 
            copyfile(os.path.join(MasterOutput,ID,ID+'_spin_systems.json'),os.path.join('Dereplication_Database',ID,ID+'_spin_systems.json'))
        Sample_Dataset.to_json(os.path.join('Dereplication_Database',ID,'DDF_'+ID+'_HSQC.json'))
    def Export_Derep_Results(self):
        import csv
        path = QFileDialog.getSaveFileName(
                self, 'Save File', '', 'CSV(*.csv)')[0]
        with open(path, 'w',newline='') as stream:
            writer = csv.writer(stream)
            headers = []
            for column in range(self.Dereplication_Report_Table.columnCount()):
                header = self.Dereplication_Report_Table.horizontalHeaderItem(column)
                if header is not None:
                        headers.append(header.text())
                else:
                    headers.append("Column " + str(column))
            writer.writerow(headers)
            for row in range(self.Dereplication_Report_Table.rowCount()):
                rowdata = []
                for column in range(self.Dereplication_Report_Table.columnCount()):
                    item = self.Dereplication_Report_Table.item(row, column)
                    if item is not None:
                        rowdata.append(str(item.text()))
                        print(str(item.text()))
                    else:
                        pass
                writer.writerow(rowdata)

    def Select_Dereplication_Library(self):
        global Dereplication_Database
        Dereplication_Database = QFileDialog.getExistingDirectory(self)
        print('Custom dereplication library loaded.')
        return Dereplication_Database
    def ViewNetwork_launch(self):
        self.window2=QMainWindow()
        self.ui = Network_Viewer()
        self.ui.show()

    def Update_Log_Fx(self):
        try:
            with open(os.path.join(MasterOutput, "MADByTE_Log.txt"), "r") as f:
                contents = f.read()
            self.Madbyte_Log_Viewer.setText(contents)
        except:
            PopUP('Log file not found.',"The MADByTE log file was not found. Please ensure you have selected a project directory to load the file.",'Error')

    def prompt_MADByTE(self):
        PopUP("Begining MADByTE","Now Begining MADByTE Analysis. \n Based on how many samples were submitted, this may take a while. Please hit 'ok'. ",'Info')
        ID = 'temp'
        global Entity
        Entity = "Extract"
        global Hppm_Error
        Hppm_Error = float(self.Hppm_Input.text())
        global Cppm_Error
        Cppm_Error = float(self.Cppm_Input.text())
        global Tocsy_Error
        Tocsy_Error = float(self.Consensus_Error_Input.text())
        if self.Multiplet_Merger_Checkbox.isChecked()== True:
            Multiplet_Merger = True
        elif self.Multiplet_Merger_Checkbox.isChecked() == False:
            Multiplet_Merger = False
        Similarity_Cutoff = float(self.Similarity_Ratio_Input.text())
        global nmr_data_type
        nmr_data_type = self.NMR_Data_Type_Combo_Box.currentText()

        self.run_MADByTE(DataDirectory, Entity, Hppm_Error, Cppm_Error,
                Tocsy_Error, MasterOutput, Multiplet_Merger, Similarity_Cutoff,
                nmr_data_type)

    def run_MADByTE(
        self,
        DataDirectory,
        Entity,
        Hppm_Error,
        Cppm_Error,
        Tocsy_Error,
        MasterOutput,
        Multiplet_Merger,
        Similarity_Cutoff,
        nmr_data_type
    ):
        
        Sample_List = []
        for x in range(self.BatchSamplesList.count()):
            Sample_List.append(self.BatchSamplesList.item(x).text())

        setup_logging("MADByTE_Log.txt", fpath=MasterOutput, level=logging.DEBUG)
        # Define workers to start processing
        Solvent = self.Solvent_comboBox.currentText()
        Restart_Flag = False
        if 'correlation_matrix.json' in os.listdir(MasterOutput): 
            DF_Dialog = Data_Found_Dialog()
            if DF_Dialog.exec_():
                print('Reprocessing Data')
                Restart_Flag = True
            else:
                print('Reprocessing Canceled')
        ss_worker = Worker(
            fn=MADByTE.spin_system_construction,
            sample_list=Sample_List,
            input_dir=DataDirectory,
            project_dir=MasterOutput,
            nmr_data_type=nmr_data_type,
            entity=Entity,
            hppm_error=Hppm_Error,
            tocsy_error=Tocsy_Error,
            merge_multiplets=Multiplet_Merger,
            restart = Restart_Flag,
            solvent=Solvent,
        )
        corr_worker = Worker(
            fn=MADByTE.correlation_matrix_generation,
            project_dir=MasterOutput,
            hppm_error=Hppm_Error,
            cppm_error=Cppm_Error,
        )
        def ss_complete():
            for s in Sample_List:
                self.Dereplication_Report_Sample_Select.addItem(s)
            # Trigger correlation network
            self.threadpool.start(corr_worker)
        def corr_complete():
            PopUP('MADByTE Analysis Completed',"MADByTE Analysis and Correlation Matrix Generation has completed on these datasets.","Info")
            self.Update_Log_Fx()
        self.TOCSY_Net_Button_2.setEnabled(True)
        self.Dereplicate_Button.setEnabled(True)
        self.SMART_Export_Button.setEnabled(True)
        self.Export_Derep_File_Button.setEnabled(True)

        # Tell workers to execute functions when complete
        ss_worker.signals.finished.connect(ss_complete)
        corr_worker.signals.finished.connect(corr_complete)
        # Execute
        self.threadpool.start(ss_worker)
        

    ###Plotting Functions###
    def mouseMoved(self,evt):
        pos = evt
        if self.plot.sceneBoundingRect().contains(pos):
            mousePoint = self.plot.plotItem.vb.mapSceneToView(pos)
            self.mousecoordinatesdisplay.setText("<span style='font-size: 15pt'>X=%0.01f, <span style='color: black'>Y=%0.01f</span>" % (mousePoint.x(),mousePoint.y()))
        vLine.setPos(mousePoint.x())
        hLine.setPos(mousePoint.y())

    ###How to view 1D NMR Data###
    def View_1D_Data(self):
        try:
            self.plot.clear()
            ID = self.NMR_Data_View_Selector.currentText()
            path_ = os.path.join(DataDirectory,ID)
            PROTON_DIR ="undefined"
            for directory in os.listdir(path_):
                with open(os.path.join(path_,directory,'pulseprogram')) as f:
                    content = f.readlines(1)
                    content = [x.strip() for x in content]
                    content = [x.rsplit('pp/')[1] for x in content]
                    if content == ['zg"']:
                        PROTON_DIR = os.path.join(path_,directory,'pdata',"1")

            dic, data = ng.bruker.read_pdata(PROTON_DIR)

            udic = ng.bruker.guess_udic(dic, data) #needed to convert from points to PPM
            uc = ng.fileiobase.uc_from_udic(udic)
            ppm_scale = uc.ppm_scale()
            self.plot.plot(ppm_scale,data)
            self.plot.invertX(True)
            self.plot.invertY(False)
        except:
            PopUP('Data Not Found','1H data not found. \n This may be for a few reasons: \n \n * MADByTE can only display data processed by Topspin.\n * The FID is corrupted and cannot be read. \n  * The pulse program file is missing or corrupted.','Error')

    def View_HSQC_Data(self):
        try:
            self.plot.clear()
            ID = self.NMR_Data_View_Selector.currentText()
            HSQC_DATA = pd.read_json(os.path.join(MasterOutput,ID,str(ID+"_HSQC_Preprocessed.json")))
            self.plot.plot(HSQC_DATA.H_PPM,HSQC_DATA.C_PPM,pen=None,symbol = "o")
            self.plot.invertX(True)
            self.plot.invertY(True)
        except:
            PopUP('Data not found','Selected Dataset not found. Please process in Topspin Prior to running MADByTE. For 2D Datasets, the displayed data is derived from peak picking lists.','Error')

    def View_TOCSY_Data(self):
        try:
            self.plot.clear()
            ID = self.NMR_Data_View_Selector.currentText()
            TOCSY_DATA = pd.read_json(os.path.join(MasterOutput,ID,str(ID+"_TOCSY_Data.json")))
            self.plot.plot(TOCSY_DATA.Ha,TOCSY_DATA.Hb,pen=None,symbol="o" )
            self.plot.invertX(True)
            self.plot.invertY(True)
            vLine = InfiniteLine(angle=45, movable=False)
            self.plot.addItem(vLine)
        except:
            PopUP('Data not found','Selected Dataset not found. Please process in Topspin Prior to running MADByTE. For 2D Datasets, the displayed data is derived from peak picking lists.','Error')
    def Bioactivity_Plotting_Fx(self):
        try:
            Bioactivity_Low = float(self.Low_Activity_Box.text())
            Bioactivity_Med = float(self.Mild_Activity_Box.text())
            Bioactivity_High = float(self.High_Activity_Box.text())
            fname = self.Bioactivity_Network_Name_Box.text()
            title = fname
            MADByTE.plotting.Bioactivity_plot(MasterOutput,Network_In_Path,Bioactivity_Data_In,title,fname,Bioactivity_Low,Bioactivity_Med,Bioactivity_High)
            PopUP('Network successfully created','The Bioactivity Network has been created successfully.','Info')
        except:
            PopUP('Something went wrong',"Please ensure you've correctly set the values for the bioactivity cutoffs and that the bioactivity data is in the correct format.",'Error')
    def Select_Network_To_Layer_Fx(self):
        global Network_In_Path
        Network_In_Path = self.openFileNameDialog()
        if '.graphml' not in Network_In_Path:
            PopUP('Incorrect data type','Please select the .graphml version of the network, the HTML file will not work.','Error')

    def Select_Bioactivity_File_Fx(self):
        global Bioactivity_Data_In
        Bioactivity_Data_In = self.openFileNameDialog()
        if Directory_Location == '':
            PopUP('Please Select A Bioactivity File', 'Please select a bioactivity file to continue.','Error')
            return
        if '.csv' not in Bioactivity_Data_In:
            PopUP('Incorrect data type','Please select a CSV file.','Error')
    
    def Ready_Check(self):
        try:
            MasterOutput
        except:
            self.MADByTE_Button_2.setToolTip('Select a project directory before proceeding.')
        try:
            DataDirectory
        except:
            self.MADByTE_Button_2.setToolTip('Select an NMR data directory.')
        try:
            MasterOutput
            DataDirectory
            self.MADByTE_Button_2.setToolTip('Ready to run MADByTE Analysis.')
            self.MADByTE_Button_2.setEnabled(True)
        except:
            return
예제 #32
0
파일: executor.py 프로젝트: prm268/Pythonic
class GridOperator(QObject):

    update_logger = pyqtSignal(name='update_logger')
    exec_pending = pyqtSignal(name='exec_pending')

    def __init__(self, grid):
        super().__init__()
        logging.debug('__init__() called on GridOperator')
        self.grid = grid
        self.stop_flag = False
        self.fastpath = False  # fastpath is active when debug is diasbled
        self.retry_counter = 0
        self.delay = 0
        self.threadpool = QThreadPool()
        self.b_debug_window = False
        self.pending_return = []
        self.pid_register = []
        self.exec_pending.connect(self.checkPending)
        mp.set_start_method('spawn')
        logging.debug('__init__() GridOperator, threadCount: {}'.format(
            self.threadpool.maxThreadCount()))

    def startExec(self, start_pos, record=None):

        logging.debug('startExec() called, start_pos = {}'.format(start_pos))

        try:
            element = self.grid.itemAtPosition(*start_pos).widget()
        except AttributeError as e:
            return

        if self.stop_flag:
            return
        self.update_logger.emit()
        executor = Executor(element, record, self.delay)
        executor.signals.finished.connect(self.execDone)
        executor.signals.pid_sig.connect(self.register_pid)
        element.highlightStart()
        self.threadpool.start(executor)

    def register_pid(self, pid):
        # register PID of spawned child process
        self.pid_register.append(pid)
        logging.debug('PID register: {}'.format(self.pid_register))

    def execDone(self, prg_return):

        logging.debug('execDone() called GridOperator from {}'.format(
            prg_return.source))

        element = self.grid.itemAtPosition(*prg_return.source).widget()

        logging.debug('PID returned: {}'.format(prg_return.pid))
        # remove returned pid from register
        try:
            self.pid_register.remove(prg_return.pid)
        except Exception as e:
            logging.error('De-registration of PID failed: {}'.format(e))

        # if an execption occured
        if (issubclass(prg_return.record_0.__class__, BaseException)):
            logging.error('Target {}|{} Exception found: {}'.format(
                prg_return.source[0], alphabet[prg_return.source[1]],
                prg_return.record_0))
            element.highlightException()
            self.exceptwindow = ExceptWindow(str(prg_return.record_0),
                                             prg_return.source)
            self.exceptwindow.window_closed.connect(self.highlightStop)
            return

        ### proceed with regular execution ###

        # when the log checkbox is activated
        if prg_return.log:
            if prg_return.log_txt:
                logging.info('Message {}|{} : {}'.format(
                    prg_return.source[0], alphabet[prg_return.source[1]],
                    prg_return.log_txt))
            if prg_return.log_output:
                log = prg_return.log_output
            else:
                log = prg_return.record_0

            logging.info('Output  {}|{} : {}'.format(
                prg_return.source[0], alphabet[prg_return.source[1]], log))

        # when the debug button on the element is active
        if element.b_debug:

            if prg_return.log_output:
                log_message = prg_return.log_output
            else:
                log_message = str(prg_return.record_0)

            logging.debug(
                'GridOperator::execDone() b_debug_window = {}'.format(
                    self.b_debug_window))

            if isinstance(element,
                          ExecStack):  # don't open the regular debug window

                logging.debug(
                    'GridOperator::execDone()Special window for Exec stack element'
                )
                element.highlightStop()
                self.goNext(prg_return)

            # check if there is already an open debug window
            elif not self.b_debug_window:

                self.debugWindow = DebugWindow(log_message, prg_return.source)
                self.debugWindow.proceed_execution.connect(
                    lambda: self.proceedExec(prg_return))
                self.debugWindow.raiseWindow()

                #if not element.self_sync:
                self.b_debug_window = True

            else:

                self.pending_return.append(prg_return)

        else:
            # highlight stop =!

            element.highlightStop()
            self.goNext(prg_return)

    def checkPending(self):

        logging.debug('GridOperator::checkPending() called')

        if self.pending_return:
            prg_return = self.pending_return.pop(0)
            self.execDone(prg_return)

    def proceedExec(self, prg_return):

        element = self.grid.itemAtPosition(*prg_return.source).widget()
        element.highlightStop()
        self.b_debug_window = False
        self.exec_pending.emit()
        self.goNext(prg_return)

    def goNext(self, prg_return):

        if prg_return.target_0:
            logging.debug(
                'GridOperator::goNext() called with next target_0: {}'.format(
                    prg_return.target_0))
            logging.debug(
                'GridOperator::goNext() called with record_0: {}'.format(
                    prg_return.record_0))

            if self.fastpath:

                new_rec = self.fastPath(prg_return.target_0,
                                        prg_return.record_0)
                if new_rec:  # check for ExecR or ExecRB
                    self.goNext(new_rec)
                else:  # if nothing found: proceed as usual
                    self.startExec(prg_return.target_0, prg_return.record_0)
            else:
                self.startExec(prg_return.target_0, prg_return.record_0)

        if prg_return.target_1:

            logging.debug(
                'GridOperator::goNext() called with additional target_1: {}'.
                format(prg_return.target_1))
            logging.debug(
                'GridOperator::goNext() called with record_1: {}'.format(
                    prg_return.record_1))

            # self_sync is true on basic_sched and binancesched
            self_sync = self.grid.itemAtPosition(
                *prg_return.target_1).widget().self_sync

            if self.fastpath and not self_sync:
                new_rec = self.fastPath(prg_return.target_1,
                                        prg_return.record_1)
                logging.debug('GridOperator::goNext() execption here')
                logging.debug(
                    'GridOperator::goNext() new_rec: {}'.format(new_rec))
                self.goNext(new_rec)
            else:
                self.startExec(prg_return.target_1, prg_return.record_1)

    def fastPath(self, target, record):

        logging.debug(
            'GridOperator::fastPath() check row: {} col: {}'.format(*target))
        element = self.grid.itemAtPosition(*target).widget()

        if isinstance(element, ExecRB):  # jump to the next target
            # record_1 -> record_0 when goNext() is called recursively
            # returning only target_0 and record_0
            new_rec = Record(element.getPos(),
                             (element.row + 1, element.column), record)
            return new_rec
        elif isinstance(element, ExecR):  # jump to the next target
            #hier testen ob target fings
            # record_1 -> record_0 when goNext() is called recursively
            # returning only target_0 and record_0
            new_rec = Record(element.getPos(),
                             (element.row, element.column + 1), record)
            return new_rec
        else:
            return None

    def highlightStop(self, position):
        logging.debug(
            'highlightStop() called for position {}'.format(position))
        element = self.grid.itemAtPosition(*position).widget()
        element.highlightStop()

    def stop_execution(self):
        logging.debug('stop_execution() called')
        self.stop_flag = True

    def kill_proc(self):
        logging.debug('kill_proc() called')

        for proc in self.pid_register:
            os.kill(proc, signal.SIGTERM)
            logging.info('Process killed, PID {}'.format(proc))

        self.pid_register.clear()