lavuelib.settings — LaVue 2.76.0 documentation

# Source code for lavuelib.settings

    # Copyright (C) 2017  DESY, Notkestr. 85, D-22607 Hamburg
    #
    # lavue is an image viewing program for photon science imaging detectors.
    # Its usual application is as a live viewer using hidra as data source.
    #
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU General Public License
    # as published by the Free Software Foundation in  version 2
    # of the License.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program; if not, write to the Free Software
    # Foundation, Inc., 51 Franklin Street, Fifth Floor,
    # Boston, MA  02110-1301, USA.
    #
    # Authors:
    #     Christoph Rosemann <christoph.rosemann@desy.de>
    #     Jan Kotanski <jan.kotanski@desy.de>
    #

    """ live viewer image display base it on a qt dialog """

    import zmq
    import sys
    import json
    from pyqtgraph import QtCore

    if sys.version_info > (3,):
        unicode = str

    try:
        __import__("pyFAI")
        #: (:obj:`bool`) pyFAI imported
        PYFAI = True
    except ImportError:
        #: (:obj:`bool`) pyFAI imported
        PYFAI = False

    class Settings(object):

        """ lavue configuration settings """

        def __init__(self):
            """ constructor
            """
            #: (:obj:`bool`) sardana enabled
            self.sardana = True
            #: (:obj:`bool`) add rois to sardana
            self.addrois = False
            #: (:obj:`bool`) fetch rois order enabled
            self.orderrois = False
            #: (:obj:`bool`) search for security stream port automatically
            self.secautoport = True
            #: (:obj:`bool`) show intensity hostogram
            self.showhisto = True
            #: (:obj:`bool`) show intensity hostogram
            self.showaddhisto = False
            #: (:obj:`bool`) show mask widget
            self.showmask = False
            #: (:obj:`bool`) map image sources to color channels
            self.imagechannels = False
            #: (:obj:`bool`) show high mask value  widget
            self.showhighvaluemask = False
            #: (:obj:`bool`) show statistics widget
            self.showstats = True
            #: (:obj:`bool`) show image step widget
            self.showsteps = True
            #: (:obj:`bool`) calculate variance
            self.calcvariance = False
            #: (:obj:`bool`) show bakcground subtraction widget
            self.showsub = True
            #: (:obj:`bool`) show image normalization widget
            self.shownorm = True
            #: (:obj:`bool`) show bakcground subtraction scaling factor widget
            self.showsubsf = False
            #: (:obj:`bool`) show image normalization scaling factor widget
            self.shownormsf = False
            #: (:obj:`bool`) show transformation widget
            self.showtrans = True
            #: (:obj:`bool`) show memory buffer widget
            self.showmbuffer = False
            #: (:obj:`bool`) show range window widget
            self.showrange = False
            #: (:obj:`bool`) show filter widget
            self.showfilters = False
            #: (:obj:`bool`) show intensity scale widget
            self.showscale = True
            #: (:obj:`bool`) show intensity levels widget
            self.showlevels = True
            #: (:obj:`bool`) show frame rate widget
            self.showframerate = True
            #: (:obj:`bool`) image aspect ratio locked
            self.aspectlocked = False
            #: (:obj:`bool`) auto down sample
            self.autodownsample = False
            #: (:obj:`bool`) keep original coordinates
            self.keepcoords = False
            #: (:obj:`bool`) accelerate buffer sum
            self.accelbuffersum = False
            #: (:obj:`bool`) image channels shown with gradient colors
            self.gradientcolors = False
            #: (:obj:`bool`) lazy image slider
            self.lazyimageslider = True
            #: (:obj:`str`) security stream port
            self.secport = "5657"
            #: (:obj:`str`) hidra data port
            self.hidraport = '["50001"]'
            #: (:obj:`str`) maximal number of images in memory buffer
            self.maxmbuffersize = "1000"
            #: (:obj:`int`) number of image sources
            self.nrsources = 1
            #: (:obj:`int`) image source timeout for connection
            self.timeout = 3000
            #: (:class:`zmq.Context`) zmq context
            self.seccontext = zmq.Context()
            #: (:class:`zmq.Socket`) zmq security stream socket
            self.secsocket = self.seccontext.socket(zmq.PUB)
            #: (:obj:`bool`) security stream enabled
            self.secstream = False
            #: (:obj:`bool`) zero mask enabled
            self.zeromask = False
            #: (:obj:`bool`) nan mask enabled
            self.nanmask = True
            #: (:obj:`bool`) adding maximal type value to negative high value mask
            self.negmask = False
            #: (:obj:`bool`) security stream options
            self.secsockopt = b""
            #: (:obj:`float`) refresh rate is s
            self.refreshrate = 0.2
            #: (:obj:`float`) tool refresh rate time is s
            self.toolrefreshtime = 0.02
            #: (:obj:`float`) tool polling interval is s
            self.toolpollinginterval = 1.0
            #: (:obj:`bool`) interrupt on error
            self.interruptonerror = True
            #: (:obj:`str`) last image file name
            self.imagename = None
            #: (:obj:`str`) calibration file name
            self.calibrationfilename = None
            #: (:obj:`str`) last mask image file name
            self.maskimagename = None
            #: (:obj:`str`) last background/darkfield image file name
            self.bkgimagename = None
            #: (:obj:`str`) last brightfield image file name
            self.bfimagename = None
            #: (:obj:`bool`) statistics without scaling
            self.statswoscaling = True
            #: (:obj:`list` < :obj:`str` > ) zmq source topics
            self.zmqtopics = []
            #: (:obj:`bool`) automatic zmq source topics
            self.autozmqtopics = False
            #: (:obj:`str`) file name translation json dictionary
            self.dirtrans = '{"/ramdisk/": "/gpfs/"}'
            #: (:obj:`str`) JSON dictionary with {label: tango attribute}
            #  for Tango Attribute source
            self.tangoattrs = '{}'
            #: (:obj:`str`) JSON dictionary with {label: tango detector attribute}
            #  for Tango Attribute source
            self.tangodetattrs = '{}'
            #: (:obj:`str`) JSON dictionary with {label: tina properties}
            #  for Tine Property source
            self.tineprops = '{}'
            #: (:obj:`str`) JSON dictionary with {label: epics PV name}
            #  for Epics PV source
            self.epicspvnames = '{}'
            #: (:obj:`str`) JSON dictionary with {label: epics PV shape}
            #  for Epics PV source
            self.epicspvshapes = '{}'
            #: (:obj:`str`) JSON dictionary with {label: doocs property}
            #  for DOOCS Property source
            self.doocsprops = '{}'
            #: (:obj:`str`) JSON dictionary with {label: tango attribute}
            #  for Tango Attribute Events source
            self.tangoevattrs = '{}'
            #: (:obj:`str`) JSON dictionary with {label: file tango attribute}
            #  for Tango Attribute source
            self.tangofileattrs = '{}'
            #: (:obj:`str`) JSON dictionary with {label: dir tango attribute}
            #  for Tango Attribute source
            self.tangodirattrs = '{}'
            #: (:obj:`str`) JSON dictionary with {label: url}
            #  for HTTP responce source
            self.httpurls = '{}'
            #: (:obj:`str`) JSON dictionary with {label: <server:port>}
            #  for ZMQ source
            self.zmqservers = '{}'
            #: (:obj:`str`) door device name
            self.doorname = ""
            #: (:obj:`str`) analysis device name
            self.analysisdevice = ""
            #: (:obj:`bool`) nexus file source keeps the file open
            self.nxsopen = False
            #: (:obj:`bool`) nexus file source starts from the last image
            self.nxslast = False
            #: (:obj:`list` < :obj:`str`>) hidra detector server list
            self.detservers = "[]"

            #: (:obj:`str`) asapo server
            self.asaposerver = ""
            #: (:obj:`str`) asapo token
            self.asapotoken = ""
            #: (:obj:`str`) asapo beamtime id
            self.asapobeamtime = ""
            #: (:obj:`str`) asapo sourcepath
            self.asaposourcepath = ""
            #: (:obj:`list` < :obj:`str` > ) asapo datasources
            self.asapodatasources = []

            #: (:obj:`bool`) use default detector servers
            self.defdetservers = True
            #: (:obj:`bool`) store detector geometry
            self.storegeometry = False
            #: (:obj:`bool`) fetch geometry from source
            self.geometryfromsource = False
            #: (:obj:`bool`) crosshair locker switched on
            self.crosshairlocker = True
            #: (:obj:`str`) json list with roi colors
            self.roiscolors = "[]"
            #: (:obj:`str`) float type for pixel intensity
            self.floattype = "float"

            #: (:obj:`str`) json list with filters
            self.filters = "[]"

            #: (:obj:`str`) json list with image source widget names
            self.imagesources = "[]"

            #: (:obj:`str`)  json list with tool widget names
            self.toolwidgets = "[]"

            #: (:class:`pyFAI.azimuthalIntegrator.AzimuthalIntegrator`)
            #       azimuthal integrator
            self.ai = None
            #: (:class:`pyFAI.azimuthalIntegrator.AzimuthalIntegrator`)
            #       azimuthal integrator
            #: (:class:`pyqtgraph.QtCore.QMutex`) ai mutex
            self.aimutex = QtCore.QMutex()

            #: (:obj:`float`) x-coordinates of the center of the image
            self.centerx = 0.0
            #: (:obj:`float`) y-coordinates of the center of the image
            self.centery = 0.0
            #: (:obj:`float`) energy in eV
            self.energy = 0.0
            #: (:obj:`float`) pixel x-size in um
            self.pixelsizex = 0.0
            #: (:obj:`float`) pixel y-size in um
            self.pixelsizey = 0.0
            #: (:obj:`float`) detector distance in mm
            self.detdistance = 0.0
            #: (:obj:`float`) poni1 parameter in m
            self.detponi1 = 0.0
            #: (:obj:`float`) poni2 parameter in m
            self.detponi2 = 0.0
            #: (:obj:`float`) rot1 parameter in rad
            self.detrot1 = 0.0
            #: (:obj:`float`) rot2 parameter in rad
            self.detrot2 = 0.0
            #: (:obj:`float`) rot3 parameter in rad
            self.detrot3 = 0.0
            #: (:obj:`str`) detector name
            self.detname = ""
            #: (:obj:`str`) detector splineFile
            self.detsplinefile = ""
            #: (:obj:`int`) number of points for diffractogram
            self.diffnpt = 1000
            #: (:obj:`bool`) correct solid angle flag
            self.correctsolidangle = True
            #: (:obj:`bool`) show all rois flag
            self.showallrois = False
            #: (:obj:`bool`) single rois flag
            self.singlerois = False
            #: (:obj:`bool`) send rois to LavueController flag
            self.sendrois = False
            #: (:obj:`bool`) send results to LavueController flag
            self.sendresults = False
            #: (:obj:`dict` < :obj:`str`, :obj:`dict` < :obj:`str`,`any`> >
            #                custom gradients
            self.__customgradients = {}
            #: (:obj:`bool`) store display parameters for specific sources
            self.sourcedisplay = False

            #: (:obj:`dict` < :obj:`str`, :obj:`dict` < :obj:`str`,`any`> >
            #                source display dictionary
            self.__sourcedisplay = {}

            self.__units = {
                'eV': ['eV'],
                'keV': ['keV'],
                'MeV': ['MeV'],
                'A': ['A', 'Angstrom'],
                'm': ['m', 'meter', 'metre'],
                'nm': ['nm', 'nanometer', 'nanometre'],
                'um': ['um', 'micrometer', 'micrometre'],
                'mm': ['mm', 'millimeter', 'millimetre'],
                'cm': ['cm', 'centimeter', 'centimetre'],
                'km': ['km', 'kilometer', 'kilometre'],
                'pixel': ['pixels', 'pixel'],
            }

            #: (:class:`pyqtgraph.QtCore.QMutex`) settings mutex
            self.__mutex = QtCore.QMutex()

        def setCustomGradients(self, gradients):
            """ sets custom gradients

            :param gradients: custom gradients
            :type gradients: :obj:`dict` <:obj:`str`, `any`>
            """
            with QtCore.QMutexLocker(self.__mutex):
                self.__customgradients = dict(gradients)

        def customGradients(self):
            """ sets source display parameters

            :returns: custom gradients
            :rtype: :obj:`dict` <:obj:`str`, `any`>
            """

            gradients = {}
            with QtCore.QMutexLocker(self.__mutex):
                gradients = dict(self.__customgradients)
            return gradients

        def setSourceDisplay(self, source, values):
            """ sets source display parameters

            :param source: source name
            :type source: :obj:`str`
            :param values: display parameter dictionary
            :type values: :obj:`dict` <:obj:`str`, `any`>
            """
            with QtCore.QMutexLocker(self.__mutex):
                if source and isinstance(values, dict):
                    self.__sourcedisplay[str(source)] = values

        def sourceDisplay(self, source):
            """ gets source display parameters

            :param source: source name
            :type source: :obj:`str`
            :returns: display parameter dictionary
            :rtype: :obj:`dict` <:obj:`str`, `any`>
            """
            values = None
            with QtCore.QMutexLocker(self.__mutex):
                if source in self.__sourcedisplay.keys():
                    values = dict(self.__sourcedisplay[str(source)])
                    if 'maskfile' not in values.keys():
                        values['maskfile'] = None
                    if 'bkgfile' not in values.keys():
                        values['bkgfile'] = None
                    if 'levels' not in values.keys() and \
                       'autofactor' in values.keys():
                        if not values['autofactor']:
                            values['autofactor'] = ''
            return values

        def load(self, settings):
            """ load settings

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            :returns: error messages list
            :rtype: :obj:`list` < (:obj:`str`, :obj:`str`) >
            """
            status = []
            qstval = str(settings.value("Configuration/Sardana", type=str))
            if qstval.lower() == "false":
                self.sardana = False
            else:
                self.sardana = True
            qstval = str(settings.value("Configuration/AddROIs", type=str))
            if qstval.lower() == "true":
                self.addrois = True
            qstval = str(settings.value("Configuration/OrderROIs", type=str))
            if qstval.lower() == "true":
                self.orderrois = True
            qstval = str(settings.value("Configuration/ImageChannels", type=str))
            if qstval.lower() == "true":
                self.imagechannels = True
            qstval = str(settings.value("Configuration/SecAutoPort", type=str))
            if qstval.lower() == "false":
                self.secautoport = False
            qstval = str(settings.value("Configuration/FloatType", type=str))
            if qstval.lower() in ["float", "float32", "float64"]:
                self.floattype = qstval.lower()
            else:
                self.floattype = "float"
            qstval = str(settings.value(
                "Configuration/ShowSubtraction", type=str))
            if qstval.lower() == "false":
                self.showsub = False
            qstval = str(settings.value(
                "Configuration/ShowNormalization", type=str))
            if qstval.lower() == "false":
                self.shownorm = False
            qstval = str(settings.value(
                "Configuration/ShowSubtractionScaling", type=str))
            if qstval.lower() == "true":
                self.showsubsf = True
            qstval = str(settings.value(
                "Configuration/ShowNormalizationScaling", type=str))
            if qstval.lower() == "true":
                self.shownormsf = True
            qstval = str(settings.value(
                "Configuration/ShowTransformations", type=str))
            if qstval.lower() == "false":
                self.showtrans = False
            qstval = str(settings.value(
                "Configuration/ShowIntensityScaling", type=str))
            if qstval.lower() == "false":
                self.showscale = False
            qstval = str(settings.value(
                "Configuration/ShowIntensityLevels", type=str))
            if qstval.lower() == "false":
                self.showlevels = False
            qstval = str(settings.value(
                "Configuration/ShowFrameRate", type=str))
            if qstval.lower() == "false":
                self.showframerate = False
            qstval = str(settings.value("Configuration/ShowHistogram", type=str))
            if qstval.lower() == "false":
                self.showhisto = False
            qstval = str(settings.value("Configuration/ShowRangeWindowWidget",
                                        type=str))
            if qstval.lower() == "true":
                self.showrange = True
            qstval = str(settings.value("Configuration/ShowFilterWidget",
                                        type=str))
            if qstval.lower() == "true":
                self.showfilters = True
            qstval = str(settings.value("Configuration/ShowMemoryBuffer",
                                        type=str))
            if qstval.lower() == "true":
                self.showmbuffer = True
            qstval = str(settings.value("Configuration/ShowAdditionalHistogram",
                                        type=str))
            if qstval.lower() == "true":
                self.showaddhisto = True
            qstval = str(settings.value("Configuration/ShowMaskWidget", type=str))
            if qstval.lower() == "true":
                self.showmask = True
            qstval = str(settings.value(
                "Configuration/ShowHighValueMaskWidget", type=str))
            if qstval.lower() == "true":
                self.showhighvaluemask = True
            qstval = str(settings.value("Configuration/ShowStatistics", type=str))
            if qstval.lower() == "false":
                self.showstats = False
            qstval = str(settings.value("Configuration/ShowImageSteps", type=str))
            if qstval.lower() == "false":
                self.showsteps = False
            qstval = str(settings.value("Configuration/CrossHairLocker", type=str))
            if qstval.lower() == "false":
                self.crosshairlocker = False
            qstval = str(settings.value(
                "Configuration/CalculateVariance", type=str))
            if qstval.lower() == "true":
                self.calcvariance = True
            qstval = str(settings.value("Configuration/AspectLocked", type=str))
            if qstval.lower() == "true":
                self.aspectlocked = True
            qstval = str(settings.value("Configuration/AutoDownSample", type=str))
            if qstval.lower() == "true":
                self.autodownsample = True
            qstval = str(settings.value(
                "Configuration/KeepOriginalCoordinates", type=str))
            if qstval.lower() == "true":
                self.keepcoords = True
            qstval = str(settings.value(
                "Configuration/AccelerateBufferSum", type=str))
            if qstval.lower() == "true":
                self.accelbuffersum = True
            qstval = str(settings.value(
                "Configuration/ChannelsWithGradientColors", type=str))
            if qstval.lower() == "true":
                self.gradientcolors = True
            qstval = str(settings.value(
                "Configuration/LazyImageSlider", type=str))
            if qstval.lower() == "false":
                self.lazyimageslider = False
            qstval = str(settings.value("Configuration/NXSFileOpen", type=str))
            if qstval.lower() == "true":
                self.nxsopen = True
            qstval = str(settings.value("Configuration/NXSLastImage", type=str))
            if qstval.lower() == "true":
                self.nxslast = True
            qstval = str(settings.value(
                "Configuration/SingleROIAliases", type=str))
            if qstval.lower() == "true":
                self.singlerois = True
            qstval = str(settings.value("Configuration/SendROIs", type=str))
            if qstval.lower() == "true":
                self.sendrois = True
            qstval = str(settings.value("Configuration/SendToolResults", type=str))
            if qstval.lower() == "true":
                self.sendresults = True
            qstval = str(settings.value("Configuration/ShowAllROIs", type=str))
            if qstval.lower() == "true":
                self.showallrois = True
            qstval = str(settings.value("Configuration/SecPort", type=str))
            try:
                int(qstval)
                self.secport = str(qstval)
            except Exception:
                pass

            qstval = str(settings.value("Configuration/HidraDataPort", type=str))
            if qstval.startswith("["):
                try:
                    ports = json.loads(qstval)
                    for port in ports:
                        int(port)
                    self.hidraport = qstval
                except Exception:
                    for port in qstval:
                        int(port)
                    self.hidraport = json.dumps([str(tp) for tp in qstval])
            else:
                try:
                    int(qstval)
                    self.hidraport = json.dumps([str(qstval)])
                except Exception:
                    pass

            qstval = str(settings.value("Configuration/MaxBufferSize", type=str))
            try:
                self.maxmbuffersize = str(qstval)
                int(self.maxmbuffersize)
            except Exception:
                self.maxmbuffersize = "1000"
            qstval = str(settings.value("Configuration/SourceTimeout", type=str))
            try:
                int(qstval)
                self.timeout = int(qstval)
            except Exception:
                pass
            qstval = str(settings.value(
                "Configuration/NumberOfImageSources", type=str))
            try:
                int(qstval)
                self.nrsources = int(qstval)
            except Exception:
                pass
            qstval = str(settings.value(
                "Configuration/MaskingWithZeros", type=str))
            if qstval.lower() == "true":
                self.zeromask = True
            qstval = str(settings.value(
                "Configuration/MaskingAsNAN", type=str))
            if qstval.lower() == "false":
                self.nanmask = False
            qstval = str(settings.value(
                "Configuration/AddMaxValueToNegativeMask", type=str))
            if qstval.lower() == "true":
                self.negmask = True

            qstval = str(settings.value("Configuration/SecStream", type=str))
            if qstval.lower() == "true":
                try:
                    if self.secautoport:
                        self.secsockopt = b"tcp://*:*"
                        self.secsocket.bind(self.secsockopt)
                        self.secport = unicode(self.secsocket.getsockopt(
                            zmq.LAST_ENDPOINT)).split(":")[-1]
                        if self.secport.endswith("'"):
                            self.secport = self.secport[:-1]
                    else:
                        self.secsockopt = b"tcp://*:%s" % self.secport
                        self.secsocket.bind(self.secsockopt)
                    self.secstream = True
                except Exception:
                    self.secstream = False
                    import traceback
                    value = traceback.format_exc()
                    text = "lavue: Cannot connect to: %s" % self.secsockopt
                    status = [(text, value)]

            try:
                self.refreshrate = float(
                    settings.value("Configuration/RefreshRate", type=str))
            except Exception:
                pass

            try:
                self.toolrefreshtime = float(
                    settings.value("Configuration/ToolRefreshTime", type=str))
            except Exception:
                pass

            try:
                self.toolpollinginterval = float(
                    settings.value("Configuration/ToolPollingInterval", type=str))
            except Exception:
                pass

            qstval = str(
                settings.value("Configuration/InterruptOnError", type=str))
            if qstval.lower() == "false":
                self.interruptonerror = False
            elif qstval.lower() == "true":
                self.interruptonerror = True
            qstval = str(
                settings.value("Configuration/LastImageFileName", type=str))
            if qstval:
                self.imagename = qstval
            qstval = str(
                settings.value("Configuration/LastMaskImageFileName", type=str))
            if qstval:
                self.maskimagename = qstval
            qstval = str(
                settings.value(
                    "Configuration/LastBackgroundImageFileName", type=str))
            if qstval:
                self.bkgimagename = qstval
            qstval = str(
                settings.value(
                    "Configuration/LastBrightFieldImageFileName", type=str))
            if qstval:
                self.bfimagename = qstval
            qstval = str(
                settings.value("Configuration/LastCalibrationFileName", type=str))
            if qstval:
                self.calibrationfilename = qstval

            qstval = str(
                settings.value(
                    "Configuration/StatisticsWithoutScaling", type=str))
            if qstval.lower() == "false":
                self.statswoscaling = False

            qstval = \
                settings.value(
                    "Configuration/ImageSources", type=str)
            if qstval:
                self.imagesources = str(qstval)

            qstval = \
                settings.value(
                    "Configuration/ToolWidgets", type=str)
            if qstval:
                self.toolwidgets = str(qstval)

            qstval = \
                settings.value(
                    "Configuration/ZMQStreamTopics", type=str)
            if qstval:
                self.zmqtopics = [str(tp) for tp in qstval]

            qstval2 = \
                settings.value(
                    "Configuration/ASAPOStreams", type=str)
            qstval = \
                settings.value(
                    "Configuration/ASAPODataSources", type=str)
            if qstval:
                self.asapodatasources = [str(tp) for tp in qstval]
            elif qstval2:
                self.asapodatasources = [str(tp) for tp in qstval2]
            else:
                self.asapodatasources = []

            qstval = \
                settings.value(
                    "Configuration/ASAPOServer", type=str)
            if qstval:
                self.asaposerver = str(qstval)
            else:
                self.asaposerver = ""

            qstval = \
                settings.value(
                    "Configuration/ASAPOToken", type=str)
            if qstval:
                self.asapotoken = str(qstval)
            else:
                self.asapotoken = ""

            qstval = \
                settings.value(
                    "Configuration/ASAPOBeamtime", type=str)
            if qstval:
                self.asapobeamtime = str(qstval)
            else:
                self.asapobeamtime = ""

            qstval = \
                settings.value(
                    "Configuration/ASAPOSourcePath", type=str)
            if qstval:
                self.asaposourcepath = str(qstval)
            else:
                self.asaposourcepath = ""

            qstval = \
                settings.value(
                    "Configuration/HidraDetectorServers", type=str)
            if qstval:
                try:
                    json.loads(qstval)
                    self.detservers = qstval
                except Exception:
                    self.detsetvers = json.dumps([str(tp) for tp in qstval])

            qstval = str(
                settings.value(
                    "Configuration/HidraDefaultDetectorServers", type=str))
            if qstval.lower() == "false":
                self.defdetservers = False

            qstval = str(settings.value(
                "Configuration/AutoZMQStreamTopics", type=str))
            if qstval.lower() == "true":
                self.autozmqtopics = True

            qstval = str(
                settings.value("Configuration/DirectoryTranslation", type=str))
            if qstval:
                self.dirtrans = qstval

            qstval = str(
                settings.value("Configuration/TangoAttributes", type=str))
            if qstval:
                self.tangoattrs = qstval

            qstval = str(
                settings.value("Configuration/TangoDetectorAttributes", type=str))
            if qstval:
                self.tangodetattrs = qstval

            qstval = str(
                settings.value("Configuration/TineProperties", type=str))
            if qstval:
                self.tineprops = qstval

            qstval = str(
                settings.value("Configuration/EpicsPVNames", type=str))
            if qstval:
                self.epicspvnames = qstval
            qstval = str(
                settings.value("Configuration/EpicsPVShapes", type=str))
            if qstval:
                self.epicspvshapes = qstval

            qstval = str(
                settings.value("Configuration/DOOCSProperties", type=str))
            if qstval:
                self.doocsprops = qstval

            qstval = str(
                settings.value("Configuration/TangoEventsAttributes", type=str))
            if qstval:
                self.tangoevattrs = qstval

            qstval = str(
                settings.value("Configuration/TangoFileAttributes", type=str))
            if qstval:
                self.tangofileattrs = qstval

            qstval = str(
                settings.value("Configuration/TangoDirAttributes", type=str))
            if qstval:
                self.tangodirattrs = qstval

            qstval = str(
                settings.value("Configuration/HTTPURLs", type=str))
            if qstval:
                self.httpurls = qstval

            qstval = str(
                settings.value("Configuration/ZMQServers", type=str))
            if qstval:
                self.zmqservers = qstval

            qstval = str(
                settings.value("Configuration/StoreGeometry", type=str))
            if qstval.lower() == "true":
                self.storegeometry = True

            qstval = str(
                settings.value("Configuration/GeometryFromSource", type=str))
            if qstval.lower() == "true":
                self.geometryfromsource = True

            qstval = str(
                settings.value("Configuration/ROIsColors", type=str))
            if qstval:
                self.roiscolors = qstval

            qstval = str(
                settings.value("Configuration/Filters", type=str))
            if qstval:
                self.filters = qstval

            qstval = str(
                settings.value(
                    "Configuration/SourceDisplayParams", type=str))
            if qstval.lower() == "true":
                self.sourcedisplay = True

            try:
                self.centerx = float(
                    settings.value("Tools/CenterX", type=str))
            except Exception:
                pass
            try:
                self.centery = float(
                    settings.value("Tools/CenterY", type=str))
            except Exception:
                pass
            try:
                self.energy = float(
                    settings.value("Tools/Energy", type=str))
            except Exception:
                pass

            try:
                self.pixelsizex = float(
                    settings.value("Tools/PixelSizeX", type=str))
            except Exception:
                pass
            try:
                self.pixelsizey = float(
                    settings.value("Tools/PixelSizeY", type=str))
            except Exception:
                pass
            try:
                self.detdistance = float(
                    settings.value("Tools/DetectorDistance", type=str))
            except Exception:
                pass
            try:
                self.detponi1 = float(
                    settings.value("Tools/DetectorPONI1", type=str))
            except Exception:
                pass
            try:
                self.detponi2 = float(
                    settings.value("Tools/DetectorPONI2", type=str))
            except Exception:
                pass
            try:
                self.diffnpt = float(
                    settings.value("Tools/DiffractogramNPT", type=str))
            except Exception:
                pass
            qstval = str(settings.value(
                "Tools/CorrectSolidAngle", type=str))
            if qstval.lower() == "false":
                self.correctsolidangle = False
            try:
                self.detrot1 = float(
                    settings.value("Tools/DetectorRot1", type=str))
            except Exception:
                pass
            try:
                self.detrot2 = float(
                    settings.value("Tools/DetectorRot2", type=str))
            except Exception:
                pass
            try:
                self.detrot3 = float(
                    settings.value("Tools/DetectorRot3", type=str))
            except Exception:
                pass
            qstval = str(
                settings.value("Tools/DetectorName", type=str))
            if qstval:
                self.detname = qstval
            qstval = str(
                settings.value("Tools/DetectorSplineFile",
                               type=str))
            if qstval:
                self.detsplinefile = qstval

            self.__loadDisplayParams(settings)
            self.__loadCustomGradients(settings)
            self.updateAISettings()
            return status

        def updateAISettings(self):
            """ update AI settings
            """
            if PYFAI:
                wvln = self.energy2m(self.energy)
                pixel1 = self.distance2m((self.pixelsizey, "um"))
                pixel2 = self.distance2m((self.pixelsizex, "um"))
                splineFile = self.detsplinefile or None
                detector = self.detname or None
                detdistance = self.distance2m((self.detdistance, "mm"))

                with QtCore.QMutexLocker(self.aimutex):
                    if wvln and detdistance and pixel1 and pixel2:
                        from pyFAI.azimuthalIntegrator import AzimuthalIntegrator
                        self.ai = AzimuthalIntegrator(
                            dist=detdistance,
                            poni1=self.detponi1,
                            poni2=self.detponi2,
                            rot1=self.detrot1,
                            rot2=self.detrot2,
                            rot3=self.detrot3,
                            pixel1=pixel1,
                            pixel2=pixel2,
                            splineFile=splineFile,
                            detector=detector,
                            wavelength=wvln)
                        if not self.detponi1 and not self.detponi2 \
                           and self.centerx and self.centery:
                            aif = self.ai.getFit2D()
                            self.ai.setFit2D(aif["directDist"],
                                             self.centerx,
                                             self.centery,
                                             aif["tilt"],
                                             aif["tiltPlanRotation"])

        def store(self, settings):
            """ Stores settings in QSettings object

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            """
            settings.setValue(
                "Configuration/AddROIs",
                self.addrois)
            settings.setValue(
                "Configuration/OrderROIs",
                self.orderrois)
            settings.setValue(
                "Configuration/ImageChannels",
                self.imagechannels)
            settings.setValue(
                "Configuration/ShowSubtraction",
                self.showsub)
            settings.setValue(
                "Configuration/ShowNormalization",
                self.shownorm)
            settings.setValue(
                "Configuration/ShowSubtractionScaling",
                self.showsubsf)
            settings.setValue(
                "Configuration/ShowNormalizationScaling",
                self.shownormsf)
            settings.setValue(
                "Configuration/ShowTransformations",
                self.showtrans)
            settings.setValue(
                "Configuration/ShowIntensityScaling",
                self.showscale)
            settings.setValue(
                "Configuration/ShowIntensityLevels",
                self.showlevels)
            settings.setValue(
                "Configuration/ShowFrameRate",
                self.showframerate)
            settings.setValue(
                "Configuration/ShowHistogram",
                self.showhisto)
            settings.setValue(
                "Configuration/ShowAdditionalHistogram",
                self.showaddhisto)
            settings.setValue(
                "Configuration/ShowMaskWidget",
                self.showmask)
            settings.setValue(
                "Configuration/ShowRangeWindowWidget",
                self.showrange)
            settings.setValue(
                "Configuration/ShowFilterWidget",
                self.showfilters)
            settings.setValue(
                "Configuration/ShowMemoryBuffer",
                self.showmbuffer)
            settings.setValue(
                "Configuration/ShowHighValueMaskWidget",
                self.showhighvaluemask)
            settings.setValue(
                "Configuration/ShowStatistics",
                self.showstats)
            settings.setValue(
                "Configuration/ShowImageSteps",
                self.showsteps)
            settings.setValue(
                "Configuration/CrossHairLocker",
                self.crosshairlocker)
            settings.setValue(
                "Configuration/CalculateVariance",
                self.calcvariance)
            settings.setValue(
                "Configuration/RefreshRate",
                self.refreshrate)
            settings.setValue(
                "Configuration/ToolRefreshTime",
                self.toolrefreshtime)
            settings.setValue(
                "Configuration/ToolPollingInterval",
                self.toolpollinginterval)
            settings.setValue(
                "Configuration/SecPort",
                self.secport)
            settings.setValue(
                "Configuration/FloatType",
                self.floattype)
            settings.setValue(
                "Configuration/HidraDataPort",
                self.hidraport)
            settings.setValue(
                "Configuration/MaxBufferSize",
                self.maxmbuffersize)
            settings.setValue(
                "Configuration/SecAutoPort",
                self.secautoport)
            settings.setValue(
                "Configuration/SecStream",
                self.secstream)
            settings.setValue(
                "Configuration/MaskingWithZeros",
                self.zeromask)
            settings.setValue(
                "Configuration/MaskingAsNAN",
                self.nanmask)
            settings.setValue(
                "Configuration/AddMaxValueToNegativeMask",
                self.negmask)
            settings.setValue(
                "Configuration/Sardana",
                self.sardana)
            settings.setValue(
                "Configuration/InterruptOnError",
                self.interruptonerror)
            settings.setValue(
                "Configuration/SourceTimeout",
                self.timeout)
            settings.setValue(
                "Configuration/NumberOfImageSources",
                self.nrsources)
            settings.setValue(
                "Configuration/AspectLocked",
                self.aspectlocked)
            settings.setValue(
                "Configuration/AutoDownSample",
                self.autodownsample)
            settings.setValue(
                "Configuration/KeepOriginalCoordinates",
                self.keepcoords)
            settings.setValue(
                "Configuration/AccelerateBufferSum",
                self.accelbuffersum)
            settings.setValue(
                "Configuration/ChannelsWithGradientColors",
                self.gradientcolors)
            settings.setValue(
                "Configuration/LazyImageSlider",
                self.lazyimageslider)
            settings.setValue(
                "Configuration/LastImageFileName",
                self.imagename)
            settings.setValue(
                "Configuration/LastMaskImageFileName",
                self.maskimagename)
            settings.setValue(
                "Configuration/LastCalibrationFileName",
                self.calibrationfilename)
            settings.setValue(
                "Configuration/LastBackgroundImageFileName",
                self.bkgimagename)
            settings.setValue(
                "Configuration/LastBrightFieldImageFileName",
                self.bfimagename)
            settings.setValue(
                "Configuration/StatisticsWithoutScaling",
                self.statswoscaling)
            settings.setValue(
                "Configuration/ImageSources",
                self.imagesources)
            settings.setValue(
                "Configuration/ToolWidgets",
                self.toolwidgets)
            settings.setValue(
                "Configuration/ZMQStreamTopics",
                self.zmqtopics)
            settings.setValue(
                "Configuration/ASAPODataSources",
                self.asapodatasources)
            settings.setValue(
                "Configuration/ASAPOServer",
                self.asaposerver)
            settings.setValue(
                "Configuration/ASAPOToken",
                self.asapotoken)
            settings.setValue(
                "Configuration/ASAPOBeamtime",
                self.asapobeamtime)
            settings.setValue(
                "Configuration/ASAPOSourcePath",
                self.asaposourcepath)
            settings.setValue(
                "Configuration/HidraDetectorServers",
                self.detservers)
            settings.setValue(
                "Configuration/HidraDefaultDetectorServers",
                self.defdetservers)
            settings.setValue(
                "Configuration/AutoZMQStreamTopics",
                self.autozmqtopics)
            settings.setValue(
                "Configuration/DirectoryTranslation",
                self.dirtrans)
            settings.setValue(
                "Configuration/TangoAttributes",
                self.tangoattrs)
            settings.setValue(
                "Configuration/TangoDetectorAttributes",
                self.tangodetattrs)
            settings.setValue(
                "Configuration/TineProperties",
                self.tineprops)
            settings.setValue(
                "Configuration/EpicsPVNames",
                self.epicspvnames)
            settings.setValue(
                "Configuration/EpicsPVShapes",
                self.epicspvshapes)
            settings.setValue(
                "Configuration/DOOCSProperties",
                self.doocsprops)
            settings.setValue(
                "Configuration/TangoEventsAttributes",
                self.tangoevattrs)
            settings.setValue(
                "Configuration/TangoFileAttributes",
                self.tangofileattrs)
            settings.setValue(
                "Configuration/TangoDirAttributes",
                self.tangodirattrs)
            settings.setValue(
                "Configuration/ZMQServers",
                self.zmqservers)
            settings.setValue(
                "Configuration/HTTPURLs",
                self.httpurls)
            settings.setValue(
                "Configuration/NXSLastImage",
                self.nxslast)
            settings.setValue(
                "Configuration/NXSFileOpen",
                self.nxsopen)
            settings.setValue(
                "Configuration/StoreGeometry",
                self.storegeometry)
            settings.setValue(
                "Tools/CorrectSolidAngle",
                self.correctsolidangle)
            settings.setValue(
                "Configuration/GeometryFromSource",
                self.geometryfromsource)
            settings.setValue(
                "Configuration/ROIsColors",
                self.roiscolors)
            settings.setValue(
                "Configuration/Filters",
                self.filters)
            settings.setValue(
                "Configuration/SendROIs",
                self.sendrois)
            settings.setValue(
                "Configuration/SendToolResults",
                self.sendresults)
            settings.setValue(
                "Configuration/SingleROIAliases",
                self.singlerois)
            settings.setValue(
                "Configuration/ShowAllROIs",
                self.showallrois)
            settings.setValue(
                "Configuration/SourceDisplayParams",
                self.sourcedisplay)

            if not self.storegeometry:
                self.centerx = 0.0
                self.centery = 0.0
                self.energy = 0.0
                self.pixelsizex = 0.0
                self.pixelsizey = 0.0
                self.detdistance = 0.0
                self.detrot1 = 0.0
                self.detrot2 = 0.0
                self.detrot3 = 0.0
                self.detponi1 = 0.0
                self.detponi2 = 0.0

            settings.setValue(
                "Tools/CenterX",
                self.centerx)
            settings.setValue(
                "Tools/CenterY",
                self.centery)
            settings.setValue(
                "Tools/Energy",
                self.energy)
            settings.setValue(
                "Tools/PixelSizeX",
                self.pixelsizex)
            settings.setValue(
                "Tools/PixelSizeY",
                self.pixelsizey)
            settings.setValue(
                "Tools/DetectorDistance",
                self.detdistance)
            settings.setValue(
                "Tools/DetectorPONI1",
                self.detponi1)
            settings.setValue(
                "Tools/DetectorPONI2",
                self.detponi2)
            settings.setValue(
                "Tools/DiffractogramNPT",
                self.diffnpt)
            settings.setValue(
                "Tools/DetectorRot1",
                self.detrot1)
            settings.setValue(
                "Tools/DetectorRot2",
                self.detrot2)
            settings.setValue(
                "Tools/DetectorRot3",
                self.detrot3)
            settings.setValue(
                "Tools/DetectorName",
                self.detname)
            settings.setValue(
                "Tools/DetectorSplineFile",
                self.detsplinefile)

            self.__storeDisplayParams(settings)
            self.__storeCustomGradients(settings)

        def length2ev(self, length):
            """ converts length to energy  in eV

            :param length: length as value in A or tuple with units
            :type length: :obj:`float` or (:obj:`float`, :obj:`str`)
            :returns: energy in eV
            :rtype: :obj:`float`
            """
            energy = None
            #: :obj:`float`  value of hc in eV * um
            hc = 1.23984193
            if length is not None:
                if type(length) in [list, tuple]:
                    if len(length) == 1:
                        if length[0]:
                            energy = hc * 10000 / length[0]
                    elif len(length) > 1:
                        if length[1] in self.__units['A']:
                            if length[0]:
                                energy = hc * 10000 / length[0]
                        elif length[1] in self.__units['nm']:
                            if length[0]:
                                energy = hc * 1000 / length[0]
                        elif length[1] in self.__units['um']:
                            if length[0]:
                                energy = hc / length[0]
                        elif length[1] in self.__units['m']:
                            if length[0]:
                                energy = hc * 1e-6 / length[0]
                        elif length[1] in self.__units['mm']:
                            if length[0]:
                                energy = hc * 1e-3 / length[0]
                        elif length[1] in self.__units['cm']:
                            if length[0]:
                                energy = hc * 1e-4 / length[0]
                else:
                    if length:
                        energy = hc * 10000 / length
            return energy

        def energy2m(self, energy):
            """ converts energy to m

            :param energy: energy as value in eV or tuple with units
            :type energy: :obj:`float` or (:obj:`float`, :obj:`str`)
            :returns: length in m
            :rtype: :obj:`float`
            """
            length = None
            #: :obj:`float`  value of hc in eV * um
            hc = 1.23984193
            if energy is not None:
                if type(energy) in [list, tuple]:
                    if len(energy) == 1:
                        if energy[0]:
                            length = hc * 1e-6 / energy[0]
                    elif len(energy) > 1:
                        if energy[1] in self.__units['eV']:
                            if energy[0]:
                                length = hc * 1e-6 / energy[0]
                        elif energy[1] in self.__units['keV']:
                            if energy[0]:
                                length = hc * 1e-3 / energy[0]
                        elif energy[1] in self.__units['MeV']:
                            if energy[0]:
                                length = hc / energy[0]
                elif energy:
                    length = hc * 1e-6 / energy
            return length

        def distance2mm(self, distance):
            """ converts distance to mm units

            :param distance: distance as value in m or tuple with units
            :type distance: :obj:`float` or (:obj:`float`, :obj:`str`)
            :returns: distance in mm
            :rtype: :obj:`float`
            """
            res = None
            if distance is not None:
                if type(distance) in [list, tuple]:
                    if len(distance) == 1:
                        res = distance[0] * 1e+3
                    elif len(distance) > 1:
                        if distance[1] in self.__units['A']:
                            res = distance[0] * 1e-7
                        elif distance[1] in self.__units['nm']:
                            res = distance[0] * 1e-6
                        elif distance[1] in self.__units['um']:
                            res = distance[0] * 1e-3
                        elif distance[1] in self.__units['km']:
                            res = distance[0] * 1e+6
                        elif distance[1] in self.__units['m']:
                            res = distance[0] * 1e+3
                        elif distance[1] in self.__units['mm']:
                            res = distance[0]
                        elif distance[1] in self.__units['cm']:
                            res = distance * 1e+1
                else:
                    res = distance * 1e+3
            return res

        def distance2m(self, distance):
            """ converts distance to m units

            :param distance: distance as value in m or tuple with units
            :type distance: :obj:`float` or (:obj:`float`, :obj:`str`)
            :returns: distance in m
            :rtype: :obj:`float`
            """
            res = None
            if distance is not None:
                if type(distance) in [list, tuple]:
                    if len(distance) == 1:
                        res = distance[0] * 1e+3
                    elif len(distance) > 1:
                        if distance[1] in self.__units['A']:
                            res = distance[0] * 1e-10
                        elif distance[1] in self.__units['nm']:
                            res = distance[0] * 1e-9
                        elif distance[1] in self.__units['um']:
                            res = distance[0] * 1e-6
                        elif distance[1] in self.__units['km']:
                            res = distance[0] * 1e+3
                        elif distance[1] in self.__units['m']:
                            res = distance[0]
                        elif distance[1] in self.__units['mm']:
                            res = distance[0] * 1e-3
                        elif distance[1] in self.__units['cm']:
                            res = distance * 1e-2
                else:
                    res = distance * 1e+3
            return res

        def distance2um(self, distance):
            """ converts distance to um units

            :param distance: distance as value in m or tuple with units
            :type distance: :obj:`float` or (:obj:`float`, :obj:`str`)
            :returns: distance in um
            :rtype: :obj:`float`
            """
            res = None
            if distance is not None:
                if type(distance) in [list, tuple]:
                    if len(distance) == 1:
                        res = distance[0] * 1e+6
                    elif len(distance) > 1:
                        if distance[1] in self.__units['A']:
                            res = distance[0] * 1e-4
                        elif distance[1] in self.__units['nm']:
                            res = distance[0] * 1e-3
                        elif distance[1] in self.__units['um']:
                            res = distance[0]
                        elif distance[1] in self.__units['km']:
                            res = distance[0] * 1e+9
                        elif distance[1] in self.__units['m']:
                            res = distance[0] * 1e+6
                        elif distance[1] in self.__units['mm']:
                            res = distance[0] * 1e+3
                        elif distance[1] in self.__units['cm']:
                            res = distance * 1e+4
                else:
                    res = distance * 1e+6
            return res

        def distance2pixels(self, distance, psize):
            """ converts distance to pixels

            :param distance: distance as value in pixels or tuple with units
            :type distance: :obj:`float` or (:obj:`float`, :obj:`str`)
            :param psize: pixel size
            :type psize: :obj:`float`
            :returns: distance in pixels
            :rtype: :obj:`float`
            """
            res = None
            if distance is not None:
                if type(distance) in [list, tuple]:
                    if len(distance) == 1:
                        res = distance[0]
                    elif len(distance) > 1:
                        if distance[1] in self.__units['pixel']:
                            res = distance[0]
                        elif distance[1] in self.__units['nm']:
                            res = distance[0] * 1e+3 / psize
                        elif distance[1] in self.__units['um']:
                            res = distance[0] / psize
                        elif distance[1] in self.__units['m']:
                            res = distance[0] * 1e-6 / psize
                        if distance[1] in self.__units['A']:
                            res = distance[0] * 1e+4 / psize
                        elif distance[1] in self.__units['mm']:
                            res = distance[0] * 1e-3 / psize
                        elif distance[1] in self.__units['cm']:
                            res = distance[0] * 1e-4 / psize
                else:
                    res = distance
            return res

        def pixelsize2um(self, psize):
            """ converts pixel size to um units

            :param psize: pixelsize as value in m or tuple with units
            :type psize: :obj:`float` or
                   (:obj:`float`, :obj:`str`, :obj:`float`, :obj:`str`)
            :returns: pixelsize in  um
            :rtype: (:obj:`float`, :obj:`float`)
            """
            resx = None
            resy = None
            if psize is not None:
                if type(psize) in [list, tuple]:
                    if len(psize) == 2:
                        if type(psize[0]) in [list, tuple]:
                            resx = self.distance2um(psize[0])
                        else:
                            resx = psize[0] * 1e+6
                        if type(psize[1]) in [list, tuple]:
                            resy = self.distance2um(psize[1])
                        else:
                            resy = psize[1] * 1e+6
                    elif len(psize) > 2:
                        if len(psize) == 3:
                            px, py, ux = psize
                            uy = ux
                        elif len(psize) >= 4:
                            px, ux,  py, uy = psize
                        resx = self.distance2um([px, ux])
                        resy = self.distance2um([py, uy])
            return resx, resy

        def xyposition2pixels(self, xypos):
            """ converts xy position to pixel units

            :param xypos: xy-position a tuple value or tuple with units
            :type xypos: :obj:`float` or
                   (:obj:`float`, :obj:`str`, :obj:`float`, :obj:`str`)
            :returns: xy-position in  pixels
            :rtype: (:obj:`float`, :obj:`float`)
            """
            resx = None
            resy = None
            if xypos is not None:
                if type(xypos) in [list, tuple]:
                    if len(xypos) == 2:
                        if type(xypos[0]) in [list, tuple]:
                            resx = self.distance2pixels(xypos[0], self.pixelsizex)
                        else:
                            resx = xypos[0]
                        if type(xypos[1]) in [list, tuple]:
                            resy = self.distance2pixels(xypos[1], self.pixelsizey)
                        else:
                            resy = xypos[1]

                    elif len(xypos) > 2:
                        if len(xypos) == 3:
                            px, py, ux = xypos
                            uy = ux
                        elif len(xypos) >= 4:
                            px, ux,  py, uy = xypos
                        resx = self.distance2pixels([px, ux], self.pixelsizex)
                        resy = self.distance2pixels([py, uy], self.pixelsizey)
            return resx, resy

        def updateDetectorParameters(self):
            """ update physical parameters

            """
            if PYFAI:
                with QtCore.QMutexLocker(self.aimutex):
                    aic = self.ai.get_config()
                    self.pixelsizex = self.distance2um(
                        (self.ai.get_pixel2(), "m"))
                    self.pixelsizey = self.distance2um(
                        (self.ai.get_pixel1(), "m"))
                self.detponi1 = aic["poni1"]
                self.detponi2 = aic["poni2"]
                self.detrot1 = aic["rot1"]
                self.detrot2 = aic["rot2"]
                self.detrot3 = aic["rot3"]
                self.detsplinefile = self.ai.splineFile
                self.detname = aic["detector"]
                self.detdistance = self.distance2mm(
                    (aic["dist"], "m"))
                self.energy = self.length2ev(
                    (float(aic["wavelength"]), "m"))
                with QtCore.QMutexLocker(self.aimutex):
                    aif = self.ai.getFit2D()
                    self.centerx = float(aif["centerX"])
                    self.centery = float(aif["centerY"])

        def updateMetaData(self, **kargs):
            """ update physical parameters

            :param kargs:  physical parameter dictionary
            :type kargs: :obj:`dict` < :obj:`str`, :obj:`any`>
            """
            # #: (:obj:`float`) x-coordinates of the center of the image
            # self.centerx = 0.0
            # #: (:obj:`float`) y-coordinates of the center of the image
            # self.centery = 0.0
            # #: (:obj:`float`) energy in eV
            # self.energy = 0.0
            # #: (:obj:`float`) pixel x-size in um
            # self.pixelsizex = 0.0
            # #: (:obj:`float`) pixel y-size in um
            # self.pixelsizey = 0.0
            # #: (:obj:`float`) detector distance in mm
            # self.detdistance = 0.0
            # beam_xy pixels
            # wavelength A
            # detector_distance m
            # pixel_size m
            if "wavelength" in kargs.keys():
                energy = self.length2ev(kargs["wavelength"])
                if energy is not None:
                    self.energy = energy

            if "detector_distance" in kargs.keys():
                detdistance = self.distance2mm(kargs["detector_distance"])
                if detdistance is not None:
                    self.detdistance = detdistance
            if "distance" in kargs.keys():
                detdistance = self.distance2mm(kargs["distance"])
                if detdistance is not None:
                    self.detdistance = detdistance

            if "pixel_size" in kargs.keys():
                psizex, psizey = self.pixelsize2um(kargs["pixel_size"])
                if psizex is not None and psizey is not None:
                    self.pixelsizex = psizex
                    self.pixelsizey = psizey

            if "x_pixel_size" in kargs.keys():
                psizex = self.distance2um(kargs["x_pixel_size"])
                if psizex is not None:
                    self.pixelsizex = psizex
            if "y_pixel_size" in kargs.keys():
                psizey = self.distance2um(kargs["y_pixel_size"])
                if psizey is not None:
                    self.pixelsizey = psizey

            if "beam_xy" in kargs.keys():
                cx, cy = self.xyposition2pixels(kargs["beam_xy"])
                if psizex is not None and psizey is not None:
                    self.centerx = cx
                    self.centery = cy
            if "beam_x" in kargs.keys():
                cx = self.distance2pixels(kargs["beam_x"], self.pixelsizex)
                if cx is not None:
                    self.centerx = cx
            if "beam_y" in kargs.keys():
                cy = self.distance2pixels(kargs["beam_y"], self.pixelsizey)
                if cy is not None:
                    self.centery = cy

            if "beam_center_x" in kargs.keys():
                cx = self.distance2pixels(kargs["beam_center_x"], self.pixelsizex)
                if cx is not None:
                    self.centerx = cx
            if "beam_center_y" in kargs.keys():
                cy = self.distance2pixels(kargs["beam_center_y"], self.pixelsizey)
                if cy is not None:
                    self.centery = cy

        def __storeCustomGradients(self, settings):
            """ Stores custom color gradients settings in QSettings object

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            """
            with QtCore.QMutexLocker(self.__mutex):
                for name, value in self.__customgradients.items():
                    settings.setValue(
                        "CustomColorGradients/%s" % (name), str(value))
                try:
                    settings.beginGroup("CustomColorGradients")
                    oldkeys = set([str(key) for key in settings.allKeys()]) - \
                        set(self.__customgradients.keys())
                    for key in oldkeys:
                        settings.remove(key)
                finally:
                    settings.endGroup()

        def __loadCustomGradients(self, settings):
            """ Loads custom color gradients settings in QSettings object

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            """
            with QtCore.QMutexLocker(self.__mutex):
                settings.beginGroup("CustomColorGradients")
                try:
                    for key in settings.allKeys():
                        qstval = str(
                            settings.value(
                                "%s" % str(key), type=str))
                        self.__customgradients[str(key)] = eval(str(qstval))
                finally:
                    settings.endGroup()

        def __storeDisplayParams(self, settings):
            """ Stores display parameters settings in QSettings object

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            """
            with QtCore.QMutexLocker(self.__mutex):
                for source, dct in self.__sourcedisplay.items():
                    for key, value in dct.items():
                        settings.setValue(
                            "Source_%s/%s" % (source, key),
                            value)
                    try:
                        settings.beginGroup("Source_%s" % source)
                        oldkeys = set([str(key) for key in settings.allKeys()]) - \
                            set(dct.keys())
                        for key in oldkeys:
                            settings.remove(key)
                    finally:
                        settings.endGroup()

        def __loadDisplayParams(self, settings):
            """ loads display parameters settings

            :param settings: QSettings object
            :type settings: :class:`pyqtgraph.QtCore.QSettings`
            """
            with QtCore.QMutexLocker(self.__mutex):
                qgroups = list(settings.childGroups())
                groups = [str(f) for f in qgroups
                          if str(f).startswith("Source_")]

                for gr in groups:
                    source = gr[7:]
                    if source not in self.__sourcedisplay.keys():
                        self.__sourcedisplay[source] = {}
                    settings.beginGroup(gr)
                    try:
                        for key in settings.allKeys():
                            qstval = str(
                                settings.value(
                                    "%s" % str(key), type=str))
                            self.__sourcedisplay[source][str(key)] = str(qstval)
                    finally:
                        settings.endGroup()