@@ -106,19 +106,26 @@ exclude: list of str
106106 Exclude a manipulations from refinement by name
107107 (e.g. exclude=["scale", "stretch"] excludes the scale and stretch morphs).
108108scale: float
109- Apply scale factor. This multiplies the function ordinate by scale.
109+ Apply scale factor.
110+
111+ This multiplies the function ordinate by scale.
110112stretch: float
111- Stretch function grid by a fraction stretch. Specifically, this multiplies the function grid by 1+stretch.
113+ Stretch function grid by a fraction stretch.
114+
115+ This multiplies the function grid by 1+stretch.
112116squeeze: list of float
113117 Squeeze function grid given a polynomial
114- p(x) = squeeze[0]+squeeze[1]*x+...+squeeze[n]*x^n. n is dependent on the number
118+ p(x) = squeeze[0]+squeeze[1]*x+...+squeeze[n]*x^n.
119+
120+ n is dependent on the number
115121 of values in the user-inputted comma-separated list.
116122 The morph transforms the function grid from x to x+p(x).
117123 When this parameter is given, hshift is disabled.
118124 When n>1, stretch is disabled.
119125smear: float
120- Smear the peaks with a Gaussian of width smear. This
121- is done by convolving the function with a Gaussian
126+ Smear the peaks with a Gaussian of width smear.
127+
128+ This is done by convolving the function with a Gaussian
122129 with standard deviation smear. If both smear and
123130 smear_pdf are used, only smear_pdf will be
124131 applied.
@@ -129,6 +136,7 @@ smear_pdf: float
129136 applied.
130137slope: float
131138 Slope of the baseline used in converting from PDF to RDF.
139+
132140 This is used with the option smear_pdf. The slope will
133141 be estimated if not provided.
134142hshift: float
@@ -139,57 +147,119 @@ qdamp: float
139147 Dampen PDF by a factor qdamp.
140148radius: float
141149 Apply characteristic function of sphere with radius
142- given by parameter radius. If pradius is also specified, instead apply
150+ given by parameter radius.
151+
152+ If pradius is also specified, instead apply
143153 characteristic function of spheroid with equatorial
144154 radius radius and polar radius pradius.
145155pradius: float
146156 Apply characteristic function of spheroid with
147157 equatorial radius given by above parameter radius and polar radius pradius.
158+
148159 If only pradius is specified, instead apply
149160 characteristic function of sphere with radius pradius.
150161iradius: float
151162 Apply inverse characteristic function of sphere with
152- radius iradius. If ipradius is also specified, instead
163+ radius iradius.
164+
165+ If ipradius is also specified, instead
153166 apply inverse characteristic function of spheroid with
154167 equatorial radius iradius and polar radius ipradius.
155168ipradius: float
156169 Apply inverse characteristic function of spheroid with
157170 equatorial radius iradius and polar radius ipradius.
171+
158172 If only ipradius is specified, instead apply inverse
159173 characteristic function of sphere with radius ipradius.
160174funcy: tuple (function, dict)
175+ Apply a function to the y-axis of the (two-column) data.
176+
161177 This morph applies the function funcy[0] with parameters given in funcy[1].
162- The function funcy[0] must be a function of both the abscissa and ordinate
163- (e.g. take in at least two inputs with as many additional parameters as needed).
178+ The function funcy[0] take in as parameters both the abscissa and ordinate
179+ (i.e. take in at least two inputs with as many additional parameters as needed).
180+ The y-axis values of the data are then replaced by the return value of funcy[0].
181+
164182 For example, let's start with a two-column table with abscissa x and ordinate y.
165183 let us say we want to apply the function ::
166184
167185 def linear(x, y, a, b, c):
168186 return a * x + b * y + c
169187
170- This function takes in both the abscissa and ordinate on top of three additional
171- parameters a, b, and c. To use the funcy parameter with initial guesses
172- a=1.0, b=2.0, c=3.0, we would pass ``funcy=(linear, {a: 1.0, b: 2.0, c: 3.0}) ``.
173- For an example use-case, see the Python-Specific Morphs section below.
188+ This example function above takes in both the abscissa and ordinate on top of
189+ three additional parameters a, b, and c.
190+ To use the funcy parameter with parameter values a=1.0, b=2.0, and c=3.0,
191+ we would pass ``funcy=(linear, {"a": 1.0, "b": 2.0, "c": 3.0}) ``.
192+ For an explicit example, see the Python-Specific Morphs section below.
193+ funcx: tuple (function, dict)
194+ Apply a function to the x-axis of the (two-column) data.
195+
196+ This morph applies the function funcx[0] with parameters given in funcx[1].
197+ The function funcx[0] take in as parameters both the abscissa and ordinate
198+ (i.e. take in at least two inputs with as many additional parameters as needed).
199+ The x-axis values of the data are then replaced by the return value of funcx[0].
200+ Note that diffpy.morph requires the x-axis be monotonic increasing
201+ (i.e. for i < j, x[i] < x[j]): as such,
202+ if funcx[0] is not a monotonic increasing function of the provided x-axis data,
203+ the error ``x must be a strictly increasing sequence `` will be thrown.
174204
205+ For example, let's start with a two-column table with abscissa x and ordinate y.
206+ let us say we want to apply the function ::
207+
208+ def exponential(x, y, amp, decay):
209+ return abs(amp) * (1 - 2**(-decay * x))
210+
211+ This example function above takes in both the abscissa and ordinate on top of
212+ three additional parameters amp and decay.
213+ (Even though the ordinate is not used in the function,
214+ it is still required that the function take in both acscissa and ordinate.)
215+ To use the funcx parameter with parameter values amp=1.0 and decay=2.0,
216+ we would pass ``funcx=(exponential, {"amp": 1.0, "decay:: 2.0}) ``.
217+ For an explicit example, see the Python-Specific Morphs section below.
218+ funcxy: tuple (function, dict)
219+ Apply a function the (two-column) data.
220+
221+ This morph applies the function funcxy[0] with parameters given in funcxy[1].
222+ The function funcxy[0] take in as parameters both the abscissa and ordinate
223+ (i.e. take in at least two inputs with as many additional parameters as needed).
224+ The two columns of the data are then replaced by the two return values of funcxy[0].
225+
226+ For example, let's start with a two-column table with abscissa x and ordinate y.
227+ let us say we want to apply the function ::
228+
229+ def shift(x, y, hshift, vshift):
230+ return x + hshift, y + vshift
231+
232+ This example function above takes in both the abscissa and ordinate on top of
233+ two additional parameters hshift and vshift.
234+ To use the funcy parameter with parameter values hshift=1.0 and vshift=2.0,
235+ we would pass ``funcy=(shift, {"hshift": 1.0, "vshift": 1.0}) ``.
236+ For an example use-case, see the Python-Specific Morphs section below.
175237
176238Python-Specific Morphs
177239======================
178240
179241Some morphs in ``diffpy.morph `` are supported only in Python. Here, we detail
180242how they are used and how to call them.
181243
182- MorphFuncy : Applying custom functions
244+ MorphFunc : Applying custom functions
183245-------------------------------------
184246
247+ In these tutorial, we walk through how to use the ``MorphFunc `` morphs
248+ (``MorphFuncy ``, ``MorphFuncx ``, ``MorphFuncxy ``)
249+ with some example transformations.
250+
251+ Unlike other morphs that can be run from the command line,
252+ ``MorphFunc `` moprhs require a Python function and is therefore
253+ intended to be used through Python scripting.
254+
255+ MorphFuncy:
256+ ^^^^^^^^^^^
257+
185258The ``MorphFuncy `` morph allows users to apply a custom Python function
186259to the y-axis values of a dataset, enabling flexible and user-defined
187260transformations.
188261
189- In this tutorial, we walk through how to use ``MorphFuncy `` with an example
190- transformation. Unlike other morphs that can be run from the command line,
191- ``MorphFuncy `` requires a Python function and is therefore intended to be used
192- through Python scripting.
262+ Let's try out this morph!
193263
194264 1. Import the necessary modules into your Python script:
195265
@@ -230,7 +300,7 @@ through Python scripting.
230300
231301 .. code-block :: python
232302
233- morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T,np.array([x_target, y_target]).T,
303+ morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T, np.array([x_target, y_target]).T,
234304 funcy = (linear_function,{' scale' : 1.2 , ' offset' : 0.1 }))
235305
236306 5. Extract the fitted parameters from the result:
@@ -246,3 +316,85 @@ to generate the target (scale=20 & offset=0.8). This example shows how
246316``MorphFuncy `` can be used to fit and apply custom transformations. Now
247317it's your turn to experiment with other custom functions that may be useful
248318for analyzing your data.
319+
320+ MorphFuncx:
321+ ^^^^^^^^^^^
322+
323+ The ``MorphFuncx `` morph allows users to apply a custom Python function
324+ to the x-axis values of a dataset, similar to the ``MorphFuncy `` morph.
325+
326+ One caveat to this morph is that the x-axis values must remain monotonic
327+ increasing, so it is possible to run into errors when applying this morph.
328+ For example, if your initial grid is ``[-1, 0, 1] ``, and your function is
329+ ``lambda x, y: x**2 ``, the grid after the function is applied will be
330+ ``[1, 0, 1] ``, which is no longer monotonic increasing.
331+ In this case, the error ``x must be a strictly increasing sequence ``
332+ will be thrown.
333+
334+ Let's try out this morph!
335+
336+ 1. Import the necessary modules into your Python script:
337+
338+ .. code-block :: python
339+
340+ from diffpy.morph.morphpy import morph_arrays
341+ import numpy as np
342+
343+ 2. Define a custom Python function to apply a transformation to the data.
344+ The function must take ``x `` and ``y `` (1D arrays of the same length)
345+ along with named parameters, and return a transformed ``x `` array of the
346+ same length. Recall that this function must maintain the monotonic
347+ increasing nature of the ``x `` array.
348+
349+ For this example, we will use a simple exponential function transformation that
350+ greatly modifies the input:
351+
352+ .. code-block :: python
353+
354+ def exp_function (x , y , scale , rate ):
355+ return np.abs(scale) * np.exp(np.abs(rate) * x)
356+
357+ Notice that, though the function only uses the ``x `` input,
358+ the function signature takes in both ``x `` and ``y ``.
359+
360+ 3. Like in the previous example, we will use a sine function for the morph
361+ data and generate the target data by applying the decay transfomration
362+ with a known scale and rate:
363+
364+ .. code-block :: python
365+
366+ x_morph = np.linspace(0 , 10 , 1001 )
367+ y_morph = np.sin(x_morph)
368+ x_target = x_target = 20 * np.exp(0.8 * x_morph)
369+ y_target = y_morph.copy()
370+
371+ 4. Setup and run the morph using the ``morph_arrays(...) ``.
372+ ``morph_arrays `` expects the morph and target data as **2D arrays ** in
373+ *two-column * format ``[[x0, y0], [x1, y1], ...] ``. This will apply
374+ the user-defined function and refine the parameters to best align the
375+ morph data with the target data. This includes both the transformation
376+ parameters (our initial guess) and the transformation function itself:
377+
378+ .. code-block :: python
379+
380+ morph_params, morph_table = morph_arrays(np.array([x_morph, y_morph]).T, np.array([x_target, y_target]).T,
381+ funcx = (decay_function, {' scale' : 1.2 , ' rate' : 1.0 }))
382+
383+ 5. Extract the fitted parameters from the result:
384+
385+ .. code-block :: python
386+
387+ fitted_params = morph_params[" funcx" ]
388+ print (f " Fitted scale: { fitted_params[' scale' ]} " )
389+ print (f " Fitted rate: { fitted_params[' rate' ]} " )
390+
391+ Again, we should see that the fitted scale and offset values match the ones used
392+ to generate the target (scale=20 & rate=0.8).
393+
394+ For fun, you can plot the original function to the morphed function to see
395+ how much the
396+
397+ MorphFuncxy:
398+ ^^^^^^^^^^^^
399+ The ``MorphFuncxy `` morph allows users to apply a custom Python function
400+ to a dataset, ***.
0 commit comments