Esempio n. 1
0
def main():
    app = QtWidgets.QApplication(sys.argv)
    win = QtWidgets.QMainWindow()
    area = DockArea()
    win.setCentralWidget(area)
    win.show()

    dock = Dock(name='Test Dock', area=area)
    area.addDock(dock)

    QtCore.QThread.sleep(2)
    dock.close()
    QtWidgets.QApplication.processEvents()
    sys.exit(app.exec_())
Esempio n. 2
0
class MainWindow(QtGui.QMainWindow):
    # for dock
    def __init__(self, parent=None):

        from pyqtgraph import exporters
        exporters.Exporter.register = self.modified_register

        QtGui.QMainWindow.__init__(self, parent)

        self.setWindowIcon(QtGui.QIcon(logo))
        self.setWindowTitle('CIVET')

        self.setGeometry(200, 143, 1574, 740)
        pg.setConfigOption('background', QtGui.QColor(215, 214, 213, 255))
        pg.setConfigOption('foreground', 'k')
        palette = QtGui.QPalette()
        palette.setColor(QtGui.QPalette.Background,
                         QtGui.QColor(215, 214, 213, 255))
        self.setPalette(palette)

        self.mainframe = QtGui.QFrame()

        self.copen = 0
        self.sopen = 0
        self.ropen = 0
        self.gridstate = 0
        self.current_docks = []

        self.loadaction = QtGui.QAction("&Open", self)
        self.loadaction.setShortcut("Ctrl+O")
        self.loadaction.setStatusTip("Open File")
        self.loadaction.triggered.connect(self.loaddata)

        self.exportaction = QtGui.QAction("&Export", self)
        self.exportaction.setShortcut("Ctrl+E")
        self.exportaction.setStatusTip("Export to a folder")
        self.exportaction.triggered.connect(self.exportdata)

        self.viewaction1 = QtGui.QAction("&Grid View 1", self)
        self.viewaction1.setStatusTip("Grid View 1")
        self.viewaction1.triggered.connect(self.grid_view_1)

        self.viewaction2 = QtGui.QAction("&Grid View 2", self)
        self.viewaction2.setStatusTip("Grid View 2")
        self.viewaction2.triggered.connect(self.grid_view_2)

        self.about = QtGui.QAction("&Info", self)
        self.about.setStatusTip("Info")
        self.about.triggered.connect(self.about_info)

        self.mainMenu = self.menuBar()
        self.fileMenu = self.mainMenu.addMenu("&File")
        self.fileMenu.addAction(self.loadaction)
        self.fileMenu.addAction(self.exportaction)

        self.viewMenu = self.mainMenu.addMenu("&Display")
        self.viewMenu.addAction(self.viewaction1)
        self.viewMenu.addAction(self.viewaction2)

        self.aboutMenu = self.mainMenu.addMenu("&About")
        self.aboutMenu.addAction(self.about)

        self.maketoolbar()

        self.area = DockArea()

        self.drho = Dock("\u03c1")
        self.dlamb = Dock("\u03bb")
        self.dalpha = Dock("\u03b1")
        self.dbeta = Dock("\u03b2")
        self.dphase = Dock("Phase")
        self.dcontrols = Dock("Controls")

        self.layout = QtGui.QHBoxLayout()
        self.layout.addWidget(self.area)
        self.mainframe.setLayout(self.layout)
        self.mainframe.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised)
        self.mainframe.setLineWidth(8)

# all those have different relative positions so made bunch of functions, not one.

    def modified_register(self, cls):

        exporters.Exporter.Exporters.append(None)

    def dlambadd(self):
        try:
            self.area.addDock(self.dlamb, 'bottom', self.drho)
        except:
            try:
                self.area.addDock(self.dlamb, 'left', self.dphase)
            except:
                self.area.addDock(self.dlamb, 'left')

    def drhoadd(self):
        try:
            self.area.addDock(self.drho, 'top', self.dlamb)
        except:
            try:
                self.area.addDock(self.drho, 'left', self.dalpha)
            except:
                self.area.addDock(self.drho, 'left')

    def dalphaadd(self):
        try:
            self.area.addDock(self.dalpha, 'left', self.dbeta)
        except:
            try:
                self.area.addDock(self.dalpha, 'right', self.drho)
            except:
                try:
                    self.area.addDock(self.dalpha, 'top', self.dphase)
                except:
                    self.area.addDock(self.dalpha, 'left')

    def dbetaadd(self):
        try:
            self.area.addDock(self.dbeta, 'top', self.dcontrols)
        except:
            try:
                self.area.addDock(self.dbeta, 'right', self.dalpha)
            except:
                self.area.addDock(self.dbeta, 'right')

    def dphaseadd(self):
        try:
            self.area.addDock(self.dphase, 'left', self.dcontrols)
        except:
            try:
                self.area.addDock(self.dphase, 'bottom', self.dalpha)
            except:
                try:
                    self.area.addDock(self.dphase, 'right', self.dlamb)
                except:
                    self.area.addDock(self.drho, 'bottom')

    def dcontrolsadd(self):
        try:
            self.area.addDock(self.dcontrols, 'right', self.dphase)
        except:
            try:
                self.area.addDock(self.dcontrols, 'bottom', self.dbeta)
            except:
                self.area.addDock(self.dcontrols, 'right')

    def checkbox_init(self):
        self.dock_on = []

        self.cwindow = QtGui.QMainWindow()
        self.cwindow.setWindowIcon(QtGui.QIcon(logo))
        self.cwindow.setWindowTitle('Plots')

        self.boxeswidget = QtGui.QWidget(self.cwindow)
        checkbox_layout = QtGui.QGridLayout(self.boxeswidget)
        self.ch_lamb = QtGui.QCheckBox(self.boxeswidget)
        self.ch_lamb.setText('\u03bb')
        self.ch_lamb.setChecked(True)
        self.ch_lamb.stateChanged.connect(lambda: self.dlamb.close(
        ) if not self.ch_lamb.isChecked() else self.dlambadd())

        self.ch_rho = QtGui.QCheckBox(self.boxeswidget)
        self.ch_rho.setText('\u03c1')
        self.ch_rho.setChecked(True)
        self.ch_rho.stateChanged.connect(lambda: self.drho.close(
        ) if not self.ch_rho.isChecked() else self.drhoadd())

        self.ch_alpha = QtGui.QCheckBox(self.boxeswidget)
        self.ch_alpha.setText('\u03b1')
        self.ch_alpha.setChecked(True)
        self.ch_alpha.stateChanged.connect(lambda: self.dalpha.close(
        ) if not self.ch_alpha.isChecked() else self.dalphaadd())

        self.ch_beta = QtGui.QCheckBox(self.boxeswidget)
        self.ch_beta.setText('\u03b2')
        self.ch_beta.setChecked(True)
        self.ch_beta.stateChanged.connect(lambda: self.dbeta.close(
        ) if not self.ch_beta.isChecked() else self.dbetaadd())

        self.ch_phase = QtGui.QCheckBox(self.boxeswidget)
        self.ch_phase.setText('Phase')
        self.ch_phase.setChecked(True)
        self.ch_phase.stateChanged.connect(lambda: self.dphase.close(
        ) if not self.ch_phase.isChecked() else self.dphaseadd())

        self.ch_controls = QtGui.QCheckBox(self.boxeswidget)
        self.ch_controls.setText('Controls')
        self.ch_controls.setChecked(True)
        self.ch_controls.stateChanged.connect(lambda: self.dcontrols.close(
        ) if not self.ch_controls.isChecked() else self.dcontrolsadd())

        checkbox_layout.addWidget(self.ch_rho, 0, 0, 1, 1)
        checkbox_layout.addWidget(self.ch_lamb, 1, 0, 1, 1)
        checkbox_layout.addWidget(self.ch_alpha, 0, 1, 1, 1)
        checkbox_layout.addWidget(self.ch_phase, 1, 1, 1, 1)
        checkbox_layout.addWidget(self.ch_beta, 0, 2, 1, 1)
        checkbox_layout.addWidget(self.ch_controls, 1, 2, 1, 1)
        self.cwindow.setCentralWidget(self.boxeswidget)

    def checkbox(self):
        if self.copen == 0:
            self.check_current_docks()
            self.closed_docks = []

            for i in self.docklist:
                if i not in self.current_docks:
                    self.closed_docks += [i]
            for i in self.closed_docks:
                eval(i[:5] + "ch_" + i[6:]).setChecked(False)

            self.cwindow.show()
            self.copen = 1
        else:
            self.cwindow.hide()
            self.copen = 0

    def about_info(self):

        self.awindow = QtGui.QMainWindow()
        self.awindow.setWindowIcon(QtGui.QIcon(logo))
        self.awindow.setWindowTitle('About')
        labels = QtGui.QWidget(self.awindow)
        labels_layout = QtGui.QVBoxLayout(labels)
        self.line0 = QtGui.QLabel()
        self.line1 = QtGui.QLabel(
            "CIVET: Current Inspired Visualization and Evaluation of the")
        self.line2 = QtGui.QLabel()
        self.line3 = QtGui.QLabel(
            "Totally asymmetric simple exclusion process (TASEP)")
        self.line4 = QtGui.QLabel()
        self.line5 = QtGui.QLabel("Copyright (c) 2018,")
        self.line6 = QtGui.QLabel()
        self.line7 = QtGui.QLabel(
            "Wonjun Son, Dan D. Erdmann-Pham,  Khanh Dao Duc, Yun S. Song")
        self.line8 = QtGui.QLabel()
        self.line9 = QtGui.QLabel("All rights reserved.")
        self.line10 = QtGui.QLabel()

        for i in range(11):
            eval("self.line" + str(i)).setAlignment(QtCore.Qt.AlignCenter)
            labels_layout.addWidget(eval("self.line" + str(i)))
        self.awindow.setCentralWidget(labels)
        self.awindow.show()

    def exportdata(self):

        self.dialog = QtGui.QFileDialog()
        self.dialog.setOption(QtGui.QFileDialog.ShowDirsOnly)
        self.dialog.setFileMode(QtGui.QFileDialog.DirectoryOnly)

        folder_name = self.dialog.getSaveFileName(self, "Save Directory")
        filepath = os.path.join(os.path.abspath(os.sep), folder_name)
        if not os.path.exists(filepath):
            makedirs(filepath)

        # arr = QtCore.QByteArray()
        # buf = QtCore.QBuffer(arr)
        # svg = QtSvg.QSvgGenerator()
        # svg.setOutputDevice(buf)
        # dpi = QtGui.QDesktopWidget().physicalDpiX()
        # svg.setResolution(dpi)

        svg = QtSvg.QSvgGenerator()
        svg.setFileName("hh")
        svg.setSize(QtCore.QSize(2000, 2000))
        svg.setViewBox(self.rect())
        svg.setTitle("SVG svg Example Drawing")
        svg.setDescription("An SVG drawing created by the SVG Generator ")

        p = QtGui.QPainter()
        p.begin(svg)
        try:
            self.render(p)
        finally:
            p.end()
        # gen.setViewBox(QtGui.QRect(0, 0, 200, 200));
        # gen.setTitle(tr("SVG Gen Example Drawing"));
        # gen.setDescription(tr("An SVG drawing created by the SVG Generator ""Example provided with Qt."));

        lambda_data = os.path.join(filepath, "Lambda_data.csv")
        with open(lambda_data, "w") as output:
            try:
                writer = csv.writer(output, lineterminator='\n')
                for val in np.array(glo_var.lambdas)[:, 1]:
                    writer.writerow([val])
            except:
                pass

        summary = os.path.join(filepath, "Summary.csv")
        with open(summary, "w") as output:
            try:
                writer = csv.writer(output,
                                    delimiter='\t',
                                    lineterminator='\n')
                writer.writerow(["alpha", glo_var.alpha])
                writer.writerow(["beta", glo_var.beta])
                writer.writerow(["l", glo_var.l])
                writer.writerow(["Phase", self.phas.pointer.region_aft])
            except:
                pass

        # for name, pitem in self.pltlist:
        # 	self.exportimg(pitem,os.path.join(filepath,name + ".svg"))
        # 	# self.exportimg(pitem,os.path.join(filepath,name + ".png"))

        currentanddensity = os.path.join(filepath, "Current & Density.csv")
        with open(currentanddensity, "w") as output:
            writer = csv.writer(output, delimiter='\t', lineterminator='\n')
            # combine alpha, beta    pre and post. Do it here to lessen the computation
            alpha_x_data = np.concatenate([
                np.array(self.jalph.alphas_pre),
                np.linspace(self.jalph.trans_point, 1, 2)
            ])
            alpha_j_data = np.concatenate(
                [self.jalph.j_l_values,
                 np.array([self.jalph.jpost] * 2)])
            alpha_rho_data = np.array(self.jalph.rho_avg_pre +
                                      self.jalph.rho_avg_post)

            beta_x_data = np.concatenate([
                np.array(self.jbet.betas_pre),
                np.linspace(self.jbet.trans_point, 1, 2)
            ])
            beta_j_data = np.concatenate(
                [self.jbet.j_r_values,
                 np.array([self.jbet.jpost] * 2)])
            beta_rho_data = np.array(self.jbet.rho_avg_pre +
                                     self.jbet.rho_avg_post)

            alpha_data = np.vstack(
                [alpha_x_data, alpha_j_data, alpha_rho_data])
            beta_data = np.vstack([beta_x_data, beta_j_data, beta_rho_data])

            writer.writerow([
                "alpha", "Current", "Average Density", '\t', '\t', "beta",
                "Current", "Average Density"
            ])
            for i in range(len(alpha_x_data)):
                writer.writerow(
                    list(alpha_data[:, i]) + [''] * 2 + list(beta_data[:, i]))
            writer.writerow('\n')
            writer.writerow(
                ['beta', glo_var.beta, '', '', '', 'alpha', glo_var.alpha, ''])
            writer.writerow([
                'transition point', self.jalph.trans_point, '', '', '',
                'transition point', self.jbet.trans_point, ''
            ])

        self.pdfgroup1 = ['Lambda_fig', 'Density_fig']
        self.pdfgroup2 = ['Current_alpha_fig', 'Current_beta_fig']

        for name, pitem in self.pltlist:
            # self.exportimg(pitem,os.path.join(filepath,name + ".png"))
            path = os.path.join(filepath, name + ".svg")
            #			if name == 'Current_alpha_fig':
            #				self.jalph.p3.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle)
            #				self.jalph.p3main.plotItem.legend.items=[]
            #				self.jalph.p3.plot(pen=self.jalph.jpen, name='J')
            #				self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329\u03c1 \u232a')

            #			elif name == 'Current_beta_fig':
            #				self.jbet.p4.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle)
            #				self.jbet.p4main.plotItem.legend.items=[]
            #				self.jbet.p4.plot(pen=self.jbet.jpen, name='J')
            #				self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329\u03c1 \u232a')
            self.exportimg(pitem, path)

            if name in self.pdfgroup1:
                self.makepdf(path, os.path.join(filepath, name + ".pdf"), 500,
                             260, 20, 240)
            elif name == 'Current_alpha_fig':
                self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350,
                             280, 30, 230)
