User Function pluginsΒΆ

A User Function plugin can be defined by a class or a function in a python package.

A user function plugin defined by a function is a simple python function with one argument: results which contain a python dictionary of ToolResults.

This function returns a python dictionary with x and y (list) data to plot , title, bottom and left (string) labels color and hvscolor (string) or (int) . For user plots with mutli-curves the python dictionary can contains nrplots (int) , x_%i, y_%i (list) data to plot, name_%i (list) names of plots, color_%i and hvscolor_%i (string) or (int) where %i runs from 1 to nrplots. If y_%i is set to None the previous plot will stay shown. Also if legend is set to True plots are discribed by its names in legend. A location of legend can be adjusted by lengend_offset (int) , e.g.

def positive(results):
    """ plot positive function values on the LineCut tool

    :param results: dictionary with tool results
    :type results: :obj:`dict`
    :returns: dictionary with user plot data
    :rtype: :obj:`dict`
    """
    userplot = {}
    if "linecut_1" in results:
        userplot = {"x": results["linecut_1"][0],
                    "y": [max(0.0, yy) for yy in results["linecut_1"][1]]}
    return userplot

A user function plugin defined by a class it should have defined __call__ method with one argument: results.

This __call__ function returns a python dictionary with x and y list data to plot and optionally title, bottom and left string labels.

Moreover, the class constructor has one configuration string argument initialized by an initialization parameter, e.g.

class LineCutFlat(object):

    """Flatten line cut"""

    def __init__(self, configuration=None):
        """ constructor

        :param configuration: JSON list with horizontal gap pixels to add
        :type configuration: :obj:`str`
        """
        #: (:obj:`list` <:obj: `str`>) list of indexes for gap
        self.__index = 1
        try:
            self.__flat = float(configuration)
        except Exception:
            self.__flat = 100000000.
            pass

    def __call__(self, results):
        """ call method

        :param results: dictionary with tool results
        :type results: :obj:`dict`
        :returns: dictionary with user plot data
        :rtype: :obj:`dict`
        """
        userplot = {}
    if "tool" in results and results["tool"] == "linecut":
        try:
            nrplots = int(results["nrlinecuts"])
        except Exception:
            nrplots = 0
        userplot["nrplots"] = nrplots
        userplot["title"] = "Linecuts flatten at '%s'" % (self.__flat)

        for i in range(nrplots):
            xlabel = "x_%s" % (i + 1)
            ylabel = "y_%s" % (i + 1)
            label = "linecut_%s" % (i + 1)
            cllabel = "hsvcolor_%s" % (i + 1)
            if label in results:
                userplot[xlabel] = results[label][0]
                userplot[ylabel] = [min(yy, self.__flat)
                                    for yy in results[label][1]]
                userplot[cllabel] = i/float(nrplots)
        if "unit" in results:
            userplot["bottom"] = results["unit"]
            userplot["left"] = "intensity"
        return userplot

or

import json


class DiffPDF(object):

    """diffpy PDF user function"""

    def __init__(self, configuration=None):
        """ constructor

        :param configuration: JSON list with config file and diff index
        :type configuration: :obj:`str`
        """
        #: (:obj:`list` <:obj: `str`>) list of indexes for gap
        self.__configfile = None

        config = None
        try:
            config = json.loads(configuration)
            try:
                self.__index = int(config[1])
            except Exception:
                self.__index = 1
            self.__configfile = str(config[0])
        except Exception:
            self.__index = 1
            self.__configfile = str(configuration)

        from diffpy.pdfgetx import loadPDFConfig
        self.__cfg = loadPDFConfig(self.__configfile)

    def __call__(self, results):
        """ call method

        :param results: dictionary with tool results
        :type results: :obj:`dict`
        :returns: dictionary with user plot data
        :rtype: :obj:`dict`
        """
        userplot = {}
        from diffpy.pdfgetx import PDFGetter
        self.__pg = PDFGetter(config=self.__cfg)
        label = "diff_%s" % self.__index
        if label in results and self.__configfile:
            qq = results[label][0]
            df = results[label][1]
            data_gr = self.__pg(qq, df)
            x = data_gr[0]
            y = data_gr[1]

            userplot = {
                "x": x, "y": y,
                "title": "DiffPDF: %s with %s" % (label, self.__configfile)
            }
        return userplot

or

import json


class LineCut(object):

    """ LineCut selection"""

    def __init__(self, configuration=None):
        """ constructor

        :param configuration: JSON list with horizontal gap pixels to add
        :type configuration: :obj:`str`
        """
        try:
            #: (:obj: `int`) line cut index
            self.__index = int(json.loads(configuration)[0])
        except Exception:
            self.__index = 1
        try:
            #: (:obj: `int`) buffer length
            self.__buflen = max(int(json.loads(configuration)[1]), 1)
        except Exception:
            self.__buflen = 20

        #: (:obj: `list`) buffer
        self.__buffer = []

    def __call__(self, results):
        """ call method

        :param results: dictionary with tool results
        :type results: :obj:`dict`
        :returns: dictionary with user plot data
        :rtype: :obj:`dict`
        """
        userplot = {}
        label = "linecut_%s" % self.__index
        if label in results:
            if len(self.__buffer) >= self.__buflen:
                self.__buffer.pop(0)
            self.__buffer.append([results[label][0], results[label][1]])
            userplot["nrplots"] = len(self.__buffer)
            for i, xy in enumerate(self.__buffer):
                userplot["x_%s" % (i + 1)] = xy[0]
                userplot["y_%s" % (i + 1)] = xy[1]
                if i != len(self.__buffer) - 1:
                    userplot["color_%s" % (i + 1)] = i/float(self.__buflen)
                else:
                    userplot["color_%s" % (i + 1)] = 'r'

            userplot["title"] = "History of %s" % label
            if "unit" in results:
                userplot["bottom"] = results["unit"]
                userplot["left"] = "intensity"
        return userplot

