コード例 #1
0
    def show_remote(self):
        """

        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        # tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        tree.setParameters(self.remote_params, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)

        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about the actions and their shortcuts')
        res = dialog.exec()

        if res == dialog.Accepted:
            # save preset parameters in a xml file
            ioxml.parameter_to_xml_file(
                self.remote_params, os.path.join(remote_path, self.remote_params.child('filename').value()))
コード例 #2
0
    def show_file_attributes(self, type_info='dataset'):
        """
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res
コード例 #3
0
    def show_overshoot(self):
        """

        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        tree.setParameters(self.overshoot_params, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)

        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this managers')
        res = dialog.exec()

        if res == dialog.Accepted:
            # save managers parameters in a xml file
            # start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            # start = os.path.join("..",'daq_scan')
            ioxml.parameter_to_xml_file(
                self.overshoot_params,
                os.path.join(overshoot_path,
                             self.overshoot_params.child('filename').value()))
コード例 #4
0
ファイル: manage_preset.py プロジェクト: seb5g-test/PyMoDAQ
    def show_preset(self):
        """

        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        tree.setParameters(self.preset_params, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)

        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this preset')
        res = dialog.exec()

        if self.pid_type:
            path = pid_path
        else:
            path = preset_path

        if res == dialog.Accepted:
            # save preset parameters in a xml file
            #start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            #start = os.path.join("..",'daq_scan')
            custom_tree.parameter_to_xml_file(
                self.preset_params,
                os.path.join(path,
                             self.preset_params.child(('filename')).value()))

            if not self.pid_type:
                #check if overshoot configuration and layout configuration with same name exists => delete them if yes
                overshoot_path = os.path.join(local_path,
                                              'overshoot_configurations')
                file = os.path.splitext(
                    self.preset_params.child(('filename')).value())[0]
                file = os.path.join(overshoot_path, file + '.xml')
                if os.path.isfile(file):
                    os.remove(file)

                layout_path = os.path.join(local_path, 'layout')
                file = os.path.splitext(
                    self.preset_params.child(('filename')).value())[0]
                file = os.path.join(layout_path, file + '.dock')
                if os.path.isfile(file):
                    os.remove(file)