#				self.jalph.p3.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle)
#				self.jalph.p3main.plotItem.legend.items=[]
#				self.jalph.p3.plot(pen=self.jalph.jpen, name='J')
#				self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329 \u03c1 \u232a')
            elif name == 'Current_beta_fig':
                self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350,
                             280, 30, 230)


#				self.jbet.p4.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle)
#				self.jbet.p4main.plotItem.legend.items=[]
#				self.jbet.p4.plot(pen=self.jbet.jpen, name='J')
#				self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329 \u03c1 \u232a')

            else:
                self.makepdf(path, os.path.join(filepath, name + ".pdf"), 410,
                             330, 10, 300)

            os.remove(path)

    def makepdf(self, path, name, x, y, z, q):

        from svglib.svglib import svg2rlg
        from reportlab.pdfgen import canvas
        from reportlab.graphics import renderPDF
        rlg = svg2rlg(path)
        rlg.scale(0.8, 0.8)
        c = canvas.Canvas(name)
        c.setPageSize((x, y))
        renderPDF.draw(rlg, c, z, q)
        c.showPage()
        c.save()

    def exportimg(self, img, path):
        # self.img = pg.exporters.ImageExporter(img)
        # self.img.export(path)
        self.svg = pg.exporters.SVGExporter(img)
        self.svg.export(fileName=path)

    def maketoolbar(self):
        self.state = None
        self.titlebarstate = 1
        self.toolbar = self.addToolBar("Toolbar")

        home = QtGui.QAction(
            QtGui.QIcon(QtGui.QApplication.style().standardIcon(
                QtGui.QStyle.SP_ComputerIcon)), 'Toggle Grid View', self)
        home.triggered.connect(self.toggle_grid_view)
        self.toolbar.addAction(home)

        fix = QtGui.QAction(
            QtGui.QIcon(QtGui.QApplication.style().standardIcon(
                QtGui.QStyle.SP_ArrowDown)), 'Fix current layout', self)
        fix.triggered.connect(self.fixdock)
        self.toolbar.addAction(fix)

        self.savedockandvaluesinit()
        save = QtGui.QAction(
            QtGui.QIcon(QtGui.QApplication.style().standardIcon(
                QtGui.QStyle.SP_FileDialogListView)), 'Save current layout',
            self)
        save.triggered.connect(self.popsavedockandvalues)
        self.toolbar.addAction(save)

        self.restoredockandvaluesinit()
        restore = QtGui.QAction(
            QtGui.QIcon(QtGui.QApplication.style().standardIcon(
                QtGui.QStyle.SP_BrowserReload)), 'Restore saved layout', self)
        restore.triggered.connect(self.poprestoredockandvalues)
        self.toolbar.addAction(restore)

        self.checkbox_init()
        checkbox = QtGui.QAction(
            QtGui.QIcon(QtGui.QApplication.style().standardIcon(
                QtGui.QStyle.SP_FileDialogDetailedView)),
            'Open & close specific windows', self)
        checkbox.triggered.connect(self.checkbox)
        self.toolbar.addAction(checkbox)

    def fixdock(self):
        if self.titlebarstate == 1:
            self.dlamb.hideTitleBar()
            self.drho.hideTitleBar()
            self.dalpha.hideTitleBar()
            self.dbeta.hideTitleBar()
            self.dcontrols.hideTitleBar()
            self.dphase.hideTitleBar()
            self.titlebarstate = 0

        else:
            self.dlamb.showTitleBar()
            self.drho.showTitleBar()
            self.dalpha.showTitleBar()
            self.dbeta.showTitleBar()
            self.dcontrols.showTitleBar()
            self.dphase.showTitleBar()
            self.titlebarstate = 1

    def savedockandvaluesinit(self):

        self.swindow = QtGui.QMainWindow()
        self.swindow.setWindowIcon(QtGui.QIcon(logo))
        self.swindow.setWindowTitle('Save')

        boxeswidget = QtGui.QWidget(self.swindow)
        checkbox_layout = QtGui.QGridLayout(boxeswidget)

        self.sa_dock = QtGui.QCheckBox(boxeswidget)
        self.sa_dock.setText('Grid View')
        self.sa_dock.setChecked(True)

        self.sa_values = QtGui.QCheckBox(boxeswidget)
        self.sa_values.setText('Values')
        self.sa_values.setChecked(True)

        self.save_button = QtGui.QPushButton('Save', self)
        self.save_button.clicked.connect(self.savedockandvalues)

        checkbox_layout.addWidget(self.sa_dock, 0, 0, 1, 1)
        checkbox_layout.addWidget(self.sa_values, 0, 1, 1, 1)
        checkbox_layout.addWidget(self.save_button, 1, 0, 1, 2)

        self.swindow.setCentralWidget(boxeswidget)

    def restoredockandvaluesinit(self):

        self.rwindow = QtGui.QMainWindow()
        self.rwindow.setWindowIcon(QtGui.QIcon(logo))
        self.rwindow.setWindowTitle('Restore')

        boxeswidget = QtGui.QWidget(self.rwindow)
        checkbox_layout = QtGui.QGridLayout(boxeswidget)

        self.re_dock = QtGui.QCheckBox(boxeswidget)
        self.re_dock.setText('Grid View')
        self.re_dock.setChecked(True)

        self.re_values = QtGui.QCheckBox(boxeswidget)
        self.re_values.setText('Values')
        self.re_values.setChecked(True)

        self.restore_button = QtGui.QPushButton('Restore', self)
        self.restore_button.clicked.connect(self.restoredockandvalues)

        checkbox_layout.addWidget(self.re_dock, 0, 0, 1, 1)
        checkbox_layout.addWidget(self.re_values, 0, 1, 1, 1)
        checkbox_layout.addWidget(self.restore_button, 1, 0, 1, 2)

        self.rwindow.setCentralWidget(boxeswidget)

    def savedockandvalues(self):
        if self.sa_values.checkState:
            self.savedlambdas = deepcopy(glo_var.lambdas)
            self.savedalpha = glo_var.alpha
            self.savedbeta = glo_var.beta
            self.savedl = glo_var.l
        if self.sa_dock.checkState:
            self.saved_state = []
            self.state = self.area.saveState()
            self.saved_state = self.check_current_docks()[:]

        self.sopen = 0
        self.swindow.hide()

    def popsavedockandvalues(self):
        if self.sopen == 0:
            self.swindow.show()
            self.sopen = 1

        else:
            self.swindow.hide()
            self.sopen = 0

    def poprestoredockandvalues(self):
        if self.ropen == 0:
            self.rwindow.show()
            self.ropen = 1

        else:
            self.rwindow.hide()
            self.ropen = 0

    def restoredockandvalues(self):
        if self.re_values.checkState:
            glo_var.lambdas = deepcopy(self.savedlambdas)
            glo_var.alpha = self.savedalpha
            glo_var.beta = self.savedbeta
            glo_var.l = self.savedl

            self.lamb_po.update()
            self.rh.update()
            self.phas.update()
            self.jalph.update()
            self.jbet.update()
            self.slid.update_alpha_slid(self.slid.ws[0])
            self.slid.update_beta_slid(self.slid.ws[1])
            self.slid.update_l_slid(self.slid.ws[2])

        if self.re_dock.checkState:

            if self.state != None:
                closed_docks = []
                self.check_current_docks()
                # Notice after below, current dock != real current dock. But it doesn't matter since we call check current dock every time.
                for i in self.current_docks:
                    if i not in self.saved_state:
                        eval(i).close()
                for i in self.saved_state:
                    if i not in self.current_docks:
                        eval(i + "add")()
                self.area.restoreState(self.state)
        self.ropen = 0
        self.rwindow.hide()

    def realinit(self):
        self.clear_buttons = [
            "self.lamb_po.p1main.coordinate_label.setText(\"\")",
            "self.rh.p2main.coordinate_label.setText(\"\")",
            "self.jalph.p3main.coordinate_label.setText(\"\")",
            "self.jbet.p4main.coordinate_label.setText(\"\")",
            "self.phas.p5main.coordinate_label.setText(\"\")"
        ]

        glo_var.pass_main(self)

        self.docklist = [
            'self.drho', 'self.dlamb', 'self.dalpha', 'self.dbeta',
            'self.dphase', 'self.dcontrols'
        ]
        self.area = DockArea()
        self.drho = Dock("Particle Density \u2374", closable=True)
        self.dlamb = Dock("Hopping Rate \u03bb", closable=True)
        self.dphase = Dock("Phase Diagram", closable=True)
        self.dcontrols = Dock("Controls", closable=True)
        self.dalpha = Dock(
            "Current J and average density \u27e8\u2374\u27e9 as a function of \u03b1",
            closable=True)
        self.dbeta = Dock(
            "Current J and average density \u27e8\u2374\u27e9 as a function of \u03b2",
            closable=True)

        self.layout = QtGui.QHBoxLayout()
        self.layout.addWidget(self.area)
        self.mainframe.setLayout(self.layout)
        self.mainframe.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised)
        self.mainframe.setLineWidth(8)

        pg.setConfigOptions(antialias=True)

        self.rh = rho.rho(self.drho)
        self.jalph = jalpha.jalpha(self.dalpha, self.rh)
        self.jbet = jbeta.jbeta(self.dbeta, self.rh)
        self.phas = phase.phase(self.dphase)
        self.lamb_po = lamb_pol.lamb_pol(self.dlamb)
        self.slid = slider.Widget(self.dcontrols, self.lamb_po, self.phas,
                                  self.rh, self.jbet, self.jalph)
        self.lamb_po.receive(self.slid)

        # default values to restore is input
        self.savedlambdas = glo_var.lambdas[:]
        self.savedalpha = glo_var.alpha
        self.savedbeta = glo_var.beta
        self.savedl = glo_var.l

        self.pltlist = [['Lambda_fig', self.lamb_po.p1],
                        ['Density_fig', self.rh.p2],
                        ['Current_alpha_fig', self.jalph.plotitemtoexport],
                        ['Current_beta_fig', self.jbet.plotitemtoexport],
                        ['Phase_fig', self.phas.p5]]

        self.grid_view_1()

        self.setCentralWidget(self.area)

        print(dir(self.area))
        print(self.area.childrenRect(), "childrenRect")
        print(self.area.contentsRect(), "contentesRect")
        print(self.area.rect())

    def check_current_docks(self):
        self.current_docks = []
        for i in self.docklist:
            if self.area.getContainer(eval(i)):
                self.current_docks += [i]
            else:
                pass
        return self.current_docks

    def toggle_grid_view(self):
        if self.gridstate == 0:
            self.grid_view_2()
            self.gridstate = 1
        else:
            self.grid_view_1()
            self.gridstate = 0

    def grid_view_1(self):
        for i in self.docklist:
            try:
                eval(i).close()
            except:
                pass

        self.drho.setMinimumSize(652, 370)
        self.dlamb.setMinimumSize(652, 370)
        self.dphase.setMinimumSize(487, 465)
        self.dcontrols.setMinimumSize(487, 275)
        self.dalpha.setMinimumSize(435, 370)
        self.dbeta.setMinimumSize(435, 370)

        self.area.addDock(self.drho, 'left')
        self.area.addDock(self.dlamb, 'bottom', self.drho)
        self.area.addDock(self.dphase, 'right')
        self.area.addDock(self.dcontrols, 'bottom', self.dphase)
        self.area.addDock(self.dalpha, 'right')
        self.area.addDock(self.dbeta, 'bottom', self.dalpha)

        self.drho.setMinimumSize(0, 0)
        self.dlamb.setMinimumSize(0, 0)
        self.dphase.setMinimumSize(0, 0)
        self.dcontrols.setMinimumSize(0, 0)
        self.dalpha.setMinimumSize(0, 0)
        self.dbeta.setMinimumSize(0, 0)

    def grid_view_2(self):
        for i in self.docklist:
            try:
                eval(i).close()
            except:
                pass
        self.area.addDock(self.drho, 'top')
        self.area.addDock(self.dlamb, 'bottom', self.drho)
        self.area.addDock(self.dphase, 'bottom')
        self.area.addDock(self.dcontrols, 'left', self.dphase)
        self.area.addDock(self.dalpha, 'right')
        self.area.addDock(self.dbeta, 'bottom', self.dalpha)

    def opengraphs(self):
        self.mn = main.main_class(app)
        self.window.hide()

    def loaddata(self):
        name = QtGui.QFileDialog.getOpenFileName(self, 'Open File', '.',
                                                 'text (*.txt *.csv)')
        if name == "":
            pass
        else:
            self.read_file(name)
            self.realinit()

    def read_file(self, input):
        global ison
        temp = []
        if ison == 0:
            ison = 1
        else:
            self.setCentralWidget(None)
            glo_var.initialize()

        if input[-3:] == 'csv':
            with open(input, newline='') as csvfile:
                spamreader = csv.reader(csvfile, delimiter=',', quotechar='|')
                lis = []
                for j in spamreader:
                    lis += j
                num_of_inputs = len(lis)
                glo_var.lambdas_degree = num_of_inputs
                for i in range(num_of_inputs):
                    glo_var.lambdas += [[
                        i / (num_of_inputs - 1),
                        round(eval(lis[i]), 2)
                    ]]
            glo_var.alpha = 0.04
            glo_var.beta = 0.04
            glo_var.l = 1

        elif input[-3:] == 'txt':
            f = open(input, 'r')
            # Breaks the loop i
            try:
                temp = []
                while (True):
                    T = f.readline().strip()
                    temp += [[glo_var.lambdas_degree, round(eval(T), 2)]]
            except:
                for x, y in temp:
                    glo_var.lambdas += [[x / (glo_var.lambdas_degree - 1), y]]
            glo_var.l = 1

        else:
            err = QtGui.QMessageBox(self.win)
            err.setIcon(QMessageBox().Warning)
            err.setText("Please select txt or csv file Format")
            err.setWindowTitle("File Format Error")
            err.setStandardButtons(QMessageBox.Ok)
            err.buttonClicked.connect()

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseMove:
            if event.buttons() == QtCore.Qt.NoButton:
                pos = event.pos()
                if self.toolbar.rect().contains(
                        pos) or not self.area.rect().contains(pos):
                    self.clear_points()
            else:
                pass
        return QtGui.QMainWindow.eventFilter(self, source, event)

    def clear_points(self, exclude=None):
        if not exclude:
            for x in self.clear_buttons:
                eval(x)
        else:
            for x in self.clear_buttons[:exclude -
                                        1] + self.clear_buttons[exclude:]:
                eval(x)