If image (numpy.array) is provided the user image is also plotted. When both image and function plots need to be displayed function has to be set to true. Also position and scale of the image can be set by image_scale namely [position_x, postion_y, scale_x, scale_y] . The colormap (string) sets a name of color maps. The levels of colormap can be set by tuple colormap_values (low, high) or separately colormap_low (float) and colormap_high (float) , e.g.

import json
import numpy as np


class DiffPDFImage(object):

    """diffpy PDF user function"""

    def __init__(self, configuration=None):
        """ constructor

        :param configuration: JSON list with config file and diff index
        :type configuration: :obj:`str`
        """
        #: (:obj:`list` <:obj: `str`>) list of indexes for gap
        self.__configfile = None

        #: (:obj: `int`) buffer length
        self.__buflen = 20
        #: (:obj: `float`) waterfall plot shift
        self.__shift = 1.0
        #: (:obj: `int`) diff label index
        self.__index = 1
        #: (:obj: `float`) number of characters cut from the image name
        self.__cut = -28
        #: (:obj: `list`) buffer
        self.__buffer = []
        #: (:obj: `int`) plot counter
        self.__counter = -1
        #: (:obj: `str`) plot mode i.e. all, image, function
        self.__mode = "all"

        self.__imgbuffer = None
        self.__ximgbuffer = None

        try:
            config = json.loads(configuration)
            self.__configfile = str(config[0])
            try:
                self.__index = int(config[1])
            except Exception:
                pass

            try:
                self.__buflen = max(int(config[2]), 1)
            except Exception:
                pass

            try:
                #: (:obj: `float`) buffer length
                self.__shift = float(config[3])
            except Exception:
                pass

            try:
                #: (:obj: `float`) buffer length
                self.__cut = int(config[4])
            except Exception:
                pass

            try:
                #: (:obj: `float`) buffer length
                self.__mode = str(config[5])
            except Exception:
                pass
        except Exception:
            self.__configfile = str(configuration)

        self.__counter = - self.__buflen

        from diffpy.pdfgetx import loadPDFConfig
        #: configuration
        self.__cfg = loadPDFConfig(self.__configfile)

    def __call__(self, results):
        """ call method

        :param results: dictionary with tool results
        :type results: :obj:`dict`
        :returns: dictionary with user plot data
        :rtype: :obj:`dict`
        """
        userplot = {}
        from diffpy.pdfgetx import PDFGetter
        self.__pg = PDFGetter(config=self.__cfg)
        label = "diff_%s" % self.__index

        if label in results and self.__configfile and "imagename" in results:
            qq = results[label][0]
            df = results[label][1]
            data_gr = self.__pg(qq, df)
            x = data_gr[0]
            y = data_gr[1]

            self.__counter += 1

            if self.__mode != "image":
                if len(self.__buffer) >= self.__buflen:
                    self.__buffer.pop(0)
                if self.__shift:
                    for i in range(len(self.__buffer)):
                        self.__buffer[i][1] = [(y + self.__shift)
                                               for y in self.__buffer[i][1]]
                self.__buffer.append([x, y, results["imagename"]])

                userplot["nrplots"] = len(self.__buffer)
                for i, xy in enumerate(self.__buffer):
                    userplot["x_%s" % (i + 1)] = xy[0]
                    userplot["y_%s" % (i + 1)] = xy[1]
                    userplot["name_%s" % (i + 1)] = "%s (+ %s)" % (
                        xy[2][self.__cut:],
                        ((len(self.__buffer) - i - 1) * self.__shift))
                    userplot["hsvcolor_%s" % (i + 1)] = \
                        ((i + max(0, self.__counter)) % self.__buflen) \
                        / float(self.__buflen)

                userplot["title"] = "History of %s" % label
                userplot["legend"] = True
                userplot["legend_offset"] = -1
                userplot["title"] = "DiffPDFImage: %s with %s" % (
                    label, self.__configfile)
                userplot["function"] = True

            if self.__mode != "function":
                newrow = np.array(y)
                if self.__imgbuffer is not None and \
                   self.__imgbuffer.shape[1] == newrow.shape[0]:
                    if self.__imgbuffer.shape[0] >= self.__buflen:
                        self.__imgbuffer = np.vstack(
                            [self.__imgbuffer[
                                self.__imgbuffer.shape[0]
                                - self.__buflen + 1:,
                                :],
                             newrow]
                        )
                    else:
                        self.__imgbuffer = np.vstack(
                            [self.__imgbuffer, newrow])
                else:
                    self.__imgbuffer = np.array([y])
                if self.__imgbuffer is not None:
                    userplot["image"] = self.__imgbuffer.T
                    xbuf = np.array(x)
                    pos = 0.0
                    sc = 1.0
                    if len(xbuf) > 0:
                        pos = xbuf[0]
                    if len(xbuf) > 1:
                        sc = float(xbuf[-1] - xbuf[0])/(len(xbuf) - 1)
                    self.__ximgbuffer = results[label][0]
                    userplot["iamge_scale"] = [
                        [pos, max(0, self.__counter)], [sc, 1]]

        return userplot

To configure user functions see User Functions settings.