コード例 #5
0
ファイル: daq_logger.py プロジェクト: quentinbournet/PyMoDAQ
    def show_file_attributes(self, type_info='dataset'):
        """
            Switch the type_info value.

            In case of :
                * *scan* : Set parameters showing top false
                * *dataset* : Set parameters showing top false
                * *managers* : Set parameters showing top false. Add the save/cancel buttons to the accept/reject dialog (to save managers parameters in a xml file).

            Finally, in case of accepted managers type info, save the managers parameters in a xml file.

            =============== =========== ====================================
            **Parameters**    **Type**    **Description**
            *type_info*       string      The file type information between
                                            * scan
                                            * dataset
                                            * managers
            =============== =========== ====================================

            See Also
            --------
            custom_tree.parameter_to_xml_file, create_menu
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res
コード例 #6
0
ファイル: db_logger.py プロジェクト: shermelin/PyMoDAQ
class DbLoggerGUI(DbLogger, QtCore.QObject):
    params = [
        {
            'title': 'Database:',
            'name': 'database_type',
            'type': 'list',
            'value': 'PostgreSQL',
            'values': [
                'PostgreSQL',
            ]
        },
        {
            'title': 'Server IP:',
            'name': 'server_ip',
            'type': 'str',
            'value': config['network']['logging']['sql']['ip']
        },
        {
            'title': 'Server port:',
            'name': 'server_port',
            'type': 'int',
            'value': config['network']['logging']['sql']['port']
        },
        {
            'title': 'Connect:',
            'name': 'connect_db',
            'type': 'bool_push',
            'value': False
        },
        {
            'title': 'Connected:',
            'name': 'connected_db',
            'type': 'led',
            'value': False,
            'readonly': True
        },
    ] + dashboard_submodules_params

    def __init__(self, database_name):
        DbLogger.__init__(self,
                          database_name,
                          ip_address=config['network']['logging']['sql']['ip'],
                          port=config['network']['logging']['sql']['port'],
                          save2D=False)
        QtCore.QObject.__init__(self)

        self.settings = Parameter.create(title='DB settings',
                                         name='db_settings',
                                         type='group',
                                         children=self.params)
        self.settings.child(('do_save')).hide()
        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumHeight(310)
        self.settings_tree.setParameters(self.settings, showTop=False)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        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() == 'server_ip':
                    self.ip_address = param.value()

                elif param.name() == 'server_port':
                    self.port = param.value()

                elif param.name() == 'connect_db':
                    status = self.connect_db()
                    self.settings.child(('connected_db')).setValue(status)

                elif param.name() == 'save_2D':
                    self.save2D = param.value()

            elif change == 'parent':
                pass
コード例 #7
0
class H5Saver(QObject):
    """QObject containing all methods in order to save datas in a *hdf5 file* with a hierachy compatible with
    the H5Browser. The saving parameters are contained within a **Parameter** object: self.settings that can be displayed
    on a UI (see :numref:`other_settings`) using the widget self.settings_tree. At the creation of a new file, a node
    group named **Raw_datas** and represented by the attribute ``raw_group`` is created and set with a metadata attribute:

    * 'type' given by the **save_type** class parameter

    The root group of the file is then set with a few metadata:

    * 'pymodaq_version' the current pymodaq version, e.g. 1.6.2
    * 'file' the file name
    * 'date' the current date
    * 'time' the current time

    All datas will then be saved under this node in various groups

    See Also
    --------
    H5Browser

    Parameters
    ----------
    h5_file: pytables hdf5 file
             object used to save all datas and metadas

    h5_file_path: str or Path
                  pyqtSignal signal represented by a float. Is emitted each time the hardware reached the target
                  position within the epsilon precision (see comon_parameters variable)

    save_type: str
               an element of the list module attribute save_types = ['scan', 'detector', 'custom']
               * 'scan' is used for DAQ_Scan module and should be used for similar application
               * 'detector' is used for DAQ_Viewer module and should be used for similar application
               * 'custom' should be used for customized applications

    Attributes
    ----------
    status_sig: pyqtSignal
                emits a signal of type Threadcommand in order to senf log information to a main UI
    new_file_sig: pyqtSignal
                  emits a boolean signal to let the program know when the user pressed the new file button on the UI

    settings: Parameter
               Parameter instance (pyqtgraph) containing all settings (could be represented using the settings_tree widget)

    settings_tree: ParameterTree
                   Widget representing as a Tree structure, all the settings defined in the class preamble variable ``params``

    """
    status_sig = pyqtSignal(utils.ThreadCommand)
    new_file_sig = pyqtSignal(bool)

    params = [
        {
            'title': 'Save type:',
            'name': 'save_type',
            'type': 'list',
            'values': save_types,
            'readonly': True
        },
        {
            'title': 'Save 2D datas:',
            'name': 'save_2D',
            'type': 'bool',
            'value': True
        },
        {
            'title':
            'Save raw datas only:',
            'name':
            'save_raw_only',
            'type':
            'bool',
            'value':
            True,
            'tooltip':
            'if True, will not save extracted ROIs used to do live plotting, only raw datas and the scan \
                        result will be saved'
        },
        {
            'title': 'Do Save:',
            'name': 'do_save',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'N saved:',
            'name': 'N_saved',
            'type': 'int',
            'default': 0,
            'value': 0,
            'visible': False
        },
        {
            'title': 'custom_name?:',
            'name': 'custom_name',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'show file content?:',
            'name': 'show_file',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'Base path:',
            'name': 'base_path',
            'type': 'browsepath',
            'value': 'C:\Data',
            'filetype': False,
            'readonly': True,
        },
        {
            'title': 'Base name:',
            'name': 'base_name',
            'type': 'str',
            'value': 'Scan',
            'readonly': True
        },
        {
            'title': 'Current scan:',
            'name': 'current_scan_name',
            'type': 'str',
            'value': '',
            'readonly': True
        },
        {
            'title': 'Current path:',
            'name': 'current_scan_path',
            'type': 'text',
            'value': 'C:\Data',
            'readonly': True,
            'visible': False
        },
        {
            'title': 'h5file:',
            'name': 'current_h5_file',
            'type': 'text_pb',
            'value': '',
            'readonly': True
        },
        {
            'title':
            'Compression options:',
            'name':
            'compression_options',
            'type':
            'group',
            'children': [
                {
                    'title': 'Compression library:',
                    'name': 'h5comp_library',
                    'type': 'list',
                    'value': 'zlib',
                    'values': ['zlib', 'lzo', 'bzip2', 'blosc']
                },
                {
                    'title': 'Compression level:',
                    'name': 'h5comp_level',
                    'type': 'int',
                    'value': 5,
                    'min': 0,
                    'max': 9
                },
            ]
        },
    ]

    def __init__(self, h5_file_path=None, h5_file=None, save_type='scan'):
        """Initialize the H5Saver object

        Creates the ``setting`` and ``settings_tree`` object



        """
        super(H5Saver, self).__init__()

        if save_type not in save_types:
            raise Exception('Invalid saving type')

        self.h5_file = h5_file
        self.h5_file_path = h5_file_path
        self.h5_file_name = None
        self.logger_array = None

        self.current_group = None
        self.current_scan_group = None
        self.current_scan_name = None
        self.raw_group = None

        self.settings = Parameter.create(title='Saving settings',
                                         name='save_settings',
                                         type='group',
                                         children=self.params)
        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumHeight(310)
        self.settings_tree.setParameters(self.settings, showTop=False)
        self.settings.child(
            ('current_h5_file'
             )).sigActivated.connect(lambda: self.emit_new_file(True))

        self.settings.child(('save_type')).setValue(save_type)

        self.filters = tables.Filters(
            complevel=self.settings.child('compression_options',
                                          'h5comp_level').value(),
            complib=self.settings.child('compression_options',
                                        'h5comp_library').value())
        # self.settings.child('saving_options', 'save_independent').show(save_type == 'scan')
        # self.settings.child('saving_options', 'do_save').show(not save_type == 'scan')
        # self.settings.child('saving_options', 'current_scan_name').show(save_type == 'scan')

        self.settings.sigTreeStateChanged.connect(
            self.parameter_tree_changed
        )  # any changes on the settings will update accordingly the detector

    def emit_new_file(self, status):
        """Emits the new_file_sig

        Parameters
        ----------
        status: bool
                emits True if a new file has been asked by the user pressing the new file button on the UI
        """
        self.new_file_sig.emit(status)

    def init_file(self,
                  update_h5=False,
                  custom_naming=False,
                  addhoc_file_path=None):
        """Initializes a new h5 file.
        Could set the h5_file attributes as:

        * a file with a name following a template if ``custom_naming`` is ``False`` and ``addhoc_file_path`` is ``None``
        * a file within a name set using a file dialog popup if ``custom_naming`` is ``True``
        * a file with a custom name if ``addhoc_file_path`` is a ``Path`` object or a path string

        Parameters
        ----------
        update_h5: bool
                   create a new h5 file with name specified by other parameters
                   if false try to open an existing file and will append new data to it
        custom_naming: bool
                       if True, a selection file dialog opens to set a new file name
        addhoc_file_path: Path or str
                          supplied name by the user for the new file

        Returns
        -------
        update_h5: bool
                   True if new file has been created, False otherwise
        """
        date = datetime.datetime.now()

        if addhoc_file_path is None:
            if not os.path.isdir(self.settings.child(('base_path')).value()):
                os.mkdir(self.settings.child(('base_path')).value())

            # set the filename and path
            base_name = self.settings.child(('base_name')).value()

            if not custom_naming:
                custom_naming = self.settings.child(('custom_name')).value()

            if not custom_naming:
                scan_type = self.settings.child(
                    ('save_type')).value() == 'scan'
                scan_path, current_scan_name, save_path = self.update_file_paths(
                    update_h5)
                self.current_scan_name = current_scan_name
                self.settings.child(
                    ('current_scan_name')).setValue(current_scan_name)
                self.settings.child(
                    ('current_scan_path')).setValue(str(scan_path))

                if not scan_type:
                    self.h5_file_path = save_path  #will remove the dataset part used for DAQ_scan datas
                    self.h5_file_name = base_name + date.strftime(
                        '_%Y%m%d_%H_%M_%S.h5')
                else:
                    self.h5_file_path = save_path
                    self.h5_file_name = save_path.name + ".h5"
            else:
                self.h5_file_name = utils.select_file(start_path=base_name,
                                                      save=True,
                                                      ext='h5')
                self.h5_file_path = self.h5_file_name.parent

        else:
            if isinstance(addhoc_file_path, str):
                addhoc_file_path = Path(addhoc_file_path)
            self.h5_file_path = addhoc_file_path.parent
            self.h5_file_name = addhoc_file_path.name

        fullpathname = str(self.h5_file_path.joinpath(self.h5_file_name))
        self.settings.child(('current_h5_file')).setValue(fullpathname)

        if update_h5:
            self.current_scan_group = None

        scan_group = None
        if self.current_scan_group is not None:
            scan_group = self.current_scan_group._v_name

        if update_h5:
            self.close_file()
            self.h5_file = tables.open_file(fullpathname,
                                            'w',
                                            title='PyMoDAQ file')
            self.h5_file.root._v_attrs['pymodaq_version'] = get_version()
        else:
            self.close_file()
            self.h5_file = tables.open_file(fullpathname,
                                            'a',
                                            title='PyMoDAQ file')

        self.raw_group = self.get_set_group(self.h5_file.root,
                                            'Raw_datas',
                                            title='Data from PyMoDAQ modules')
        self.get_set_logger(self.raw_group)
        if scan_group is not None:
            self.current_scan_group = self.get_set_group(
                self.raw_group, scan_group)
        else:
            self.current_scan_group = self.get_last_scan()

        self.raw_group._v_attrs['type'] = self.settings.child(
            ('save_type')).value()
        self.h5_file.root._v_attrs['file'] = date.strftime(self.h5_file_name)
        if update_h5:
            self.h5_file.root._v_attrs['date'] = date.strftime('%Y%m%d')
            self.h5_file.root._v_attrs['time'] = date.strftime('%H:%M:%S')

        return update_h5

    def update_file_paths(self, update_h5=False):
        """Apply the template depending on the 'save_type' settings child

        Parameters
        ----------
        update_h5: bool
                   if True, will increment the file name and eventually the current scan index
                   if False, get the current scan index in the h5 file

        Returns
        -------
        scan_path: Path
        current_filename: str
        dataset_path: Path

        See Also
        --------
        :py:meth:`pymodaq.daq_utils.daq_utils.set_current_scan_path`

        """

        try:
            # set the filename and path
            base_path = self.settings.child(('base_path')).value()
            base_name = self.settings.child(('base_name')).value()
            current_scan = self.settings.child(('current_scan_name')).value()
            scan_type = self.settings.child(('save_type')).value() == 'scan'

            if current_scan == '' or update_h5:
                next_scan_index = 0
                update_h5 = True  #just started the main program so one should create a new h5
            else:
                next_scan_index = self.get_scan_index()

            scan_path, current_filename, dataset_path = utils.set_current_scan_path(
                base_path,
                base_name,
                update_h5,
                next_scan_index,
                create_dataset_folder=scan_type)
            self.settings.child(('current_scan_path')).setValue(str(scan_path))

            return scan_path, current_filename, dataset_path

        except Exception as e:
            print(e)

    def get_last_scan(self):
        """Gets the last scan node within the h5_file and under the the **raw_group**

        Returns
        -------
        scan_group: pytables group or None


        """
        groups = [
            group for group in list(self.raw_group._v_groups)
            if 'Scan' in group
        ]
        groups.sort()
        if len(groups) != 0:
            scan_group = self.h5_file.get_node(self.raw_group, groups[-1])
        else:
            scan_group = None
        return scan_group

    def get_scan_index(self):
        """ return the scan group index in the "scan templating": Scan000, Scan001 as an integer
        """
        try:
            if self.current_scan_group is None:
                return 0
            else:

                groups = [
                    group for group in list(self.raw_group._v_groups)
                    if 'Scan' in group
                ]
                groups.sort()
                flag = False
                for child in list(
                        self.h5_file.get_node(self.raw_group,
                                              groups[-1])._v_groups):
                    if 'scan' in child:
                        return len(groups)

                return 0

        except Exception as e:
            return 0

    def load_file(self, base_path=None, file_path=None):
        """Opens a file dialog to select a h5file saved on disk to be used

        Parameters
        ----------
        base_path
        file_path

        See Also
        --------
        :py:meth:`init_file`
        :py:meth:`pymodaq.daq_utils.daq_utils.select_file`

        """
        if base_path is None:
            base_path = self.settings.child('base_path').value()
            if not os.path.isdir(base_path):
                base_path = None

        if file_path is None:
            file_path = utils.select_file(base_path, save=False, ext='h5')

        if not isinstance(file_path, Path):
            file_path = Path(file_path)

        if 'h5' not in file_path.suffix:
            raise IOError('Invalid file type, should be a h5 file')

        self.init_file(addhoc_file_path=file_path)

    def close_file(self):
        """Flush data and close the h5file

        """
        try:
            if self.h5_file is not None:
                self.h5_file.flush()
                if self.h5_file.isopen:
                    self.h5_file.close()
        except Exception as e:
            print(e)  #no big deal

    def is_node_in_group(self, where, name):
        """
        Check if a given node with name is in the group defined by where (comparison on lower case strings)
        Parameters
        ----------
        where: (str or node)
                path or parent node instance
        name: (str)
              group node name

        Returns
        -------
        bool
            True if node exists, False otherwise
        """

        nodes_names = [
            node._v_name.lower() for node in self.h5_file.list_nodes(where)
        ]
        return name.lower() in nodes_names

    def get_set_logger(self, where):
        """ Retrieve or create (if absent) a logger enlargeable array to store logs
        Get attributed to the class attribute ``logger_array``
        Parameters
        ----------
        where: node
               location within the tree where to save or retrieve the array

        Returns
        -------
        logger_array: vlarray
                      enlargeable array accepting strings as elements
        """
        logger = 'Logger'
        if not logger in list(self.h5_file.get_node(where)._v_children.keys()):
            # check if logger node exist
            text_atom = tables.atom.ObjectAtom()
            self.logger_array = self.h5_file.create_vlarray(where,
                                                            logger,
                                                            atom=text_atom)
            self.logger_array._v_attrs['type'] = 'log'
        else:
            self.logger_array = self.h5_file.get_node(where, name=logger)
        return self.logger_array

    def get_set_group(self, where, name, title=''):
        """Retrieve or create (if absent) a node group
        Get attributed to the class attribute ``current_group``

        Parameters
        ----------
        where: str or node
               path or parent node instance
        name: str
              group node name
        title: str
               node title

        Returns
        -------
        group: group node
        """
        if not name in list(self.h5_file.get_node(where)._v_children.keys()):
            self.current_group = self.h5_file.create_group(where, name, title)
        else:
            self.current_group = self.h5_file.get_node(where, name)
        return self.current_group

    def add_data_group(self,
                       where,
                       group_data_type,
                       title='',
                       settings_as_xml='',
                       metadata=dict([])):
        """Creates a group node at given location in the tree

        Parameters
        ----------
        where: group node
               where to create data group
        group_data_type: list of str
                         either ['data0D', 'data1D', 'data2D']
        title: str, optional
               a title for this node, will be saved as metadata
        settings_as_xml: str, optional
                         XML string created from a Parameter object to be saved as metadata
        metadata: dict, optional
                  will be saved as a new metadata attribute with name: key and value: dict value

        Returns
        -------
        group: group node

        See Also
        --------
        :py:meth:`àdd_group`
        """
        if group_data_type not in group_data_types:
            raise Exception('Invalid data group type')
        group = self.add_group(group_data_type, '', where, title,
                               settings_as_xml, metadata)
        return group

    def add_navigation_axis(self,
                            data,
                            parent_group,
                            axis='x_axis',
                            enlargeable=False,
                            title='',
                            metadata=dict([])):
        """
        Create carray for navigation axis within a scan
        Parameters
        ----------
        data: (ndarray) of dimension 1
        parent_group: (str or node) parent node where to save new data
        axis: (str) either x_axis or y_axis
        """
        if axis not in ['x_axis', 'y_axis', 'z_axis']:
            raise Exception('Invalid navigation axis name')
        array = self.add_array(parent_group,
                               'scan_{:s}'.format(axis),
                               'navigation_axis',
                               data_shape=data.shape,
                               data_dimension='1D',
                               array_to_save=data,
                               enlargeable=enlargeable,
                               title=title,
                               metadata=metadata)
        return array

    def add_data_live_scan(self,
                           channel_group,
                           data_dict,
                           scan_type='scan1D',
                           title=''):
        shape, dimension, size = utils.get_data_dimension(
            data_dict['data'], scan_type=scan_type, remove_scan_dimension=True)
        data_array = self.add_array(channel_group,
                                    'Data',
                                    'data',
                                    array_type=np.float,
                                    title=title,
                                    data_shape=shape,
                                    data_dimension=dimension,
                                    scan_type=scan_type,
                                    array_to_save=data_dict['data'])
        if 'x_axis' in data_dict:
            if not isinstance(data_dict['x_axis'], dict):
                array_to_save = data_dict['x_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['x_axis'])
                array_to_save = tmp_dict.pop('data')
        if 'x_axis' in data_dict:

            array = self.add_array(channel_group,
                                   'x_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)
        if 'y_axis' in data_dict:
            if not isinstance(data_dict['y_axis'], dict):
                array_to_save = data_dict['y_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['y_axis'])
                array_to_save = tmp_dict.pop('data')
        if 'y_axis' in data_dict:
            array = self.add_array(channel_group,
                                   'y_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)
        return data_array

    def add_data(self,
                 channel_group,
                 data_dict,
                 scan_type='scan1D',
                 scan_shape=[],
                 title='',
                 enlargeable=False,
                 init=False,
                 add_scan_dim=False):

        shape, dimension, size = utils.get_data_dimension(data_dict['data'])
        data_array = self.add_array(channel_group,
                                    'Data',
                                    'data',
                                    array_type=np.float,
                                    title=title,
                                    data_shape=shape,
                                    enlargeable=enlargeable,
                                    data_dimension=dimension,
                                    scan_type=scan_type,
                                    scan_shape=scan_shape,
                                    array_to_save=data_dict['data'],
                                    init=init,
                                    add_scan_dim=add_scan_dim)

        if 'x_axis' in data_dict:
            if not isinstance(data_dict['x_axis'], dict):
                array_to_save = data_dict['x_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['x_axis'])
                array_to_save = tmp_dict.pop('data')

            array = self.add_array(channel_group,
                                   'x_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)

        if 'y_axis' in data_dict:
            if not isinstance(data_dict['y_axis'], dict):
                array_to_save = data_dict['y_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['y_axis'])
                array_to_save = tmp_dict.pop('data')

            array = self.add_array(channel_group,
                                   'y_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)

        self.h5_file.flush()
        return data_array

    def add_array(self,
                  where,
                  name,
                  data_type,
                  data_shape=(1, ),
                  data_dimension='0D',
                  scan_type='',
                  scan_shape=[],
                  title='',
                  array_to_save=None,
                  array_type=np.float,
                  enlargeable=False,
                  metadata=dict([]),
                  init=False,
                  add_scan_dim=False):

        if data_dimension not in data_dimensions:
            raise Exception('Invalid data dimension')
        if data_type not in data_types:
            raise Exception('Invalid data type')
        if scan_type != '':
            scan_type = utils.uncapitalize(scan_type)
        if scan_type not in scan_types:
            raise Exception('Invalid scan type')
        if enlargeable:
            shape = [0]
            if data_shape != (1, ):
                shape.extend(data_shape)
            shape = tuple(shape)
            array = self.h5_file.create_earray(where,
                                               utils.capitalize(name),
                                               tables.Atom.from_dtype(
                                                   np.dtype(array_type)),
                                               shape=shape,
                                               title=title,
                                               filters=self.filters)
            array._v_attrs['shape'] = shape
        else:
            if add_scan_dim:  #means it is an array initialization to zero
                shape = scan_shape[:]
                shape.extend(data_shape)
                if init or array_to_save is None:
                    array_to_save = np.zeros(shape)

            array = self.h5_file.create_carray(where,
                                               utils.capitalize(name),
                                               obj=array_to_save,
                                               title=title,
                                               filters=self.filters)
            array._v_attrs['shape'] = array_to_save.shape

        array._v_attrs['type'] = data_type
        array._v_attrs['data_dimension'] = data_dimension
        array._v_attrs['scan_type'] = scan_type

        for metadat in metadata:
            array._v_attrs[metadat] = metadata[metadat]
        return array

    def append(self, array, data):
        if not (isinstance(array, tables.vlarray.VLArray)
                or isinstance(array, tables.earray.EArray)):
            raise Exception('This array cannot be appended')
        if isinstance(data, np.ndarray):
            if data.shape != (1, ):
                shape = [1]
                shape.extend(data.shape)
                array.append(data.reshape(shape))
            else:
                array.append(data)
        else:
            array.append(data)
        sh = list(array._v_attrs['shape'])
        sh[0] += 1
        array._v_attrs['shape'] = tuple(sh)

    def add_group(self,
                  group_name,
                  group_type,
                  where,
                  title='',
                  settings_as_xml='',
                  metadata=dict([])):
        """
        Add a node in the h5 file tree of the group type
        Parameters
        ----------
        group_name: (str) a custom name for this group
        group_type: (str) one of the possible values of **group_types**
        where: (str or node) parent node where to create the new group
        settings_as_xml: (str) XML string containing Parameters representation (see custom_Tree)
        metadata: (dict) extra metadata to be saved with this new group node

        Returns
        -------
        (node): newly created group node
        """

        if group_type not in group_types:
            raise Exception('Invalid group type')

        try:
            node = self.h5_file.get_node(where, utils.capitalize(group_name))
        except tables.NoSuchNodeError as e:
            node = None

        if node is None:
            node = self.get_set_group(where, utils.capitalize(group_name),
                                      title)
            node._v_attrs['settings'] = settings_as_xml
            node._v_attrs['type'] = group_type.lower()
            for metadat in metadata:
                node._v_attrs[metadat] = metadata[metadat]

        return node

    def add_incremental_group(self,
                              group_type,
                              where,
                              title='',
                              settings_as_xml='',
                              metadata=dict([])):
        """
        Add a node in the h5 file tree of the group type with an increment in the given name
        Parameters
        ----------
        group_type: (str) one of the possible values of **group_types**
        where: (str or node) parent node where to create the new group
        settings_as_xml: (str) XML string containing Parameters representation (see custom_Tree)
        metadata: (dict) extra metadata to be saved with this new group node

        Returns
        -------
        (node): newly created group node
        """
        if group_type not in group_types:
            raise Exception('Invalid group type')
        nodes = list(self.h5_file.get_node(where)._v_children.keys())
        nodes_tmp = []
        for node in nodes:
            if utils.capitalize(group_type) in node:
                nodes_tmp.append(node)
        nodes_tmp.sort()
        if len(nodes_tmp) == 0:
            ind_group = -1
        else:
            ind_group = int(nodes_tmp[-1][-3:])
        group = self.get_set_group(
            where,
            utils.capitalize(group_type) + '{:03d}'.format(ind_group + 1),
            title)
        group._v_attrs['settings'] = settings_as_xml
        if group_type.lower() != 'ch':
            group._v_attrs['type'] = group_type.lower()
        else:
            group._v_attrs['type'] = ''
        for metadat in metadata:
            group._v_attrs[metadat] = metadata[metadat]
        return group

    def add_det_group(self,
                      where,
                      title='',
                      settings_as_xml='',
                      metadata=dict([])):
        """
        Add a new group of type detector
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('detector', where, title,
                                           settings_as_xml, metadata)
        return group

    def add_CH_group(self,
                     where,
                     title='',
                     settings_as_xml='',
                     metadata=dict([])):
        """
        Add a new group of type channel
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('ch', where, title, settings_as_xml,
                                           metadata)
        return group

    def add_live_scan_group(self,
                            where,
                            dimensionality,
                            title='',
                            settings_as_xml='',
                            metadata=dict([])):
        """
        Add a new group of type live scan
        See Also
        -------
        add_incremental_group
        """
        group = self.add_group('Live_scan_{:s}'.format(dimensionality),
                               '',
                               where,
                               title=title,
                               settings_as_xml=settings_as_xml,
                               metadata=metadata)
        return group

    def add_scan_group(self, title='', settings_as_xml='', metadata=dict([])):
        """
        Add a new group of type scan
        See Also
        -------
        add_incremental_group
        """

        if self.current_scan_group is not None:
            if list(self.current_scan_group._v_children) == []:
                new_scan = False
            else:
                new_scan = True
        else:
            new_scan = True
        if new_scan:
            self.current_scan_group = self.add_incremental_group(
                'scan', self.raw_group, title, settings_as_xml, metadata)
            self.current_scan_group._v_attrs['description'] = ''
            self.settings.child(('current_scan_name')).setValue(
                self.current_scan_group._v_name)

        return self.current_scan_group

    def add_move_group(self,
                       where,
                       title='',
                       settings_as_xml='',
                       metadata=dict([])):
        """
        Add a new group of type move
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('move', where, title,
                                           settings_as_xml, metadata)
        return group

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)

            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'show_file':
                    param.setValue(False)
                    self.show_file_content()

                elif param.name() == 'base_path':
                    try:
                        if not os.path.isdir(param.value()):
                            os.mkdir(param.value())
                    except:
                        self.update_status(
                            "The base path couldn't be set, please check your options"
                        )

                elif param.name() in custom_tree.iter_children(
                        self.settings.child(('compression_options')), []):
                    self.filters = tables.Filters(
                        complevel=self.settings.child('compression_options',
                                                      'h5comp_level').value(),
                        complib=self.settings.child('compression_options',
                                                    'h5comp_library').value())

            elif change == 'parent':
                pass

    def update_status(self, status):
        self.status_sig.emit(
            utils.ThreadCommand("Update_Status", [status, 'log']))

    def show_file_content(self):
        form = QtWidgets.QWidget()
        if not self.h5_file.isopen:
            if self.h5_file_path.exists():
                self.analysis_prog = H5Browser(form, h5file=self.h5_file_path)
            else:
                raise FileExistsError('no File presents')
        else:
            self.analysis_prog = H5Browser(form, h5file=self.h5_file)
        form.show()