Esempio n. 3
0
class MainWindow(QMainWindow):
    """
    Main control window for showing the live captured images and initiating special tasks
    """
    def __init__(self, experiment):
        """
        Inits the camera window

        :param experiment: Experiment that is controlled by the GUI
        """
        super().__init__()
        self.setWindowTitle('PyNTA: Python Nanoparticle Tracking Analysis')
        self.setMouseTracking(True)
        self.experiment = experiment
        self.area = DockArea()
        self.setCentralWidget(self.area)
        self.resize(1064, 840)
        self.area.setMouseTracking(True)

        # Main widget
        self.camWidget = MonitorMainWidget()
        self.camWidget.setup_cross_cut(self.experiment.max_height)
        self.camWidget.setup_cross_hair(
            [self.experiment.max_width, self.experiment.max_height])
        self.camWidget.setup_roi_lines(
            [self.experiment.max_width, self.experiment.max_height])
        self.camWidget.setup_mouse_tracking()

        self.messageWidget = messageWidget()

        self.cheatSheet = popOutWindow()

        self.dmainImage = Dock("Camera",
                               size=(80, 35))  # sizes are in percentage
        self.dmainImage.addWidget(self.camWidget)
        self.area.addDock(self.dmainImage, 'right')
        self.dmessage = Dock("Messages", size=(40, 30))
        self.dmessage.addWidget(self.messageWidget)
        self.area.addDock(self.dmessage, 'right')

        # # Widget for displaying information to the user

        # # Small window to display the results of the special task
        # self.trajectoryWidget = trajectoryWidget()
        # # Window for the camera viewer
        # # self.camViewer = cameraViewer(self._session, self.camera, parent=self)
        # # Configuration widget with a parameter tree
        # # self.config = ConfigWidget(self._session)
        # # Line cut widget
        # self.crossCut = crossCutWindow(parent=self)
        # self.popOut = popOutWindow(parent=self) #_future: for making long message pop-ups
        # # Select settings Window
        # # self.selectSettings = HDFLoader()
        #
        self.refreshTimer = QtCore.QTimer()
        self.refreshTimer.timeout.connect(self.updateGUI)
        # self.refreshTimer.timeout.connect(self.crossCut.update)
        #
        self.refreshTimer.start(self.experiment.config['GUI']['refresh_time'])
        #
        # self.acquiring = False
        # self.logmessage = []
        #
        # ''' Initialize the camera and the camera related things '''
        # self.max_sizex = self.camera.GetCCDWidth()
        # self.max_sizey = self.camera.GetCCDHeight()
        # self.current_width = self.max_sizex
        # self.current_height = self.max_sizey
        #
        # # if self._session.Camera['roi_x1'] == 0:
        # #     self._session.Camera = {'roi_x1': 1}
        # # if self._session.Camera['roi_x2'] == 0 or self._session.Camera['roi_x2'] > self.max_sizex:
        # #     self._session.Camera = {'roi_x2': self.max_sizex}
        # # if self._session.Camera['roi_y1'] == 0:
        # #     self._session.Camera = {'roi_y1': 1}
        # # if self._session.Camera['roi_y2'] == 0 or self._session.Camera['roi_y2'] > self.max_sizey:
        # #     self._session.Camera = {'roi_y2': self.max_sizey}
        #
        # # self.config.populateTree(self.experiment.config)
        # self.lastBuffer = time.time()
        # self.lastRefresh = time.time()
        #
        # # Program variables
        # self.tempimage = []
        # self.bgimage = []
        # self.trackinfo = np.zeros((1,5)) # real particle trajectory filled by "LocateParticle" analysis
        # # self.noiselvl = self._session.Tracking['noise_level']
        # self.fps = 0
        # self.buffertime = 0
        # self.buffertimes = []
        # self.refreshtimes = []
        # self.totalframes = 0
        # self.droppedframes = 0
        # self.buffer_memory = 0
        # self.waterfall_data = []
        # self.watindex = 0 # Waterfall index
        # self.corner_roi = [] # Real coordinates of the corner of the ROI region. (Min_x and Min_y).
        # self.docks = []
        # # self.corner_roi.append(self._session.Camera['roi_x1'])
        # # self.corner_roi.append(self._session.Camera['roi_y1'])
        #
        # # Program status controllers
        # self.continuous_saving = False
        # self.show_waterfall = False
        # self.subtract_background = False
        # self.save_running = False
        # self.accumulate_buffer = False
        # self.specialtask_running = False
        # self.dock_state = None
        #
        self.setupActions()
        self.setupToolbar()
        self.setupMenubar()
        # self.setupDocks()
        # self.setupSignals()

        ### This block should erased in due time and one must rely exclusively on Session variables.
        # self.filedir = self._session.Saving['directory']
        # self.snap_filename = self._session.Saving['filename_photo']
        # self.movie_filename = self._session.Saving['filename_video']
        ###
        self.messageWidget.appendLog(
            'i',
            'Program started by %s' % self.experiment.config['User']['name'])

    def start_tracking(self):
        self.experiment.start_tracking()

    def showHelp(self):
        """To show the cheatsheet for shortcuts in a pop-up meassage box
        OBSOLETE, will be deleted after transferring info into a better message viewer!
        """
        self.experiment.plot_histogram()
        # msgBox = QtGui.QMessageBox()
        # msgBox.setIcon(QtGui.QMessageBox.Information)
        # msgBox.setText("Keyboard shortcuts and Hotkeys")
        # msgBox.setInformativeText("Press details for a full list")
        # msgBox.setWindowTitle("pynta CheatSheet")
        # msgBox.setDetailedText("""
        #     F1, Show cheatsheet\n
        #     F5, Snap image\n
        #     F6, Continuous run\n
        #     Alt+mouse: Select line \n
        #     Ctrl+mouse: Crosshair \n
        #     Ctrl+B: Toggle buffering\n
        #     Ctrl+G: Toggle background subtraction\n
        #     Ctrl+F: Empty buffer\n
        #     Ctrl+C: Start tracking\n
        #     Ctrl+V: Stop tracking\n
        #     Ctrl+M: Autosave on\n
        #     Ctrl+N: Autosave off\n
        #     Ctrl+S: Save image\n
        #     Ctrl+W: Start waterfall\n
        #     Ctrl+Q: Exit application\n
        #     Ctrl+Shift+W: Save waterfall data\n
        #     Ctrl+Shift+T: Save trajectory\n
        #     """)

    def setupActions(self):
        """Setups the actions that the program will have. It is placed into a function
        to make it easier to reuse in other windows.

        :rtype: None
        """
        self.exitAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/power-icon.png'), '&Exit', self)
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.setStatusTip('Exit application')
        self.exitAction.triggered.connect(self.exitSafe)

        self.saveAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/floppy-icon.png'), '&Save image',
            self)
        self.saveAction.setShortcut('Ctrl+S')
        self.saveAction.setStatusTip('Save Image')
        self.saveAction.triggered.connect(self.saveImage)

        self.showHelpAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/info-icon.png'),
            'Show cheatsheet', self)
        self.showHelpAction.setShortcut(QtCore.Qt.Key_F1)
        self.showHelpAction.setStatusTip('Show Cheatsheet')
        self.showHelpAction.triggered.connect(self.showHelp)

        self.saveWaterfallAction = QtGui.QAction("Save Waterfall", self)
        self.saveWaterfallAction.setShortcut('Ctrl+Shift+W')
        self.saveWaterfallAction.setStatusTip(
            'Save waterfall data to new file')
        self.saveWaterfallAction.triggered.connect(self.saveWaterfall)

        self.saveTrajectoryAction = QtGui.QAction("Save Trajectory", self)
        self.saveTrajectoryAction.setShortcut('Ctrl+Shift+T')
        self.saveTrajectoryAction.setStatusTip(
            'Save trajectory data to new file')
        self.saveTrajectoryAction.triggered.connect(self.saveTrajectory)

        self.snapAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/snap.png'), 'S&nap photo', self)
        self.snapAction.setShortcut(QtCore.Qt.Key_F5)
        self.snapAction.setStatusTip('Snap Image')
        self.snapAction.triggered.connect(self.snap)

        self.movieAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/video-icon.png'), 'Start &movie',
            self)
        self.movieAction.setShortcut(QtCore.Qt.Key_F6)
        self.movieAction.setStatusTip('Start Movie')
        self.movieAction.triggered.connect(self.startMovie)

        self.movieSaveStartAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Download-Database-icon.png'),
            'Continuous saves', self)
        self.movieSaveStartAction.setShortcut('Ctrl+M')
        self.movieSaveStartAction.setStatusTip('Continuous save to disk')
        self.movieSaveStartAction.triggered.connect(self.movieSave)

        self.movieSaveStopAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Delete-Database-icon.png'),
            'Stop continuous saves', self)
        self.movieSaveStopAction.setShortcut('Ctrl+N')
        self.movieSaveStopAction.setStatusTip('Stop continuous save to disk')
        self.movieSaveStopAction.triggered.connect(self.movieSaveStop)

        self.startWaterfallAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Blue-Waterfall-icon.png'),
            'Start &Waterfall', self)
        self.startWaterfallAction.setShortcut('Ctrl+W')
        self.startWaterfallAction.setStatusTip('Start Waterfall')
        self.startWaterfallAction.triggered.connect(self.startWaterfall)

        self.toggleBGAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/noBg.png'),
            'Toggle B&G-reduction', self)
        self.toggleBGAction.setShortcut('Ctrl+G')
        self.toggleBGAction.setStatusTip('Toggle Background Reduction')
        self.toggleBGAction.triggered.connect(self.start_tracking)

        self.setROIAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Zoom-In-icon.png'), 'Set &ROI',
            self)
        self.setROIAction.setShortcut('Ctrl+T')
        self.setROIAction.setStatusTip('Set ROI')
        self.setROIAction.triggered.connect(self.getROI)

        self.clearROIAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Zoom-Out-icon.png'), 'Set R&OI',
            self)
        self.clearROIAction.setShortcut('Ctrl+T')
        self.clearROIAction.setStatusTip('Clear ROI')
        self.clearROIAction.triggered.connect(self.clearROI)

        self.accumulateBufferAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/disk-save.png'),
            'Accumulate buffer', self)
        self.accumulateBufferAction.setShortcut('Ctrl+B')
        self.accumulateBufferAction.setStatusTip(
            'Start or stop buffer accumulation')
        self.accumulateBufferAction.triggered.connect(self.bufferStatus)

        self.clearBufferAction = QtGui.QAction('Clear Buffer', self)
        self.clearBufferAction.setShortcut('Ctrl+F')
        self.clearBufferAction.setStatusTip('Clears the buffer')
        self.clearBufferAction.triggered.connect(self.emptyQueue)

        self.viewerAction = QtGui.QAction('Start Viewer', self)
        # self.viewerAction.triggered.connect(self.camViewer.show)

        self.configAction = QtGui.QAction('Config Window', self)
        # self.configAction.triggered.connect(self.config.show)

        self.dockAction = QtGui.QAction('Restore Docks', self)
        self.dockAction.triggered.connect(self.setupDocks)

        self.crossCutAction = QtGui.QAction(
            QtGui.QIcon('pynta/View/GUI/Icons/Ruler-icon.png'),
            'Show cross cut', self)
        # self.crossCutAction.triggered.connect(self.crossCut.show)

        self.settingsAction = QtGui.QAction('Load config', self)
        # self.settingsAction.triggered.connect(self.selectSettings.show)

    def setupToolbar(self):
        """Setups the toolbar with the desired icons. It's placed into a function
        to make it easier to reuse in other windows.
        """
        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(self.exitAction)
        self.toolbar2 = self.addToolBar('Image')
        self.toolbar2.addAction(self.saveAction)
        self.toolbar2.addAction(self.snapAction)
        self.toolbar2.addAction(self.crossCutAction)
        self.toolbar3 = self.addToolBar('Movie')
        self.toolbar3.addAction(self.movieAction)
        self.toolbar3.addAction(self.movieSaveStartAction)
        self.toolbar3.addAction(self.movieSaveStopAction)
        self.toolbar4 = self.addToolBar('Extra')
        self.toolbar4.addAction(self.startWaterfallAction)
        self.toolbar4.addAction(self.setROIAction)
        self.toolbar4.addAction(self.clearROIAction)
        self.toolbar4.addAction(self.clearROIAction)
        self.toolbar4.addAction(self.toggleBGAction)
        self.toolbar5 = self.addToolBar('Help')
        self.toolbar5.addAction(self.showHelpAction)

    def setupMenubar(self):
        """Setups the menubar.
        """
        menubar = self.menuBar()
        self.fileMenu = menubar.addMenu('&File')
        self.fileMenu.addAction(self.settingsAction)
        self.fileMenu.addAction(self.saveAction)
        self.fileMenu.addAction(self.exitAction)
        self.snapMenu = menubar.addMenu('&Snap')
        self.snapMenu.addAction(self.snapAction)
        self.snapMenu.addAction(self.saveAction)
        self.movieMenu = menubar.addMenu('&Movie')
        self.movieMenu.addAction(self.movieAction)
        self.movieMenu.addAction(self.movieSaveStartAction)
        self.movieMenu.addAction(self.movieSaveStopAction)
        self.movieMenu.addAction(self.startWaterfallAction)
        self.configMenu = menubar.addMenu('&Configure')
        self.configMenu.addAction(self.toggleBGAction)
        self.configMenu.addAction(self.setROIAction)
        self.configMenu.addAction(self.clearROIAction)
        self.configMenu.addAction(self.accumulateBufferAction)
        self.configMenu.addAction(self.clearBufferAction)
        self.configMenu.addAction(self.viewerAction)
        self.configMenu.addAction(self.configAction)
        self.configMenu.addAction(self.dockAction)
        self.saveMenu = menubar.addMenu('S&ave')
        self.snapMenu.addAction(self.saveAction)
        self.saveMenu.addAction(self.saveWaterfallAction)
        self.saveMenu.addAction(self.saveTrajectoryAction)
        self.helpMenu = menubar.addMenu('&Help')
        self.helpMenu.addAction(self.showHelpAction)

    def setupDocks(self):
        """Setups the docks in order to recover the initial configuration if one gets closed."""

        for d in self.docks:
            try:
                d.close()
            except:
                pass

        self.docks = []

        self.dmainImage = Dock("Camera",
                               size=(80, 35))  #sizes are in percentage
        self.dwaterfall = Dock("Waterfall", size=(80, 35))
        self.dparams = Dock("Parameters", size=(20, 100))
        self.dtraj = Dock("Trajectory", size=(40, 30))

        # self.dstatus = Dock("Status", size=(100, 3))

        self.area.addDock(self.dmainImage, 'right')
        self.area.addDock(self.dparams, 'left', self.dmainImage)
        self.area.addDock(self.dtraj, 'bottom', self.dmainImage)
        self.area.addDock(self.dmessage, 'right', self.dtraj)

        self.docks.append(self.dmainImage)
        self.docks.append(self.dtraj)
        self.docks.append(self.dmessage)
        self.docks.append(self.dparams)
        self.docks.append(self.dwaterfall)
        # self.area.addDock(self.dstatus, 'bottom', self.dparams)

        self.dmainImage.addWidget(self.camWidget)

        self.dparams.addWidget(self.config)
        self.dtraj.addWidget(self.trajectoryWidget)

        self.dock_state = self.area.saveState()

    def setupSignals(self):
        """Setups all the signals that are going to be handled during the excution of the program."""
        self.connect(self._session, QtCore.SIGNAL('updated'),
                     self.config.populateTree)
        self.connect(self.config, QtCore.SIGNAL('updateSession'),
                     self.updateSession)
        self.connect(self.camWidget, QtCore.SIGNAL('specialTask'),
                     self.startSpecialTask)
        self.connect(self.camWidget, QtCore.SIGNAL('stopSpecialTask'),
                     self.stopSpecialTask)
        self.connect(self.camViewer, QtCore.SIGNAL('stopMainAcquisition'),
                     self.stopMovie)
        self.connect(self, QtCore.SIGNAL('stopChildMovie'),
                     self.camViewer.stopCamera)
        self.connect(self, QtCore.SIGNAL('closeAll'),
                     self.camViewer.closeViewer)
        self.connect(self.selectSettings, QtCore.SIGNAL("settings"),
                     self.update_settings)
        self.connect(self, QtCore.SIGNAL('closeAll'),
                     self.selectSettings.close)

    def snap(self):
        """Function for acquiring a single frame from the camera. It is triggered by the user.
        It gets the data the GUI will be updated at a fixed framerate.
        """
        if self.experiment.acquiring:  #If it is itself acquiring a message is displayed to the user warning him
            msgBox = QtGui.QMessageBox()
            msgBox.setIcon(QtGui.QMessageBox.Critical)
            msgBox.setText("You cant snap a photo while in free run")
            msgBox.setInformativeText("The program is already acquiring data")
            msgBox.setWindowTitle("Already acquiring")
            msgBox.setDetailedText(
                """When in free run, you can\'t trigger another acquisition. \n
                You should stop the free run acquisition and then snap a photo."""
            )
            msgBox.setStandardButtons(QtGui.QMessageBox.Ok)
            retval = msgBox.exec_()
            self.messageWidget.appendLog('e',
                                         'Tried to snap while in free run')
        else:
            self.experiment.snap()
            # self.messageWidget.appendLog('i', 'Snapped photo')

    def toggleBGReduction(self):
        """Toggles between background cancellation modes. Takes a background snap if necessary
        """

        if self.subtract_background:
            self.subtract_background = False
            self.messageWidget.appendLog('i',
                                         'Background reduction deactivated')
        else:
            if len(self.tempimage) == 0:
                self.snap()
                self.messageWidget.appendLog('i',
                                             'Snapped an image as background')
            else:
                self.subtract_background = True
                self.bgimage = self.tempimage.astype(float)
                self.messageWidget.appendLog('i',
                                             'Background reduction active')

    def saveImage(self):
        """Saves the image that is being displayed to the user.
        """
        if len(self.tempimage) >= 1:
            # Data will be appended to existing file
            fn = self._session.Saving['filename_photo']
            filename = '%s.hdf5' % (fn)
            fileDir = self._session.Saving['directory']
            if not os.path.exists(fileDir):
                os.makedirs(fileDir)

            f = h5py.File(os.path.join(fileDir, filename), "a")
            now = str(datetime.now())
            g = f.create_group(now)
            dset = g.create_dataset('image', data=self.tempimage)
            meta = g.create_dataset('metadata', data=self._session.serialize())
            f.flush()
            f.close()
            self.messageWidget.appendLog('i', 'Saved photo')

    def startMovie(self):
        self.experiment.start_free_run()

    def stopMovie(self):
        if self.acquiring:
            self.workerThread.keep_acquiring = False
            while self.workerThread.isRunning():
                pass
            self.acquiring = False
            self.camera.stopAcq()
            self.messageWidget.appendLog('i', 'Continuous run stopped')
            if self.continuous_saving:
                self.movieSaveStop()

    def movieData(self):
        """Function just to trigger and read the camera in the separate thread.
        """
        self.workerThread.start()

    def movieSave(self):
        """Saves the data accumulated in the queue continuously.
        """
        if not self.continuous_saving:
            # Child process to save the data. It runs continuously until and exit flag
            # is passed through the Queue. (self.q.put('exit'))
            self.accumulate_buffer = True
            if len(self.tempimage) > 1:
                im_size = self.tempimage.nbytes
                max_element = int(self._session.Saving['max_memory'] / im_size)
                #self.q = Queue(0)
            fn = self._session.Saving['filename_video']
            filename = '%s.hdf5' % (fn)
            fileDir = self._session.Saving['directory']
            if not os.path.exists(fileDir):
                os.makedirs(fileDir)
            to_save = os.path.join(fileDir, filename)
            metaData = self._session.serialize(
            )  # This prints a YAML-ready version of the session.
            self.p = Process(target=workerSaver,
                             args=(
                                 to_save,
                                 metaData,
                                 self.q,
                             ))  #
            self.p.start()
            self.continuous_saving = True
            self.messageWidget.appendLog('i', 'Continuous autosaving started')
        else:
            self.messageWidget.appendLog(
                'w', 'Continuous savings already triggered')

    def movieSaveStop(self):
        """Stops the saving to disk. It will however flush the queue.
        """
        if self.continuous_saving:
            self.q.put('Stop')
            self.accumulate_buffer = False
            #self.p.join()
            self.messageWidget.appendLog('i', 'Continuous autosaving stopped')
            self.continuous_saving = False

    def emptyQueue(self):
        """Clears the queue.
        """
        # Worker thread for clearing the queue.
        self.clearWorker = Process(target=clearQueue, args=(self.q, ))
        self.clearWorker.start()

    def startWaterfall(self):
        """Starts the waterfall. The waterfall can be accelerated if camera supports hardware binning in the appropriate
        direction. If not, has to be done via software but the acquisition time cannot be improved.
        TODO: Fast waterfall should have separate window, since the acquisition of the full CCD will be stopped.
        """
        if not self.show_waterfall:
            self.watWidget = waterfallWidget()
            self.area.addDock(self.dwaterfall, 'bottom', self.dmainImage)
            self.dwaterfall.addWidget(self.watWidget)
            self.show_waterfall = True
            Sx, Sy = self.camera.getSize()
            self.waterfall_data = np.zeros(
                (self._session.GUI['length_waterfall'], Sx))
            self.watWidget.img.setImage(np.transpose(self.waterfall_data),
                                        autoLevels=False,
                                        autoRange=False,
                                        autoHistogramRange=False)
            self.messageWidget.appendLog('i', 'Waterfall opened')
        else:
            self.closeWaterfall()

    def stopWaterfall(self):
        """Stops the acquisition of the waterfall.
        """
        pass

    def closeWaterfall(self):
        """Closes the waterfall widget.
        """
        if self.show_waterfall:
            self.watWidget.close()
            self.dwaterfall.close()
            self.show_waterfall = False
            del self.waterfall_data
            self.messageWidget.appendLog('i', 'Waterfall closed')

    def setROI(self, X, Y):
        """
        Gets the ROI from the lines on the image. It also updates the GUI to accommodate the changes.
        :param X:
        :param Y:
        :return:
        """
        if not self.acquiring:
            self.corner_roi[0] = X[0]
            self.corner_roi[1] = Y[0]
            if self._session.Debug['to_screen']:
                print('Corner: %s, %s' %
                      (self.corner_roi[0], self.corner_roi[1]))
            self._session.Camera = {'roi_x1': int(X[0])}
            self._session.Camera = {'roi_x2': int(X[1])}
            self._session.Camera = {'roi_y1': int(Y[0])}
            self._session.Camera = {'roi_y2': int(Y[1])}
            self.messageWidget.appendLog('i', 'Updated roi_x1: %s' % int(X[0]))
            self.messageWidget.appendLog('i', 'Updated roi_x2: %s' % int(X[1]))
            self.messageWidget.appendLog('i', 'Updated roi_y1: %s' % int(Y[0]))
            self.messageWidget.appendLog('i', 'Updated roi_y2: %s' % int(Y[1]))

            Nx, Ny = self.camera.setROI(X, Y)
            Sx, Sy = self.camera.getSize()
            self.current_width = Sx
            self.current_height = Sy

            self.tempimage = np.zeros((Nx, Ny))
            self.camWidget.hline1.setValue(1)
            self.camWidget.hline2.setValue(Ny)
            self.camWidget.vline1.setValue(1)
            self.camWidget.vline2.setValue(Nx)
            self.trackinfo = np.zeros((1, 5))
            #self.camWidget.img2.clear()
            if self.show_waterfall:
                self.waterfall_data = np.zeros(
                    (self._session.GUI['length_waterfall'],
                     self.current_width))
                self.watWidget.img.setImage(np.transpose(self.waterfall_data))

            self.config.populateTree(self._session)
            self.messageWidget.appendLog('i', 'Updated the ROI')
        else:
            self.messageWidget.appendLog('e',
                                         'Cannot change ROI while acquiring.')

    def getROI(self):
        """Gets the ROI coordinates from the GUI and updates the values."""
        y1 = np.int(self.camWidget.hline1.value())
        y2 = np.int(self.camWidget.hline2.value())
        x1 = np.int(self.camWidget.vline1.value())
        x2 = np.int(self.camWidget.vline2.value())
        X = np.sort((x1, x2))
        Y = np.sort((y1, y2))
        # Updates to the real values
        X += self.corner_roi[0] - 1
        Y += self.corner_roi[1] - 1
        self.setROI(X, Y)

    def clearROI(self):
        """Resets the roi to the full image.
        """
        if not self.acquiring:
            self.camWidget.hline1.setValue(1)
            self.camWidget.vline1.setValue(1)
            self.camWidget.vline2.setValue(self.max_sizex)
            self.camWidget.hline2.setValue(self.max_sizey)
            self.corner_roi = [1, 1]
            self.getROI()
        else:
            self.messageWidget.appendLog('e',
                                         'Cannot change ROI while acquiring.')

    def bufferStatus(self):
        """Starts or stops the buffer accumulation.
        """
        if self.accumulate_buffer:
            self.accumulate_buffer = False
            self.messageWidget.appendLog('i', 'Buffer accumulation stopped')
        else:
            self.accumulate_buffer = True
            self.messageWidget.appendLog('i', 'Buffer accumulation started')

    def getData(self, data, origin):
        """Gets the data that is being gathered by the working thread.

        .. _getData:
        .. data: single image or a list of images (saved in buffer)
        .. origin: indicates which command has trigerred execution of this method (e.g. 'snap' of 'movie')
        both input variables are handed it through QThread signal that is "emit"ted
        """
        s = 0
        if origin == 'snap':  # Single snap.
            self.acquiring = False
            self.workerThread.origin = None
            self.workerThread.keep_acquiring = False  # This already happens in the worker thread itself.
            self.camera.stopAcq()

        if isinstance(data, list):
            for d in data:
                if self.accumulate_buffer:
                    s = float(self.q.qsize()) * int(d.nbytes) / 1024 / 1024
                    if s < self._session.Saving['max_memory']:
                        self.q.put(d)
                    else:
                        self.droppedframes += 1

                if self.show_waterfall:
                    if self.watindex == self._session.GUI['length_waterfall']:
                        if self._session.Saving['autosave_trajectory']:
                            self.saveWaterfall()

                        self.waterfall_data = np.zeros(
                            (self._session.GUI['length_waterfall'],
                             self.current_width))
                        self.watindex = 0

                    centerline = np.int(self.current_height / 2)
                    vbinhalf = np.int(self._session.GUI['vbin_waterfall'])
                    if vbinhalf >= self.current_height / 2 - 1:
                        wf = np.array([np.sum(d, 1)])
                    else:
                        wf = np.array([
                            np.sum(
                                d[:,
                                  centerline - vbinhalf:centerline + vbinhalf],
                                1)
                        ])
                    self.waterfall_data[self.watindex, :] = wf
                    self.watindex += 1
                self.totalframes += 1
            self.tempimage = d
        else:
            self.tempimage = data
            if self.accumulate_buffer:
                s = float(self.q.qsize()) * int(data.nbytes) / 1024 / 1024

                if s < self._session.Saving['max_memory']:
                    self.q.put(data)
                else:
                    self.droppedframes += 1

            if self.show_waterfall:
                if self.watindex == self._session.GUI['length_waterfall']:
                    # checks if the buffer variable for waterfall image is full, saves it if requested, and sets it to zero.
                    if self._session.Saving['autosave_trajectory']:
                        self.saveWaterfall()

                    self.waterfall_data = np.zeros(
                        (self._session.GUI['length_waterfall'],
                         self.current_width))
                    self.watindex = 0

                centerline = np.int(self.current_height / 2)
                vbinhalf = np.int(self._session.GUI['vbin_waterfall'] / 2)

                if vbinhalf >= self.current_height - 1:
                    wf = np.array([np.sum(data, 1)])
                else:
                    wf = np.array([
                        np.sum(
                            data[:,
                                 centerline - vbinhalf:centerline + vbinhalf],
                            1)
                    ])
                self.waterfall_data[self.watindex, :] = wf
                self.watindex += 1

            self.totalframes += 1

        new_time = time.time()
        self.buffertime = new_time - self.lastBuffer
        self.lastBuffer = new_time
        self.buffer_memory = s
        if self._session.Debug['queue_memory']:
            print('Queue Memory: %3.2f MB' % self.buffer_memory)

    def updateGUI(self):
        """Updates the image displayed to the user.
        """
        if self.experiment.temp_image is not None:
            img = self.experiment.temp_image
            self.camWidget.img.setImage(img.astype(int),
                                        autoLevels=False,
                                        autoRange=False,
                                        autoHistogramRange=False)
        if self.experiment.link_particles_running:
            self.camWidget.draw_target_pointer(
                self.experiment.localize_particles_image(img))

    def saveWaterfall(self):
        """Saves the waterfall data, if any.
        """
        if len(self.waterfall_data) > 1:
            fn = self._session.Saving['filename_waterfall']
            filename = '%s.hdf5' % (fn)
            fileDir = self._session.Saving['directory']
            if not os.path.exists(fileDir):
                os.makedirs(fileDir)

            f = h5py.File(os.path.join(fileDir, filename), "a")
            now = str(datetime.now())
            g = f.create_group(now)
            dset = g.create_dataset('waterfall', data=self.waterfall_data)
            meta = g.create_dataset('metadata',
                                    data=self._session.serialize().encode(
                                        "ascii", "ignore"))
            f.flush()
            f.close()
            self.messageWidget.appendLog('i', 'Saved Waterfall')

    def saveTrajectory(self):
        """Saves the trajectory data, if any.
        """
        if len(self.trackinfo) > 1:
            fn = self._session.Saving['filename_trajectory']
            filename = '%s.hdf5' % (fn)
            fileDir = self._session.Saving['directory']
            if not os.path.exists(fileDir):
                os.makedirs(fileDir)

            f = h5py.File(os.path.join(fileDir, filename), "a")
            now = str(datetime.now())
            g = f.create_group(now)
            dset = g.create_dataset('trajectory', data=[self.trackinfo])
            meta = g.create_dataset('metadata',
                                    data=self._session.serialize().encode(
                                        "ascii", "ignore"))
            f.flush()
            f.close()
            self.messageWidget.appendLog('i', 'Saved Trajectory')

    def update_settings(self, settings):
        new_session = _session(settings)
        self.updateSession(new_session)
        self.config.populateTree(self._session)

    def updateSession(self, session):
        """Updates the session variables passed by the config window.
        """
        update_cam = False
        update_roi = False
        update_exposure = False
        update_binning = True
        for k in session.params['Camera']:
            new_prop = session.params['Camera'][k]
            old_prop = self._session.params['Camera'][k]
            if new_prop != old_prop:
                update_cam = True
                if k in ['roi_x1', 'roi_x2', 'roi_y1', 'roi_y2']:
                    update_roi = True
                    if self._session.Debug['to_screen']:
                        print('Update ROI')
                elif k == 'exposure_time':
                    update_exposure = True
                elif k in ['binning_x', 'binning_y']:
                    update_binning = True

        if session.GUI['length_waterfall'] != self._session.GUI[
                'length_waterfall']:
            if self.show_waterfall:
                self.closeWaterfall()
                self.restart_waterfall = True

        self.messageWidget.appendLog('i', 'Parameters updated')
        self.messageWidget.appendLog(
            'i', 'Measurement: %s' % session.User['measurement'])
        self._session = session.copy()

        if update_cam:
            if self.acquiring:
                self.stopMovie()

            if update_roi:
                X = np.sort(
                    [session.Camera['roi_x1'], session.Camera['roi_x2']])
                Y = np.sort(
                    [session.Camera['roi_y1'], session.Camera['roi_y2']])
                self.setROI(X, Y)

            if update_exposure:
                new_exp = self.camera.setExposure(
                    session.Camera['exposure_time'])
                self._session.Camera = {'exposure_time': new_exp}
                self.messageWidget.appendLog('i',
                                             'Updated exposure: %s' % new_exp)
                if self._session.Debug['to_screen']:
                    print("New Exposure: %s" % new_exp)
                    print(self._session)

            if update_binning:
                self.camera.setBinning(session.Camera['binning_x'],
                                       session.Camera['binning_y'])

        self.refreshTimer.stop()
        self.refreshTimer.start(session.GUI['refresh_time'])

    def startSpecialTask(self):
        """Starts a special task. This is triggered by the user with a special combination of actions, for example clicking
        with the mouse on a plot, draggin a crosshair, etc."""
        if not self.specialtask_running:
            if self.acquiring:
                self.stopMovie()
                self.acquiring = False

            locy = self.camWidget.crosshair[0].getPos()[1]
            locx = self.camWidget.crosshair[1].getPos()[0]
            self.trackinfo = np.zeros((1, 5))
            self.trajectoryWidget.plot.clear()
            imgsize = self.tempimage.shape
            iniloc = [locx, locy]
            self.specialTaskWorker = specialTaskTracking(
                self._session, self.camera, self.noiselvl, imgsize, iniloc)
            self.connect(self.specialTaskWorker, QtCore.SIGNAL('image'),
                         self.getData)
            self.connect(self.specialTaskWorker, QtCore.SIGNAL('coordinates'),
                         self.getParticleLocation)
            self.specialTaskWorker.start()
            self.specialtask_running = True
            self.messageWidget.appendLog('i', 'Live tracking started')
        else:
            print('Special task already running')

    def stopSpecialTask(self):
        """Stops the special task"""
        if self.specialtask_running:
            self.specialTaskWorker.keep_running = False
            self.specialtask_running = False
            if self._session.Saving['autosave_trajectory'] == True:
                self.saveTrajectory()
            self.messageWidget.appendLog('i', 'Live tracking stopped')

    def done(self):
        #self.saveRunning = False
        self.acquiring = False

    def exitSafe(self):
        self.close()

    def closeEvent(self, evnt):
        """
            Triggered at closing. Checks that the save is complete and closes the dataFile
        """
        self.experiment.finalize()

        # self.messageWidget.appendLog('i', 'Closing the program')
        # if self.acquiring:
        #     self.stopMovie()
        # if self.specialtask_running:
        #     self.stopSpecialTask()
        #     while self.specialTaskWorker.isRunning():
        #         pass
        # self.emit(QtCore.SIGNAL('closeAll'))
        # self.camera.stopCamera()
        # self.movieSaveStop()
        # try:
        #     # Checks if the process P exists and tries to close it.
        #     if self.p.is_alive():
        #         qs = self.q.qsize()
        #         with ProgressDialog("Finish saving data...", 0, qs) as dlg:
        #             while self.q.qsize() > 1:
        #                 dlg.setValue(qs - self.q.qsize())
        #                 time.sleep(0.5)
        #     self.p.join()
        # except AttributeError:
        #     pass
        # if self.q.qsize() > 0:
        #     self.messageWidget.appendLog('i', 'The queue was not empty')
        #     print('Freeing up memory...')
        #     self.emptyQueue()
        #
        # # Save LOG.
        # fn = self._session.Saving['filename_log']
        # timestamp = datetime.now().strftime('%H%M%S')
        # filename = '%s%s.log' % (fn, timestamp)
        # fileDir = self._session.Saving['directory']
        # if not os.path.exists(fileDir):
        #     os.makedirs(fileDir)
        #
        # f = open(os.path.join(fileDir,filename), "a")
        # for line in self.messageWidget.logText:
        #     f.write(line+'\n')
        # f.flush()
        # f.close()
        # print('Saved LOG')
        super(MainWindow, self).closeEvent(evnt)
