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.