コード例 #8
0
class BeeActions(QObject):
    log_signal = pyqtSignal(str)

    def __init__(self, dockarea):
        super().__init__()
        self.dockarea = dockarea
        self.dockarea.dock_signal.connect(self.save_layout_state_auto)
        self.mainwindow = dockarea.parent()
        self.chrono = ChronoTimer(dockarea)
        self.author = 'Aurore Avargues'
        self.h5saver = H5Saver()
        self.h5saver.new_file_sig.connect(self.create_new_file)
        self.settings = None
        self.shortcut_file = None
        self.shortcuts = []
        self.shortcut_manager = ShortCutManager(list_actions)
        self.timestamp_array = None
        self.action_array = None
        self.bee_array = None
        self.setup_ui()

    def setup_ui(self):
        #creating the menubar
        self.menubar = self.mainwindow.menuBar()
        self.create_menu(self.menubar)

        #disconnect normal chrono/timer behaviour with the start button
        self.chrono.start_pb.disconnect()
        self.chrono.start_pb.clicked.connect(self.set_scan)
        self.chrono.reset_pb.clicked.connect(self.stop_daq)

        self.settings_dock = Dock('Settings')
        self.dockarea.addDock(self.settings_dock, 'bottom',
                              self.chrono.dock_controls)

        self.dock_daq = Dock('Data Acquisition')
        self.dockarea.addDock(self.dock_daq, 'right')
        self.logger_list = QtWidgets.QListWidget()
        self.logger_list.setMinimumWidth(300)
        self.dock_daq.addWidget(self.logger_list)

        self.init_tree = ParameterTree()
        self.init_tree.setMinimumWidth(300)
        self.init_tree.setMinimumHeight(150)
        self.settings_dock.addWidget(self.init_tree)
        self.settings_dock.addWidget(self.h5saver.settings_tree)
        self.h5saver.settings.child(('save_type')).hide()
        self.h5saver.settings.child(('save_2D')).hide()
        self.h5saver.settings.child(('save_raw_only')).hide()
        self.h5saver.settings.child(('do_save')).hide()
        self.h5saver.settings.child(('custom_name')).hide()

        self.settings = Parameter.create(name='init_settings',
                                         type='group',
                                         children=[
                                             {
                                                 'title':
                                                 'Loaded presets',
                                                 'name':
                                                 'loaded_files',
                                                 'type':
                                                 'group',
                                                 'children': [
                                                     {
                                                         'title':
                                                         'Shortcut file',
                                                         'name':
                                                         'shortcut_file',
                                                         'type': 'str',
                                                         'value': '',
                                                         'readonly': True
                                                     },
                                                     {
                                                         'title':
                                                         'Layout file',
                                                         'name': 'layout_file',
                                                         'type': 'str',
                                                         'value': '',
                                                         'readonly': True
                                                     },
                                                 ]
                                             },
                                             {
                                                 'title':
                                                 'Settings',
                                                 'name':
                                                 'settings',
                                                 'type':
                                                 'group',
                                                 'children': [
                                                     {
                                                         'title':
                                                         'Save Bee number',
                                                         'name':
                                                         'save_bee_number',
                                                         'type': 'bool',
                                                         'value': True
                                                     },
                                                 ]
                                             },
                                             {
                                                 'title': 'Shortcuts',
                                                 'name': 'shortcuts',
                                                 'type': 'group',
                                                 'children': []
                                             },
                                         ])
        self.init_tree.setParameters(self.settings, showTop=False)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        #params about dataset attributes and scan attibutes
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        params_dataset = [{
            'title':
            'Dataset information',
            'name':
            'dataset_info',
            'type':
            'group',
            'children': [{
                'title': 'Author:',
                'name': 'author',
                'type': 'str',
                'value': self.author
            }, {
                'title': 'Date/time:',
                'name': 'date_time',
                'type': 'date_time',
                'value': date
            }, {
                'title': 'Sample:',
                'name': 'sample',
                'type': 'str',
                'value': ''
            }, {
                'title': 'Experiment type:',
                'name': 'experiment_type',
                'type': 'str',
                'value': ''
            }, {
                'title': 'Description:',
                'name': 'description',
                'type': 'text',
                'value': ''
            }]
        }]

        params_scan = [{
            'title':
            'Scan information',
            'name':
            'scan_info',
            'type':
            'group',
            'children': [
                {
                    'title': 'Author:',
                    'name': 'author',
                    'type': 'str',
                    'value': self.author
                },
                {
                    'title': 'Date/time:',
                    'name': 'date_time',
                    'type': 'date_time',
                    'value': date
                },
                {
                    'title': 'Scan type:',
                    'name': 'scan_type',
                    'type': 'list',
                    'value': 'Scan1D',
                    'values': ['Scan1D', 'Scan2D']
                },
                {
                    'title': 'Scan name:',
                    'name': 'scan_name',
                    'type': 'str',
                    'value': '',
                    'readonly': True
                },
                {
                    'title': 'Description:',
                    'name': 'description',
                    'type': 'text',
                    'value': ''
                },
            ]
        }]

        self.dataset_attributes = Parameter.create(name='Attributes',
                                                   type='group',
                                                   children=params_dataset)
        self.scan_attributes = Parameter.create(name='Attributes',
                                                type='group',
                                                children=params_scan)

    def parameter_tree_changed(self, param, changes):
        """
            | Check eventual changes in the changes list parameter.
            |
            | In case of changed values, emit the signal containing the current path and parameter via update_settings_signal to the connected hardware.

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

             *param*         instance of pyqtgraph parameter         The parameter to be checked

             *changes*       (parameter,change,infos) tuple list     The (parameter,change,infos) list to be treated
            =============== ====================================    ==================================================
        """

        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() in custom_tree.iter_children(
                        self.settings.child(('shortcuts')), []):
                    if param.parent().name() == 'shortcuts':
                        param_index = custom_tree.iter_children(
                            self.settings.child(('shortcuts')),
                            []).index(param.name())
                        action = self.shortcut_manager.shortcut_params.child(
                            ('actions')).children()[param_index].child(
                                ('action')).value()
                        self.activate_shortcut(self.shortcuts[param_index],
                                               action,
                                               activate=param.value())

            elif change == 'parent':
                pass

    def activate_shortcut(self, shortcut, action='', activate=True):
        if activate:
            shortcut.activated.connect(self.create_activated_slot(action))
        else:
            try:
                shortcut.activated.disconnect()
            except:
                pass

    def create_activated_slot(self, action):
        return lambda: self.log_data(action)

    def log_data(self, action=''):
        now = self.chrono.get_elapsed_time()
        if self.settings.child('settings', 'save_bee_number').value():
            widget = QtWidgets.QWidget()
            index, res = QtWidgets.QInputDialog.getInt(
                widget, 'Bee number', 'Pick a number for this bee!')
            if res:
                new_item = QtWidgets.QListWidgetItem(
                    f'Elapsed time: {int(now)} s, Bee {index} did :{action}')
                self.logger_list.insertItem(0, new_item)

                self.h5saver.append(self.action_array, action)
                self.h5saver.append(self.timestamp_array, np.array([now]))
                self.h5saver.append(self.bee_array, np.array([index]))
        else:
            new_item = QtWidgets.QListWidgetItem(
                f'Elapsed time: {int(now)} s:{action}')
            self.logger_list.insertItem(0, new_item)
            self.h5saver.append(self.action_array, action)
            self.h5saver.append(self.timestamp_array, np.array([now]))
        self.h5saver.flush()

    def create_shortcuts(self):
        pass

    def create_new_file(self, new_file):
        self.h5saver.init_file(update_h5=new_file)
        res = self.update_file_settings(new_file)
        return res

    def set_scan(self):
        """
        Sets the current scan given the selected settings. Makes some checks, increments the h5 file scans.
        In case the dialog is cancelled, return False and aborts the scan
        """
        try:
            if self.shortcut_file is not None:

                # set the filename and path
                res = self.create_new_file(False)
                if not res:
                    return

                #create the arrays within the current scan group
                self.timestamp_array = self.h5saver.add_array(
                    self.h5saver.current_scan_group,
                    'time_axis',
                    'data',
                    scan_type='scan1D',
                    enlargeable=True,
                    array_to_save=np.array([
                        0.,
                    ]),
                    data_shape=(1, ),
                    title='Timestamps',
                    metadata=dict(units='seconds'))

                self.action_array = self.h5saver.add_string_array(
                    self.h5saver.current_scan_group,
                    'actions',
                    title='Actions',
                    metadata=dict([]))
                if self.settings.child('settings', 'save_bee_number').value():
                    self.bee_array = self.h5saver.add_array(
                        self.h5saver.current_scan_group,
                        'bees',
                        'data',
                        scan_type='scan1D',
                        enlargeable=True,
                        array_to_save=np.array([
                            0,
                        ]),
                        title='Bees',
                        data_shape=(1, ))

                current_filename = self.h5saver.settings.child(
                    ('current_scan_name')).value()
                self.init_tree.setEnabled(False)
                self.h5saver.settings_tree.setEnabled(False)
                self.logger_list.clear()

                self.h5saver.current_scan_group._v_attrs['scan_done'] = False
                # if all metadat steps have been validated, start the chrono
                self.chrono.start()

                return True
            else:
                mssg = QtWidgets.QMessageBox()
                mssg.setText(
                    'You have to load a shortcut file configuration before starting'
                )
                mssg.exec()
                return False

        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def stop_daq(self):
        self.h5saver.current_scan_group._v_attrs['scan_done'] = True
        self.init_tree.setEnabled(True)
        self.h5saver.settings_tree.setEnabled(True)
        self.h5saver.flush()

    def update_file_settings(self, new_file=False):
        try:
            if self.h5saver.current_scan_group is None:
                new_file = True

            if new_file:
                self.set_metadata_about_dataset()
                self.save_metadata(self.h5saver.raw_group, 'dataset_info')

            if self.h5saver.current_scan_name is None:
                self.h5saver.add_scan_group()
            elif not self.h5saver.is_node_in_group(
                    self.h5saver.raw_group, self.h5saver.current_scan_name):
                self.h5saver.add_scan_group()

            #set attributes to the current group, such as scan_type....
            self.scan_attributes.child('scan_info',
                                       'scan_type').setValue('Scan1D')
            self.scan_attributes.child('scan_info', 'scan_name').setValue(
                self.h5saver.current_scan_group._v_name)
            self.scan_attributes.child('scan_info', 'description').setValue(
                self.h5saver.current_scan_group._v_attrs['description'])
            res = self.set_metadata_about_current_scan()
            self.save_metadata(self.h5saver.current_scan_group, 'scan_info')
            return res

        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def set_metadata_about_current_scan(self):
        """
            Set the date/time and author values of the scan_info child of the scan_attributes tree.
            Show the 'scan' file attributes.

            See Also
            --------
            show_file_attributes
        """
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        self.scan_attributes.child('scan_info', 'date_time').setValue(date)
        self.scan_attributes.child('scan_info', 'author').setValue(
            self.dataset_attributes.child('dataset_info', 'author').value())
        res = self.show_file_attributes('scan')
        return res

    def set_metadata_about_dataset(self):
        """
            Set the date value of the data_set_info-date_time child of the data_set_attributes tree.
            Show the 'dataset' file attributes.

            See Also
            --------
            show_file_attributes
        """
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        self.dataset_attributes.child('dataset_info',
                                      'date_time').setValue(date)
        res = self.show_file_attributes('dataset')
        return res

    def show_file_attributes(self, type_info='dataset'):
        """
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res

    def save_metadata(self, node, type_info='dataset_info'):
        """
        """

        attr = node._v_attrs
        if type_info == 'dataset_info':
            attr['type'] = 'dataset'
            params = self.dataset_attributes
        else:
            attr['type'] = 'scan'
            params = self.scan_attributes
        for child in params.child((type_info)).children():
            if isinstance(child.value(), QDateTime):
                attr[child.name()] = child.value().toString(
                    'dd/mm/yyyy HH:MM:ss')
            else:
                attr[child.name()] = child.value()
        if type_info == 'dataset_info':
            #save contents of given parameter object into an xml string under the attribute settings
            settings_str = b'<All_settings title="All Settings" type="group">'
            settings_str += custom_tree.parameter_to_xml_string(params)
            settings_str += custom_tree.parameter_to_xml_string(self.settings)
            if hasattr(self.shortcut_manager, 'shortcut_params'):
                settings_str += custom_tree.parameter_to_xml_string(
                    self.shortcut_manager.shortcut_params)
            settings_str += b'</All_settings>'

            attr.settings = settings_str

        elif type_info == 'scan_info':
            settings_str = b'<All_settings title="All Settings" type="group">' + \
                           custom_tree.parameter_to_xml_string(params) + \
                           custom_tree.parameter_to_xml_string(self.settings) + \
                           custom_tree.parameter_to_xml_string(self.h5saver.settings) + b'</All_settings>'

            attr.settings = settings_str

    def show_log(self):
        import webbrowser
        webbrowser.open(logging.getLoggerClass().root.handlers[0].baseFilename)

    def show_file(self):
        self.h5saver.flush()
        self.h5saver.show_file_content()

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

        # %% create Settings menu
        self.file_menu = menubar.addMenu('File')
        self.file_menu.addAction('Show log file', self.show_log)
        self.file_menu.addAction('Show data file', self.show_file)

        self.file_menu.addSeparator()
        quit_action = self.file_menu.addAction('Quit')
        quit_action.triggered.connect(self.quit_fun)

        self.settings_menu = menubar.addMenu('Settings')
        docked_menu = self.settings_menu.addMenu('Docked windows')
        action_load = docked_menu.addAction('Load Layout')
        action_save = docked_menu.addAction('Save Layout')

        action_load.triggered.connect(self.load_layout_state)
        action_save.triggered.connect(self.save_layout_state)
        docked_menu.addSeparator()

        self.preset_menu = menubar.addMenu('Preset Shortcuts')
        action_new_preset = self.preset_menu.addAction('New preset')
        # action.triggered.connect(lambda: self.show_file_attributes(type_info='preset'))
        action_new_preset.triggered.connect(self.create_preset)
        action_modify_preset = self.preset_menu.addAction('Modify preset')
        action_modify_preset.triggered.connect(self.modify_shortcuts)
        self.preset_menu.addSeparator()
        load_preset = self.preset_menu.addMenu('Load presets')

        slots = dict([])
        for ind_file, file in enumerate(os.listdir(shortcut_path)):
            if file.endswith(".xml"):
                (filesplited, ext) = os.path.splitext(file)
                slots[filesplited] = load_preset.addAction(filesplited)
                slots[filesplited].triggered.connect(
                    self.create_menu_slot(os.path.join(shortcut_path, file)))

    def modify_shortcuts(self):
        try:
            path = select_file(start_path=shortcut_path, save=False, ext='xml')
            if path != '':
                self.shortcut_manager.set_file_preset(str(path))

                mssg = QtWidgets.QMessageBox()
                mssg.setText(
                    f'You have to restart the application to take the modifications into account! '
                    f'Quitting the application...')
                mssg.exec()
                self.quit_fun()
            else:  # cancel
                pass
        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def create_menu_slot(self, filename):
        return lambda: self.set_shortcut_mode(filename)

    def set_shortcut_mode(self, filename):
        #TODO: apply shortcuts to this widget
        tail, fileext = os.path.split(filename)
        file, ext = os.path.splitext(fileext)
        if ext == '.xml':
            self.shortcut_file = filename
            self.shortcut_manager.set_file_preset(filename, show=False)
            self.settings.child('loaded_files',
                                'shortcut_file').setValue(filename)
            self.author = self.shortcut_manager.shortcut_params.child(
                ('author')).value()
            self.dataset_attributes.child('dataset_info',
                                          'author').setValue(self.author)
            self.scan_attributes.child('scan_info',
                                       'author').setValue(self.author)

            path = os.path.join(layout_path, file + '.dock')
            if os.path.isfile(path):
                self.load_layout_state(path)

            #remove existing shorcuts
            while len(self.shortcuts):
                self.shortcuts.pop(0)

            for ind, shortcut in enumerate(
                    self.shortcut_manager.shortcut_params.child(
                        ('actions')).children()):
                stc = QtWidgets.QShortcut(
                    QtGui.QKeySequence(shortcut.child(('shortcut')).value()),
                    self.dockarea)
                self.settings.child(('shortcuts')).addChild({
                    'title':
                    f"Shortcut{ind:02d}: {shortcut.child(('action')).value()} {shortcut.child(('shortcut')).value()}:",
                    'name': f'shortcut{ind:02d}',
                    'type': 'led_push',
                    'value': True
                })

                self.shortcuts.append(stc)
                self.activate_shortcut(stc,
                                       shortcut.child(('action')).value(),
                                       activate=True)

    def create_preset(self):
        try:
            self.shortcut_manager.set_new_preset()
            self.create_menu(self.menubar)
        except Exception as e:
            self.update_status(getLineInfo() + 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 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:
            pass

    def save_layout_state_auto(self):
        if self.shortcut_file is not None:
            file = os.path.split(self.shortcut_file)[1]
            file = os.path.splitext(file)[0]
            path = os.path.join(layout_path, file + '.dock')
            self.save_layout_state(path)

    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 = os.path.split(file)[1]
            self.settings.child('loaded_files', 'layout_file').setValue(file)
        except:
            pass

    def quit_fun(self):
        """
            Quit the current instance of DAQ_scan and close on cascade move and detector modules.

            See Also
            --------
            quit_fun
        """
        try:
            areas = self.dockarea.tempAreas[:]
            for area in areas:
                area.win.close()
                QtWidgets.QApplication.processEvents()
                QThread.msleep(1000)
                QtWidgets.QApplication.processEvents()

            if hasattr(self, 'mainwindow'):
                self.mainwindow.close()

        except Exception as e:
            pass

    def update_status(self, txt):
        """
            Show the txt message in the status bar with a delay of wait_time ms.

            =============== =========== =======================
            **Parameters**    **Type**    **Description**
            *txt*             string      The message to show
            *wait_time*       int         the delay of showing
            *log_type*        string      the type of the log
            =============== =========== =======================
        """
        try:
            self.log_signal.emit(txt)
            logging.info(txt)

        except Exception as e:
            pass
コード例 #9
0
class BatchManager:

    params = [{'title': 'Filename:', 'name': 'filename', 'type': 'str', 'value': 'batch_default'},
              {'title': 'Scans', 'name': 'scans', 'type': 'group', 'children': []}]

    def __init__(self, msgbox=False, actuators=[], detectors=[], path=None):
        self.actuators = actuators
        self.detectors = detectors

        self.scans = OrderedDict([])

        self.tree = ParameterTree()
        self.tree.setMinimumWidth(400)
        self.tree.setMaximumWidth(500)
        self.tree.setMinimumHeight(500)

        if path is None:
            path = batch_path
        else:
            assert isinstance(path, Path)
        self.batch_path = path

        self.settings = None


        if msgbox:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setText("Scan Batch Manager?")
            msgBox.setInformativeText("What do you want to do?")
            cancel_button = msgBox.addButton(QtWidgets.QMessageBox.Cancel)
            new_button = msgBox.addButton("New", QtWidgets.QMessageBox.ActionRole)
            modify_button = msgBox.addButton('Modify', QtWidgets.QMessageBox.AcceptRole)
            msgBox.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            ret = msgBox.exec()

            if msgBox.clickedButton() == new_button:
                self.set_new_batch()

            elif msgBox.clickedButton() == modify_button:
                self.set_file_batch()
            else:  # cancel
                pass


    def get_act_dets(self):
        acts = dict([])
        dets = dict([])
        for name in self.scans:
            acts[name] = self.settings.child('scans', name, 'modules',
                            'actuators').value()['selected']
            dets[name] = self.settings.child('scans', name, 'modules',
                                             'detectors').value()['selected']
        return acts, dets

    def set_file_batch(self, filename=None, show=True):
        """

        """

        if filename is None or filename == False:
            filename = pymodaq.daq_utils.gui_utils.file_io.select_file(start_path=self.batch_path, save=False, ext='xml')
            if filename == '':
                return

        status = False
        settings_tmp = Parameter.create(title='Batch', name='settings_tmp',
                                        type='group', children=ioxml.XML_file_to_parameter(str(filename)))

        children = settings_tmp.child('scans').children()
        self.settings = Parameter.create(title='Batch', name='settings', type='group', children=self.params)
        actuators = children[0].child('modules', 'actuators').value()['all_items']
        if actuators != self.actuators:
            pymodaq.daq_utils.messenger.show_message('The loaded actuators from the batch file do not corresponds to the'
                                ' dashboard actuators')
            return
        else:
            self.actuators = actuators

        detectors = children[0].child('modules', 'detectors').value()['all_items']
        if detectors != self.detectors:
            pymodaq.daq_utils.messenger.show_message('The loaded detectors from the batch file do not corresponds to the'
                                ' dashboard detectors')
            return
        else:
            self.detectors = detectors

        for child in children:
            self.add_scan(name=child.name(), title=child.opts['title'])
            self.settings.child('scans', child.name()).restoreState(child.saveState())

        if show:
            status = self.show_tree()
        else:
            self.tree.setParameters(self.settings, showTop=False)
        return status

    def set_scans(self):
        infos = []
        acts, dets = self.get_act_dets()
        for scan in self.scans:
            infos.append(f'{scan}: {acts[scan]} / {dets[scan]}')
            infos.append(f'{scan}: {self.scans[scan].set_scan()}')
        return infos

    def set_new_batch(self):
        self.settings = Parameter.create(title='Batch', name='settings', type='group', children=self.params)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        status = self.show_tree()
        return status

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if change == 'childAdded':
                pass

            elif change == 'value':

                pass

            elif change == 'parent':
                pass

    def show_tree(self):
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        add_scan = QtWidgets.QPushButton('Add Scan')
        add_scan.clicked.connect(self.add_scan)
        self.tree.setParameters(self.settings, showTop=False)
        vlayout.addWidget(add_scan)
        vlayout.addWidget(self.tree)
        dialog.setLayout(vlayout)

        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this Scan batch')
        res = dialog.exec()

        if res == dialog.Accepted:
            # save managers parameters in a xml file
            # start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            # start = os.path.join("..",'daq_scan')
            ioxml.parameter_to_xml_file(
                self.settings, os.path.join(self.batch_path, self.settings.child('filename').value()))

        return res == dialog.Accepted

    def add_scan(self, name=None, title=None):
        if name is None or name is False:
            name_prefix = 'scan'
            child_indexes = [int(par.name()[len(name_prefix) + 1:]) for par in self.settings.child('scans').children()]
            if child_indexes == []:
                newindex = 0
            else:
                newindex = max(child_indexes) + 1
            name = f'{name_prefix}{newindex:02.0f}'
            title = f'Scan {newindex:02.0f}'

        child = {'title': title, 'name': name, 'type': 'group', 'removable': True, 'children': params}

        self.scans[name] = Scanner(actuators=[self.actuators[0]], adaptive_losses=adaptive_losses)
        self.settings.child('scans').addChild(child)
        self.settings.child('scans', name, 'modules',
                            'actuators').setValue(dict(all_items=self.actuators,
                                                       selected=[self.actuators[0]]))
        self.settings.child('scans', name, 'modules',
                            'detectors').setValue(dict(all_items=self.detectors,
                                                       selected=[self.detectors[0]]))

        self.settings.child('scans', name).addChild(
            self.scans[name].settings)
コード例 #10
0
class H5Saver(QObject):
    status_sig = pyqtSignal(utils.ThreadCommand)
    new_file_sig = pyqtSignal(bool)

    params = [
        {
            'title': 'Save type:',
            'name': 'save_type',
            'type': 'list',
            'values': save_types,
            'readonly': True
        },
        {
            'title': 'Save 2D datas:',
            'name': 'save_2D',
            'type': 'bool',
            'value': True
        },
        {
            'title':
            'Save raw datas only:',
            'name':
            'save_raw_only',
            'type':
            'bool',
            'value':
            True,
            'tooltip':
            'if True, will not save extracted ROIs used to do live plotting, only raw datas and the scan \
                        result will be saved'
        },
        {
            'title': 'Do Save:',
            'name': 'do_save',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'N saved:',
            'name': 'N_saved',
            'type': 'int',
            'default': 0,
            'value': 0,
            'visible': False
        },
        {
            'title': 'custom_name?:',
            'name': 'custom_name',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'show file content?:',
            'name': 'show_file',
            'type': 'bool',
            'default': False,
            'value': False
        },
        {
            'title': 'Base path:',
            'name': 'base_path',
            'type': 'browsepath',
            'value': 'C:\Data',
            'filetype': False,
            'readonly': True,
        },
        {
            'title': 'Base name:',
            'name': 'base_name',
            'type': 'str',
            'value': 'Scan',
            'readonly': True
        },
        {
            'title': 'Current scan:',
            'name': 'current_scan_name',
            'type': 'str',
            'value': '',
            'readonly': True
        },
        {
            'title': 'Current path:',
            'name': 'current_scan_path',
            'type': 'text',
            'value': 'C:\Data',
            'readonly': True,
            'visible': False
        },
        {
            'title': 'h5file:',
            'name': 'current_h5_file',
            'type': 'text_pb',
            'value': '',
            'readonly': True
        },
        {
            'title':
            'Compression options:',
            'name':
            'compression_options',
            'type':
            'group',
            'children': [
                {
                    'title': 'Compression library:',
                    'name': 'h5comp_library',
                    'type': 'list',
                    'value': 'zlib',
                    'values': ['zlib', 'lzo', 'bzip2', 'blosc']
                },
                {
                    'title': 'Compression level:',
                    'name': 'h5comp_level',
                    'type': 'int',
                    'value': 5,
                    'min': 0,
                    'max': 9
                },
            ]
        },
    ]

    def __init__(self, h5_file_path=None, h5_file=None, save_type='scan'):
        """
        Initialize the h5Saver object
        Parameters
        ----------
        h5_file_path: (Path) Path object pointing to the h5_file
        h5_file: instance of a h5 file as opened using the pytables module
        save_type: (str) either 'scan', 'detector' or 'custom'
        """
        super(H5Saver, self).__init__()

        if save_type not in save_types:
            raise Exception('Invalid saving type')

        self.h5_file = h5_file
        self.h5_file_path = h5_file_path
        self.h5_file_name = None
        self.logger_array = None

        self.current_group = None
        self.current_scan_group = None
        self.current_scan_name = None
        self.raw_group = None

        self.settings = Parameter.create(title='Saving settings',
                                         name='save_settings',
                                         type='group',
                                         children=self.params)
        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumHeight(310)
        self.settings_tree.setParameters(self.settings, showTop=False)
        self.settings.child(
            ('current_h5_file'
             )).sigActivated.connect(lambda: self.emit_new_file(True))

        self.settings.child(('save_type')).setValue(save_type)

        self.filters = tables.Filters(
            complevel=self.settings.child('compression_options',
                                          'h5comp_level').value(),
            complib=self.settings.child('compression_options',
                                        'h5comp_library').value())
        # self.settings.child('saving_options', 'save_independent').show(save_type == 'scan')
        # self.settings.child('saving_options', 'do_save').show(not save_type == 'scan')
        # self.settings.child('saving_options', 'current_scan_name').show(save_type == 'scan')

        self.settings.sigTreeStateChanged.connect(
            self.parameter_tree_changed
        )  # any changes on the settings will update accordingly the detector

    def emit_new_file(self, status):
        self.new_file_sig.emit(status)

    def init_file(self,
                  update_h5=False,
                  custom_naming=False,
                  addhoc_file_path=None):
        """
        init a new h5 file. Could be a file with a given name (addhoc_file_path) or following the template for scans
        (datasets) or for detectors or a box to set a custom name (custom naming)
        Parameters
        ----------
        update_h5: (bool) create a new h5 file with name specified by other parameters if false try to open an existing
        file or create it if it doesn't exists
        custom_naming: (bool) if True, a selection file dialog opens to set a new file name
        addhoc_file_path: (Path) supplied name for the file

        Returns
        -------
        bool: True if new file has been created, False otherwise
        """
        date = datetime.datetime.now()

        if addhoc_file_path is None:
            if not os.path.isdir(self.settings.child(('base_path')).value()):
                os.mkdir(self.settings.child(('base_path')).value())

            # set the filename and path
            base_name = self.settings.child(('base_name')).value()

            if not custom_naming:
                custom_naming = self.settings.child(('custom_name')).value()

            if not custom_naming:
                scan_type = self.settings.child(
                    ('save_type')).value() == 'scan'
                scan_path, current_scan_name, save_path = self.update_file_paths(
                    update_h5)
                self.current_scan_name = current_scan_name
                self.settings.child(
                    ('current_scan_name')).setValue(current_scan_name)
                self.settings.child(
                    ('current_scan_path')).setValue(str(scan_path))

                if not scan_type:
                    self.h5_file_path = save_path  #will remove the dataset part used for DAQ_scan datas
                    self.h5_file_name = base_name + date.strftime(
                        '_%Y%m%d_%H_%M_%S.h5')
                else:
                    self.h5_file_path = save_path
                    self.h5_file_name = save_path.name + ".h5"
            else:
                self.h5_file_name = utils.select_file(start_path=base_name,
                                                      save=True,
                                                      ext='h5')
                self.h5_file_path = self.h5_file_name.parent

        else:
            if isinstance(addhoc_file_path, str):
                addhoc_file_path = Path(addhoc_file_path)
            self.h5_file_path = addhoc_file_path.parent
            self.h5_file_name = addhoc_file_path.name

        fullpathname = str(self.h5_file_path.joinpath(self.h5_file_name))
        self.settings.child(('current_h5_file')).setValue(fullpathname)

        if update_h5:
            self.current_scan_group = None

        scan_group = None
        if self.current_scan_group is not None:
            scan_group = self.current_scan_group._v_name

        if update_h5:
            self.close_file()
            self.h5_file = tables.open_file(fullpathname,
                                            'w',
                                            title='PyMoDAQ file')
            self.h5_file.root._v_attrs['pymodaq_version'] = get_version()
        else:
            self.close_file()
            self.h5_file = tables.open_file(fullpathname,
                                            'a',
                                            title='PyMoDAQ file')

        self.raw_group = self.get_set_group(self.h5_file.root,
                                            'Raw_datas',
                                            title='Data from PyMoDAQ modules')
        self.get_set_logger(self.raw_group)
        if scan_group is not None:
            self.current_scan_group = self.get_set_group(
                self.raw_group, scan_group)
        else:
            self.current_scan_group = self.get_last_scan()

        self.raw_group._v_attrs['type'] = self.settings.child(
            ('save_type')).value()
        self.h5_file.root._v_attrs['file'] = date.strftime(self.h5_file_name)
        if update_h5:
            self.h5_file.root._v_attrs['date'] = date.strftime('%Y%m%d')
            self.h5_file.root._v_attrs['time'] = date.strftime('%H:%M:%S')

        return update_h5

    def update_file_paths(self, update_h5=False):
        """
        """
        try:
            # set the filename and path
            base_path = self.settings.child(('base_path')).value()
            base_name = self.settings.child(('base_name')).value()
            current_scan = self.settings.child(('current_scan_name')).value()
            scan_type = self.settings.child(('save_type')).value() == 'scan'

            if current_scan == '' or update_h5:
                next_scan_index = 0
                update_h5 = True  #just started the main program so one should create a new h5
            else:
                next_scan_index = self.get_scan_index()

            scan_path, current_filename, dataset_path = utils.set_current_scan_path(
                base_path,
                base_name,
                update_h5,
                next_scan_index,
                create_dataset_folder=scan_type)
            self.settings.child(('current_scan_path')).setValue(str(scan_path))

            return scan_path, current_filename, dataset_path

        except Exception as e:
            print(e)

    def get_last_scan(self):
        groups = [
            group for group in list(self.raw_group._v_groups)
            if 'Scan' in group
        ]
        groups.sort()
        if len(groups) != 0:
            scan_group = self.h5_file.get_node(self.raw_group, groups[-1])
        else:
            scan_group = None
        return scan_group

    def get_scan_index(self):
        try:
            if self.current_scan_group is None:
                return 0
            else:

                groups = [
                    group for group in list(self.raw_group._v_groups)
                    if 'Scan' in group
                ]
                groups.sort()
                flag = False
                for child in list(
                        self.h5_file.get_node(self.raw_group,
                                              groups[-1])._v_groups):
                    if 'scan' in child:
                        return len(groups)

                return 0

        except Exception as e:
            return 0

    def load_file(self, base_path=None, file_path=None):
        if base_path is None:
            base_path = self.settings.child('base_path').value()
            if not os.path.isdir(base_path):
                base_path = None

        if file_path is None:
            file_path = utils.select_file(base_path, save=False, ext='h5')

        if not isinstance(file_path, Path):
            file_path = Path(file_path)

        if not file_path.suffix == 'h5':
            raise IOError('Invalid file type, should be a h5 file')

        self.init_file(addhoc_file_path=file_path)

    def close_file(self):
        try:
            if self.h5_file is not None:
                self.h5_file.flush()
                if self.h5_file.isopen:
                    self.h5_file.close()
        except Exception as e:
            print(e)  #no big deal

    def is_node_in_group(self, where, name):
        """
        Check if a given node with name is in the group defined by where (comparison on lower case strings)
        Parameters
        ----------
        where: (str or node) path or parent node instance
        name: (str) group node name

        Returns
        -------
        bool: True if node exists, False otherwise
        """

        nodes_names = [
            node._v_name.lower() for node in self.h5_file.list_nodes(where)
        ]
        return name.lower() in nodes_names

    def get_set_logger(self, where):
        logger = 'Logger'
        if not logger in list(self.h5_file.get_node(where)._v_children.keys()):
            # check if logger node exist
            text_atom = tables.atom.ObjectAtom()
            self.logger_array = self.h5_file.create_vlarray(where,
                                                            logger,
                                                            atom=text_atom)
            self.logger_array._v_attrs['type'] = 'log'
        else:
            self.logger_array = self.h5_file.get_node(where, name=logger)
        return self.logger_array

    def get_set_group(self, where, name, title=''):
        """
        Retrieve or create (if absent) a node group
        Parameters
        ----------
        where: (str or node) path or parent node instance
        name: (str) group node name
        title: (str) node title

        Returns
        -------
        node: group node
        """
        if not name in list(self.h5_file.get_node(where)._v_children.keys()):
            self.current_group = self.h5_file.create_group(where, name, title)
        else:
            self.current_group = self.h5_file.get_node(where, name)
        return self.current_group

    def add_data_group(self,
                       where,
                       group_data_type,
                       title='',
                       settings_as_xml='',
                       metadata=dict([])):
        if group_data_type not in group_data_types:
            raise Exception('Invalid data group type')
        group = self.add_group(group_data_type, '', where, title,
                               settings_as_xml, metadata)
        return group

    def add_navigation_axis(self,
                            data,
                            parent_group,
                            axis='x_axis',
                            enlargeable=False,
                            title='',
                            metadata=dict([])):
        """
        Create carray for navigation axis within a scan
        Parameters
        ----------
        data: (ndarray) of dimension 1
        parent_group: (str or node) parent node where to save new data
        axis: (str) either x_axis or y_axis
        """
        if axis not in ['x_axis', 'y_axis', 'z_axis']:
            raise Exception('Invalid navigation axis name')
        array = self.add_array(parent_group,
                               'scan_{:s}'.format(axis),
                               'navigation_axis',
                               data_shape=data.shape,
                               data_dimension='1D',
                               array_to_save=data,
                               enlargeable=enlargeable,
                               title=title,
                               metadata=metadata)
        return array

    def add_data_live_scan(self,
                           channel_group,
                           data_dict,
                           scan_type='scan1D',
                           title=''):
        shape, dimension, size = utils.get_data_dimension(
            data_dict['data'], scan_type=scan_type, remove_scan_dimension=True)
        data_array = self.add_array(channel_group,
                                    'Data',
                                    'data',
                                    array_type=np.float,
                                    title=title,
                                    data_shape=shape,
                                    data_dimension=dimension,
                                    scan_type=scan_type,
                                    array_to_save=data_dict['data'])
        if 'x_axis' in data_dict:
            if not isinstance(data_dict['x_axis'], dict):
                array_to_save = data_dict['x_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['x_axis'])
                array_to_save = tmp_dict.pop('data')
        if 'x_axis' in data_dict:

            array = self.add_array(channel_group,
                                   'x_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)
        if 'y_axis' in data_dict:
            if not isinstance(data_dict['y_axis'], dict):
                array_to_save = data_dict['y_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['y_axis'])
                array_to_save = tmp_dict.pop('data')
        if 'y_axis' in data_dict:
            array = self.add_array(channel_group,
                                   'y_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)
        return data_array

    def add_data(self,
                 channel_group,
                 data_dict,
                 scan_type='scan1D',
                 scan_shape=[],
                 title='',
                 enlargeable=False,
                 init=False,
                 add_scan_dim=False):

        shape, dimension, size = utils.get_data_dimension(data_dict['data'])
        data_array = self.add_array(channel_group,
                                    'Data',
                                    'data',
                                    array_type=np.float,
                                    title=title,
                                    data_shape=shape,
                                    enlargeable=enlargeable,
                                    data_dimension=dimension,
                                    scan_type=scan_type,
                                    scan_shape=scan_shape,
                                    array_to_save=data_dict['data'],
                                    init=init,
                                    add_scan_dim=add_scan_dim)

        if 'x_axis' in data_dict:
            if not isinstance(data_dict['x_axis'], dict):
                array_to_save = data_dict['x_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['x_axis'])
                array_to_save = tmp_dict.pop('data')

            array = self.add_array(channel_group,
                                   'x_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)

        if 'y_axis' in data_dict:
            if not isinstance(data_dict['y_axis'], dict):
                array_to_save = data_dict['y_axis']
                tmp_dict = dict(label='', units='')
            else:
                tmp_dict = copy.deepcopy(data_dict['y_axis'])
                array_to_save = tmp_dict.pop('data')

            array = self.add_array(channel_group,
                                   'y_axis',
                                   'axis',
                                   array_type=np.float,
                                   array_to_save=array_to_save,
                                   enlargeable=False,
                                   data_dimension='1D',
                                   metadata=tmp_dict)

        self.h5_file.flush()
        return data_array

    def add_array(self,
                  where,
                  name,
                  data_type,
                  data_shape=(1, ),
                  data_dimension='0D',
                  scan_type='',
                  scan_shape=[],
                  title='',
                  array_to_save=None,
                  array_type=np.float,
                  enlargeable=False,
                  metadata=dict([]),
                  init=False,
                  add_scan_dim=False):

        if data_dimension not in data_dimensions:
            raise Exception('Invalid data dimension')
        if data_type not in data_types:
            raise Exception('Invalid data type')
        if scan_type != '':
            scan_type = utils.uncapitalize(scan_type)
        if scan_type not in scan_types:
            raise Exception('Invalid scan type')
        if enlargeable:
            shape = [0]
            if data_shape != (1, ):
                shape.extend(data_shape)
            shape = tuple(shape)
            array = self.h5_file.create_earray(where,
                                               utils.capitalize(name),
                                               tables.Atom.from_dtype(
                                                   np.dtype(array_type)),
                                               shape=shape,
                                               title=title,
                                               filters=self.filters)
            array._v_attrs['shape'] = shape
        else:
            if add_scan_dim:  #means it is an array initialization to zero
                shape = scan_shape[:]
                shape.extend(data_shape)
                if init or array_to_save is None:
                    array_to_save = np.zeros(shape)

            array = self.h5_file.create_carray(where,
                                               utils.capitalize(name),
                                               obj=array_to_save,
                                               title=title,
                                               filters=self.filters)
            array._v_attrs['shape'] = array_to_save.shape

        array._v_attrs['type'] = data_type
        array._v_attrs['data_dimension'] = data_dimension
        array._v_attrs['scan_type'] = scan_type

        for metadat in metadata:
            array._v_attrs[metadat] = metadata[metadat]
        return array

    def append(self, array, data):
        if not (isinstance(array, tables.vlarray.VLArray)
                or isinstance(array, tables.earray.EArray)):
            raise Exception('This array cannot be appended')
        if isinstance(data, np.ndarray):
            if data.shape != (1, ):
                shape = [1]
                shape.extend(data.shape)
                array.append(data.reshape(shape))
            else:
                array.append(data)
        else:
            array.append(data)
        sh = list(array._v_attrs['shape'])
        sh[0] += 1
        array._v_attrs['shape'] = tuple(sh)

    def add_group(self,
                  group_name,
                  group_type,
                  where,
                  title='',
                  settings_as_xml='',
                  metadata=dict([])):
        """
        Add a node in the h5 file tree of the group type
        Parameters
        ----------
        group_name: (str) a custom name for this group
        group_type: (str) one of the possible values of **group_types**
        where: (str or node) parent node where to create the new group
        settings_as_xml: (str) XML string containing Parameters representation (see custom_Tree)
        metadata: (dict) extra metadata to be saved with this new group node

        Returns
        -------
        (node): newly created group node
        """

        if group_type not in group_types:
            raise Exception('Invalid group type')

        try:
            node = self.h5_file.get_node(where, utils.capitalize(group_name))
        except tables.NoSuchNodeError as e:
            node = None

        if node is None:
            node = self.get_set_group(where, utils.capitalize(group_name),
                                      title)
            node._v_attrs['settings'] = settings_as_xml
            node._v_attrs['type'] = group_type.lower()
            for metadat in metadata:
                node._v_attrs[metadat] = metadata[metadat]

        return node

    def add_incremental_group(self,
                              group_type,
                              where,
                              title='',
                              settings_as_xml='',
                              metadata=dict([])):
        """
        Add a node in the h5 file tree of the group type with an increment in the given name
        Parameters
        ----------
        group_type: (str) one of the possible values of **group_types**
        where: (str or node) parent node where to create the new group
        settings_as_xml: (str) XML string containing Parameters representation (see custom_Tree)
        metadata: (dict) extra metadata to be saved with this new group node

        Returns
        -------
        (node): newly created group node
        """
        if group_type not in group_types:
            raise Exception('Invalid group type')
        nodes = list(self.h5_file.get_node(where)._v_children.keys())
        nodes_tmp = []
        for node in nodes:
            if utils.capitalize(group_type) in node:
                nodes_tmp.append(node)
        nodes_tmp.sort()
        if len(nodes_tmp) == 0:
            ind_group = -1
        else:
            ind_group = int(nodes_tmp[-1][-3:])
        group = self.get_set_group(
            where,
            utils.capitalize(group_type) + '{:03d}'.format(ind_group + 1),
            title)
        group._v_attrs['settings'] = settings_as_xml
        if group_type.lower() != 'ch':
            group._v_attrs['type'] = group_type.lower()
        else:
            group._v_attrs['type'] = ''
        for metadat in metadata:
            group._v_attrs[metadat] = metadata[metadat]
        return group

    def add_det_group(self,
                      where,
                      title='',
                      settings_as_xml='',
                      metadata=dict([])):
        """
        Add a new group of type detector
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('detector', where, title,
                                           settings_as_xml, metadata)
        return group

    def add_CH_group(self,
                     where,
                     title='',
                     settings_as_xml='',
                     metadata=dict([])):
        """
        Add a new group of type channel
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('ch', where, title, settings_as_xml,
                                           metadata)
        return group

    def add_live_scan_group(self,
                            where,
                            dimensionality,
                            title='',
                            settings_as_xml='',
                            metadata=dict([])):
        """
        Add a new group of type live scan
        See Also
        -------
        add_incremental_group
        """
        group = self.add_group('Live_scan_{:s}'.format(dimensionality),
                               '',
                               where,
                               title=title,
                               settings_as_xml=settings_as_xml,
                               metadata=metadata)
        return group

    def add_scan_group(self, title='', settings_as_xml='', metadata=dict([])):
        """
        Add a new group of type scan
        See Also
        -------
        add_incremental_group
        """

        if self.current_scan_group is not None:
            if list(self.current_scan_group._v_children) == []:
                new_scan = False
            else:
                new_scan = True
        else:
            new_scan = True
        if new_scan:
            self.current_scan_group = self.add_incremental_group(
                'scan', self.raw_group, title, settings_as_xml, metadata)
            self.current_scan_group._v_attrs['description'] = ''
            self.settings.child(('current_scan_name')).setValue(
                self.current_scan_group._v_name)

        return self.current_scan_group

    def add_move_group(self,
                       where,
                       title='',
                       settings_as_xml='',
                       metadata=dict([])):
        """
        Add a new group of type move
        See Also
        -------
        add_incremental_group
        """
        group = self.add_incremental_group('move', where, title,
                                           settings_as_xml, metadata)
        return group

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)

            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'show_file':
                    param.setValue(False)
                    self.show_file_content()

                elif param.name() == 'base_path':
                    try:
                        if not os.path.isdir(param.value()):
                            os.mkdir(param.value())
                    except:
                        self.update_status(
                            "The base path couldn't be set, please check your options"
                        )

                elif param.name() in custom_tree.iter_children(
                        self.settings.child(('compression_options')), []):
                    self.filters = tables.Filters(
                        complevel=self.settings.child('compression_options',
                                                      'h5comp_level').value(),
                        complib=self.settings.child('compression_options',
                                                    'h5comp_library').value())

            elif change == 'parent':
                pass

    def update_status(self, status):
        self.status_sig.emit(
            utils.ThreadCommand("Update_Status", [status, 'log']))

    def show_file_content(self):
        form = QtWidgets.QWidget()
        if not self.h5_file.isopen:
            if self.h5_file_path.exists():
                self.analysis_prog = H5Browser(form, h5file=self.h5_file_path)
            else:
                raise FileExistsError('no File presents')
        else:
            self.analysis_prog = H5Browser(form, h5file=self.h5_file)
        form.show()