Esempio n. 4
0
class Spectrometer(QObject):
    """
    Defines a Spectrometer object, unified interface for many spectrometers

    Parameters that could be set in the selected detector plugin (should be defined there):
    'laser_wl' : value of the configured laser (could eventually be changed, case of Xplora, Labram...)
    'spectro_center_freq': value of the configured grating center wavelength (could eventually be changed, case of Shamrock, Xplora...)


    """
    #custom signal that will be fired sometimes. Could be connected to an external object method or an internal method
    log_signal = Signal(str)

    #list of dicts enabling the settings tree on the user interface
    params = [
        {
            'title':
            'Configuration settings:',
            'name':
            'config_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Laser wavelength (nm):',
                    'name': 'laser_wl',
                    'type': 'float',
                    'value': 515.
                },
                {
                    'title': 'Laser wavelength (nm):',
                    'name': 'laser_wl_list',
                    'type': 'list',
                    'limits': ['']
                },
                {
                    'title': 'Current Detector:',
                    'name': 'curr_det',
                    'type': 'str',
                    'value': ''
                },
                {
                    'title': 'Show detector:',
                    'name': 'show_det',
                    'type': 'bool',
                    'value': False
                },
            ],
        },
        {
            'title':
            'Calibration settings:',
            'name':
            'calib_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Use calibration:',
                    'name': 'use_calib',
                    'type': 'bool',
                    'value': False
                },
                {
                    'title': 'Save calibration',
                    'name': 'save_calib',
                    'type': 'bool_push',
                    'value': False
                },
                {
                    'title': 'Load calibration',
                    'name': 'load_calib',
                    'type': 'bool_push',
                    'value': False
                },
                {
                    'title':
                    'Calibration coeffs:',
                    'name':
                    'calib_coeffs',
                    'type':
                    'group',
                    'children': [
                        {
                            'title': 'Center wavelength (nm):',
                            'name': 'center_calib',
                            'type': 'float',
                            'value': 515.
                        },
                        {
                            'title': 'Slope (nm/pxl):',
                            'name': 'slope_calib',
                            'type': 'float',
                            'value': 1.
                        },
                        {
                            'title': 'Second order :',
                            'name': 'second_calib',
                            'type': 'float',
                            'value': 0
                        },
                        {
                            'title': 'third:',
                            'name': 'third_calib',
                            'type': 'float',
                            'value': 0
                        },
                    ]
                },
                {
                    'title': 'Perform calibration:',
                    'name': 'do_calib',
                    'type': 'bool',
                    'value': False
                },
            ]
        },
        {
            'title':
            'Acquisition settings:',
            'name':
            'acq_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Spectro. Center:',
                    'name': 'spectro_center_freq',
                    'type': 'float',
                    'value': 800,
                },
                {
                    'title': 'Spectro. Center:',
                    'name': 'spectro_center_freq_txt',
                    'type': 'str',
                    'value': '????',
                    'readonly': True
                },
                {
                    'title': 'Units:',
                    'name': 'units',
                    'type': 'list',
                    'value': 'nm',
                    'limits': ['nm', 'cm-1', 'eV']
                },
                {
                    'title': 'Exposure (ms):',
                    'name': 'exposure_ms',
                    'type': 'float',
                    'value': 100,
                },
            ]
        },
    ]

    def __init__(self, parent):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super().__init__()
        if not isinstance(parent, DockArea):
            raise Exception('no valid parent container, expected a DockArea')

        self.wait_time = 2000  #ms
        self.offline = True
        self.dockarea = parent
        self.mainwindow = parent.parent()
        self.spectro_widget = QtWidgets.QWidget()
        self.data_dict = None
        """
        List of the possible plugins that could be used with Spectrometer module
        type : dimensionality of the detector
        name: name of the plugin
        calib = True means there is a builtin calibration of the frequency axis
        movable : tells if the dispersion can be set (for instance by moving a grating)
        unit: valid only if calib is True. Unit of the calibration axis (x_axis of the detector), most often in
              nanometers. Possible values are 'nm', 'radfs' (rad/femtosecond), 'eV'
        laser: if False,  laser cannot be changed by the program, do it manually
        laser_list: if laser is True, laser_list gives a list of selectable lasers
        
        """

        self.current_det = None  # will be after initialization

        self.laser_set_manual = True

        #init the object parameters
        self.detector = None
        self.save_file_pathname = None
        self._spectro_wl = 550  # center wavelngth of the spectrum
        self.viewer_freq_axis = utils.Axis(data=None,
                                           label='Photon energy',
                                           units='')
        self.raw_data = []

        #init the user interface
        self.dashboard = self.set_dashboard()
        self.dashboard.preset_loaded_signal.connect(
            lambda: self.show_detector(False))
        self.dashboard.preset_loaded_signal.connect(self.set_detector)
        self.dashboard.preset_loaded_signal.connect(self.initialized)
        self.set_GUI()
        self.dashboard.new_preset_created.connect(
            lambda: self.create_menu(self.menubar))

        self.show_detector(False)
        self.dockarea.setEnabled(False)

    def set_dashboard(self):
        params = [
            {
                'title':
                'Spectro Settings:',
                'name':
                'spectro_settings',
                'type':
                'group',
                'children': [
                    {
                        'title':
                        'Is calibrated?',
                        'name':
                        'iscalibrated',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has internal frequency calibration or not.'
                    },
                    {
                        'title':
                        'Movable?',
                        'name':
                        'ismovable',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has a functionality to change its central frequency: as a movable grating'
                        ' for instance.'
                    },
                    {
                        'title':
                        'Laser selectable?',
                        'name':
                        'laser_selectable',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has a functionality to change its excitation ray'
                    },
                    {
                        'title': 'Laser ray:',
                        'name': 'laser_ray',
                        'type': 'list',
                        'value': '',
                        'show_pb': True,
                        'tooltip':
                        'List of settable laser rays (not manual ones)'
                    },
                ]
            },
        ]
        dashboard = DashBoard(self.dockarea.addTempArea())
        dashboard.set_preset_path(spectro_path)
        options = [
            dict(path='saving_options', options_dict=dict(visible=False)),
            dict(path='use_pid', options_dict=dict(visible=False)),
            dict(path='Moves', options_dict=dict(visible=False))
        ]
        dashboard.set_extra_preset_params(params, options)

        dashboard.dockarea.window().setVisible(False)
        return dashboard

    def set_GUI(self):
        ###########################################
        ###########################################
        #init the docks containing the main widgets

        #######################################################################################################################
        #create a dock containing a viewer object, displaying the data for the spectrometer
        self.dock_viewer = Dock('Viewer dock', size=(350, 350))
        self.dockarea.addDock(self.dock_viewer, 'left')
        target_widget = QtWidgets.QWidget()
        self.viewer = Viewer1D(target_widget)
        self.dock_viewer.addWidget(target_widget)

        ################################################################
        #create a logger dock where to store info senf from the programm
        self.dock_logger = Dock("Logger")
        self.logger_list = QtWidgets.QListWidget()
        self.logger_list.setMinimumWidth(300)
        self.dock_logger.addWidget(self.logger_list)
        self.dockarea.addDock(self.dock_logger, 'right')
        self.log_signal[str].connect(self.add_log)

        ############################################
        # creating a menubar
        self.menubar = self.mainwindow.menuBar()
        self.create_menu(self.menubar)

        #creating a toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.create_toolbar()
        self.mainwindow.addToolBar(self.toolbar)

        #creating a status bar
        self.statusbar = QtWidgets.QStatusBar()
        self.statusbar.setMaximumHeight(25)

        self.status_laser = QtWidgets.QLabel('????')
        self.status_laser.setAlignment(Qt.AlignCenter)
        #self.status_laser.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        #self.status_laser.setReadOnly(True)
        self.status_laser.setMaximumWidth(80)
        self.status_laser.setMinimumWidth(80)
        self.status_laser.setToolTip('Current laser wavelength')
        self.status_laser.setStyleSheet("background-color: red")

        self.status_center = QtWidgets.QLabel('????')
        self.status_center.setAlignment(Qt.AlignCenter)
        #self.status_center.setReadOnly(True)
        #self.status_center.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.status_center.setMaximumWidth(80)
        self.status_center.setMinimumWidth(80)
        self.status_center.setToolTip(
            'center frequency of the spectrum, either in nm or cm-1')
        self.status_center.setStyleSheet("background-color: red")

        self.status_init = QLED()
        self.status_init.setToolTip('Initialization state of the detector')
        self.status_init.set_as_false()
        self.status_init.clickable = False

        self.statusbar.addPermanentWidget(self.status_laser)
        self.statusbar.addPermanentWidget(self.status_center)
        self.statusbar.addPermanentWidget(self.status_init)
        self.dockarea.window().setStatusBar(self.statusbar)

        #############################################
        self.settings = Parameter.create(name='settings',
                                         type='group',
                                         children=self.params)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        dock_config_settings = Dock('Configuration', size=(300, 350))
        self.dockarea.addDock(dock_config_settings, 'above', self.dock_logger)
        # create main parameter tree
        self.config_settings_tree = ParameterTree()
        dock_config_settings.addWidget(self.config_settings_tree, 10)
        self.config_settings_tree.setMinimumWidth(300)
        self.config_settings_tree.setParameters(self.settings.child(
            ('config_settings')),
                                                showTop=False)
        #any change to the tree on the user interface will call the parameter_tree_changed method where all actions will be applied

        dock_calib_settings = Dock('Calibration', size=(300, 350))
        self.dockarea.addDock(dock_calib_settings, 'above', self.dock_logger)
        # create main parameter tree
        self.calib_settings_tree = ParameterTree()
        dock_calib_settings.addWidget(self.calib_settings_tree, 10)
        self.calib_settings_tree.setMinimumWidth(300)
        self.calib_settings_tree.setParameters(self.settings.child(
            ('calib_settings')),
                                               showTop=False)
        #any change to the tree on the user interface will call the parameter_tree_changed method where all actions will be applied

        #this one for the custom application settings
        dock_acq_settings = Dock('Acquisition', size=(300, 350))
        self.dockarea.addDock(dock_acq_settings, 'above', dock_config_settings)
        # create main parameter tree
        self.acq_settings_tree = ParameterTree()
        dock_acq_settings.addWidget(self.acq_settings_tree, 10)
        self.acq_settings_tree.setMinimumWidth(300)
        self.acq_settings_tree.setParameters(self.settings.child(
            ('acq_settings')),
                                             showTop=False)

    @Slot(ThreadCommand)
    def cmd_from_det(self, status):
        try:
            if status.command == 'spectro_wl':
                self.status_center.setStyleSheet("background-color: green")
                self.spectro_wl_is(status.attributes[0])

            elif status.command == 'laser_wl':
                #self.laser_set_manual = False
                self.settings.child('config_settings',
                                    'laser_wl_list').setValue(
                                        status.attributes[0])
                self.status_laser.setText('{:}nm'.format(status.attributes[0]))
                self.status_laser.setStyleSheet("background-color: green")
                self.update_center_frequency(self.spectro_wl)

            elif status.command == 'exposure_ms':
                self.settings.child('acq_settings', 'exposure_ms').setValue(
                    status.attributes[0])

            elif status.command == "x_axis":
                x_axis = status.attributes[0]
                if np.any(x_axis['data'] != self.viewer_freq_axis['data']
                          ) and self.current_det['calib']:
                    self.viewer_freq_axis.update(x_axis)
                    self.update_axis()

        except Exception as e:
            logger.exception(str(e))

    def update_status(self, txt, wait_time=1000, log_type=None):
        """

        """
        self.statusbar.showMessage(txt, wait_time)
        if log_type is not None:
            self.log_signal.emit(txt)

    def set_detector(self):

        self.detector = self.dashboard.detector_modules[0]
        self.settings.child('config_settings', 'curr_det').setValue(
            f"{self.detector.settings.child('main_settings','DAQ_type').value()} / "
            f"{self.detector.settings.child('main_settings','detector_type').value()} / {self.detector.title}"
        )
        self.detector.custom_sig[ThreadCommand].connect(self.cmd_from_det)
        self.current_det = \
            dict(laser=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'laser_selectable').value(),
                 laser_list=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'laser_ray').opts['limits'],
                 movable=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'ismovable').value(),
                 calib=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'iscalibrated').value(),
                 )

        self.detector.grab_done_signal.connect(self.show_data)

        self.settings.sigTreeStateChanged.disconnect(
            self.parameter_tree_changed)
        if self.current_det['laser']:
            self.settings.child('config_settings', 'laser_wl_list').show()
            self.settings.child('config_settings', 'laser_wl').hide()
            self.settings.child(
                'config_settings',
                'laser_wl_list').setOpts(limits=self.current_det['laser_list'])
        else:
            self.settings.child('config_settings', 'laser_wl').show()
            self.settings.child('config_settings', 'laser_wl_list').hide()
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        #apply current detector particularities
        #self.settings.child('acq_settings', 'spectro_center_freq').setOpts(readonly=not self.current_det['movable'])
        self.get_spectro_wl()
        QtWidgets.QApplication.processEvents()

        self.get_laser_wl()
        QtWidgets.QApplication.processEvents()

        self.get_exposure_ms()
        QtWidgets.QApplication.processEvents()

    def get_exposure_ms(self):
        self.detector.command_detector.emit(ThreadCommand('get_exposure_ms'))

    def set_exposure_ms(self, data):
        self.detector.command_detector.emit(
            ThreadCommand('set_exposure_ms', [data]))

    @Slot(bool)
    def initialized(self, state, offline=False):
        self.offline = offline
        self.grab_action.setEnabled(state)
        self.snap_action.setEnabled(state)
        if state or offline:
            self.status_init.set_as_true()
            self.dockarea.setEnabled(True)
        else:
            self.status_init.set_as_false()

    def update_center_frequency(self, spectro_wl):
        self._spectro_wl = spectro_wl
        if self.settings.child('acq_settings', 'units').value() == 'nm':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(spectro_wl)
        elif self.settings.child('acq_settings', 'units').value() == 'cm-1':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(
                                    Enm2cmrel(
                                        spectro_wl,
                                        self.settings.child(
                                            'config_settings',
                                            'laser_wl').value()))
        elif self.settings.child('acq_settings', 'units').value() == 'eV':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(
                                    nm2eV(spectro_wl))

        self.set_status_center(
            self.settings.child('acq_settings', 'spectro_center_freq').value(),
            self.settings.child('acq_settings', 'units').value())

    def set_status_center(self, val, unit, precision=3):
        self.status_center.setText(f'{val:.{precision}f} {unit}')

    def spectro_wl_is(self, spectro_wl):
        """
        this slot receives a signal from the detector telling it what's the current spectro_wl
        Parameters
        ----------
        spectro_wl
        """
        self._spectro_wl = spectro_wl
        self.update_center_frequency(spectro_wl)

    def set_spectro_wl(self, spectro_wl):
        try:
            if self.current_det['movable']:
                self.detector.command_detector.emit(
                    ThreadCommand('set_spectro_wl', [spectro_wl]))
        except Exception as e:
            logger.exception(str(e))

    def get_spectro_wl(self):
        if self.current_det['calib']:
            self.settings.child('acq_settings', 'spectro_center_freq').show()
            self.settings.child('acq_settings',
                                'spectro_center_freq_txt').hide()
            self.detector.command_detector.emit(
                ThreadCommand('get_spectro_wl'))
            self.detector.command_detector.emit(ThreadCommand('get_axis'))
        else:
            self.settings.child('acq_settings', 'spectro_center_freq').hide()
            self.settings.child('acq_settings',
                                'spectro_center_freq_txt').show()
            self.viewer_freq_axis['units'] = 'Pxls'

    def get_laser_wl(self):
        if self.current_det['laser']:
            self.detector.command_detector.emit(ThreadCommand('get_laser_wl'))
        else:
            self.settings.child('config_settings', 'laser_wl').setValue(0)

    @property
    def spectro_wl(self):
        # try to get the param value from detector (if it has been added in the plugin)
        return self._spectro_wl

    @spectro_wl.setter
    def spectro_wl(self, spec_wl):
        # try to get the param value from detector (if it has been added in the plugin)
        self.set_spectro_wl(spec_wl)

    def show_detector(self, show=True):
        self.dashboard.mainwindow.setVisible(show)
        for area in self.dashboard.dockarea.tempAreas:
            area.window().setVisible(show)

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'show_det':
                    self.show_detector(data)

                elif param.name() == 'spectro_center_freq':
                    unit = self.settings.child('acq_settings', 'units').value()
                    if unit == 'nm':
                        center_wavelength = data
                    elif unit == 'cm-1':
                        center_wavelength = Ecmrel2Enm(
                            data,
                            self.settings.child('config_settings',
                                                'laser_wl').value())
                    elif unit == 'eV':
                        center_wavelength = eV2nm(data)

                    if int(self.spectro_wl * 100) != int(
                            100 * center_wavelength):  #comprison at 1e-2
                        self.spectro_wl = center_wavelength

                    self.update_axis()

                elif param.name() == 'units':
                    if self.settings.child(
                            'acq_settings',
                            'spectro_center_freq').value() > 0.000000001:
                        if data == 'nm':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    self._spectro_wl)
                        elif data == 'cm-1':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    Enm2cmrel(
                                        self._spectro_wl,
                                        self.settings.child(
                                            'config_settings',
                                            'laser_wl').value()))
                        elif data == 'eV':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    nm2eV(self._spectro_wl))

                        self.set_status_center(
                            self.settings.child('acq_settings',
                                                'spectro_center_freq').value(),
                            self.settings.child('acq_settings',
                                                'units').value())

                elif param.name() == 'laser_wl_list':
                    if data is not None:
                        self.move_laser_wavelength(data)

                elif param.name() == 'laser_wl':
                    if data is not None:
                        self.move_laser_wavelength(data)
                        if int(data) == 0:
                            self.settings.child('acq_settings',
                                                'units').setValue('nm')
                            self.settings.child('acq_settings',
                                                'units').setOpts(readonly=True)
                        else:
                            self.settings.child(
                                'acq_settings',
                                'units').setOpts(readonly=False)
                        if data != 0:
                            self.set_manual_laser_wl(data)

                elif param.name() == 'exposure_ms':
                    self.set_exposure_ms(data)

                elif param.name() == 'do_calib':
                    if len(self.raw_data) != 0:
                        if data:
                            self.calib_dock = Dock('Calibration module')
                            self.dockarea.addDock(self.calib_dock)
                            self.calibration = Calibration(self.dockarea)
                            self.calib_dock.addWidget(self.calibration)

                            self.calibration.coeffs_calib.connect(
                                self.update_calibration)
                        else:
                            self.calib_dock.close()

                elif param.name() == 'save_calib':
                    filename = select_file(start_path=self.save_file_pathname,
                                           save=True,
                                           ext='xml')
                    if filename != '':
                        custom_tree.parameter_to_xml_file(
                            self.settings.child('calib_settings',
                                                'calib_coeffs'), filename)

                elif param.name() == 'load_calib':
                    filename = select_file(start_path=self.save_file_pathname,
                                           save=False,
                                           ext='xml')
                    if filename != '':
                        children = custom_tree.XML_file_to_parameter(filename)
                        self.settings.child(
                            'calib_settings', 'calib_coeffs').restoreState(
                                Parameter.create(
                                    title='Calibration coeffs:',
                                    name='calib_coeffs',
                                    type='group',
                                    children=children).saveState())



                elif param.name() in custom_tree.iter_children(self.settings.child('calib_settings', 'calib_coeffs')) \
                        or param.name() == 'use_calib':
                    if self.settings.child('calib_settings',
                                           'use_calib').value():
                        calib_coeffs = [
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'third_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'second_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'slope_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'center_calib').value()
                        ]

                        self.update_center_frequency(
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'center_calib').value())
                        self.settings.child('acq_settings',
                                            'spectro_center_freq').show()
                        self.settings.child(
                            'acq_settings',
                            'spectro_center_freq').setOpts(readonly=True)
                        self.status_center.setStyleSheet(
                            "background-color: green")
                        self.settings.child('acq_settings',
                                            'spectro_center_freq_txt').hide()
                        x_axis_pxls = np.linspace(0, self.raw_data[0].size - 1,
                                                  self.raw_data[0].size)
                        self.viewer_freq_axis['data'] = np.polyval(
                            calib_coeffs,
                            x_axis_pxls - np.max(x_axis_pxls) / 2)
                        self.update_axis()
                    else:
                        self.settings.child('acq_settings',
                                            'spectro_center_freq').hide()
                        self.settings.child('acq_settings',
                                            'spectro_center_freq_txt').show()
                        self.status_center.setStyleSheet(
                            "background-color: red")

            elif change == 'parent':
                pass

    @Slot(list)
    def update_calibration(self, coeffs):
        self.settings.child('calib_settings', 'calib_coeffs',
                            'center_calib').setValue(coeffs[0])
        self.settings.child('calib_settings', 'calib_coeffs',
                            'slope_calib').setValue(coeffs[1])
        if len(coeffs) > 2:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'second_calib').setValue(coeffs[2])
        else:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'second_calib').setValue(0)
        if len(coeffs) > 3:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'third_calib').setValue(coeffs[3])
        else:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'third_calib').setValue(0)

    def set_manual_laser_wl(self, laser_wl):
        messg = QtWidgets.QMessageBox()
        messg.setText(
            'You manually changed the laser wavelength to {:}nm!'.format(
                laser_wl))
        messg.setInformativeText("Is that correct?")
        messg.setStandardButtons(QtWidgets.QMessageBox.Yes
                                 | QtWidgets.QMessageBox.No)
        ret = messg.exec()
        if ret == QtWidgets.QMessageBox.Yes:
            self.status_laser.setText('{:}nm'.format(laser_wl))
            self.status_laser.setStyleSheet("background-color: green")
            self.settings.child('acq_settings',
                                'units').setOpts(readonly=False)

    def move_laser_wavelength(self, laser_wavelength):
        #do hardware stuff if possible (Mock, labspec...)
        try:
            if self.current_det['laser']:
                self.detector.command_detector.emit(
                    ThreadCommand('set_laser_wl', [laser_wavelength]))
        except Exception as e:
            logger.exception(str(e))

    @Slot(OrderedDict)
    def show_data(self, data):
        """
        do stuff with data from the detector if its grab_done_signal has been connected
        Parameters
        ----------
        data: (OrderedDict) #OrderedDict(name=self.title,x_axis=None,y_axis=None,z_axis=None,data0D=None,data1D=None,data2D=None)
        """
        self.data_dict = data
        if 'data1D' in data:
            self.raw_data = []
            for key in data['data1D']:
                self.raw_data.append(data['data1D'][key]['data'])
                if 'x_axis' in data['data1D'][key]:
                    x_axis = data['data1D'][key]['x_axis']
                else:
                    x_axis = utils.Axis(data=np.linspace(
                        0,
                        len(data['data1D'][key]['data']) - 1,
                        len(data['data1D'][key]['data'])),
                                        units='pxls',
                                        label='')
                if self.viewer_freq_axis['data'] is None:
                    self.viewer_freq_axis.update(x_axis)
                elif np.any(x_axis['data'] != self.viewer_freq_axis['data']
                            ) and self.current_det['calib']:
                    self.viewer_freq_axis.update(x_axis)

            self.viewer.show_data(self.raw_data)
            self.update_axis()

    def update_axis(self):
        axis = utils.Axis()
        unit = self.settings.child('acq_settings', 'units').value()
        if unit == 'nm':
            axis['data'] = self.viewer_freq_axis['data']
        elif unit == 'cm-1':
            axis['data'] = Enm2cmrel(
                self.viewer_freq_axis['data'],
                self.settings.child('config_settings', 'laser_wl').value())
        elif unit == 'eV':
            axis['data'] = nm2eV(self.viewer_freq_axis['data'])
        axis['units'] = unit
        axis['label'] = 'Photon energy'
        self.viewer.x_axis = axis

    def create_menu(self, menubar):
        """
        """
        menubar.clear()

        # %% create file menu
        file_menu = menubar.addMenu('File')
        load_action = file_menu.addAction('Load file')
        load_action.triggered.connect(self.load_file)
        save_action = file_menu.addAction('Save file')
        save_action.triggered.connect(self.save_data)
        export_action = file_menu.addAction('Export as ascii')
        export_action.triggered.connect(lambda: self.save_data(export=True))

        file_menu.addSeparator()
        file_menu.addAction('Show log file', self.show_log)
        file_menu.addSeparator()
        quit_action = file_menu.addAction('Quit')
        quit_action.triggered.connect(self.quit_function)

        settings_menu = menubar.addMenu('Settings')
        settings_menu.addAction('Show Units Converter',
                                self.show_units_converter)
        docked_menu = settings_menu.addMenu('Docked windows')
        docked_menu.addAction('Load Layout', self.load_layout_state)
        docked_menu.addAction('Save Layout', self.save_layout_state)

        self.preset_menu = menubar.addMenu(self.dashboard.preset_menu)
        self.preset_menu.menu().addSeparator()
        self.preset_menu.menu().addAction(
            'Offline Mode',
            lambda: self.initialized(state=False, offline=True))

    def load_layout_state(self, file=None):
        """
            Load and restore a layout state from the select_file obtained pathname file.

            See Also
            --------
            utils.select_file
        """
        try:
            if file is None:
                file = select_file(save=False, ext='dock')
            if file is not None:
                with open(str(file), 'rb') as f:
                    dockstate = pickle.load(f)
                    self.dockarea.restoreState(dockstate)
            file = file.name
            self.settings.child('loaded_files', 'layout_file').setValue(file)
        except Exception as e:
            logger.exception(str(e))

    def save_layout_state(self, file=None):
        """
            Save the current layout state in the select_file obtained pathname file.
            Once done dump the pickle.

            See Also
            --------
            utils.select_file
        """
        try:
            dockstate = self.dockarea.saveState()
            if 'float' in dockstate:
                dockstate['float'] = []
            if file is None:
                file = select_file(start_path=None, save=True, ext='dock')
            if file is not None:
                with open(str(file), 'wb') as f:
                    pickle.dump(dockstate, f, pickle.HIGHEST_PROTOCOL)
        except Exception as e:
            logger.exception(str(e))

    def show_log(self):
        import webbrowser
        webbrowser.open(logging.getLogger('pymodaq').handlers[0].baseFilename)

    def show_units_converter(self):
        self.units_converter = UnitsConverter()
        dock_converter = Dock('Units Converter', size=(300, 350))
        self.dockarea.addDock(dock_converter, 'bottom', self.dock_logger)
        dock_converter.addWidget(self.units_converter.parent)

    def load_file(self):
        data, fname, node_path = browse_data(ret_all=True)
        if data is not None:
            h5utils = H5BrowserUtil()
            h5utils.open_file(fname)
            data, axes, nav_axes, is_spread = h5utils.get_h5_data(node_path)
            data_node = h5utils.get_node(node_path)
            if data_node.attrs['type'] == 'data':
                if data_node.attrs['data_dimension'] == '1D':
                    data_dict = OrderedDict(data1D=dict(
                        raw=dict(data=data, x_axis=axes['x_axis'])))
                    self.show_data(data_dict)
            h5utils.close_file()

    def quit_function(self):
        #close all stuff that need to be
        if self.detector is not None:
            self.detector.quit_fun()
            QtWidgets.QApplication.processEvents()
            self.mainwindow.close()

    def create_toolbar(self):
        self.toolbar.addWidget(QtWidgets.QLabel('Acquisition:'))

        iconquit = QtGui.QIcon()
        iconquit.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/close2.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.quit_action = QtWidgets.QAction(iconquit, "Quit program", None)
        self.toolbar.addAction(self.quit_action)
        self.quit_action.triggered.connect(self.quit_function)

        iconload = QtGui.QIcon()
        iconload.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/Open.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.loadaction = QtWidgets.QAction(
            iconload, "Load target file (.h5, .png, .jpg) or data from camera",
            None)
        self.toolbar.addAction(self.loadaction)
        self.loadaction.triggered.connect(self.load_file)

        iconsave = QtGui.QIcon()
        iconsave.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/SaveAs.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.saveaction = QtWidgets.QAction(iconsave, "Save current data",
                                            None)
        self.toolbar.addAction(self.saveaction)
        self.saveaction.triggered.connect(self.save_data)

        iconrun = QtGui.QIcon()
        iconrun.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/run2.png"),
                          QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.grab_action = QtWidgets.QAction(iconrun, 'Grab', None)
        self.grab_action.setCheckable(True)
        self.toolbar.addAction(self.grab_action)
        self.grab_action.triggered.connect(self.grab_detector)

        iconsnap = QtGui.QIcon()
        iconsnap.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/snap.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.snap_action = QtWidgets.QAction(iconsnap, 'Snap', None)
        self.snap_action.triggered.connect(self.snap_detector)
        self.toolbar.addAction(self.snap_action)

        self.grab_action.setEnabled(False)
        self.snap_action.setEnabled(False)

    def grab_detector(self):
        self.detector.ui.grab_pb.click()

    def snap_detector(self):
        self.detector.ui.single_pb.click()

    def save_data(self, export=False):
        try:
            if export:
                ext = 'dat'
            else:
                ext = 'h5'
            path = select_file(start_path=self.save_file_pathname,
                               save=True,
                               ext=ext)
            if not (not (path)):
                if not export:
                    h5saver = H5Saver(save_type='detector')
                    h5saver.init_file(update_h5=True,
                                      custom_naming=False,
                                      addhoc_file_path=path)

                    settings_str = b'<All_settings>' + custom_tree.parameter_to_xml_string(
                        self.settings)
                    if self.detector is not None:
                        settings_str += custom_tree.parameter_to_xml_string(
                            self.detector.settings)
                        if hasattr(self.detector.ui.viewers[0], 'roi_manager'):
                            settings_str += custom_tree.parameter_to_xml_string(
                                self.detector.ui.viewers[0].roi_manager.
                                settings)
                    settings_str += custom_tree.parameter_to_xml_string(
                        h5saver.settings)
                    settings_str += b'</All_settings>'

                    det_group = h5saver.add_det_group(h5saver.raw_group,
                                                      "Data", settings_str)
                    try:
                        self.channel_arrays = OrderedDict([])
                        data_dim = 'data1D'
                        if not h5saver.is_node_in_group(det_group, data_dim):
                            self.channel_arrays['data1D'] = OrderedDict([])
                            data_group = h5saver.add_data_group(
                                det_group, data_dim)
                            for ind_channel, data in enumerate(
                                    self.raw_data):  # list of numpy arrays
                                channel = f'CH{ind_channel:03d}'
                                channel_group = h5saver.add_CH_group(
                                    data_group, title=channel)

                                self.channel_arrays[data_dim][
                                    'parent'] = channel_group
                                self.channel_arrays[data_dim][
                                    channel] = h5saver.add_data(
                                        channel_group,
                                        dict(data=data,
                                             x_axis=self.viewer_freq_axis),
                                        scan_type='',
                                        enlargeable=False)
                        h5saver.close_file()
                    except Exception as e:
                        logger.exception(str(e))
                else:
                    data_to_save = [self.viewer_freq_axis['data']]
                    data_to_save.extend([dat for dat in self.raw_data])
                    np.savetxt(path, data_to_save, delimiter='\t')

        except Exception as e:
            logger.exception(str(e))

    @Slot(str)
    def add_log(self, txt):
        """
            Add a log to the logger list from the given text log and the current time

            ================ ========= ======================
            **Parameters**   **Type**   **Description**

             *txt*             string    the log to be added
            ================ ========= ======================

        """
        now = datetime.datetime.now()
        new_item = QtWidgets.QListWidgetItem(str(now) + ": " + txt)
        self.logger_list.addItem(new_item)
        ##to do
        ##self.save_parameters.logger_array.append(str(now)+": "+txt)

    @Slot(str)
    def emit_log(self, txt):
        """
            Emit a log-signal from the given log index

            =============== ======== =======================
            **Parameters**  **Type** **Description**

             *txt*           string   the log to be emitted
            =============== ======== =======================

        """
        self.log_signal.emit(txt)